summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
authorbell@sanja.is.com.ua <>2004-04-08 00:19:43 +0300
committerbell@sanja.is.com.ua <>2004-04-08 00:19:43 +0300
commit56be6f3f9325f056b5343fc9a4a122f30e280d12 (patch)
tree8623a46473c8c2cb769c792a41b7a28bae698da7 /sql/sql_parse.cc
parent3b6c3dd2f5b2416a02b0a878187e977d9bf1d044 (diff)
parent5e37c41faee13cdc977842d253e6da0266766baf (diff)
downloadmariadb-git-56be6f3f9325f056b5343fc9a4a122f30e280d12.tar.gz
merge
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc348
1 files changed, 219 insertions, 129 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 37e0ca7a0c5..0a501dd86c2 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -53,13 +53,10 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
#endif
static void decrease_user_connections(USER_CONN *uc);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
-static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
const char *table_name);
-static int check_one_table_access(THD *thd, ulong privilege,
- TABLE_LIST *tables, bool no_errors);
const char *any_db="*any*"; // Special symbol for check_access
@@ -2168,17 +2165,9 @@ mysql_execute_command(THD *thd)
case SQLCOM_CREATE_TABLE:
{
/* Skip first table, which is the table we are creating */
- TABLE_LIST *create_table= tables;
- TABLE_LIST *create_table_local=
- (TABLE_LIST*)lex->select_lex.table_list.first;
- // exclude from global table list
- tables= tables->next;
- // and from local list if it is not the same
- if (&lex->select_lex != lex->all_selects_list)
- lex->select_lex.table_list.first= (gptr)create_table_local->next;
- else
- lex->select_lex.table_list.first= (gptr)tables;
- create_table->next= 0;
+ TABLE_LIST *create_table, *create_table_local;
+ 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);
@@ -2188,10 +2177,10 @@ mysql_execute_command(THD *thd)
check_merge_table_access(thd, create_table->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
- goto create_eror; /* purecov: inspected */
+ goto create_error; /* purecov: inspected */
if (grant_option && want_priv != CREATE_TMP_ACL &&
check_grant(thd, want_priv, create_table,0,0))
- goto create_eror;
+ goto create_error;
#ifndef HAVE_READLINK
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
@@ -2227,10 +2216,10 @@ mysql_execute_command(THD *thd)
create_table->real_name))
{
net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name);
- goto create_eror;
+ goto create_error;
}
if (tables && check_table_access(thd, SELECT_ACL, tables,0))
- goto create_eror; // Error message is given
+ goto create_error; // Error message is given
select_lex->options|= SELECT_NO_UNLOCK;
unit->offset_limit_cnt= select_lex->offset_limit;
unit->select_limit_cnt= select_lex->select_limit+
@@ -2248,6 +2237,9 @@ mysql_execute_command(THD *thd)
lex->key_list,
select_lex->item_list,lex->duplicates)))
res=handle_select(thd, lex, result);
+ //reset for PS
+ lex->create_list.empty();
+ lex->key_list.empty();
}
}
else // regular create
@@ -2265,35 +2257,18 @@ mysql_execute_command(THD *thd)
if (!res)
send_ok(thd);
}
+
// put tables back for PS rexecuting
- create_table->next= tables;
- tables= create_table;
- if (&lex->select_lex != lex->all_selects_list)
- {
- /*
- we do not touch local table 'next' field => we need just
- put the table in the list
- */
- lex->select_lex.table_list.first= (gptr) create_table_local;
- }
- else
- lex->select_lex.table_list.first= (gptr) tables;
+ tables= lex->link_first_table_back(tables, create_table,
+ create_table_local);
break;
-create_eror:
+create_error:
res= 1; //error reported
unsent_create_error:
// put tables back for PS rexecuting
- create_table->next= tables;
- tables= create_table;
- if (&lex->select_lex != lex->all_selects_list)
- {
- /*
- we do not touch local table 'next' field => we need just
- put the table in the list
- */
- lex->select_lex.table_list.first= (gptr) create_table_local;
- }
+ tables= lex->link_first_table_back(tables, create_table,
+ create_table_local);
break;
}
case SQLCOM_CREATE_INDEX:
@@ -2582,39 +2557,8 @@ unsent_create_error:
break;
case SQLCOM_UPDATE_MULTI:
{
- const char *msg= 0;
- TABLE_LIST *table;
-
- if (select_lex->item_list.elements != lex->value_list.elements)
- {
- send_error(thd,ER_WRONG_VALUE_COUNT);
- DBUG_VOID_RETURN;
- }
- /*
- Ensure that we have UPDATE or SELECT privilege for each table
- The exact privilege is checked in mysql_multi_update()
- */
- for (table= tables ; table ; table= table->next)
- {
- TABLE_LIST *save= table->next;
- table->next= 0;
- if (check_one_table_access(thd, UPDATE_ACL, table, 1) &&
- check_one_table_access(thd, SELECT_ACL, table, 0))
- goto error;
- table->next= save;
- }
-
- if (select_lex->order_list.elements)
- msg= "ORDER BY";
- else if (select_lex->select_limit && select_lex->select_limit !=
- HA_POS_ERROR)
- msg= "LIMIT";
- if (msg)
- {
- net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
- res= 1;
+ if ((res= multi_update_precheck(thd, tables)))
break;
- }
res= mysql_multi_update(thd,tables,
&select_lex->item_list,
&lex->value_list,
@@ -2647,16 +2591,9 @@ unsent_create_error:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
- /*
- Check that we have modify privileges for the first table and
- select privileges for the rest
- */
- {
- ulong privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL);
- if (check_one_table_access(thd, privilege, tables, 0))
- goto error;
- }
+ TABLE_LIST *first_local_table= (TABLE_LIST *) select_lex->table_list.first;
+ if ((res= insert_select_precheck(thd, tables)))
+ break;
/* Fix lock for first table */
if (tables->lock_type == TL_WRITE_DELAYED)
@@ -2677,16 +2614,18 @@ unsent_create_error:
select_lex->options |= OPTION_BUFFER_RESULT;
}
- /* Skip first table, which is the table we are inserting in */
- lex->select_lex.table_list.first=
- (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
- lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;
if (!(res=open_and_lock_tables(thd, tables)))
{
if ((result=new select_insert(tables->table,&lex->field_list,
lex->duplicates)))
+ /* Skip first table, which is the table we are inserting in */
+ lex->select_lex.table_list.first= (gptr) first_local_table->next;
+ lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;
res=handle_select(thd,lex,result);
+ /* revert changes for SP */
+ lex->select_lex.table_list.first= (gptr) first_local_table;
+ lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
if (thd->net.report_error)
res= -1;
}
@@ -2723,51 +2662,25 @@ unsent_create_error:
}
case SQLCOM_DELETE_MULTI:
{
- TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
+ 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;
+ uint table_count= 0;
multi_delete *result;
+ if ((res= multi_delete_precheck(thd, tables, &table_count)))
+ break;
- /* sql_yacc guarantees that tables and aux_tables are not zero */
- if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
- check_table_access(thd,SELECT_ACL, tables,0) ||
- check_table_access(thd,DELETE_ACL, aux_tables,0))
- goto error;
- if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
- {
- send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
- goto error;
- }
- for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
- {
- table_count++;
- /* All tables in aux_tables must be found in FROM PART */
- TABLE_LIST *walk;
- for (walk= (TABLE_LIST*) tables; walk; walk= walk->next)
- {
- if (!my_strcasecmp(table_alias_charset, auxi->alias, walk->alias) &&
- !strcmp(walk->db, auxi->db))
- break;
- }
- if (!walk)
- {
- net_printf(thd, ER_NONUNIQ_TABLE, auxi->real_name);
- goto error;
- }
- if (walk->derived)
- {
- net_printf(thd, ER_NON_UPDATABLE_TABLE,
- auxi->real_name, "DELETE");
- goto error;
- }
- walk->lock_type= auxi->lock_type;
- auxi->table_list= walk; // Remember corresponding table
- }
+ // condition will be TRUE on SP re esexcuting
+ if (select_lex->item_list.elements != 0)
+ select_lex->item_list.empty();
if (add_item_to_list(thd, new Item_null()))
{
res= -1;
break;
}
+
thd->proc_info="init";
if ((res=open_and_lock_tables(thd,tables)))
break;
@@ -3499,9 +3412,8 @@ error:
0 - OK
1 - access denied, error is sent to client
*/
-
-static int check_one_table_access(THD *thd, ulong privilege,
- TABLE_LIST *tables, bool no_errors)
+int check_one_table_access(THD *thd, ulong privilege,
+ TABLE_LIST *tables, bool no_errors)
{
if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
@@ -3702,8 +3614,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
return FALSE;
}
-static bool check_merge_table_access(THD *thd, char *db,
- TABLE_LIST *table_list)
+bool check_merge_table_access(THD *thd, char *db,
+ TABLE_LIST *table_list)
{
int error=0;
if (table_list)
@@ -4993,3 +4905,181 @@ Item * all_any_subquery_creator(Item *left_expr,
return it; /* ANY/SOME */
}
+
+
+/*
+ Multi update query pre-check
+
+ SYNOPSIS
+ multi_update_precheck()
+ thd - thread handler
+ tables - global table list
+
+ RETURN
+ 0 - OK
+ 1 - error (message is sent to user)
+ -1 - error (message is not sent to user)
+*/
+int multi_update_precheck(THD *thd, TABLE_LIST *tables)
+{
+ DBUG_ENTER("multi_update_precheck");
+ const char *msg= 0;
+ TABLE_LIST *table;
+ LEX *lex= thd->lex;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ TABLE_LIST *update_list= (TABLE_LIST*)select_lex->table_list.first;
+
+ if (select_lex->item_list.elements != lex->value_list.elements)
+ {
+ my_error(ER_WRONG_VALUE_COUNT, MYF(0));
+ DBUG_RETURN(-1);
+ }
+ /*
+ Ensure that we have UPDATE or SELECT privilege for each table
+ The exact privilege is checked in mysql_multi_update()
+ */
+ 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)) &&
+ (check_access(thd, SELECT_ACL, table->db,
+ &table->grant.privilege, 0, 0) ||
+ grant_option && check_grant(thd, SELECT_ACL, table, 0, 0)))
+ DBUG_RETURN(1);
+ table->next= save;
+ if (table->table_list)
+ table->table_list->checked= 1;
+ }
+ // tables of subqueries
+ if (&lex->select_lex != lex->all_selects_list)
+ {
+ for (table= tables; table; table= table->next)
+ {
+ if (table->checked)
+ {
+ 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
+ opening.
+ */
+ if (table->table_list)
+ table->grant= table->table_list->grant;
+ }
+ 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))
+ DBUG_RETURN(1);
+ table->next= save;
+ }
+ }
+ }
+
+ if (select_lex->order_list.elements)
+ msg= "ORDER BY";
+ else if (select_lex->select_limit && select_lex->select_limit !=
+ HA_POS_ERROR)
+ msg= "LIMIT";
+ if (msg)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+/*
+ Multi delete query pre-check
+
+ SYNOPSIS
+ multi_delete_precheck()
+ thd - thread handler
+ tables - global table list
+ table_count - pointer to table counter
+
+ RETURN
+ 0 - OK
+ 1 - error (message is sent to user)
+ -1 - error (message is not sent to user)
+*/
+int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
+{
+ DBUG_ENTER("multi_delete_precheck");
+ SELECT_LEX *select_lex= &thd->lex->select_lex;
+ 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;
+
+ /* sql_yacc guarantees that tables and aux_tables are not zero */
+ DBUG_ASSERT(aux_tables != 0);
+ if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
+ check_table_access(thd,SELECT_ACL, tables,0) ||
+ check_table_access(thd,DELETE_ACL, aux_tables,0))
+ DBUG_RETURN(1);
+ if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
+ {
+ my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, MYF(0));
+ DBUG_RETURN(-1);
+ }
+ for (auxi= aux_tables; auxi; auxi= auxi->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))
+ break;
+ }
+ if (!walk)
+ {
+ my_error(ER_UNKNOWN_TABLE, MYF(0), auxi->real_name, "MULTI DELETE");
+ DBUG_RETURN(-1);
+ }
+ if (walk->derived)
+ {
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), auxi->real_name, "DELETE");
+ DBUG_RETURN(-1);
+ }
+ walk->lock_type= auxi->lock_type;
+ auxi->table_list= walk; // Remember corresponding table
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ INSERT ... SELECT query pre-check
+
+ SYNOPSIS
+ multi_delete_precheck()
+ thd - thread handler
+ tables - global table list
+
+ RETURN
+ 0 - OK
+ 1 - error (message is sent to user)
+ -1 - error (message is not sent to user)
+*/
+int insert_select_precheck(THD *thd, TABLE_LIST *tables)
+{
+ DBUG_ENTER("insert_select_precheck");
+ /*
+ Check that we have modify privileges for the first table and
+ select privileges for the rest
+ */
+ ulong privilege= (thd->lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL);
+ if (check_one_table_access(thd, privilege, tables, 0))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}