diff options
author | unknown <pem@mysql.com> | 2004-05-07 18:52:06 +0200 |
---|---|---|
committer | unknown <pem@mysql.com> | 2004-05-07 18:52:06 +0200 |
commit | e9c1e75b48e5d2c0047a3e88b35667a33d6395e4 (patch) | |
tree | 2f7b236a8721d14f1b398964b898d922fd133131 /sql/sql_parse.cc | |
parent | f3d691a970627f34ed825a9cf7b84520dcdd43b3 (diff) | |
parent | e3211fbd6a59c3dc6a97066c97ab86bfc67d382f (diff) | |
download | mariadb-git-e9c1e75b48e5d2c0047a3e88b35667a33d6395e4.tar.gz |
Merge 4.1 -> 5.0
BitKeeper/etc/ignore:
auto-union
BitKeeper/etc/logging_ok:
auto-union
VC++Files/sql/mysqld.dsp:
Auto merged
configure.in:
Auto merged
include/my_global.h:
Auto merged
include/mysql_com.h:
Auto merged
libmysql/libmysql.c:
Auto merged
libmysqld/Makefile.am:
Auto merged
myisam/myisamchk.c:
Auto merged
myisam/myisamdef.h:
Auto merged
mysql-test/install_test_db.sh:
Auto merged
mysql-test/r/func_time.result:
Auto merged
mysql-test/r/mysqldump.result:
Auto merged
mysql-test/r/show_check.result:
Auto merged
mysql-test/r/subselect.result:
Auto merged
mysql-test/r/union.result:
Auto merged
mysql-test/t/func_time.test:
Auto merged
mysql-test/t/subselect.test:
Auto merged
scripts/make_binary_distribution.sh:
Auto merged
scripts/mysql_install_db.sh:
Auto merged
sql/ha_berkeley.cc:
Auto merged
mysql-test/t/rpl_error_ignored_table.test:
Auto merged
sql/ha_berkeley.h:
Auto merged
sql/ha_innodb.cc:
Auto merged
sql/ha_innodb.h:
Auto merged
sql/ha_myisam.cc:
Auto merged
sql/handler.cc:
Auto merged
sql/handler.h:
Auto merged
sql/item.cc:
Auto merged
sql/item.h:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
sql/item_cmpfunc.h:
Auto merged
sql/item_subselect.cc:
Auto merged
sql/item_sum.cc:
Auto merged
sql/item_sum.h:
Auto merged
sql/lex.h:
Auto merged
sql/log.cc:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/mysqld.cc:
Auto merged
sql/protocol.cc:
Auto merged
sql/records.cc:
Auto merged
sql/set_var.cc:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_acl.h:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_cache.cc:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_db.cc:
Auto merged
sql/sql_delete.cc:
Auto merged
sql/sql_insert.cc:
Auto merged
sql/sql_lex.cc:
Auto merged
sql/sql_load.cc:
Auto merged
sql/sql_prepare.cc:
Auto merged
sql/sql_select.h:
Auto merged
sql/sql_show.cc:
Auto merged
sql/sql_string.cc:
Auto merged
sql/sql_test.cc:
Auto merged
sql/sql_update.cc:
Auto merged
sql/sql_yacc.yy:
Auto merged
sql/table.h:
Auto merged
tests/client_test.c:
Auto merged
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 658 |
1 files changed, 450 insertions, 208 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4ea1fcf3301..057ea6e8bd5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -65,13 +65,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 @@ -1109,6 +1106,12 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg) while (fgets(buff, thd->net.max_packet, file)) { uint length=(uint) strlen(buff); + if (buff[length-1]!='\n' && !feof(file)) + { + send_error(thd,ER_NET_PACKET_TOO_LARGE, NullS); + thd->is_fatal_error= 1; + break; + } while (length && (my_isspace(thd->charset(), buff[length-1]) || buff[length-1] == ';')) length--; @@ -1191,7 +1194,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); @@ -1439,6 +1442,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_EXECUTE: { + thd->free_list= NULL; mysql_stmt_execute(thd, packet, packet_length); break; } @@ -1551,7 +1555,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); @@ -1894,7 +1899,7 @@ mysql_execute_command(THD *thd) if (&lex->select_lex != lex->all_selects_list && lex->unit.create_total_list(thd, lex, &tables)) DBUG_RETURN(0); - + /* When option readonly is set deny operations which change tables. Except for the replication thread and the 'super' users. @@ -1911,6 +1916,13 @@ mysql_execute_command(THD *thd) switch (lex->sql_command) { case SQLCOM_SELECT: { + /* assign global limit variable if limit is not given */ + { + SELECT_LEX *param= lex->unit.global_parameters; + if (!param->explicit_limit) + param->select_limit= thd->variables.select_limit; + } + select_result *result=lex->result; if (tables) { @@ -2150,11 +2162,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; - if (error) + if (check_grant(thd, CREATE_ACL, tables, 0, 1, 0)) goto error; } if (strlen(tables->real_name) > NAME_LEN) @@ -2180,30 +2188,13 @@ 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; - - 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_eror; /* purecov: inspected */ - if (grant_option && want_priv != CREATE_TMP_ACL && - check_grant(thd, want_priv, create_table,0,0)) - goto create_eror; + TABLE_LIST *create_table, *create_table_local; + tables= lex->unlink_first_table(tables, &create_table, + &create_table_local); + + 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 @@ -2239,10 +2230,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->set_limit(select_lex, select_lex); @@ -2256,6 +2247,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 @@ -2273,39 +2267,22 @@ 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: - 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)) @@ -2372,7 +2349,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 @@ -2381,7 +2358,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; } } @@ -2399,6 +2377,7 @@ unsent_create_error: lex->key_list, lex->drop_list, lex->alter_list, select_lex->order_list.elements, (ORDER *) select_lex->order_list.first, + lex->alter_flags, lex->duplicates, lex->alter_keys_onoff, lex->tablespace_op, @@ -2429,10 +2408,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; } } @@ -2547,7 +2527,7 @@ unsent_create_error: res= mysql_alter_table(thd, NullS, NullS, &create_info, tables, lex->create_list, lex->key_list, lex->drop_list, lex->alter_list, - 0, (ORDER *) 0, + 0, (ORDER *) 0, 0, DUP_ERROR); } else @@ -2564,15 +2544,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); - goto error; - } - 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, @@ -2586,39 +2559,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); - goto error; - } - /* - 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, @@ -2630,17 +2572,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); - goto error; - } + 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)); @@ -2651,16 +2585,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) @@ -2678,16 +2605,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= (byte*) 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= (byte*) first_local_table; + lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; if (thd->net.report_error) res= -1; } @@ -2696,7 +2625,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 @@ -2711,10 +2640,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); @@ -2724,58 +2651,33 @@ unsent_create_error: } case SQLCOM_DELETE_MULTI: { - TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first; - TABLE_LIST *auxi; - uint table_count=0; + TABLE_LIST *aux_tables= + (TABLE_LIST *)thd->lex->auxilliary_table_list.first; + TABLE_LIST *target_tbl; + uint table_count; multi_delete *result; - /* 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 - } + if ((res= multi_delete_precheck(thd, tables, &table_count))) + break; + + /* condition will be TRUE on SP re-excuting */ + 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; /* 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 @@ -2785,10 +2687,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; } @@ -2846,7 +2749,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; @@ -2961,7 +2864,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), @@ -2981,7 +2884,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; @@ -3009,7 +2912,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, @@ -3273,7 +3176,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, @@ -3768,33 +3671,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 */ -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) { 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; + /* Show only 1 table for check_grant */ + if (grant_option && check_grant(thd, privilege, tables, 0, 1, 0)) return 1; - } - // check rights on tables of subselect (if exists) - if (subselects_tables) + /* Check rights on tables of subselect (if exists) */ + 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; } @@ -3973,12 +3869,12 @@ 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; } -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) @@ -4135,9 +4031,7 @@ mysql_init_select(LEX *lex) { SELECT_LEX *select_lex= lex->current_select; select_lex->init_select(); - select_lex->select_limit= (&lex->select_lex == select_lex) ? - lex->thd->variables.select_limit : /* Primry UNION */ - HA_POS_ERROR; /* subquery */ + select_lex->select_limit= HA_POS_ERROR; if (select_lex == &lex->select_lex) { lex->exchange= 0; @@ -4189,9 +4083,7 @@ mysql_new_select(LEX *lex, bool move_down) fake->select_number= INT_MAX; fake->make_empty_select(); fake->linkage= GLOBAL_OPTIONS_TYPE; - fake->select_limit= (&lex->unit == unit) ? - lex->thd->variables.select_limit : /* Primry UNION */ - HA_POS_ERROR; /* subquery */ + fake->select_limit= HA_POS_ERROR; } } @@ -4249,6 +4141,7 @@ void mysql_init_multi_delete(LEX *lex) When you modify mysql_parse(), you may need to mofify mysql_test_parse_for_slave() in this same file. */ + void mysql_parse(THD *thd, char *inBuf, uint length) { DBUG_ENTER("mysql_parse"); @@ -4771,7 +4664,6 @@ static void remove_escape(char *name) bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) { ORDER *order; - Item **item_ptr; DBUG_ENTER("add_to_list"); if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)))) DBUG_RETURN(1); @@ -5289,3 +5181,353 @@ Item * all_any_subquery_creator(Item *left_expr, return it; /* ANY/SOME */ } + + +/* + CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with + the proper arguments. This isn't very fast but it should work for most + cases. + + In the future ALTER TABLE will notice that only added indexes + and create these one by one for the existing table without having to do + a full rebuild. + + One should normally create all indexes with CREATE TABLE or ALTER TABLE. +*/ + +int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys) +{ + List<create_field> fields; + List<Alter_drop> drop; + List<Alter_column> alter; + HA_CREATE_INFO create_info; + DBUG_ENTER("mysql_create_index"); + bzero((char*) &create_info,sizeof(create_info)); + create_info.db_type=DB_TYPE_DEFAULT; + create_info.default_table_charset= thd->variables.collation_database; + DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name, + &create_info, table_list, + fields, keys, drop, alter, 0, (ORDER*)0, + ALTER_ADD_INDEX, DUP_ERROR)); +} + + +int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop) +{ + List<create_field> fields; + List<Key> keys; + List<Alter_column> alter; + HA_CREATE_INFO create_info; + DBUG_ENTER("mysql_drop_index"); + bzero((char*) &create_info,sizeof(create_info)); + create_info.db_type=DB_TYPE_DEFAULT; + create_info.default_table_charset= thd->variables.collation_database; + DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name, + &create_info, table_list, + fields, keys, drop, alter, 0, (ORDER*)0, + ALTER_DROP_INDEX, DUP_ERROR)); +} + + +/* + Multi update query pre-check + + SYNOPSIS + multi_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 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) + { + if ((check_access(thd, UPDATE_ACL, table->db, + &table->grant.privilege, 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, 1, 0))) + DBUG_RETURN(1); + + /* + 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->table_in_update_from_clause= 1; + } + /* + Is there tables of subqueries? + */ + if (&lex->select_lex != lex->all_selects_list) + { + for (table= tables; table; table= table->next) + { + if (table->table_in_update_from_clause) + { + /* + 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 + { + if (check_access(thd, SELECT_ACL, table->db, + &table->grant.privilege, 0, 0) || + grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)) + DBUG_RETURN(1); + } + } + } + + 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 VALUE + 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 *target_tbl; + + *table_count= 0; + + /* 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 (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, + target_tbl->alias, walk->alias) && + !strcmp(walk->db, target_tbl->db)) + break; + } + if (!walk) + { + 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), target_tbl->real_name, + "DELETE"); + DBUG_RETURN(-1); + } + walk->lock_type= target_tbl->lock_type; + target_tbl->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 VALUE + 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); + 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); +} |