diff options
author | bell@sanja.is.com.ua <> | 2004-04-08 00:19:43 +0300 |
---|---|---|
committer | bell@sanja.is.com.ua <> | 2004-04-08 00:19:43 +0300 |
commit | 56be6f3f9325f056b5343fc9a4a122f30e280d12 (patch) | |
tree | 8623a46473c8c2cb769c792a41b7a28bae698da7 /sql/sql_parse.cc | |
parent | 3b6c3dd2f5b2416a02b0a878187e977d9bf1d044 (diff) | |
parent | 5e37c41faee13cdc977842d253e6da0266766baf (diff) | |
download | mariadb-git-56be6f3f9325f056b5343fc9a4a122f30e280d12.tar.gz |
merge
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 348 |
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); +} |