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:
parent
10d0dca6b4
commit
d0211cf5be
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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,10 +765,8 @@ 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,
|
||||
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);
|
||||
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
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,
|
||||
|
178
sql/sql_base.cc
178
sql/sql_base.cc
@ -548,15 +548,20 @@ 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
|
||||
@ -564,65 +569,16 @@ void close_temporary_tables(THD *thd)
|
||||
*/
|
||||
|
||||
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
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,
|
||||
uint offset,
|
||||
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_LIST **) ((char*) table + offset))
|
||||
{
|
||||
for (; table; table= table->next_local)
|
||||
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
|
||||
@ -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;
|
||||
for (; tables; tables= tables->next_local)
|
||||
{
|
||||
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;
|
||||
|
||||
natural_join_table= 0;
|
||||
thd->used_tables|= table->map;
|
||||
TABLE_LIST *embedded= tables;
|
||||
TABLE_LIST *last= embedded;
|
||||
TABLE_LIST *embedding;
|
||||
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 (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(!found);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,7 +2381,7 @@ 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,
|
||||
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);
|
||||
@ -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,6 +3965,7 @@ 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 */
|
||||
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);
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
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)
|
||||
else
|
||||
{
|
||||
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);
|
||||
if (my_strcasecmp(table_alias_charset, view_name.str, alias))
|
||||
{
|
||||
str->append(' ');
|
||||
str->append(alias);
|
||||
}
|
||||
cmp_name= view_name.str;
|
||||
}
|
||||
else if (derived)
|
||||
{
|
||||
str->append('(');
|
||||
derived->print(str);
|
||||
str->append(") ", 2);
|
||||
str->append(alias);
|
||||
str->append(')');
|
||||
cmp_name= ""; // Force printing of alias
|
||||
}
|
||||
else
|
||||
{
|
||||
str->append(db);
|
||||
str->append('.');
|
||||
str->append(real_name);
|
||||
if (my_strcasecmp(table_alias_charset, real_name, alias))
|
||||
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)
|
||||
|
@ -1552,10 +1552,10 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
|
||||
MODE_ANSI)) != 0;
|
||||
buff->append("CREATE ", 7);
|
||||
if (!foreign_db_mode && (table->algorithm == VIEW_ALGORITHM_MERGE ||
|
||||
table->algorithm == VIEW_ALGORITHM_TMEPTABLE))
|
||||
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);
|
||||
|
@ -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> ¬_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
|
||||
}
|
||||
|
246
sql/sql_view.cc
246
sql/sql_view.cc
@ -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,20 +172,19 @@ 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++))
|
||||
{
|
||||
item->set_name(name->str, name->length, system_charset_info);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
/*
|
||||
@ -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)))
|
||||
{
|
||||
res= mysql_register_view(thd, view, mode);
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
start_waiting_global_read_lock(thd);
|
||||
if (res)
|
||||
goto err;
|
||||
}
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
start_waiting_global_read_lock(thd);
|
||||
|
||||
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,12 +367,17 @@ 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))
|
||||
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
|
||||
|
||||
@ -409,18 +391,6 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
my_error(ER_WRONG_OBJECT, MYF(0), (view->db?view->db:thd->db),
|
||||
view->real_name, "VIEW");
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode == VIEW_ALTER)
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
length= my_read(file, header, 10, MYF(MY_WME));
|
||||
my_close(file, MYF(MY_WME));
|
||||
if (length == (int) MY_FILE_ERROR)
|
||||
DBUG_RETURN(FRMTYPE_ERROR);
|
||||
}
|
||||
my_close(file, MYF(MY_WME));
|
||||
if (strncmp(header, "TYPE=VIEW\n", 10) != 0)
|
||||
DBUG_RETURN(FRMTYPE_TABLE);
|
||||
if (!strncmp(header, "TYPE=VIEW\n", 10))
|
||||
DBUG_RETURN(FRMTYPE_VIEW);
|
||||
DBUG_RETURN(FRMTYPE_TABLE); // Is probably a .frm table
|
||||
}
|
||||
|
||||
|
||||
@ -815,75 +795,84 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
28
sql/table.cc
28
sql/table.cc
@ -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,12 +1444,13 @@ 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];
|
||||
uchar digest[16];
|
||||
my_MD5Init(&context);
|
||||
my_MD5Update (&context,(unsigned char *) query.str, query.length);
|
||||
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",
|
||||
@ -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)
|
||||
{
|
||||
|
@ -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; }
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user