diff options
-rw-r--r-- | sql/item_cmpfunc.cc | 5 | ||||
-rw-r--r-- | sql/mysql_priv.h | 16 | ||||
-rw-r--r-- | sql/set_var.cc | 26 | ||||
-rw-r--r-- | sql/sql_acl.cc | 6 | ||||
-rw-r--r-- | sql/sql_acl.h | 4 | ||||
-rw-r--r-- | sql/sql_delete.cc | 48 | ||||
-rw-r--r-- | sql/sql_insert.cc | 52 | ||||
-rw-r--r-- | sql/sql_lex.cc | 20 | ||||
-rw-r--r-- | sql/sql_parse.cc | 286 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 294 | ||||
-rw-r--r-- | sql/sql_show.cc | 2 | ||||
-rw-r--r-- | sql/sql_update.cc | 82 | ||||
-rw-r--r-- | sql/table.h | 3 |
13 files changed, 527 insertions, 317 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 8da517a8d99..afbf0b7163e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -477,10 +477,9 @@ bool Item_in_optimizer::fix_left(THD *thd, struct st_table_list *tables, Item **ref) { - if ((!args[0]->fixed && args[0]->fix_fields(thd, tables, args))) + if (!args[0]->fixed && args[0]->fix_fields(thd, tables, args) || + !cache && !(cache= Item_cache::get_cache(args[0]->result_type()))) return 1; - if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))) - return 1; cache->setup(args[0]); cache->store(args[0]); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7b73897eb18..1175b93b9ba 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -348,12 +348,17 @@ 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, - TABLE_LIST *tables, bool no_errors); + TABLE_LIST *tables); bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list); int multi_update_precheck(THD *thd, TABLE_LIST *tables); int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count); int insert_select_precheck(THD *thd, TABLE_LIST *tables); +int update_precheck(THD *thd, TABLE_LIST *tables); +int delete_precheck(THD *thd, TABLE_LIST *tables); +int insert_precheck(THD *thd, TABLE_LIST *tables, bool update); +int create_table_precheck(THD *thd, TABLE_LIST *tables, + TABLE_LIST *create_table); #include "sql_class.h" #include "opt_range.h" @@ -532,6 +537,9 @@ bool mysql_rename_table(enum db_type base, int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys); int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop_list); +int mysql_prepare_update(THD *thd, TABLE_LIST *table_list, + TABLE_LIST *update_table_list, + Item **conds, uint order_num, ORDER *order); int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, List<Item> &values,COND *conds, uint order_num, ORDER *order, ha_rows limit, @@ -541,9 +549,15 @@ int mysql_multi_update(THD *thd, TABLE_LIST *table_list, COND *conds, ulong options, enum enum_duplicates handle_duplicates, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex); +int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, + TABLE_LIST *insert_table_list, TABLE *table, + List<Item> &fields, List_item *values, + List<Item> &update_fields, + List<Item> &update_values, enum_duplicates duplic); int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields, List<List_item> &values, List<Item> &update_fields, List<Item> &update_values, enum_duplicates flag); +int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, SQL_LIST *order, ha_rows rows, ulong options); int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok=0); diff --git a/sql/set_var.cc b/sql/set_var.cc index 54f2d75d6a8..9250177e721 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2529,6 +2529,18 @@ int set_var::check(THD *thd) } +/* + Check variable, but without assigning value (used by PS) + + SYNOPSIS + set_var::light_check() + thd thread handler + + RETURN VALUE + 0 ok + 1 ERROR, message sent (normally no variables was updated) + -1 ERROR, message not sent +*/ int set_var::light_check(THD *thd) { if (var->check_type(type)) @@ -2538,7 +2550,7 @@ int set_var::light_check(THD *thd) var->name); return -1; } - if ((type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL))) + if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)) return 1; if (value && (value->fix_fields(thd, 0, &value) || value->check_cols(1))) @@ -2574,6 +2586,18 @@ int set_var_user::check(THD *thd) } +/* + Check variable, but without assigning value (used by PS) + + SYNOPSIS + set_var_user::light_check() + thd thread handler + + RETURN VALUE + 0 ok + 1 ERROR, message sent (normally no variables was updated) + -1 ERROR, message not sent +*/ int set_var_user::light_check(THD *thd) { /* diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 4b287ea9a8d..72a68af54c0 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1388,7 +1388,7 @@ static bool test_if_create_new_users(THD *thd) thd->priv_user, tl.db, 0); if (!(db_access & INSERT_ACL)) { - if (check_grant(thd,INSERT_ACL,&tl,0,1)) + if (check_grant(thd, INSERT_ACL, &tl, 0, UINT_MAX, 1)) create_new_users=0; } } @@ -2650,7 +2650,7 @@ void grant_reload(THD *thd) ****************************************************************************/ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, - uint show_table, bool no_errors) + uint show_table, uint number, bool no_errors) { TABLE_LIST *table; char *user = thd->priv_user; @@ -2660,7 +2660,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, return 0; // ok rw_rdlock(&LOCK_grant); - for (table=tables; table ;table=table->next) + for (table= tables; table && number--; table= table->next) { if (!(~table->grant.privilege & want_access) || table->derived) { diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 4b911b44f77..a237b45e29c 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -154,7 +154,7 @@ my_bool grant_init(THD *thd); void grant_free(void); void grant_reload(THD *thd); bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, - uint show_command, bool dont_print_error); + uint show_command, uint number, bool dont_print_error); bool check_grant_column (THD *thd,TABLE *table, const char *name, uint length, uint show_command=0); bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table); @@ -168,6 +168,6 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list); int mysql_revoke_all(THD *thd, List <LEX_USER> &list); #ifdef NO_EMBEDDED_ACCESS_CHECKS -#define check_grant(A,B,C,D,E) 0 +#define check_grant(A,B,C,D,E,F) 0 #define check_grant_db(A,B) 0 #endif diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index a2f2c4abae4..269633aa709 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -37,8 +37,6 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, bool using_limit=limit != HA_POS_ERROR; bool transactional_table, log_delayed, safe_update, const_cond; ha_rows deleted; - TABLE_LIST *delete_table_list= (TABLE_LIST*) - thd->lex->select_lex.table_list.first; DBUG_ENTER("mysql_delete"); if ((open_and_lock_tables(thd, table_list))) @@ -47,15 +45,9 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); thd->proc_info="init"; table->map=1; - if (setup_conds(thd, delete_table_list, &conds) || - setup_ftfuncs(&thd->lex->select_lex)) - DBUG_RETURN(-1); - if (find_real_table_in_list(table_list->next, - table_list->db, table_list->real_name)) - { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); - DBUG_RETURN(-1); - } + + if ((error= mysql_prepare_delete(thd, table_list, &conds))) + DBUG_RETURN(error); const_cond= (!conds || conds->const_item()); safe_update=test(thd->options & OPTION_SAFE_UPDATES); @@ -242,7 +234,39 @@ cleanup: send_ok(thd,deleted); DBUG_PRINT("info",("%d records deleted",deleted)); } - DBUG_RETURN(0); + DBUG_RETURN(0); +} + + +/* + Prepare items in DELETE statement + + SYNOPSIS + mysql_prepare_delete() + thd - thread handler + table_list - global table list + conds - conditions + + RETURN VALUE + 0 - OK + 1 - error (message is sent to user) + -1 - error (message is not sent to user) +*/ +int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) +{ + TABLE_LIST *delete_table_list= + (TABLE_LIST*)thd->lex->select_lex.table_list.first; + DBUG_ENTER(" mysql_prepare_delete"); + + if (setup_conds(thd, delete_table_list, conds) || + setup_ftfuncs(&thd->lex->select_lex)) + DBUG_RETURN(-1); + if (find_real_table_in_list(table_list->next, + table_list->db, table_list->real_name)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); + DBUG_RETURN(-1); + } } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index cc2ba29dbd8..8185c716228 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -207,19 +207,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, goto abort; } - if (check_insert_fields(thd,table,fields,*values,1) || - setup_tables(insert_table_list) || - setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) || - (duplic == DUP_UPDATE && - (setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) || - setup_fields(thd, 0, insert_table_list, update_values, 0, 0, 0)))) - goto abort; - if (find_real_table_in_list(table_list->next, - table_list->db, table_list->real_name)) - { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); + if (mysql_prepare_insert(thd, table_list, insert_table_list, table, + fields, values, update_fields, + update_values, duplic)) goto abort; - } value_count= values->elements; while ((values= its++)) @@ -438,6 +429,43 @@ abort: } +/* + Prepare items in INSERT statement + + SYNOPSIS + mysql_prepare_update() + thd - thread handler + table_list - global table list + insert_table_list - local table list of INSERT SELECT_LEX + + RETURN VALUE + 0 - OK + -1 - error (message is not sent to user) +*/ +int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, + TABLE_LIST *insert_table_list, TABLE *table, + List<Item> &fields, List_item *values, + List<Item> &update_fields, List<Item> &update_values, + enum_duplicates duplic) +{ + DBUG_ENTER("mysql_prepare_insert"); + if (check_insert_fields(thd, table, fields, *values, 1) || + setup_tables(insert_table_list) || + setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) || + (duplic == DUP_UPDATE && + (setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) || + setup_fields(thd, 0, insert_table_list, update_values, 0, 0, 0)))) + DBUG_RETURN(-1); + if (find_real_table_in_list(table_list->next, + table_list->db, table_list->real_name)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); + DBUG_RETURN(-1); + } + DBUG_RETURN(0); +} + + /* Check if there is more uniq keys after field */ static int last_uniq_key(TABLE *table,uint keynr) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7fa0591ddc8..995f3702ab3 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1634,8 +1634,10 @@ void st_select_lex::print_limit(THD *thd, String *str) } } + /* - unlink first table from table lists + Unlink first table from global table list and first must outer select list + (lex->select_lex) SYNOPSIS unlink_first_table() @@ -1652,9 +1654,13 @@ TABLE_LIST *st_lex::unlink_first_table(TABLE_LIST *tables, { *global_first= tables; *local_first= (TABLE_LIST*)select_lex.table_list.first; - // exclude from global table list + /* + exclude from global table list + */ tables= tables->next; - // and from local list if it is not the same + /* + and from local list if it is not the same + */ if (&select_lex != all_selects_list) select_lex.table_list.first= (gptr)(*local_first)->next; else @@ -1663,8 +1669,9 @@ TABLE_LIST *st_lex::unlink_first_table(TABLE_LIST *tables, return tables; } + /* - link unlinked first table back + Link table back that was unlinked with unlink_first_table() SYNOPSIS link_first_table_back() @@ -1680,7 +1687,6 @@ TABLE_LIST *st_lex::link_first_table_back(TABLE_LIST *tables, TABLE_LIST *local_first) { global_first->next= tables; - tables= global_first; if (&select_lex != all_selects_list) { /* @@ -1690,8 +1696,8 @@ TABLE_LIST *st_lex::link_first_table_back(TABLE_LIST *tables, select_lex.table_list.first= (gptr) local_first; } else - select_lex.table_list.first= (gptr) tables; - return tables; + select_lex.table_list.first= (gptr) global_first; + return global_first; } /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b6ce2424c96..cf8369b778d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1173,7 +1173,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd) if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT))) DBUG_RETURN(1); - if (check_one_table_access(thd, SELECT_ACL, table_list, 0)) + if (check_one_table_access(thd, SELECT_ACL, table_list)) goto err; thd->free_list = 0; thd->query_length=(uint) strlen(tbl_name); @@ -1530,7 +1530,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege, 0, 0)) break; - if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2,0)) + if (grant_option && + check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0)) break; mysqld_list_fields(thd,&table_list,fields); free_items(thd->free_list); @@ -2135,10 +2136,7 @@ mysql_execute_command(THD *thd) if (grant_option) { /* Check that the first table has CREATE privilege */ - TABLE_LIST *tmp_table_list=tables->next; - tables->next=0; - bool error=check_grant(thd,CREATE_ACL,tables,0,0); - tables->next=tmp_table_list; + bool error= check_grant(thd, CREATE_ACL, tables, 0, 1, 0); if (error) goto error; } @@ -2169,18 +2167,9 @@ mysql_execute_command(THD *thd) tables= lex->unlink_first_table(tables, &create_table, &create_table_local); - ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? - CREATE_TMP_ACL : CREATE_ACL); - lex->create_info.alias= create_table->alias; - if (check_access(thd, want_priv, create_table->db, - &create_table->grant.privilege, 0, 0) || - check_merge_table_access(thd, create_table->db, - (TABLE_LIST *) - lex->create_info.merge_list.first)) - goto create_error; /* purecov: inspected */ - if (grant_option && want_priv != CREATE_TMP_ACL && - check_grant(thd, want_priv, create_table,0,0)) - goto create_error; + if ((res= create_table_precheck(thd, tables, create_table))) + goto unsent_create_error; + #ifndef HAVE_READLINK lex->create_info.data_file_name=lex->create_info.index_file_name=0; #else @@ -2272,7 +2261,7 @@ unsent_create_error: break; } case SQLCOM_CREATE_INDEX: - if (check_one_table_access(thd, INDEX_ACL, tables, 0)) + if (check_one_table_access(thd, INDEX_ACL, tables)) goto error; /* purecov: inspected */ thd->slow_command=TRUE; if (end_active_trans(thd)) @@ -2339,7 +2328,7 @@ unsent_create_error: goto error; /* purecov: inspected */ if (grant_option) { - if (check_grant(thd,ALTER_ACL,tables,0,0)) + if (check_grant(thd, ALTER_ACL, tables, 0, UINT_MAX, 0)) goto error; if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL)) { // Rename of table @@ -2348,7 +2337,8 @@ unsent_create_error: tmp_table.real_name=lex->name; tmp_table.db=select_lex->db; tmp_table.grant.privilege=priv; - if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0, 0)) + if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0, + UINT_MAX, 0)) goto error; } } @@ -2397,10 +2387,11 @@ unsent_create_error: old_list=table[0]; new_list=table->next[0]; old_list.next=new_list.next=0; - if (check_grant(thd,ALTER_ACL,&old_list,0,0) || + if (check_grant(thd, ALTER_ACL, &old_list, 0, UINT_MAX, 0) || (!test_all_bits(table->next->grant.privilege, INSERT_ACL | CREATE_ACL) && - check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list,0,0))) + check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, + UINT_MAX, 0))) goto error; } } @@ -2535,15 +2526,8 @@ unsent_create_error: break; } case SQLCOM_UPDATE: - if (select_lex->item_list.elements != lex->value_list.elements) - { - send_error(thd,ER_WRONG_VALUE_COUNT); - DBUG_VOID_RETURN; - } - if (check_db_used(thd,tables)) - goto error; - if (check_one_table_access(thd, UPDATE_ACL, tables, 0)) - goto error; + if (update_precheck(thd, tables)) + break; res= mysql_update(thd,tables, select_lex->item_list, lex->value_list, @@ -2570,17 +2554,9 @@ unsent_create_error: case SQLCOM_REPLACE: case SQLCOM_INSERT: { - my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0); - ulong privilege= (lex->duplicates == DUP_REPLACE ? - INSERT_ACL | DELETE_ACL : INSERT_ACL | update); - - if (check_one_table_access(thd, privilege, tables, 0)) - goto error; - if (select_lex->item_list.elements != lex->value_list.elements) - { - send_error(thd,ER_WRONG_VALUE_COUNT); - DBUG_VOID_RETURN; - } + my_bool update= (lex->value_list.elements ? UPDATE_ACL : 0); + if ((res= insert_precheck(thd, tables, update))) + break; res = mysql_insert(thd,tables,lex->field_list,lex->many_values, select_lex->item_list, lex->value_list, (update ? DUP_UPDATE : lex->duplicates)); @@ -2634,7 +2610,7 @@ unsent_create_error: break; } case SQLCOM_TRUNCATE: - if (check_one_table_access(thd, DELETE_ACL, tables, 0)) + if (check_one_table_access(thd, DELETE_ACL, tables)) goto error; /* Don't allow this within a transaction because we want to use @@ -2649,10 +2625,8 @@ unsent_create_error: break; case SQLCOM_DELETE: { - if (check_one_table_access(thd, DELETE_ACL, tables, 0)) - goto error; - // Set privilege for the WHERE clause - tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); + if ((res= delete_precheck(thd, tables))) + break; res = mysql_delete(thd,tables, select_lex->where, &select_lex->order_list, select_lex->select_limit, select_lex->options); @@ -2664,10 +2638,9 @@ unsent_create_error: { TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first; - TABLE_LIST *delete_tables= (TABLE_LIST*)select_lex->table_list.first; - - TABLE_LIST *auxi; - uint table_count= 0; + + TABLE_LIST *target_tbl; + uint table_count; multi_delete *result; if ((res= multi_delete_precheck(thd, tables, &table_count))) break; @@ -2685,9 +2658,11 @@ unsent_create_error: if ((res=open_and_lock_tables(thd,tables))) break; /* Fix tables-to-be-deleted-from list to point at opened tables */ - for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next) + for (target_tbl= (TABLE_LIST*) aux_tables; + target_tbl; + target_tbl= target_tbl->next) { - auxi->table= auxi->table_list->table; + target_tbl->table= target_tbl->table_list->table; /* Multi-delete can't be constructed over-union => we always have single SELECT on top and have to check underlaying SELECTs of it @@ -2697,10 +2672,11 @@ unsent_create_error: un= un->next_unit()) { if (un->first_select()->linkage != DERIVED_TABLE_TYPE && - un->check_updateable(auxi->table_list->db, - auxi->table_list->real_name)) + un->check_updateable(target_tbl->table_list->db, + target_tbl->table_list->real_name)) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), auxi->table_list->real_name); + my_error(ER_UPDATE_TABLE_USED, MYF(0), + target_tbl->table_list->real_name); res= -1; break; } @@ -2758,7 +2734,7 @@ unsent_create_error: } break; case SQLCOM_DROP_INDEX: - if (check_one_table_access(thd, INDEX_ACL, tables, 0)) + if (check_one_table_access(thd, INDEX_ACL, tables)) goto error; /* purecov: inspected */ if (end_active_trans(thd)) res= -1; @@ -2873,7 +2849,7 @@ unsent_create_error: if (check_access(thd,SELECT_ACL | EXTRA_ACL,db, &tables->grant.privilege, 0, 0)) goto error; /* purecov: inspected */ - if (grant_option && check_grant(thd,SELECT_ACL,tables,2,0)) + if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0)) goto error; res= mysqld_show_fields(thd,tables, (lex->wild ? lex->wild->ptr() : NullS), @@ -2893,7 +2869,7 @@ unsent_create_error: if (check_access(thd,SELECT_ACL | EXTRA_ACL,db, &tables->grant.privilege, 0, 0)) goto error; /* purecov: inspected */ - if (grant_option && check_grant(thd,SELECT_ACL,tables,2,0)) + if (grant_option && check_grant(thd, SELECT_ACL, tables, 2, UINT_MAX, 0)) goto error; res= mysqld_show_keys(thd,tables); break; @@ -2921,7 +2897,7 @@ unsent_create_error: send_error(thd,ER_NOT_ALLOWED_COMMAND); goto error; } - if (check_one_table_access(thd, privilege, tables, 0)) + if (check_one_table_access(thd, privilege, tables)) goto error; } res=mysql_load(thd, lex->exchange, tables, lex->field_list, @@ -3189,7 +3165,7 @@ unsent_create_error: if (grant_option && check_grant(thd, (lex->grant | lex->grant_tot_col | GRANT_ACL), - tables,0,0)) + tables, 0, UINT_MAX, 0)) goto error; if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns, lex->grant, @@ -3406,32 +3382,26 @@ error: thd Thread handler privilege requested privelage tables table list of command - no_errors Don't send error to client RETURN 0 - OK 1 - access denied, error is sent to client */ int check_one_table_access(THD *thd, ulong privilege, - TABLE_LIST *tables, bool no_errors) + TABLE_LIST *tables) { if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0)) return 1; // Show only 1 table for check_grant - TABLE_LIST *subselects_tables= tables->next; - tables->next= 0; - if (grant_option && check_grant(thd, privilege, tables, 0, 0)) - { - tables->next= subselects_tables; + if (grant_option && check_grant(thd, privilege, tables, 0, 1, 0)) return 1; - } // check rights on tables of subselect (if exists) - if (subselects_tables) + TABLE_LIST *subselects_tables; + if ((subselects_tables= tables->next)) { - tables->next= subselects_tables; if ((check_table_access(thd, SELECT_ACL, subselects_tables,0))) return 1; } @@ -3610,7 +3580,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, } if (grant_option) return check_grant(thd,want_access & ~EXTRA_ACL,org_tables, - test(want_access & EXTRA_ACL), no_errors); + test(want_access & EXTRA_ACL), UINT_MAX, no_errors); return FALSE; } @@ -4961,7 +4931,7 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop) thd - thread handler tables - global table list - RETURN + RETURN VALUE 0 - OK 1 - error (message is sent to user) -1 - error (message is not sent to user) @@ -4986,27 +4956,30 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables) */ for (table= update_list; table; table= table->next) { - TABLE_LIST *save= table->next; - table->next= 0; if ((check_access(thd, UPDATE_ACL, table->db, &table->grant.privilege, 0, 1) || - grant_option && check_grant(thd, UPDATE_ACL, table, 0, 1)) && + grant_option && check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) && (check_access(thd, SELECT_ACL, table->db, &table->grant.privilege, 0, 0) || - grant_option && check_grant(thd, SELECT_ACL, table, 0, 0))) + grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))) DBUG_RETURN(1); - table->next= save; + + /* + We assign following flag only to copy of table, because it will + be checked only if query contains subqueries i.e. only if copy exists + */ if (table->table_list) - table->table_list->checked= 1; + table->table_list->table_in_update_from_clause= 1; } - // tables of subqueries + /* + Is there tables of subqueries? + */ if (&lex->select_lex != lex->all_selects_list) { for (table= tables; table; table= table->next) { - if (table->checked) + if (table->table_in_update_from_clause) { - table->checked= 0; /* If we check table by local TABLE_LIST copy then we should copy grants to global table list, because it will be used for table @@ -5017,13 +4990,10 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables) } else { - TABLE_LIST *save= table->next; - table->next= 0; if (check_access(thd, SELECT_ACL, table->db, &table->grant.privilege, 0, 0) || - grant_option && check_grant(thd, SELECT_ACL, table, 0, 0)) + grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)) DBUG_RETURN(1); - table->next= save; } } } @@ -5050,7 +5020,7 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables) tables - global table list table_count - pointer to table counter - RETURN + RETURN VALUE 0 - OK 1 - error (message is sent to user) -1 - error (message is not sent to user) @@ -5062,7 +5032,9 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first; TABLE_LIST *delete_tables= (TABLE_LIST *)select_lex->table_list.first; - TABLE_LIST *auxi; + TABLE_LIST *target_tbl; + + *table_count= 0; /* sql_yacc guarantees that tables and aux_tables are not zero */ DBUG_ASSERT(aux_tables != 0); @@ -5075,29 +5047,32 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, MYF(0)); DBUG_RETURN(-1); } - for (auxi= aux_tables; auxi; auxi= auxi->next) + for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next) { (*table_count)++; /* All tables in aux_tables must be found in FROM PART */ TABLE_LIST *walk; for (walk= delete_tables; walk; walk= walk->next) { - if (!my_strcasecmp(table_alias_charset, auxi->alias, walk->alias) && - !strcmp(walk->db, auxi->db)) + if (!my_strcasecmp(table_alias_charset, + target_tbl->alias, walk->alias) && + !strcmp(walk->db, target_tbl->db)) break; } if (!walk) { - my_error(ER_UNKNOWN_TABLE, MYF(0), auxi->real_name, "MULTI DELETE"); + my_error(ER_UNKNOWN_TABLE, MYF(0), target_tbl->real_name, + "MULTI DELETE"); DBUG_RETURN(-1); } if (walk->derived) { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), auxi->real_name, "DELETE"); + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), target_tbl->real_name, + "DELETE"); DBUG_RETURN(-1); } - walk->lock_type= auxi->lock_type; - auxi->table_list= walk; // Remember corresponding table + walk->lock_type= target_tbl->lock_type; + target_tbl->table_list= walk; // Remember corresponding table } DBUG_RETURN(0); } @@ -5111,7 +5086,7 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) thd - thread handler tables - global table list - RETURN + RETURN VALUE 0 - OK 1 - error (message is sent to user) -1 - error (message is not sent to user) @@ -5125,7 +5100,122 @@ int insert_select_precheck(THD *thd, TABLE_LIST *tables) */ ulong privilege= (thd->lex->duplicates == DUP_REPLACE ? INSERT_ACL | DELETE_ACL : INSERT_ACL); - if (check_one_table_access(thd, privilege, tables, 0)) + DBUG_RETURN(check_one_table_access(thd, privilege, tables) ? 1 : 0); +} + + +/* + simple UPDATE query pre-check + + SYNOPSIS + update_precheck() + thd - thread handler + tables - global table list + + RETURN VALUE + 0 - OK + 1 - error (message is sent to user) + -1 - error (message is not sent to user) +*/ +int update_precheck(THD *thd, TABLE_LIST *tables) +{ + DBUG_ENTER("update_precheck"); + if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements) + { + my_error(ER_WRONG_VALUE_COUNT, MYF(0)); + DBUG_RETURN(-1); + } + DBUG_RETURN((check_db_used(thd, tables) || + check_one_table_access(thd, UPDATE_ACL, tables)) ? 1 : 0); +} + + +/* + simple DELETE query pre-check + + SYNOPSIS + delete_precheck() + thd - thread handler + tables - global table list + + RETURN VALUE + 0 - OK + 1 - error (message is sent to user) + -1 - error (message is not sent to user) +*/ +int delete_precheck(THD *thd, TABLE_LIST *tables) +{ + DBUG_ENTER("delete_precheck"); + if (check_one_table_access(thd, DELETE_ACL, tables)) + DBUG_RETURN(1); + // Set privilege for the WHERE clause + tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); + DBUG_RETURN(0); +} + + +/* + simple INSERT query pre-check + + SYNOPSIS + insert_precheck() + thd - thread handler + tables - global table list + + RETURN VALUE + 0 - OK + 1 - error (message is sent to user) + -1 - error (message is not sent to user) +*/ +int insert_precheck(THD *thd, TABLE_LIST *tables, bool update) +{ + LEX *lex= thd->lex; + DBUG_ENTER("insert_precheck"); + + ulong privilege= (lex->duplicates == DUP_REPLACE ? + INSERT_ACL | DELETE_ACL : INSERT_ACL | update); + + if (check_one_table_access(thd, privilege, tables)) DBUG_RETURN(1); + + if (lex->select_lex.item_list.elements != lex->value_list.elements) + { + my_error(ER_WRONG_VALUE_COUNT, MYF(0)); + DBUG_RETURN(-1); + } DBUG_RETURN(0); } + + +/* + CREATE TABLE query pre-check + + SYNOPSIS + create_table_precheck() + thd - thread handler + tables - global table list + create_table - table which will be created + + RETURN VALUE + 0 - OK + 1 - error (message is sent to user) + -1 - error (message is not sent to user) +*/ +int create_table_precheck(THD *thd, TABLE_LIST *tables, + TABLE_LIST *create_table) +{ + LEX *lex= thd->lex; + DBUG_ENTER("create_table_precheck"); + ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? + CREATE_TMP_ACL : CREATE_ACL); + lex->create_info.alias= create_table->alias; + if (check_access(thd, want_priv, create_table->db, + &create_table->grant.privilege, 0, 0) || + check_merge_table_access(thd, create_table->db, + (TABLE_LIST *) + lex->create_info.merge_list.first)) + DBUG_RETURN(1); + DBUG_RETURN((grant_option && want_priv != CREATE_TMP_ACL && + check_grant(thd, want_priv, create_table, 0, UINT_MAX, 0)) ? + 1 : 0) +} diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 395adcf974c..69c5be69210 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -631,42 +631,40 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt) #endif /*!EMBEDDED_LIBRARY*/ + /* - Validate the following information for INSERT statement: - - field existence - - fields count + Validate INSERT statement: + SYNOPSIS - mysql_test_insert_fields() + mysql_test_insert() + stmt prepared statemen handler + tables list of tables queries + RETURN VALUE 0 ok 1 error, sent to the client -1 error, not sent to client */ - -static int mysql_test_insert_fields(Prepared_statement *stmt, - TABLE_LIST *table_list, - List<Item> &fields, - List<List_item> &values_list, - List<Item> &update_fields, - List<Item> &update_values, - enum_duplicates duplic) +static int mysql_test_insert(Prepared_statement *stmt, + TABLE_LIST *table_list, + List<Item> &fields, + List<List_item> &values_list, + List<Item> &update_fields, + List<Item> &update_values, + enum_duplicates duplic) { THD *thd= stmt->thd; LEX *lex= stmt->lex; - TABLE *table; List_iterator_fast<List_item> its(values_list); List_item *values; + int res= -1; TABLE_LIST *insert_table_list= (TABLE_LIST*) lex->select_lex.table_list.first; - + my_bool update= (lex->value_list.elements ? UPDATE_ACL : 0); DBUG_ENTER("mysql_test_insert_fields"); -#ifndef NO_EMBEDDED_ACCESS_CHECKS - ulong privilege= (lex->duplicates == DUP_REPLACE ? - INSERT_ACL | DELETE_ACL : INSERT_ACL); - if (check_one_table_access(thd, privilege, table_list, 0)) - DBUG_RETURN(1); -#endif + if ((res= insert_precheck(thd, table_list, update))) + DBUG_RETURN(res); /* open temporary memory pool for temporary data allocated by derived @@ -679,27 +677,16 @@ static int mysql_test_insert_fields(Prepared_statement *stmt, DBUG_RETURN(-1); } - table= table_list->table; - if ((values= its++)) { uint value_count; ulong counter= 0; - - if (check_insert_fields(thd, table, fields, *values, 1) || - setup_tables(insert_table_list) || - setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) || - (duplic == DUP_UPDATE && - (setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) || - setup_fields(thd, 0, insert_table_list, update_values, 0, 0, 0)))) - goto error; - if (find_real_table_in_list(table_list->next, - table_list->db, table_list->real_name)) - { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); - goto error; - } + if ((res= mysql_prepare_insert(thd, table_list, insert_table_list, + table_list->table, fields, values, + update_fields, update_values, duplic))) + goto error; + value_count= values->elements; its.rewind(); @@ -717,50 +704,38 @@ static int mysql_test_insert_fields(Prepared_statement *stmt, goto error; } } - lex->unit.cleanup(); - thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(0); + res= 0; error: lex->unit.cleanup(); thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(-1); + DBUG_RETURN(res); } /* - Validate the following information: - UPDATE - set and where clause - DELETE - where clause + Validate UPDATE statement + SYNOPSIS - mysql_test_upd_fields() + mysql_test_delete() + stmt prepared statemen handler + tables list of tables queries + RETURN VALUE 0 success 1 error, sent to client -1 error, not sent to client */ - -static int mysql_test_upd_fields(Prepared_statement *stmt, - TABLE_LIST *table_list, - List<Item> &fields, List<Item> &values, - COND *conds, ulong privelege) +static int mysql_test_update(Prepared_statement *stmt, + TABLE_LIST *table_list) { + int res; THD *thd= stmt->thd; - SELECT_LEX *select_lex= &stmt->lex->select_lex; - TABLE_LIST *upd_table_list= - (TABLE_LIST*) select_lex->table_list.first; - List<Item> all_fields; - uint order_num= select_lex->order_list.elements; - ORDER *order= (ORDER *) select_lex->order_list.first; - - DBUG_ENTER("mysql_test_upd_fields"); -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_one_table_access(thd, privelege, table_list, 0)) - DBUG_RETURN(1); - // Set privilege for the WHERE clause - table_list->grant.want_privilege= (SELECT_ACL & - ~table_list->grant.privilege); -#endif + SELECT_LEX *select= &stmt->lex->select_lex; + DBUG_ENTER("mysql_test_update"); + + if ((res= update_precheck(thd, table_list))) + DBUG_RETURN(res); /* open temporary memory pool for temporary data allocated by derived @@ -769,57 +744,97 @@ static int mysql_test_upd_fields(Prepared_statement *stmt, thd->allocate_temporary_memory_pool_for_ps_preparing(); if (open_and_lock_tables(thd, table_list)) - goto err; - if (setup_tables(upd_table_list) || - setup_conds(thd, upd_table_list, &conds) || - thd->lex->select_lex.setup_ref_array(thd, order_num) || - setup_fields(thd, 0, upd_table_list, fields, 1, 0, 0) || - setup_order(thd, thd->lex->select_lex.ref_pointer_array, - upd_table_list, all_fields, all_fields, order) || - thd->net.report_error) + res= -1; + else { + TABLE_LIST *update_table_list= (TABLE_LIST *)select->table_list.first; + if (!(res= mysql_prepare_update(thd, table_list, + update_table_list, + &select->where, + select->order_list.elements, + (ORDER *) select->order_list.first))) + { + if (setup_fields(thd, 0, update_table_list, + select->item_list, 1, 0, 0) || + setup_fields(thd, 0, update_table_list, + stmt->lex->value_list, 0, 0, 0)) + res= -1; + } stmt->lex->unit.cleanup(); - goto err; } - - stmt->lex->unit.cleanup(); thd->free_temporary_memory_pool_for_ps_preparing(); + /* TODO: here we should send types of placeholders to the client. */ + DBUG_RETURN(res); +} - /* TODO: here we should send types of placeholders to the client. */ - DBUG_RETURN(0); -err: + +/* + Validate DELETE statement + + SYNOPSIS + mysql_test_delete() + stmt prepared statemen handler + tables list of tables queries + + RETURN VALUE + 0 success + 1 error, sent to client + -1 error, not sent to client +*/ +static int mysql_test_delete(Prepared_statement *stmt, + TABLE_LIST *table_list) +{ + int res; + THD *thd= stmt->thd; + LEX *lex= stmt->lex; + DBUG_ENTER("mysql_test_delete"); + + if ((res= delete_precheck(thd, table_list))) + DBUG_RETURN(res); + + /* + open temporary memory pool for temporary data allocated by derived + tables & preparation procedure + */ + thd->allocate_temporary_memory_pool_for_ps_preparing(); + + if (open_and_lock_tables(thd, table_list)) + res= -1; + else + { + res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where); + lex->unit.cleanup(); + } thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(-1); + /* TODO: here we should send types of placeholders to the client. */ + DBUG_RETURN(res); } + /* - Validate the following information: - SELECT - column list - - where clause - - order clause - - having clause - - group by clause - - if no column spec i.e. '*', then setup all fields + Validate SELECT statement. In case of success, if this query is not EXPLAIN, send column list info back to client. + SYNOPSIS - mysql_test_select_fields() + mysql_test_select() + stmt prepared statemen handler + tables list of tables queries + RETURN VALUE 0 success 1 error, sent to client -1 error, not sent to client */ -static int mysql_test_select_fields(Prepared_statement *stmt, - TABLE_LIST *tables, - List<Item> &fields) +static int mysql_test_select(Prepared_statement *stmt, + TABLE_LIST *tables) { THD *thd= stmt->thd; LEX *lex= stmt->lex; SELECT_LEX_UNIT *unit= &lex->unit; - - DBUG_ENTER("mysql_test_select_fields"); + DBUG_ENTER("mysql_test_select"); #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL; @@ -852,14 +867,15 @@ static int mysql_test_select_fields(Prepared_statement *stmt, { thd->used_tables= 0; // Updated by setup_fields + // JOIN::prepare calls if (unit->prepare(thd, 0, 0)) { send_error(thd); goto err_prep; } - if (send_prep_stmt(stmt, fields.elements) || - thd->protocol_simple.send_fields(&fields, 0) + if (send_prep_stmt(stmt, lex->select_lex.item_list.elements) || + thd->protocol_simple.send_fields(&lex->select_lex.item_list, 0) #ifndef EMBEDDED_LIBRARY || net_flush(&thd->net) #endif @@ -964,11 +980,8 @@ static int mysql_test_set_fields(Prepared_statement *stmt, goto error; } } - stmt->lex->unit.cleanup(); - thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(0); - error: + stmt->lex->unit.cleanup(); thd->free_temporary_memory_pool_for_ps_preparing(); DBUG_RETURN(res); } @@ -982,7 +995,7 @@ error: stmt - prepared table handler tables - global list of tables - RETURN + RETURN VALUE 0 success 1 error, sent to client -1 error, not sent to client @@ -1004,6 +1017,7 @@ static int select_like_statement_test(Prepared_statement *stmt, thd->used_tables= 0; // Updated by setup_fields + // JOIN::prepare calls if (lex->unit.prepare(thd, 0, 0)) { res= thd->net.report_error ? -1 : 1; @@ -1035,37 +1049,23 @@ static int mysql_test_create_table(Prepared_statement *stmt, THD *thd= stmt->thd; LEX *lex= stmt->lex; int res= 0; - - ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? - CREATE_TMP_ACL : CREATE_ACL); - if (check_one_table_access(thd, want_priv, tables, 0) || - check_merge_table_access(thd, tables->db, - (TABLE_LIST *) - lex->create_info.merge_list.first)) - DBUG_RETURN(1); /* Skip first table, which is the table we are creating */ TABLE_LIST *create_table, *create_table_local; tables= lex->unlink_first_table(tables, &create_table, - &create_table_local); - - if (grant_option && want_priv != CREATE_TMP_ACL && - check_grant(thd, want_priv, create_table,0,0)) - { - res= 1; - goto end; - } + &create_table_local); - if (tables) + if (!(res= create_table_precheck(thd, tables, create_table)) && + lex->select_lex.item_list.elements) res= select_like_statement_test(stmt, tables); -end: - // put tables back for PS rexecuting + /* put tables back for PS rexecuting */ tables= lex->link_first_table_back(tables, create_table, create_table_local); DBUG_RETURN(res); } + /* Validate and prepare for execution multy update statement @@ -1110,7 +1110,7 @@ static int mysql_test_multidelete(Prepared_statement *stmt, if (add_item_to_list(stmt->thd, new Item_null())) return -1; - uint fake_counter= 0; + uint fake_counter; if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter))) return res; return select_like_statement_test(stmt, tables); @@ -1161,78 +1161,68 @@ static int mysql_test_insert_select(Prepared_statement *stmt, */ static int send_prepare_results(Prepared_statement *stmt) { - DBUG_ENTER("send_prepare_results"); THD *thd= stmt->thd; LEX *lex= stmt->lex; SELECT_LEX *select_lex= &lex->select_lex; TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first; enum enum_sql_command sql_command= lex->sql_command; - int res; + int res= 0; + DBUG_ENTER("send_prepare_results"); + DBUG_PRINT("enter",("command: %d, param_count: %ld", sql_command, stmt->param_count)); - if (&lex->select_lex != lex->all_selects_list && + if (select_lex != lex->all_selects_list && lex->unit.create_total_list(thd, lex, &tables)) DBUG_RETURN(1); switch (sql_command) { - case SQLCOM_REPLACE: case SQLCOM_INSERT: - if ((res= - mysql_test_insert_fields(stmt, tables, lex->field_list, - lex->many_values, - select_lex->item_list, lex->value_list, - (lex->value_list.elements ? - DUP_UPDATE : lex->duplicates)))) - goto error; + res= mysql_test_insert(stmt, tables, lex->field_list, + lex->many_values, + select_lex->item_list, lex->value_list, + (lex->value_list.elements ? + DUP_UPDATE : lex->duplicates)); break; case SQLCOM_UPDATE: - /* XXX: fallthrough */ + res= mysql_test_update(stmt, tables); + break; + case SQLCOM_DELETE: - if ((res= mysql_test_upd_fields(stmt, tables, select_lex->item_list, - lex->value_list, select_lex->where, - ((sql_command == SQLCOM_DELETE)? - DELETE_ACL : UPDATE_ACL)))) - goto error; + res= mysql_test_delete(stmt, tables); break; case SQLCOM_SELECT: - if ((res= mysql_test_select_fields(stmt, tables, select_lex->item_list))) + if ((res= mysql_test_select(stmt, tables))) goto error; /* Statement and field info has already been sent */ DBUG_RETURN(0); case SQLCOM_CREATE_TABLE: - if ((res= mysql_test_create_table(stmt, tables))) - goto error; + res= mysql_test_create_table(stmt, tables); break; case SQLCOM_DO: - if ((res= mysql_test_do_fields(stmt, tables, lex->insert_list))) - goto error; - break; + res= mysql_test_do_fields(stmt, tables, lex->insert_list); + break; case SQLCOM_SET_OPTION: - if ((res= mysql_test_set_fields(stmt, tables, &lex->var_list))) - goto error; + res= mysql_test_set_fields(stmt, tables, &lex->var_list); break; case SQLCOM_DELETE_MULTI: - if ((res= mysql_test_multidelete(stmt, tables))) - goto error; + res= mysql_test_multidelete(stmt, tables); break; case SQLCOM_UPDATE_MULTI: - if ((res= mysql_test_multiupdate(stmt, tables))) - goto error; + res= mysql_test_multiupdate(stmt, tables); break; case SQLCOM_INSERT_SELECT: - if ((res= mysql_test_insert_select(stmt, tables))) - goto error; + res= mysql_test_insert_select(stmt, tables); break; case SQLCOM_SHOW_DATABASES: @@ -1263,8 +1253,8 @@ static int send_prepare_results(Prepared_statement *stmt) my_error(ER_UNSUPPORTED_PS, MYF(0)); goto error; } - DBUG_RETURN(send_prep_stmt(stmt, 0)); - + if (res == 0) + DBUG_RETURN(send_prep_stmt(stmt, 0)); error: if (res < 0) send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c3c4124db1c..e87a37150ea 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -436,7 +436,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, table_list.db= (char*) db; table_list.real_name=file->name; table_list.grant.privilege=col_access; - if (check_grant(thd,TABLE_ACLS,&table_list,1,1)) + if (check_grant(thd, TABLE_ACLS, &table_list, 1, UINT_MAX, 1)) continue; } #endif diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c7c87a488fd..55ea15f1af4 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -70,8 +70,6 @@ int mysql_update(THD *thd, READ_RECORD info; TABLE_LIST *update_table_list= ((TABLE_LIST*) thd->lex->select_lex.table_list.first); - TABLE_LIST tables; - List<Item> all_fields; DBUG_ENTER("mysql_update"); LINT_INIT(used_index); @@ -86,30 +84,13 @@ int mysql_update(THD *thd, /* Calculate "table->used_keys" based on the WHERE */ table->used_keys=table->keys_in_use; table->quick_keys.clear_all(); + #ifndef NO_EMBEDDED_ACCESS_CHECKS - want_privilege=table->grant.want_privilege; - table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); + want_privilege= table->grant.want_privilege; #endif - - bzero((char*) &tables,sizeof(tables)); // For ORDER BY - tables.table= table; - tables.alias= table_list->alias; - - if (setup_tables(update_table_list) || - setup_conds(thd,update_table_list,&conds) || - thd->lex->select_lex.setup_ref_array(thd, order_num) || - setup_order(thd, thd->lex->select_lex.ref_pointer_array, - update_table_list, all_fields, all_fields, order) || - setup_ftfuncs(&thd->lex->select_lex)) - DBUG_RETURN(-1); /* purecov: inspected */ - - /* Check that we are not using table that we are updating in a sub select */ - if (find_real_table_in_list(table_list->next, - table_list->db, table_list->real_name)) - { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); - DBUG_RETURN(-1); - } + if ((error= mysql_prepare_update(thd, table_list, update_table_list, + &conds, order_num, order))) + DBUG_RETURN(error); old_used_keys= table->used_keys; // Keys used in WHERE /* @@ -406,6 +387,59 @@ err: DBUG_RETURN(-1); } +/* + Prepare items in UPDATE statement + + SYNOPSIS + mysql_prepare_update() + thd - thread handler + table_list - global table list + update_table_list - local table list of UPDATE SELECT_LEX + conds - conditions + order_num - number of ORDER BY list entries + order - ORDER BY clause list + + RETURN VALUE + 0 - OK + 1 - error (message is sent to user) + -1 - error (message is not sent to user) +*/ +int mysql_prepare_update(THD *thd, TABLE_LIST *table_list, + TABLE_LIST *update_table_list, + Item **conds, uint order_num, ORDER *order) +{ + TABLE *table= table_list->table; + TABLE_LIST tables; + List<Item> all_fields; + DBUG_ENTER("mysql_prepare_update"); + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); +#endif + + bzero((char*) &tables,sizeof(tables)); // For ORDER BY + tables.table= table; + tables.alias= table_list->alias; + + if (setup_tables(update_table_list) || + setup_conds(thd, update_table_list, conds) || + thd->lex->select_lex.setup_ref_array(thd, order_num) || + setup_order(thd, thd->lex->select_lex.ref_pointer_array, + update_table_list, all_fields, all_fields, order) || + setup_ftfuncs(&thd->lex->select_lex)) + 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, + table_list->db, table_list->real_name)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); + DBUG_RETURN(-1); + } + + DBUG_RETURN(0); +} + /*************************************************************************** Update multiple tables from join diff --git a/sql/table.h b/sql/table.h index 46516c839a3..b558436de1d 100644 --- a/sql/table.h +++ b/sql/table.h @@ -194,7 +194,8 @@ typedef struct st_table_list bool force_index; /* Prefer index over table scan */ bool ignore_leaves; /* Preload only non-leaf nodes */ bool cacheable_table; /* stop PS caching */ - bool checked; /* used in multi-upd privelege check */ + /* used in multi-upd privelege check */ + bool table_in_update_from_clause; } TABLE_LIST; typedef struct st_changed_table_list |