summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/item_cmpfunc.cc5
-rw-r--r--sql/mysql_priv.h16
-rw-r--r--sql/set_var.cc26
-rw-r--r--sql/sql_acl.cc6
-rw-r--r--sql/sql_acl.h4
-rw-r--r--sql/sql_delete.cc48
-rw-r--r--sql/sql_insert.cc52
-rw-r--r--sql/sql_lex.cc20
-rw-r--r--sql/sql_parse.cc286
-rw-r--r--sql/sql_prepare.cc294
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_update.cc82
-rw-r--r--sql/table.h3
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