Cleanup of new code pushed into 5.0 since last pull

Merged the different find_xxxx_table_in_list functions to one + some inline functions


mysql-test/r/view.result:
  Fix result (remove not used view from show tables)
sql/item_subselect.cc:
  Remove not used functions
sql/item_subselect.h:
  Remove not used functions
sql/mysql_priv.h:
  Merged the different find_xxxx_table_in_list functions to one + some inline functions
sql/sql_acl.cc:
  More debugging + simple cleanups
sql/sql_base.cc:
  Merged the different find_xxxx_table_in_list functions to one + some inline functions
  Indentation cleanups & more comments
sql/sql_delete.cc:
  Namechange
sql/sql_insert.cc:
  Simple optimizations & Style cleanups
  Merged common code (in mysql_prepare_insert_check_table)
sql/sql_lex.cc:
  function name changes
  More comments
sql/sql_parse.cc:
  Function name changes
  Made check_one_table_access returning bool
  More debugging in 'check_access'
  Added function 'check_some_access', which is used when creating a view
sql/sql_prepare.cc:
  Resetting flag directly after test makes code easier to read
sql/sql_select.cc:
  Code simplifications
sql/sql_show.cc:
  Indentation cleanups.
  Fixed typo in name
sql/sql_update.cc:
  Function name change
sql/sql_view.cc:
  Simple optimizations.
  Style fixes.
  Remove view_field_names[]
  Simplified 'check_key_in_view()'
sql/table.cc:
  Simplified new code in openfrm()
  variable name change i -> item
  Indentation changes
sql/table.h:
  Fixed typo in variable name
  Method name change in field iterator: end() -> end_of_fields()
tests/client_test.c:
  Changed number to macro
This commit is contained in:
unknown 2004-09-03 21:43:04 +03:00
parent 10d0dca6b4
commit d0211cf5be
18 changed files with 491 additions and 458 deletions

View File

@ -138,7 +138,6 @@ v3 VIEW
v4 VIEW
v5 VIEW
v6 VIEW
vt1 VIEW
show table status;
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
t1 MyISAM 9 Fixed 5 9 45 38654705663 1024 0 NULL # # NULL latin1_swedish_ci NULL
@ -148,7 +147,6 @@ v3 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL vie
v4 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view
v5 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view
v6 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view
vt1 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view
drop view v1,v2,v3,v4,v5,v6;
create view v1 (c,d,e,f) as select a,b,
a in (select a+2 from t1), a = all (select a from t1) from t1;

View File

@ -990,23 +990,6 @@ Item_in_subselect::select_transformer(JOIN *join)
}
Item_subselect::trans_res
Item_in_subselect::no_select_transform()
{
DBUG_ENTER("Item_in_subselect::no_select_transform");
// We have execute fix_fields() for left expression
SELECT_LEX *current= thd->lex->current_select, *up;
thd->lex->current_select= up= current->return_after_parsing();
if (left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
{
thd->lex->current_select= current;
DBUG_RETURN(RES_ERROR);
}
thd->lex->current_select= current;
DBUG_RETURN(RES_OK);
}
void Item_in_subselect::print(String *str)
{
if (transformed)

View File

@ -84,7 +84,6 @@ public:
null_value= 1;
}
virtual trans_res select_transformer(JOIN *join);
virtual trans_res no_select_transform() { return RES_OK; }
bool assigned() { return value_assigned; }
void assigned(bool a) { value_assigned= a; }
enum Type type() const;
@ -220,7 +219,6 @@ public:
was_null= 0;
}
trans_res select_transformer(JOIN *join);
trans_res no_select_transform();
trans_res single_value_transformer(JOIN *join,
Comp_creator *func);
trans_res row_value_transformer(JOIN * join);

View File

@ -398,8 +398,9 @@ void free_items(Item *item);
void cleanup_items(Item *item);
class THD;
void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
int check_one_table_access(THD *thd, ulong privilege,
bool check_one_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables);
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list);
int multi_update_precheck(THD *thd, TABLE_LIST *tables);
@ -764,12 +765,10 @@ void free_io_cache(TABLE *entry);
void intern_close_table(TABLE *entry);
bool close_thread_table(THD *thd, TABLE **table_ptr);
void close_temporary_tables(THD *thd);
TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
const char *db_name,
const char *table_name);
TABLE_LIST * find_real_table_in_local_list(TABLE_LIST *table,
const char *db_name,
const char *table_name);
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
uint offset_to_list,
const char *db_name,
const char *table_name);
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
void close_temporary(TABLE *table, bool delete_table=1);
@ -785,6 +784,23 @@ int fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors);
int fill_record(Field **field,List<Item> &values, bool ignore_errors);
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild);
inline TABLE_LIST *find_table_in_global_list(TABLE_LIST *table,
const char *db_name,
const char *table_name)
{
return find_table_in_list(table, offsetof(TABLE_LIST, next_global),
db_name, table_name);
}
inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table,
const char *db_name,
const char *table_name)
{
return find_table_in_list(table, offsetof(TABLE_LIST, next_local),
db_name, table_name);
}
/* sql_calc.cc */
bool eval_const_cond(COND *cond);

View File

