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
unlock tables;
drop procedure bug9486;
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;
drop procedure bug9486;
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
......
......@@ -482,7 +482,7 @@ bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list);
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_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_delete_prepare(THD *thd);
bool mysql_insert_select_prepare(THD *thd);
......@@ -577,6 +577,7 @@ void mysql_init_query(THD *thd, uchar *buf, uint length);
bool mysql_new_select(LEX *lex, bool move_down);
void create_select_for_variable(const char *var_name);
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_update_queries(void);
void free_max_user_conn(void);
......
......@@ -42,7 +42,6 @@ static my_bool open_new_frm(const char *path, const char *alias,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam,
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,
my_bool not_used __attribute__((unused)))
......@@ -2089,7 +2088,6 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
(thd->fill_derived_tables() &&
mysql_handle_derived(thd->lex, &mysql_derived_filling)))
DBUG_RETURN(TRUE); /* purecov: inspected */
relink_tables_for_multidelete(thd);
DBUG_RETURN(0);
}
......@@ -2119,36 +2117,10 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
if (open_tables(thd, &tables, &counter) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE); /* purecov: inspected */
relink_tables_for_multidelete(thd); // Not really needed, but
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.
......
......@@ -751,7 +751,12 @@ typedef struct st_lex
uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
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 derived_tables;
uint8 create_view_algorithm;
......
......@@ -3291,10 +3291,9 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
uint table_count;
multi_delete *result;
if ((res= multi_delete_precheck(thd, all_tables, &table_count)))
if ((res= multi_delete_precheck(thd, all_tables)))
break;
/* condition will be TRUE on SP re-excuting */
......@@ -3311,7 +3310,7 @@ end_with_restore_list:
goto error;
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,
select_lex->get_table_list(),
......@@ -6801,23 +6800,19 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
multi_delete_precheck()
thd Thread handler
tables Global/local table list
table_count Pointer to table counter
RETURN VALUE
FALSE OK
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;
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
TABLE_LIST *target_tbl;
DBUG_ENTER("multi_delete_precheck");
*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) ||
......@@ -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));
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 */
TABLE_LIST *walk;
for (walk= tables; walk; walk= walk->next_local)
......@@ -6850,14 +6871,6 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
}
walk->lock_type= target_tbl->lock_type;
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);
}
......
......@@ -1402,8 +1402,6 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt,
static bool mysql_test_multidelete(Prepared_statement *stmt,
TABLE_LIST *tables)
{
uint fake_counter;
stmt->thd->lex->current_select= &stmt->thd->lex->select_lex;
if (add_item_to_list(stmt->thd, new Item_null()))
{
......@@ -1411,7 +1409,7 @@ static bool mysql_test_multidelete(Prepared_statement *stmt,
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,
&mysql_multi_delete_prepare,
OPTION_SETUP_TABLES_DONE))
......
......@@ -6132,10 +6132,17 @@ single_multi:
| table_wild_list
{ mysql_init_multi_delete(Lex); }
FROM join_table_list where_clause
{
if (multi_delete_set_locks_and_link_aux_tables(Lex))
YYABORT;
}
| FROM table_wild_list
{ mysql_init_multi_delete(Lex); }
USING join_table_list where_clause
{}
{
if (multi_delete_set_locks_and_link_aux_tables(Lex))
YYABORT;
}
;
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