Fix for bug #9486 "Can't perform multi-update in stored procedure".

New more SP-locking friendly approach to handling locks in multi-update.
Now we mark all tables of multi-update as needing write lock at parsing
stage and if possible downgrade lock at execution stage (For its work
SP-locking mechanism needs to know all lock types right after parsing
stage).
parent 32221d9b
......@@ -23,3 +23,20 @@ select * from t1;
s1 s2 s3
drop table t1;
drop procedure bug4934;
drop procedure if exists bug9486;
drop table if exists t1, t2;
create table t1 (id1 int, val int);
create table t2 (id2 int);
create procedure bug9486()
update t1, t2 set val= 1 where id1=id2;
call bug9486();
lock tables t2 write;
call bug9486();
show processlist;
Id User Host db Command Time State Info
# root localhost test Sleep # NULL
# root localhost test Query # Locked call bug9486()
# root localhost test Query # NULL show processlist
unlock tables;
drop procedure bug9486;
drop table t1, t2;
......@@ -54,6 +54,37 @@ drop table t1;
drop procedure bug4934;
#
# BUG #9486 "Can't perform multi-update in stored procedure"
#
--disable_warnings
drop procedure if exists bug9486;
drop table if exists t1, t2;
--enable_warnings
create table t1 (id1 int, val int);
create table t2 (id2 int);
create procedure bug9486()
update t1, t2 set val= 1 where id1=id2;
call bug9486();
# Let us check that SP invocation requires write lock for t2.
connection con2root;
lock tables t2 write;
connection con1root;
send call bug9486();
connection con2root;
--sleep 2
# There should be call statement in locked state.
--replace_column 1 # 6 #
show processlist;
unlock tables;
connection con1root;
reap;
drop procedure bug9486;
drop table t1, t2;
#
# BUG#NNNN: New bug synopsis
#
......
......@@ -2026,6 +2026,12 @@ typedef struct st_sp_table
LEX_STRING qname;
bool temp;
TABLE_LIST *table;
/*
We can't use table->lock_type as lock type for table
in multi-set since it can be changed by statement during
its execution (e.g. as this happens for multi-update).
*/
thr_lock_type lock_type;
uint lock_count;
uint query_lock_count;
} SP_TABLE;
......@@ -2097,8 +2103,8 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
*/
if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen)))
{
if (tab->table->lock_type < table->lock_type)
tab->table= table; // Use the table with the highest lock type
if (tab->lock_type < table->lock_type)
tab->lock_type= table->lock_type; // Use the table with the highest lock type
tab->query_lock_count++;
if (tab->query_lock_count > tab->lock_count)
tab->lock_count++;
......@@ -2116,6 +2122,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
tab->temp= TRUE;
tab->table= table;
tab->lock_type= table->lock_type;
tab->lock_count= tab->query_lock_count= 1;
my_hash_insert(&m_sptabs, (byte *)tab);
}
......@@ -2188,7 +2195,7 @@ sp_head::add_used_tables_to_table_list(THD *thd,
table->alias= otable->alias;
table->table_name= otable->table_name;
table->table_name_length= otable->table_name_length;
table->lock_type= otable->lock_type;
table->lock_type= stab->lock_type;
table->cacheable_table= 1;
table->prelocking_placeholder= 1;
......
......@@ -732,7 +732,7 @@ typedef struct st_lex
USER_RESOURCES mqh;
ulong type;
enum_sql_command sql_command, orig_sql_command;
thr_lock_type lock_option, multi_lock_option;
thr_lock_type lock_option;
enum SSL_type ssl_type; /* defined in violite.h */
enum my_lex_states next_state;
enum enum_duplicates duplicates;
......
......@@ -1012,11 +1012,6 @@ static int mysql_test_update(Prepared_statement *stmt,
DBUG_PRINT("info", ("Switch to multi-update"));
/* pass counter value */
thd->lex->table_count= table_count;
/*
give correct value to multi_lock_option, because it will be used
in multiupdate
*/
thd->lex->multi_lock_option= table_list->lock_type;
/* convert to multiupdate */
return 2;
}
......
......@@ -145,11 +145,6 @@ int mysql_update(THD *thd,
DBUG_PRINT("info", ("Switch to multi-update"));
/* pass counter value */
thd->lex->table_count= table_count;
/*
give correct value to multi_lock_option, because it will be used
in multiupdate
*/
thd->lex->multi_lock_option= table_list->lock_type;
/* convert to multiupdate */
return 2;
}
......@@ -692,8 +687,10 @@ bool mysql_multi_update_prepare(THD *thd)
}
DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
tl->lock_type= lex->multi_lock_option;
tl->updating= 1;
/*
If table will be updated we should not downgrade lock for it and
leave it as is.
*/
}
else
{
......@@ -705,15 +702,15 @@ bool mysql_multi_update_prepare(THD *thd)
*/
tl->lock_type= using_update_log ? TL_READ_NO_INSERT : TL_READ;
tl->updating= 0;
/* Update TABLE::lock_type accordingly. */
if (!tl->placeholder() && !tl->schema_table && !using_lock_tables)
tl->table->reginfo.lock_type= tl->lock_type;
}
/* Check access privileges for table */
if (!tl->derived && !tl->belong_to_view)
{
uint want_privilege= tl->updating ? UPDATE_ACL : SELECT_ACL;
if (!using_lock_tables)
tl->table->reginfo.lock_type= tl->lock_type;
if (check_access(thd, want_privilege,
tl->db, &tl->grant.privilege, 0, 0) ||
(grant_option && check_grant(thd, want_privilege, tl, 0, 1, 0)))
......@@ -847,7 +844,7 @@ bool mysql_multi_update(THD *thd,
result, unit, select_lex);
delete result;
thd->abort_on_warning= 0;
DBUG_RETURN(TRUE);
DBUG_RETURN(FALSE);
}
......
......@@ -5969,10 +5969,7 @@ update:
{
LEX *lex= Lex;
if (lex->select_lex.table_list.elements > 1)
{
lex->sql_command= SQLCOM_UPDATE_MULTI;
lex->multi_lock_option= $3;
}
else if (lex->select_lex.get_table_list()->derived)
{
/* it is single table update and it is update of derived table */
......@@ -5980,7 +5977,11 @@ update:
lex->select_lex.get_table_list()->alias, "UPDATE");
YYABORT;
}
else
/*
In case of multi-update setting write lock for all tables may
be too pessimistic. We will decrease lock level if possible in
mysql_multi_update().
*/
Select->set_lock_for_tables($3);
}
where_clause opt_order_clause delete_limit_clause {}
......
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