@ -2750,7 +2750,22 @@ void grant_reload(THD *thd)
/****************************************************************************
Check table level grants
All errors are written directly to the client if no_errors is given !
SYNPOSIS
bool check_grant()
thd Thread handler
want_access Bits of privileges user needs to have
tables List of tables to check. The user should have 'want_access'
to all tables in list.
show_table <> 0 if we are in show table. In this case it's enough to have
any privilege for the table
number Check at most this number of tables.
no_errors If 0 then we write an error. The error is sent directly to
the client
RETURN
0 ok
1 Error: User did not have the requested privielges
****************************************************************************/
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
@ -2758,14 +2773,17 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
{
TABLE_LIST *table;
char *user = thd->priv_user;
DBUG_ENTER("check_grant");
DBUG_ASSERT(number > 0);
want_access &= ~thd->master_access;
want_access&= ~thd->master_access;
if (!want_access)
return 0; // ok
DBUG_RETURN(0); // ok
rw_rdlock(&LOCK_grant);
for (table= tables; table && number--; table= table->next_global)
{
GRANT_TABLE *grant_table;
if (!(~table->grant.privilege & want_access) || table->derived)
{
/*
@ -2775,10 +2793,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
table->grant.want_privilege= 0;
continue; // Already checked
}
GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,
table->db,user,
table->real_name,0);
if (!grant_table)
if (!(grant_table= table_hash_search(thd->host,thd->ip,
table->db,user, table->real_name,0)))
{
want_access &= ~table->grant.privilege;
goto err; // No grants
@ -2802,7 +2818,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
}
}
rw_unlock(&LOCK_grant);
return 0;
DBUG_RETURN(0);
err:
rw_unlock(&LOCK_grant);
@ -2837,7 +2853,7 @@ err:
thd->host_or_ip,
table ? table->real_name : "unknown");
}
return 1;
DBUG_RETURN(1);
}
@ -2931,7 +2947,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
if (!(grant_table= grant->grant_table))
goto err; /* purecov: inspected */
for (; fields->end(); fields->next())
for (; !fields->end_of_fields(); fields->next())
{
const char *field_name= fields->name();
grant_column= column_hash_search(grant_table, field_name,

View File

@ -548,81 +548,37 @@ void close_temporary_tables(THD *thd)
thd->temporary_tables=0;
}
#ifdef UNUSED
/*
Find first suitable table by alias in given list.
Find table in list.
SYNOPSIS
find_table_in_list()
table - pointer to table list
db_name - data base name or 0 for any
table_name - table name or 0 for any
table Pointer to table list
offset Offset to which list in table structure to use
db_name Data base name
table_name Table name
NOTES:
This is called by find_table_in_local_list() and
find_table_in_global_list().
RETURN VALUES
NULL Table not found
# Pointer to found table.
*/
TABLE_LIST * find_table_in_list(TABLE_LIST *table,
const char *db_name, const char *table_name)
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
uint offset,
const char *db_name,
const char *table_name)
{
for (; table; table= table->next)
if ((!db_name || !strcmp(table->db, db_name)) &&
(!table_name || !my_strcasecmp(table_alias_charset,
table->alias, table_name)))
break;
return table;
}
#endif /*UNUSED*/
/*
Find real table in given global list.
SYNOPSIS
find_real_table_in_list()
table - pointer to table list
db_name - data base name
table_name - table name
RETURN VALUES
NULL Table not found
# Pointer to found table.
*/
TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
const char *db_name,
const char *table_name)
{
for (; table; table= table->next_global)
if (!strcmp(table->db, db_name) &&
!strcmp(table->real_name, table_name))
break;
return table;
}
/*
Find real table in given local list.
SYNOPSIS
find_real_table_in_local_list()
table - pointer to table list
db_name - data base name
table_name - table name
RETURN VALUES
NULL Table not found
# Pointer to found table.
*/
TABLE_LIST * find_real_table_in_local_list(TABLE_LIST *table,
const char *db_name,
const char *table_name)
{
for (; table; table= table->next_local)
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
{
if (!strcmp(table->db, db_name) &&
!strcmp(table->real_name, table_name))
break;
}
return table;
}
@ -1363,7 +1319,7 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
db Database name
name Table name
alias Alias name
table_desc TABLE_LIST descriptor
table_desc TABLE_LIST descriptor (used with views)
mem_root temporary mem_root for parsing
NOTES
@ -1403,10 +1359,10 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
if (!entry->crashed)
{
/*
Frm file could not be found on disk
Since it does not exist, no one can be using it
LOCK_open has been locked to protect from someone else
trying to discover the table at the same time.
Frm file could not be found on disk
Since it does not exist, no one can be using it
LOCK_open has been locked to protect from someone else
trying to discover the table at the same time.
*/
if (discover_retry_count++ != 0)
goto err;
@ -1603,7 +1559,7 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
tables->table->grant= tables->grant;
}
thd->proc_info=0;
free_root(&new_frm_mem, MYF(0));
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
DBUG_RETURN(result);
}
@ -1671,7 +1627,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
thd->proc_info="Opening table";
thd->current_tablenr= 0;
while (!(table= open_table(thd, table_list, 0, &refresh)) && refresh) ;
while (!(table= open_table(thd, table_list, 0, &refresh)) && refresh)
;
if (table)
{
@ -1900,7 +1857,7 @@ bool rm_temporary_table(enum db_type base, char *path)
** return unique field
******************************************************************************/
// Special Field pointers for find_field_in_tables returning
/* Special Field pointers for find_field_in_tables returning */
const Field *not_found_field= (Field*) 0x1;
const Field *view_ref_found= (Field*) 0x2;
@ -1979,6 +1936,7 @@ Field *find_field_in_table(THD *thd, TABLE_LIST *table_list,
return fld;
}
/*
Find field in table
@ -2561,23 +2519,47 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
}
/****************************************************************************
This just drops in all fields instead of current '*' field
Returns pointer to last inserted field if ok
****************************************************************************/
/*
Drops in all fields instead of current '*' field
SYNOPSIS
insert_fields()
thd Thread handler
tables List of tables
db_name Database name in case of 'database_name.table_name.*'
table_name Table name in case of 'table_name.*'
it Pointer to '*'
any_privileges 0 If we should ensure that we have SELECT privileges
for all columns
1 If any privilege is ok
RETURN
0 ok
'it' is updated to point at last inserted
1 error. The error message is sent to client
*/
bool
insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
const char *table_name, List_iterator<Item> *it,
bool any_privileges)
{
/* allocate variables on stack to avoid pool alloaction */
Field_iterator_table table_iter;
Field_iterator_view view_iter;
uint found;
DBUG_ENTER("insert_fields");
found=0;
found= 0;
for (; tables; tables= tables->next_local)
{
TABLE *table=tables->table;
Field_iterator *iterator;
TABLE_LIST *natural_join_table;
Field *field;
TABLE_LIST *embedded;
TABLE_LIST *last;
TABLE_LIST *embedding;
TABLE *table= tables->table;
if (!table_name || (!my_strcasecmp(table_alias_charset, table_name,
tables->alias) &&
(!db_name || !strcmp(tables->db,db_name))))
@ -2588,36 +2570,26 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
{
if (tables->view)
{
Field_iterator_view fields;
fields.set(tables);
view_iter.set(tables);
if (check_grant_all_columns(thd, SELECT_ACL, &tables->grant,
tables->view_db.str,
tables->view_name.str,
&fields))
DBUG_RETURN(1);
&view_iter))
goto err;
}
else
{
Field_iterator_table fields;
fields.set(tables);
table_iter.set(tables);
if (check_grant_all_columns(thd, SELECT_ACL, &table->grant,
table->table_cache_key, table->real_name,
&fields))
DBUG_RETURN(1);
&table_iter))
goto err;
}
}
#endif
/* allocate 2 variables on stack to avoid pool alloaction */
Field_iterator_table table_iter;
Field_iterator_view view_iter;
Field_iterator *iterator;
TABLE_LIST *natural_join_table= 0;
Field *field;
thd->used_tables|=table->map;
TABLE_LIST *embedded= tables;
TABLE_LIST *last= embedded;
TABLE_LIST *embedding;
natural_join_table= 0;
thd->used_tables|= table->map;
last= embedded= tables;
while ((embedding= embedded->embedding) &&
embedding->join_list->elements != 1)
@ -2648,7 +2620,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
iterator= &table_iter;
iterator->set(tables);
for (; iterator->end(); iterator->next())
for (; !iterator->end_of_fields(); iterator->next())
{
Item *not_used_item;
uint not_used_field_index= NO_CACHED_FIELD_INDEX;
@ -2699,9 +2671,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
thd->host_or_ip,
fld->field_name,
tab);
/* TODO: should be removed to have only one send_error */
send_error(thd);
DBUG_RETURN(1);
goto err;
}
}
#endif
@ -2735,15 +2705,17 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
table->used_fields=table->fields;
}
}
if (!found)
{
if (!table_name)
my_error(ER_NO_TABLES_USED,MYF(0));
else
my_error(ER_BAD_TABLE_ERROR,MYF(0),table_name);
send_error(thd);
}
DBUG_RETURN(!found);
if (found)
DBUG_RETURN(0);
if (!table_name)
my_error(ER_NO_TABLES_USED, MYF(0));
else
my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name);
err:
send_error(thd);
DBUG_RETURN(1);
}
@ -2832,13 +2804,16 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
TABLE *t1=tab1->table;
TABLE *t2=tab2->table;
/* allocate 2 variables on stack to avoid pool alloaction */
Field_iterator_table table_iter;
Field_iterator_view view_iter;
Field_iterator *iterator;
Field *t1_field, *t2_field;
Item *item_t2;
Item_cond_and *cond_and=new Item_cond_and();
if (!cond_and) // If not out of memory
DBUG_RETURN(1);
cond_and->top_level_item();
@ -2854,9 +2829,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
table_iter.set(tab1);
}
Field *t1_field, *t2_field;
Item *item_t2;
for (; iterator->end(); iterator->next())
for (; !iterator->end_of_fields(); iterator->next())
{
const char *t1_field_name= iterator->name();
uint not_used_field_index= NO_CACHED_FIELD_INDEX;
@ -3190,17 +3163,19 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
table_desc TABLE_LIST descriptor
mem_root temporary MEM_ROOT for parsing
*/
static my_bool
open_new_frm(const char *path, const char *alias, uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
MEM_ROOT *mem_root)
{
DBUG_ENTER("open_new_frm");
LEX_STRING pathstr;
pathstr.str= (char *)path;
File_parser *parser;
DBUG_ENTER("open_new_frm");
pathstr.str= (char*) path;
pathstr.length= strlen(path);
File_parser *parser= sql_parse_prepare(&pathstr, mem_root, 1);
if (parser)
if ((parser= sql_parse_prepare(&pathstr, mem_root, 1)))
{
if (!strncmp("VIEW", parser->type()->str, parser->type()->length))
{
@ -3217,10 +3192,7 @@ open_new_frm(const char *path, const char *alias, uint db_stat, uint prgflag,
bzero(outparam, sizeof(outparam)); // do not run repair
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
else
{
DBUG_RETURN(1);
}
DBUG_RETURN(0);
DBUG_RETURN(1);
}

View File

@ -282,7 +282,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
DBUG_RETURN(-1);
}
if (find_real_table_in_list(table_list->next_global,
if (find_table_in_global_list(table_list->next_global,
table_list->db, table_list->real_name))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);

View File

@ -51,6 +51,8 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
List<Item> &values, ulong counter, bool check_unique)
{
TABLE *table= table_list->table;
int error;
if (fields.elements == 0 && values.elements != 0)
{
if (values.elements != table->fields)
@ -61,11 +63,11 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
return -1;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option)
{
Field_iterator_table fields;
fields.set_table(table);
if (grant_option &&
check_grant_all_columns(thd, INSERT_ACL, &table->grant,
if (check_grant_all_columns(thd, INSERT_ACL, &table->grant,
table->table_cache_key, table->real_name,
&fields))
return -1;
@ -75,7 +77,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
}
else
{ // Part field list
TABLE_LIST *save_next= table_list->next_local;
TABLE_LIST *save_next;
if (fields.elements != values.elements)
{
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
@ -84,14 +86,13 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
return -1;
}
table_list->next_local= 0;
thd->dupp_field=0;
if (setup_fields(thd, 0, table_list, fields, 1, 0, 0))
{
table_list->next_local= save_next;
return -1;
}
save_next= table_list->next_local; // fields only from first table
table_list->next_local= 0;
error= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
table_list->next_local= save_next;
if (error)
return -1; // setup_fields failed
if (check_unique && thd->dupp_field)
{
@ -407,7 +408,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
!thd->cuted_fields))
{
thd->row_count_func= info.copied+info.deleted+info.updated;
send_ok(thd, (ulong) (ulong) thd->row_count_func, id);
send_ok(thd, (ulong) thd->row_count_func, id);
}
else
{
@ -420,7 +421,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
(ulong) (info.deleted+info.updated), (ulong) thd->cuted_fields);
thd->row_count_func= info.copied+info.deleted+info.updated;
::send_ok(thd, (ulong) thd->row_count_func, (ulonglong)id,buff);
::send_ok(thd, (ulong) thd->row_count_func, id, buff);
}
free_underlaid_joins(thd, &thd->lex->select_lex);
table->insert_values=0;
@ -444,46 +445,58 @@ abort:
check_view_insertability()
view - reference on VIEW
IMPLEMENTATION
A view is insertable if the folloings are true:
- All columns in the view are columns from a table
- All not used columns in table have a default values
- All field in view are unique (not referring to the same column)
RETURN
FALSE - OK
view->contain_auto_increment is 1 if and only if the view contains an
auto_increment field
TRUE - can't be used for insert
*/
static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
{
uint num= view->view->select_lex.item_list.elements;
TABLE *table= view->table;
Item **trans_start= view->field_translation, **trans_end=trans_start+num;
Item **trans;
Field **field_ptr= table->field;
ulong other_query_id= query_id - 1;
DBUG_ENTER("check_key_in_view");
uint i;
TABLE *table= view->table;
Item **trans= view->field_translation;
Field **field_ptr= table->field;
uint num= view->view->select_lex.item_list.elements;
ulong other_query_id= query_id - 1;
DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
view->contain_auto_increment= 0;
/* check simplicity and prepare unique test of view */
for (i= 0; i < num; i++)
for (trans= trans_start; trans != trans_end; trans++)
{
Item_field *field;
/* simple SELECT list entry (field without expression) */
if (trans[i]->type() != Item::FIELD_ITEM)
if ((*trans)->type() != Item::FIELD_ITEM)
DBUG_RETURN(TRUE);
if (((Item_field *)trans[i])->field->type() == Field::NEXT_NUMBER)
field= (Item_field *)(*trans);
if (field->field->unireg_check == Field::NEXT_NUMBER)
view->contain_auto_increment= 1;
/* prepare unique test */
((Item_field *)trans[i])->field->query_id= other_query_id;
field->field->query_id= other_query_id;
}
/* unique test */
for (i= 0; i < num; i++)
for (trans= trans_start; trans != trans_end; trans++)
{
Item_field *field= (Item_field *)trans[i];
/* Thanks to test above, we know that all columns are of type Item_field */
Item_field *field= (Item_field *)(*trans);
if (field->field->query_id == query_id)
DBUG_RETURN(TRUE);
field->field->query_id= query_id;
}
/* VIEW contain all fields without default value */
for (; *field_ptr; ++field_ptr)
for (; *field_ptr; field_ptr++)
{
Field *field= *field_ptr;
/* field have not default value */
@ -491,14 +504,13 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
(table->timestamp_field != field ||
field->unireg_check == Field::TIMESTAMP_UN_FIELD))
{
uint i= 0;
for (; i < num; i++)
for (trans= trans_start; ; trans++)
{
if (((Item_field *)trans[i])->field == *field_ptr)
break;
if (trans == trans_end)
DBUG_RETURN(TRUE); // Field was not part of view
if (((Item_field *)(*trans))->field == *field_ptr)
break; // ok
}
if (i >= num)
DBUG_RETURN(TRUE);
}
}
DBUG_RETURN(FALSE);
@ -506,29 +518,28 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
/*
Prepare items in INSERT statement
Check if table can be updated
SYNOPSIS
mysql_prepare_insert()
thd - thread handler
table_list - global/local table list
mysql_prepare_insert_check_table()
thd Thread handle
table_list Table list (only one table)
fields List of fields to be updated
where Pointer to where clause
RETURN VALUE
0 - OK
-1 - error (message is not sent to user)
RETURN
0 ok
1 ERROR
*/
int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
List<Item> &fields, List_item *values,
List<Item> &update_fields, List<Item> &update_values,
enum_duplicates duplic)
static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, COND **where)
{
bool insert_into_view= (table_list->view != 0);
DBUG_ENTER("mysql_prepare_insert");
DBUG_ENTER("mysql_prepare_insert_check_table");
/* TODO: use this condition for 'WHITH CHECK OPTION' */
Item *unused_conds= 0;
if (setup_tables(thd, table_list, &unused_conds))
DBUG_RETURN(-1);
if (setup_tables(thd, table_list, where))
DBUG_RETURN(1);
if (insert_into_view && !fields.elements)
{
@ -542,8 +553,37 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
check_view_insertability(table_list, thd->query_id)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
DBUG_RETURN(-1);
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
/*
Prepare items in INSERT statement
SYNOPSIS
mysql_prepare_insert()
thd Thread handler
table_list Global/local table list
RETURN VALUE
0 OK
-1 error (message is not sent to user)
*/
int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
List<Item> &fields, List_item *values,
List<Item> &update_fields, List<Item> &update_values,
enum_duplicates duplic)
{
bool insert_into_view= (table_list->view != 0);
/* TODO: use this condition for 'WITH CHECK OPTION' */
Item *unused_conds= 0;
DBUG_ENTER("mysql_prepare_insert");
if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds))
DBUG_RETURN(-1);
if (check_insert_fields(thd, table_list, fields, *values, 1,
!insert_into_view) ||
@ -553,7 +593,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
setup_fields(thd, 0, table_list, update_values, 0, 0, 0))))
DBUG_RETURN(-1);
if (find_real_table_in_list(table_list->next_global,
if (find_table_in_global_list(table_list->next_global,
table_list->db, table_list->real_name))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
@ -1555,27 +1595,11 @@ bool delayed_insert::handle_inserts(void)
int mysql_insert_select_prepare(THD *thd)
{
LEX *lex= thd->lex;
TABLE_LIST *table_list= lex->query_tables;
bool insert_into_view= (table_list->view != 0);
DBUG_ENTER("mysql_insert_select_prepare");
if (setup_tables(thd, table_list, &lex->select_lex.where))
if (mysql_prepare_insert_check_table(thd, lex->query_tables,
lex->field_list,
&lex->select_lex.where))
DBUG_RETURN(-1);
if (insert_into_view && !lex->field_list.elements)
{
lex->empty_field_list_on_rset= 1;
insert_view_fields(&lex->field_list, table_list);
}
if (!table_list->updatable ||
check_key_in_view(thd, table_list) ||
(insert_into_view &&
check_view_insertability(table_list, thd->query_id)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
DBUG_RETURN(-1);
}
DBUG_RETURN(0);
}

View File

@ -1422,7 +1422,7 @@ bool st_select_lex_unit::check_updateable(char *db, char *table)
*/
bool st_select_lex::check_updateable(char *db, char *table)
{
if (find_real_table_in_local_list(get_table_list(), db, table))
if (find_table_in_local_list(get_table_list(), db, table))
return 1;
for (SELECT_LEX_UNIT *un= first_inner_unit();
@ -1631,14 +1631,16 @@ void st_select_lex_unit::set_limit(SELECT_LEX *values,
SYNOPSIS
unlink_first_table()
link_to_local do we need link this table to local
link_to_local Set to 1 if caller should link this table to local
NOTES
We rely on fact that first table in both list are same or local list
is empty
RETURN
0 If 'query_tables' == 0
unlinked table
In this case link_to_local is set.
*/
TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
@ -1692,11 +1694,11 @@ void st_lex::first_lists_tables_same()
TABLE_LIST *first_table= (TABLE_LIST*) select_lex.table_list.first;
if (query_tables != first_table && first_table != 0)
{
TABLE_LIST *next;
if (query_tables_last == &first_table->next_global)
query_tables_last= first_table->prev_global;
TABLE_LIST *next= *first_table->prev_global= first_table->next_global;
first_table->next_global= 0;
if (next)
if ((next= *first_table->prev_global= first_table->next_global))
next->prev_global= first_table->prev_global;
/* include in new place */
first_table->next_global= query_tables;

View File

@ -1905,7 +1905,7 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0);
*/
lex->first_lists_tables_same();
/* should be assigned after making firts tables same */
/* should be assigned after making first tables same */
all_tables= lex->query_tables;
if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
@ -2381,8 +2381,8 @@ mysql_execute_command(THD *thd)
of query
*/
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
find_real_table_in_list(select_tables, create_table->db,
create_table->real_name))
find_table_in_global_list(select_tables, create_table->db,
create_table->real_name))
{
net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name);
goto create_error;
@ -2752,7 +2752,7 @@ unsent_create_error:
unit->set_limit(select_lex, select_lex);
// is table which we are changing used somewhere in other parts of query
if (find_real_table_in_list(all_tables->next_global,
if (find_table_in_global_list(all_tables->next_global,
first_table->db, first_table->real_name))
{
/* Using same table for INSERT and SELECT */
@ -3907,7 +3907,7 @@ error:
1 - access denied, error is sent to client
*/
int check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
{
if (check_access(thd, privilege, all_tables->db,
&all_tables->grant.privilege, 0, 0))
@ -3951,13 +3951,13 @@ bool
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool dont_check_global_grants, bool no_errors)
{
DBUG_ENTER("check_access");
DBUG_PRINT("enter",("want_access: %lu master_access: %lu", want_access,
thd->master_access));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access;
#endif
ulong dummy;
DBUG_ENTER("check_access");
DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
db ? db : "", want_access, thd->master_access));
if (save_priv)
*save_priv=0;
else
@ -3965,8 +3965,9 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
DBUG_PRINT("error",("No database"));
if (!no_errors)
send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
}
@ -3991,6 +3992,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
! db && dont_check_global_grants)
{ // We can never grant this
DBUG_PRINT("error",("No possible access"));
if (!no_errors)
net_printf(thd,ER_ACCESS_DENIED_ERROR,
thd->priv_user,
@ -4009,13 +4011,17 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
db_access=thd->db_access;
/* Remove SHOW attribute and access rights we already have */
want_access &= ~(thd->master_access | EXTRA_ACL);
DBUG_PRINT("info",("db_access: %lu want_access: %lu",
db_access, want_access));
db_access= ((*save_priv=(db_access | thd->master_access)) & want_access);
/* grant_option is set if there exists a single table or column grant */
if (db_access == want_access ||
((grant_option && !dont_check_global_grants) &&
(grant_option && !dont_check_global_grants &&
!(want_access & ~(db_access | TABLE_ACLS))))
DBUG_RETURN(FALSE); /* Ok */
DBUG_PRINT("error",("Access denied"));
if (!no_errors)
net_printf(thd,ER_DBACCESS_DENIED_ERROR,
thd->priv_user,
@ -4103,6 +4109,42 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
return FALSE;
}
/*
Check if the given table has any of the asked privileges
SYNOPSIS
check_some_access()
thd Thread handler
want_access Bitmap of possible privileges to check for
RETURN
0 ok
1 error
*/
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
{
ulong access;
DBUG_ENTER("check_some_access");
/* This loop will work as long as we have less than 32 privileges */
for (access= 1; access < want_access ; access<<= 1)
{
if (access & want_access)
{
if (!check_access(thd, access, table->db,
&table->grant.privilege, 0, 1) &&
!grant_option || !check_grant(thd, access, table, 0, 1, 1))
DBUG_RETURN(0);
}
}
DBUG_PRINT("exit",("no matching access rights"));
DBUG_RETURN(1);
}
bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list)
{
@ -4960,6 +5002,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
{
register TABLE_LIST *ptr;
char *alias_str;
LEX *lex= thd->lex;
DBUG_ENTER("add_table_to_list");
if (!table)
@ -5011,7 +5054,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->derived= table->sel;
ptr->select_lex= thd->lex->current_select;
ptr->select_lex= lex->current_select;
ptr->cacheable_table= 1;
if (use_index_arg)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg,
@ -5035,8 +5078,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
}
}
/* Link table in local list (list for current select) */
table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
LEX *lex= thd->lex;
/* Link table in global list (all used tables) */
*(ptr->prev_global= lex->query_tables_last)= ptr;
lex->query_tables_last= &ptr->next_global;
DBUG_RETURN(ptr);

View File

@ -1665,8 +1665,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
if (lex->empty_field_list_on_rset)
{
lex->field_list.empty();
lex->empty_field_list_on_rset= 0;
lex->field_list.empty();
}
for (; sl; sl= sl->next_select_in_list())
{

View File

@ -225,25 +225,18 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
thd->net.report_error));
if (thd->net.report_error)
res= 1;
if (res > 0)
if (unlikely(res))
{
if (result)
{
result->send_error(0, NullS);
if (res > 0)
result->send_error(0, NullS);
result->abort();
}
else
else if (res > 0)
send_error(thd, 0, NullS);
res= 1; // Error sent to client
}
if (res < 0)
{
if (result)
{
result->abort();
}
res= 1;
}
if (result != lex->result)
delete result;
DBUG_RETURN(res);
@ -348,9 +341,7 @@ JOIN::prepare(Item ***rref_pointer_array,
if ((subselect= select_lex->master_unit()->item))
{
Item_subselect::trans_res res;
if ((res= ((!thd->lex->view_prepare_mode) ?
subselect->select_transformer(this) :
subselect->no_select_transform())) !=
if ((res= subselect->select_transformer(this)) !=
Item_subselect::RES_OK)
{
select_lex->fix_prepare_information(thd, &conds);
@ -11192,7 +11183,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
SYNOPSIS
print_join()
thd thread handler
str string where table should bbe printed
str string where table should be printed
tables list of tables in join
*/
@ -11248,30 +11239,31 @@ void st_table_list::print(THD *thd, String *str)
print_join(thd, str, &nested_join->join_list);
str->append(')');
}
else if (view_name.str)
{
str->append(view_db.str, view_db.length);
str->append('.');
str->append(view_name.str, view_name.length);
if (my_strcasecmp(table_alias_charset, view_name.str, alias))
{
str->append(' ');
str->append(alias);
}
}
else if (derived)
{
str->append('(');
derived->print(str);
str->append(") ", 2);
str->append(alias);
}
else
{
str->append(db);
str->append('.');
str->append(real_name);
if (my_strcasecmp(table_alias_charset, real_name, alias))
const char *cmp_name; // Name to compare with alias
if (view_name.str)
{
str->append(view_db.str, view_db.length);
str->append('.');
str->append(view_name.str, view_name.length);
cmp_name= view_name.str;
}
else if (derived)
{
str->append('(');
derived->print(str);
str->append(')');
cmp_name= ""; // Force printing of alias
}
else
{
str->append(db);
str->append('.');
str->append(real_name);
cmp_name= real_name;
}
if (my_strcasecmp(table_alias_charset, cmp_name, alias))
{
str->append(' ');
str->append(alias);
@ -11279,6 +11271,7 @@ void st_table_list::print(THD *thd, String *str)
}
}
void st_select_lex::print(THD *thd, String *str)
{
if (!thd)

View File

@ -1551,11 +1551,11 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
MODE_MAXDB |
MODE_ANSI)) != 0;
buff->append("CREATE ", 7);
if(!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE ||
table->algorithm == VIEW_ALGORITHM_TMEPTABLE))
if (!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE ||
table->algorithm == VIEW_ALGORITHM_TMPTABLE))
{
buff->append("ALGORITHM=", 10);
if (table->algorithm == VIEW_ALGORITHM_TMEPTABLE)
if (table->algorithm == VIEW_ALGORITHM_TMPTABLE)
buff->append("TMPTABLE ", 9);
else
buff->append("MERGE ", 6);

View File

@ -483,7 +483,7 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(-1);
/* Check that we are not using table that we are updating in a sub select */
if (find_real_table_in_list(table_list->next_global,
if (find_table_in_global_list(table_list->next_global,
table_list->db, table_list->real_name))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
@ -760,7 +760,7 @@ int multi_update::prepare(List<Item> &not_used_values,
{
TABLE *table=table_ref->table;
if (!(tables_to_update & table->map) &&
find_real_table_in_list(update_tables, table_ref->db,
find_table_in_global_list(update_tables, table_ref->db,
table_ref->real_name))
table->no_cache= 1; // Disable row cache
}

View File

@ -79,25 +79,8 @@ int mysql_create_view(THD *thd,
/*
Ensure that we have some privilage on this table, more strict check
will be done on column level after preparation,
SELECT_ACL will be checked for sure for all fields because it is
listed first (if we have not rights to SELECT from whole table this
right will be written as tbl->grant.want_privilege and will be checked
later (except fields which need any privilege and can be updated).
*/
if ((check_access(thd, SELECT_ACL, tbl->db,
&tbl->grant.privilege, 0, 1) ||
grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 1)) &&
(check_access(thd, INSERT_ACL, tbl->db,
&tbl->grant.privilege, 0, 1) ||
grant_option && check_grant(thd, INSERT_ACL, tbl, 0, 1, 1)) &&
(check_access(thd, DELETE_ACL, tbl->db,
&tbl->grant.privilege, 0, 1) ||
grant_option && check_grant(thd, DELETE_ACL, tbl, 0, 1, 1)) &&
(check_access(thd, UPDATE_ACL, tbl->db,
&tbl->grant.privilege, 0, 1) ||
grant_option && check_grant(thd, UPDATE_ACL, tbl, 0, 1, 1))
)
if (check_some_access(thd, VIEW_ANY_ACL, tbl))
{
my_printf_error(ER_TABLEACCESS_DENIED_ERROR,
ER(ER_TABLEACCESS_DENIED_ERROR),
@ -113,7 +96,7 @@ int mysql_create_view(THD *thd,
/*
We need to check only SELECT_ACL for all normal fields, fields
where we need any privilege will be pmarked later
where we need any privilege will be marked later
*/
tbl->grant.want_privilege= SELECT_ACL;
/*
@ -166,7 +149,7 @@ int mysql_create_view(THD *thd,
/* check that tables are not temporary */
for (tbl= tables; tbl; tbl= tbl->next_global)
{
if (tbl->table->tmp_table != NO_TMP_TABLE && !test(tbl->view))
if (tbl->table->tmp_table != NO_TMP_TABLE && !tbl->view)
{
my_error(ER_VIEW_SELECT_TMPTABLE, MYF(0), tbl->alias);
res= -1;
@ -189,19 +172,18 @@ int mysql_create_view(THD *thd,
/* view list (list of view fields names) */
if (lex->view_list.elements)
{
List_iterator_fast<Item> it(select_lex->item_list);
List_iterator_fast<LEX_STRING> nm(lex->view_list);
Item *item;
LEX_STRING *name;
if (lex->view_list.elements != select_lex->item_list.elements)
{
my_message(ER_VIEW_WRONG_LIST, ER(ER_VIEW_WRONG_LIST), MYF(0));
goto err;
}
List_iterator_fast<Item> it(select_lex->item_list);
List_iterator_fast<LEX_STRING> nm(lex->view_list);
Item *item;
LEX_STRING *name;
while((item= it++, name= nm++))
{
while ((item= it++, name= nm++))
item->set_name(name->str, name->length, system_charset_info);
}
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@ -214,7 +196,7 @@ int mysql_create_view(THD *thd,
Item *item;
fill_effective_table_privileges(thd, &view->grant, db,
view->real_name);
while((item= it++))
while ((item= it++))
{
uint priv= (get_column_grant(thd, &view->grant, db,
view->real_name, item->name) &
@ -223,10 +205,10 @@ int mysql_create_view(THD *thd,
{
Item_field *fld= (Item_field *)item;
/*
There are no any privileges on VIWE column or there are
There are no any privileges on VIEW column or there are
some other privileges then we have for underlaying table
*/
if (priv == 0 || test(~fld->have_privileges & priv))
if (priv == 0 || (~fld->have_privileges & priv))
{
/* VIEW column has more privileges */
my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
@ -242,7 +224,7 @@ int mysql_create_view(THD *thd,
}
else
{
if (!test(priv & SELECT_ACL))
if (!(priv & SELECT_ACL))
{
/* user have not privilege to SELECT expression */
my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
@ -266,14 +248,11 @@ int mysql_create_view(THD *thd,
goto err;
}
VOID(pthread_mutex_lock(&LOCK_open));
if ((res= mysql_register_view(thd, view, mode)))
{
VOID(pthread_mutex_unlock(&LOCK_open));
start_waiting_global_read_lock(thd);
goto err;
}
res= mysql_register_view(thd, view, mode);
VOID(pthread_mutex_unlock(&LOCK_open));
start_waiting_global_read_lock(thd);
if (res)
goto err;
send_ok(thd);
lex->link_first_table_back(view, link_to_local);
@ -292,40 +271,36 @@ err:
// index of revision number in following table
static const int revision_number_position= 4;
static char *view_field_names[]=
{
(char*)"query",
(char*)"md5",
(char*)"updatable",
(char*)"algorithm",
(char*)"revision",
(char*)"timestamp",
(char*)"create-version",
(char*)"source"
};
/*
table of VIEW .frm field descriptors
Note that one should NOT change the order for this, as it's used by
parse()
*/
// table of VIEW .frm field descriprors
static File_option view_parameters[]=
{{{view_field_names[0], 5}, offsetof(TABLE_LIST, query),
{{{(char*) "query", 5}, offsetof(TABLE_LIST, query),
FILE_OPTIONS_STRING},
{{view_field_names[1], 3}, offsetof(TABLE_LIST, md5),
{{(char*) "md5", 3}, offsetof(TABLE_LIST, md5),
FILE_OPTIONS_STRING},
{{view_field_names[2], 9}, offsetof(TABLE_LIST, updatable),
{{(char*) "updatable", 9}, offsetof(TABLE_LIST, updatable),
FILE_OPTIONS_ULONGLONG},
{{view_field_names[3], 9}, offsetof(TABLE_LIST, algorithm),
{{(char*) "algorithm", 9}, offsetof(TABLE_LIST, algorithm),
FILE_OPTIONS_ULONGLONG},
{{view_field_names[4], 8}, offsetof(TABLE_LIST, revision),
{{(char*) "revision", 8}, offsetof(TABLE_LIST, revision),
FILE_OPTIONS_REV},
{{view_field_names[5], 9}, offsetof(TABLE_LIST, timestamp),
{{(char*) "timestamp", 9}, offsetof(TABLE_LIST, timestamp),
FILE_OPTIONS_TIMESTAMP},
{{view_field_names[6], 14}, offsetof(TABLE_LIST, file_version),
{{(char*)"create-version", 14},offsetof(TABLE_LIST, file_version),
FILE_OPTIONS_ULONGLONG},
{{view_field_names[7], 6}, offsetof(TABLE_LIST, source),
{{(char*) "source", 6}, offsetof(TABLE_LIST, source),
FILE_OPTIONS_ESTRING},
{{NULL, 0}, 0,
FILE_OPTIONS_STRING}
};
static const uint required_view_parameters= 6;
static LEX_STRING view_file_type[]= {{(char*)"VIEW", 4}};
@ -368,16 +343,18 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
dir.length= strlen(dir_buff);
file.str= file_buff;
file.length= my_snprintf(file_buff, FN_REFLEN, "%s%s",
view->real_name, reg_ext);
file.length= (strxnmov(file_buff, FN_REFLEN, view->real_name, reg_ext,
NullS) - file_buff);
/* init timestamp */
if (!test(view->timestamp.str))
if (!view->timestamp.str)
view->timestamp.str= view->timestamp_buffer;
// check old .frm
{
char path_buff[FN_REFLEN];
LEX_STRING path;
File_parser *parser;
path.str= path_buff;
fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME);
path.length= strlen(path_buff);
@ -390,34 +367,27 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
DBUG_RETURN(1);
}
File_parser *parser= sql_parse_prepare(&path, &thd->mem_root, 0);
if (parser)
{
if(parser->ok() &&
!strncmp("VIEW", parser->type()->str, parser->type()->length))
{
/*
read revision number
TODO: read dependense list, too, to process cascade/restrict
TODO: special cascade/restrict procedure for alter?
*/
if (parser->parse((gptr)view, &thd->mem_root,
view_parameters + revision_number_position, 1))
{
DBUG_RETURN(1);
}
}
else
{
my_error(ER_WRONG_OBJECT, MYF(0), (view->db?view->db:thd->db),
view->real_name, "VIEW");
DBUG_RETURN(1);
}
}
else
{
if (!(parser= sql_parse_prepare(&path, &thd->mem_root, 0)))
DBUG_RETURN(1);
if (!parser->ok() ||
strncmp("VIEW", parser->type()->str, parser->type()->length))
{
my_error(ER_WRONG_OBJECT, MYF(0), (view->db ? view->db : thd->db),
view->real_name, "VIEW");
DBUG_RETURN(1);
}
/*
read revision number
TODO: read dependense list, too, to process cascade/restrict
TODO: special cascade/restrict procedure for alter?
*/
if (parser->parse((gptr)view, &thd->mem_root,
view_parameters + revision_number_position, 1))
{
DBUG_RETURN(1);
}
}
else
@ -448,14 +418,14 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
}
view->algorithm= thd->lex->create_view_algorithm;
if ((view->updatable= (can_be_merged &&
view->algorithm != VIEW_ALGORITHM_TMEPTABLE)))
view->algorithm != VIEW_ALGORITHM_TMPTABLE)))
{
// TODO: change here when we will support UNIONs
for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first;
tbl;
tbl= tbl->next_local)
{
if (tbl->view != 0 && !tbl->updatable)
if (tbl->view && !tbl->updatable)
{
view->updatable= 0;
break;
@ -478,7 +448,13 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
mysql_make_view()
parser - parser object;
table - TABLE_LIST structure for filling
RETURN
0 ok
1 error
*/
my_bool
mysql_make_view(File_parser *parser, TABLE_LIST *table)
{
@ -487,7 +463,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
if (table->view)
{
DBUG_PRINT("info",
("VIEW %s.%s is already processed on previos PS/SP execution",
("VIEW %s.%s is already processed on previous PS/SP execution",
table->view_db.str, table->view_name.str));
DBUG_RETURN(0);
}
@ -507,13 +483,14 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
thd->set_n_backup_item_arena(arena, &backup);
/* init timestamp */
if (!test(table->timestamp.str))
if (!table->timestamp.str)
table->timestamp.str= table->timestamp_buffer;
/*
TODO: when VIEWs will be stored in cache, table mem_root should
be used here
*/
if (parser->parse((gptr)table, &thd->mem_root, view_parameters, 6))
if (parser->parse((gptr)table, &thd->mem_root, view_parameters,
required_view_parameters))
goto err;
/*
@ -535,7 +512,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
*/
table->view= lex= thd->lex= (LEX*) new(&thd->mem_root) st_lex_local;
lex_start(thd, (uchar*)table->query.str, table->query.length);
mysql_init_query(thd, true);
mysql_init_query(thd, TRUE);
lex->select_lex.select_number= ++thd->select_number;
old_lex->derived_tables|= DERIVED_VIEW;
{
@ -613,7 +590,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
- VIEW SELECT allow marging
- VIEW used in subquery or command support MERGE algorithm
*/
if (table->algorithm != VIEW_ALGORITHM_TMEPTABLE &&
if (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
lex->can_be_merged() &&
(table->select_lex->master_unit() != &old_lex->unit ||
old_lex->can_use_merged()))
@ -656,11 +633,13 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
goto ok;
}
table->effective_algorithm= VIEW_ALGORITHM_TMEPTABLE;
table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE;
if (table->updatable)
{
//TOTO: warning: can't be updateable, .frm edited by hand. version
//downgrade?
/*
TODO: warning: can't be updateable, .frm edited by hand. version
downgrade?
*/
table->updatable= 0;
}
@ -672,7 +651,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
{
if ((tbl_end= table->next_global))
{
for (; (tbl_next= tbl_end->next_global); tbl_end= tbl_next);
for (; (tbl_next= tbl_end->next_global); tbl_end= tbl_next)
;
if ((tbl_end->next_global= old_next))
tbl_end->next_global->prev_global= &tbl_end->next_global;
}
@ -720,6 +700,7 @@ err:
-1 Error
1 Error and error message given
*/
int mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
{
DBUG_ENTER("mysql_drop_view");
@ -729,8 +710,8 @@ int mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
for (view= views; view; view= view->next_local)
{
strxmov(path, mysql_data_home, "/", view->db, "/", view->real_name,
reg_ext, NullS);
strxnmov(path, FN_REFLEN, mysql_data_home, "/", view->db, "/",
view->real_name, reg_ext, NullS);
(void) unpack_filename(path, path);
VOID(pthread_mutex_lock(&LOCK_open));
if (access(path, F_OK) || (type= (mysql_frm_type(path) != FRMTYPE_VIEW)))
@ -782,21 +763,20 @@ frm_type_enum mysql_frm_type(char *path)
{
File file;
char header[10]; //"TYPE=VIEW\n" it is 10 characters
int length;
DBUG_ENTER("mysql_frm_type");
if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
{
DBUG_RETURN(FRMTYPE_ERROR);
}
if (my_read(file, header, 10, MYF(MY_WME)) == MY_FILE_ERROR)
{
my_close(file, MYF(MY_WME));
DBUG_RETURN(FRMTYPE_ERROR);
}
length= my_read(file, header, 10, MYF(MY_WME));
my_close(file, MYF(MY_WME));
if (strncmp(header, "TYPE=VIEW\n", 10) != 0)
DBUG_RETURN(FRMTYPE_TABLE);
DBUG_RETURN(FRMTYPE_VIEW);
if (length == (int) MY_FILE_ERROR)
DBUG_RETURN(FRMTYPE_ERROR);
if (!strncmp(header, "TYPE=VIEW\n", 10))
DBUG_RETURN(FRMTYPE_VIEW);
DBUG_RETURN(FRMTYPE_TABLE); // Is probably a .frm table
}
@ -815,72 +795,81 @@ frm_type_enum mysql_frm_type(char *path)
bool check_key_in_view(THD *thd, TABLE_LIST *view)
{
TABLE *table;
Item **trans;
KEY *key_info, *key_info_end;
uint i, elements_in_view;
DBUG_ENTER("check_key_in_view");
if (!view->view)
DBUG_RETURN(FALSE); /* it is normal table */
table= view->table;
trans= view->field_translation;
key_info_end= (key_info= table->key_info)+ table->keys;
TABLE *table= view->table;
Item **trans= view->field_translation;
KEY *key_info= table->key_info;
uint primary_key= table->primary_key;
uint num= view->view->select_lex.item_list.elements;
elements_in_view= view->view->select_lex.item_list.elements;
DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
/* try to find key */
for (uint i=0; i < table->keys; i++, key_info++)
/* Loop over all keys to see if a unique-not-null key is used */
for (;key_info != key_info_end ; key_info++)
{
if (i == primary_key && !strcmp(key_info->name, primary_key_name) ||
key_info->flags & HA_NOSAME)
if ((key_info->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
{
KEY_PART_INFO *key_part= key_info->key_part;
bool found= 1;
for (uint j=0; j < key_info->key_parts && found; j++, key_part++)
KEY_PART_INFO *key_part_end= key_part + key_info->key_parts;
/* check that all key parts are used */
for (;;)
{
found= 0;
for (uint k= 0; k < num; k++)
uint k;
for (k= 0; k < elements_in_view; k++)
{
if (trans[k]->type() == Item::FIELD_ITEM &&
((Item_field *)trans[k])->field == key_part->field &&
(key_part->field->flags & NOT_NULL_FLAG))
{
found= 1;
((Item_field *)trans[k])->field == key_part->field)
break;
}
}
if (k == elements_in_view)
break; // Key is not possible
if (++key_part == key_part_end)
DBUG_RETURN(FALSE); // Found usable key
}
if (found)
DBUG_RETURN(FALSE);
}
}
DBUG_PRINT("info", ("checking if all fields of table are used"));
/* check all fields presence */
{
Field **field_ptr= table->field;
for (; *field_ptr; ++field_ptr)
Field **field_ptr;
for (field_ptr= table->field; *field_ptr; field_ptr++)
{
uint i= 0;
for (; i < num; i++)
for (i= 0; i < elements_in_view; i++)
{
if (trans[i]->type() == Item::FIELD_ITEM &&
((Item_field *)trans[i])->field == *field_ptr)
break;
}
if (i >= num)
if (i == elements_in_view) // If field didn't exists
{
ulong mode= thd->variables.sql_updatable_view_key;
/* 1 == YES, 2 == LIMIT1 */
/*
0 == NO ; Don't give any errors
1 == YES ; Give always an error
2 == LIMIT1 ; Give an error if this is used with LIMIT 1
This is used to protect against gui programs that
uses LIMIT 1 to update just the current row. This
doesn't work reliable if the view doesn't have a
unique key or if the view doesn't use all fields in
table.
*/
if (mode == 1 ||
(mode == 2 &&
thd->lex->select_lex.select_limit == 1))
thd->lex->unit.global_parameters->select_limit == 1))
{
DBUG_RETURN(TRUE);
}
else
{
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_WARN_VIEW_WITHOUT_KEY, ER(ER_WARN_VIEW_WITHOUT_KEY));
DBUG_RETURN(FALSE);
}
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_WARN_VIEW_WITHOUT_KEY, ER(ER_WARN_VIEW_WITHOUT_KEY));
DBUG_RETURN(FALSE);
}
}
}
@ -899,18 +888,17 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
void insert_view_fields(List<Item> *list, TABLE_LIST *view)
{
uint num= view->view->select_lex.item_list.elements;
Item **trans= view->field_translation;
uint elements_in_view= view->view->select_lex.item_list.elements;
Item **trans;
DBUG_ENTER("insert_view_fields");
if (!trans)
if (!(trans= view->field_translation))
DBUG_VOID_RETURN;
for (uint i= 0; i < num; i++)
for (uint i= 0; i < elements_in_view; i++)
{
if (trans[i]->type() == Item::FIELD_ITEM)
{
list->push_back(trans[i]);
}
}
DBUG_VOID_RETURN;
}

View File

@ -88,6 +88,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
DBUG_PRINT("enter",("name: '%s' form: %lx",name,outparam));
error=1;
disk_buff=NULL;
old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
if ((file=my_open(fn_format(index_file, name, "", reg_ext,
MY_UNPACK_FILENAME),
@ -118,11 +120,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
bzero((char*) outparam,sizeof(*outparam));
outparam->blob_ptr_size=sizeof(char*);
disk_buff=NULL; record= NULL; keynames=NullS;
outparam->db_stat = db_stat;
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
outparam->real_name=strdup_root(&outparam->mem_root,
@ -742,11 +741,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
DBUG_RETURN (0);
err_w_init:
//awoid problem with uninitialized data
/* Avoid problem with uninitialized data */
bzero((char*) outparam,sizeof(*outparam));
outparam->real_name= (char*)name+dirname_length(name);
old_root= my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
disk_buff= 0;
err_not_open:
x_free((gptr) disk_buff);
@ -1447,13 +1444,14 @@ db_type get_table_type(const char *name)
st_table_list::calc_md5()
buffer buffer for md5 writing
*/
void st_table_list::calc_md5(char *buffer)
{
my_MD5_CTX context;
unsigned char digest[16];
my_MD5Init (&context);
my_MD5Update (&context,(unsigned char *) query.str, query.length);
my_MD5Final (digest, &context);
uchar digest[16];
my_MD5Init(&context);
my_MD5Update(&context,(uchar *) query.str, query.length);
my_MD5Final(digest, &context);
sprintf((char *) buffer,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3],
@ -1469,6 +1467,7 @@ void st_table_list::calc_md5(char *buffer)
SYNOPSIS
st_table_list::set_ancestor()
*/
void st_table_list::set_ancestor()
{
if (ancestor->ancestor)
@ -1496,6 +1495,7 @@ void st_table_list::set_ancestor()
(without fields) for name resolving, but substituted expressions will
return correct used tables mask.
*/
bool st_table_list::setup_ancestor(THD *thd, Item **conds)
{
Item **transl;
@ -1515,13 +1515,13 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
thd->set_query_id= 1;
/* this view was prepared already on previous PS/SP execution */
Item **end= field_translation + select->item_list.elements;
for (Item **i= field_translation; i < end; i++)
for (Item **item= field_translation; item < end; item++)
{
//TODO: fix for several tables in VIEW
/* TODO: fix for several tables in VIEW */
uint want_privilege= ancestor->table->grant.want_privilege;
/* real rights will be checked in VIEW field */
ancestor->table->grant.want_privilege= 0;
if (!(*i)->fixed && (*i)->fix_fields(thd, ancestor, i))
if (!(*item)->fixed && (*item)->fix_fields(thd, ancestor, item))
goto err;
ancestor->table->grant.want_privilege= want_privilege;
}
@ -1545,19 +1545,17 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
thd->set_query_id= 1;
while ((item= it++))
{
//TODO: fix for several tables in VIEW
/* TODO: fix for several tables in VIEW */
uint want_privilege= ancestor->table->grant.want_privilege;
/* real rights will be checked in VIEW field */
ancestor->table->grant.want_privilege= 0;
if (!item->fixed && item->fix_fields(thd, ancestor, &item))
{
goto err;
}
ancestor->table->grant.want_privilege= want_privilege;
transl[i++]= item;
}
field_translation= transl;
//TODO: sort this list? Use hash for big number of fields
/* TODO: sort this list? Use hash for big number of fields */
if (where)
{
@ -1566,12 +1564,12 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
goto err;
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
thd->set_n_backup_item_arena(arena, &backup);
if (outer_join)
{
/*
Store WHERE condition to ON expression for outer join, because we
can't use WHERE to correctly execute jeft joins on VIEWs and this
can't use WHERE to correctly execute jeft joins on VIEWs and this
expression will not be moved to WHERE condition (i.e. will be clean
correctly for PS/SP)
*/

View File

@ -172,7 +172,7 @@ struct st_table {
#define JOIN_TYPE_RIGHT 2
#define VIEW_ALGORITHM_UNDEFINED 0
#define VIEW_ALGORITHM_TMEPTABLE 1
#define VIEW_ALGORITHM_TMPTABLE 1
#define VIEW_ALGORITHM_MERGE 2
struct st_lex;
@ -255,7 +255,7 @@ public:
virtual ~Field_iterator() {}
virtual void set(TABLE_LIST *)= 0;
virtual void next()= 0;
virtual bool end()= 0;
virtual bool end_of_fields()= 0; /* Return 1 at end of list */
virtual const char *name()= 0;
virtual Item *item(THD *)= 0;
virtual Field *field()= 0;
@ -270,7 +270,7 @@ public:
void set(TABLE_LIST *table) { ptr= table->table->field; }
void set_table(TABLE *table) { ptr= table->field; }
void next() { ptr++; }
bool end() { return test(*ptr); }
bool end_of_fields() { return *ptr == 0; }
const char *name();
Item *item(THD *thd);
Field *field() { return *ptr; }
@ -284,7 +284,7 @@ public:
Field_iterator_view() :ptr(0), array_end(0) {}
void set(TABLE_LIST *table);
void next() { ptr++; }
bool end() { return ptr < array_end; }
bool end_of_fields() { return ptr == array_end; }
const char *name();
Item *item(THD *thd) { return *ptr; }
Field *field() { return 0; }

View File

@ -30,6 +30,7 @@
#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */
#define MAX_KEY 64
/* set default options */
static char *opt_db= 0;
@ -6818,13 +6819,13 @@ static void test_explain_bug()
"", "", "", 10, 0);
verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN*64, 0);
"", "", "", NAME_LEN*MAX_KEY, 0);
verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN, 0);
verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN*64, 0);
"", "", "", NAME_LEN*MAX_KEY, 0);
verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING,
"", "", "", NAME_LEN*16, 0);