Commit fae0b7f7 authored by dlenev@mysql.com's avatar dlenev@mysql.com

Manual merge

parents 8feae4d4 5394a1a4
...@@ -40,3 +40,18 @@ Id User Host db Command Time State Info ...@@ -40,3 +40,18 @@ Id User Host db Command Time State Info
unlock tables; unlock tables;
drop procedure bug9486; drop procedure bug9486;
drop table t1, t2; drop table t1, t2;
drop procedure if exists bug11158;
create procedure bug11158() delete t1 from t1, t2 where t1.id = t2.id;
create table t1 (id int, j int);
insert into t1 values (1, 1), (2, 2);
create table t2 (id int);
insert into t2 values (1);
call bug11158();
select * from t1;
id j
2 2
lock tables t2 read;
call bug11158();
unlock tables;
drop procedure bug11158;
drop table t1, t2;
...@@ -84,6 +84,32 @@ reap; ...@@ -84,6 +84,32 @@ reap;
drop procedure bug9486; drop procedure bug9486;
drop table t1, t2; drop table t1, t2;
#
# BUG#11158: Can't perform multi-delete in stored procedure
#
--disable_warnings
drop procedure if exists bug11158;
--enable_warnings
create procedure bug11158() delete t1 from t1, t2 where t1.id = t2.id;
create table t1 (id int, j int);
insert into t1 values (1, 1), (2, 2);
create table t2 (id int);
insert into t2 values (1);
# Procedure should work and cause proper effect (delete only first row)
call bug11158();
select * from t1;
# Also let us test that we obtain only read (and thus non exclusive) lock
# for table from which we are not going to delete rows.
connection con2root;
lock tables t2 read;
connection con1root;
call bug11158();
connection con2root;
unlock tables;
connection con1root;
# Clean-up
drop procedure bug11158;
drop table t1, t2;
# #
# BUG#NNNN: New bug synopsis # BUG#NNNN: New bug synopsis
......
...@@ -482,7 +482,7 @@ bool check_merge_table_access(THD *thd, char *db, ...@@ -482,7 +482,7 @@ bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list); TABLE_LIST *table_list);
bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc); bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc);
bool multi_update_precheck(THD *thd, TABLE_LIST *tables); bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count); bool multi_delete_precheck(THD *thd, TABLE_LIST *tables);
bool mysql_multi_update_prepare(THD *thd); bool mysql_multi_update_prepare(THD *thd);
bool mysql_multi_delete_prepare(THD *thd); bool mysql_multi_delete_prepare(THD *thd);
bool mysql_insert_select_prepare(THD *thd); bool mysql_insert_select_prepare(THD *thd);
...@@ -577,6 +577,7 @@ void mysql_init_query(THD *thd, uchar *buf, uint length); ...@@ -577,6 +577,7 @@ void mysql_init_query(THD *thd, uchar *buf, uint length);
bool mysql_new_select(LEX *lex, bool move_down); bool mysql_new_select(LEX *lex, bool move_down);
void create_select_for_variable(const char *var_name); void create_select_for_variable(const char *var_name);
void mysql_init_multi_delete(LEX *lex); void mysql_init_multi_delete(LEX *lex);
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
void init_max_user_conn(void); void init_max_user_conn(void);
void init_update_queries(void); void init_update_queries(void);
void free_max_user_conn(void); void free_max_user_conn(void);
......
...@@ -42,7 +42,6 @@ static my_bool open_new_frm(const char *path, const char *alias, ...@@ -42,7 +42,6 @@ static my_bool open_new_frm(const char *path, const char *alias,
uint db_stat, uint prgflag, uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam, uint ha_open_flags, TABLE *outparam,
TABLE_LIST *table_desc, MEM_ROOT *mem_root); TABLE_LIST *table_desc, MEM_ROOT *mem_root);
static void relink_tables_for_multidelete(THD *thd);
extern "C" byte *table_cache_key(const byte *record,uint *length, extern "C" byte *table_cache_key(const byte *record,uint *length,
my_bool not_used __attribute__((unused))) my_bool not_used __attribute__((unused)))
...@@ -2089,7 +2088,6 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) ...@@ -2089,7 +2088,6 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
(thd->fill_derived_tables() && (thd->fill_derived_tables() &&
mysql_handle_derived(thd->lex, &mysql_derived_filling))) mysql_handle_derived(thd->lex, &mysql_derived_filling)))
DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(TRUE); /* purecov: inspected */
relink_tables_for_multidelete(thd);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -2119,36 +2117,10 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables) ...@@ -2119,36 +2117,10 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
if (open_tables(thd, &tables, &counter) || if (open_tables(thd, &tables, &counter) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare)) mysql_handle_derived(thd->lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(TRUE); /* purecov: inspected */
relink_tables_for_multidelete(thd); // Not really needed, but
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/*
Let us propagate pointers to open tables from global table list
to table lists for multi-delete
*/
static void relink_tables_for_multidelete(THD *thd)
{
if (thd->lex->all_selects_list->next_select_in_list())
{
for (SELECT_LEX *sl= thd->lex->all_selects_list;
sl;
sl= sl->next_select_in_list())
{
for (TABLE_LIST *cursor= (TABLE_LIST *) sl->table_list.first;
cursor;
cursor=cursor->next_local)
{
if (cursor->correspondent_table)
cursor->table= cursor->correspondent_table->table;
}
}
}
}
/* /*
Mark all real tables in the list as free for reuse. Mark all real tables in the list as free for reuse.
......
...@@ -751,7 +751,12 @@ typedef struct st_lex ...@@ -751,7 +751,12 @@ typedef struct st_lex
uint grant, grant_tot_col, which_columns; uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option; uint fk_delete_opt, fk_update_opt, fk_match_option;
uint slave_thd_opt, start_transaction_opt; uint slave_thd_opt, start_transaction_opt;
uint table_count; /* used when usual update transformed in multiupdate */ /*
In LEX representing update which were transformed to multi-update
stores total number of tables. For LEX representing multi-delete
holds number of tables from which we will delete records.
*/
uint table_count;
uint8 describe; uint8 describe;
uint8 derived_tables; uint8 derived_tables;
uint8 create_view_algorithm; uint8 create_view_algorithm;
......
...@@ -3291,10 +3291,9 @@ end_with_restore_list: ...@@ -3291,10 +3291,9 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0); DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables= TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first; (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
uint table_count;
multi_delete *result; multi_delete *result;
if ((res= multi_delete_precheck(thd, all_tables, &table_count))) if ((res= multi_delete_precheck(thd, all_tables)))
break; break;
/* condition will be TRUE on SP re-excuting */ /* condition will be TRUE on SP re-excuting */
...@@ -3311,7 +3310,7 @@ end_with_restore_list: ...@@ -3311,7 +3310,7 @@ end_with_restore_list:
goto error; goto error;
if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables, if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
table_count))) lex->table_count)))
{ {
res= mysql_select(thd, &select_lex->ref_pointer_array, res= mysql_select(thd, &select_lex->ref_pointer_array,
select_lex->get_table_list(), select_lex->get_table_list(),
...@@ -6801,23 +6800,19 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) ...@@ -6801,23 +6800,19 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
multi_delete_precheck() multi_delete_precheck()
thd Thread handler thd Thread handler
tables Global/local table list tables Global/local table list
table_count Pointer to table counter
RETURN VALUE RETURN VALUE
FALSE OK FALSE OK
TRUE error TRUE error
*/ */
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
{ {
SELECT_LEX *select_lex= &thd->lex->select_lex; SELECT_LEX *select_lex= &thd->lex->select_lex;
TABLE_LIST *aux_tables= TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first; (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
TABLE_LIST *target_tbl;
DBUG_ENTER("multi_delete_precheck"); DBUG_ENTER("multi_delete_precheck");
*table_count= 0;
/* sql_yacc guarantees that tables and aux_tables are not zero */ /* sql_yacc guarantees that tables and aux_tables are not zero */
DBUG_ASSERT(aux_tables != 0); DBUG_ASSERT(aux_tables != 0);
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) || if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
...@@ -6830,9 +6825,35 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) ...@@ -6830,9 +6825,35 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0)); ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next_local) DBUG_RETURN(FALSE);
}
/*
Link tables in auxilary table list of multi-delete with corresponding
elements in main table list, and set proper locks for them.
SYNOPSIS
multi_delete_set_locks_and_link_aux_tables()
lex - pointer to LEX representing multi-delete
RETURN VALUE
FALSE - success
TRUE - error
*/
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
{
TABLE_LIST *tables= (TABLE_LIST*)lex->select_lex.table_list.first;
TABLE_LIST *target_tbl;
DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables");
lex->table_count= 0;
for (target_tbl= (TABLE_LIST *)lex->auxilliary_table_list.first;
target_tbl; target_tbl= target_tbl->next_local)
{ {
(*table_count)++; lex->table_count++;
/* All tables in aux_tables must be found in FROM PART */ /* All tables in aux_tables must be found in FROM PART */
TABLE_LIST *walk; TABLE_LIST *walk;
for (walk= tables; walk; walk= walk->next_local) for (walk= tables; walk; walk= walk->next_local)
...@@ -6850,14 +6871,6 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) ...@@ -6850,14 +6871,6 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
} }
walk->lock_type= target_tbl->lock_type; walk->lock_type= target_tbl->lock_type;
target_tbl->correspondent_table= walk; // Remember corresponding table target_tbl->correspondent_table= walk; // Remember corresponding table
/* in case of subselects, we need to set lock_type in
* corresponding table in list of all tables */
if (walk->correspondent_table)
{
target_tbl->correspondent_table= walk->correspondent_table;
walk->correspondent_table->lock_type= walk->lock_type;
}
} }
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
......
...@@ -1402,8 +1402,6 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt, ...@@ -1402,8 +1402,6 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt,
static bool mysql_test_multidelete(Prepared_statement *stmt, static bool mysql_test_multidelete(Prepared_statement *stmt,
TABLE_LIST *tables) TABLE_LIST *tables)
{ {
uint fake_counter;
stmt->thd->lex->current_select= &stmt->thd->lex->select_lex; stmt->thd->lex->current_select= &stmt->thd->lex->select_lex;
if (add_item_to_list(stmt->thd, new Item_null())) if (add_item_to_list(stmt->thd, new Item_null()))
{ {
...@@ -1411,7 +1409,7 @@ static bool mysql_test_multidelete(Prepared_statement *stmt, ...@@ -1411,7 +1409,7 @@ static bool mysql_test_multidelete(Prepared_statement *stmt,
goto error; goto error;
} }
if (multi_delete_precheck(stmt->thd, tables, &fake_counter) || if (multi_delete_precheck(stmt->thd, tables) ||
select_like_stmt_test_with_open_n_lock(stmt, tables, select_like_stmt_test_with_open_n_lock(stmt, tables,
&mysql_multi_delete_prepare, &mysql_multi_delete_prepare,
OPTION_SETUP_TABLES_DONE)) OPTION_SETUP_TABLES_DONE))
......
...@@ -6132,10 +6132,17 @@ single_multi: ...@@ -6132,10 +6132,17 @@ single_multi:
| table_wild_list | table_wild_list
{ mysql_init_multi_delete(Lex); } { mysql_init_multi_delete(Lex); }
FROM join_table_list where_clause FROM join_table_list where_clause
{
if (multi_delete_set_locks_and_link_aux_tables(Lex))
YYABORT;
}
| FROM table_wild_list | FROM table_wild_list
{ mysql_init_multi_delete(Lex); } { mysql_init_multi_delete(Lex); }
USING join_table_list where_clause USING join_table_list where_clause
{} {
if (multi_delete_set_locks_and_link_aux_tables(Lex))
YYABORT;
}
; ;
table_wild_list: table_wild_list:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment