MDEV-6050 MySQL Bug#13036505 62540: TABLE LOCKS WITHIN STORED FUNCTIONS ARE BACK IN 5.5 WITH MIXED AND ROW BI
cherry-pick revno 4053 committer: Gopal Shankar <gopal.shankar@oracle.com> branch nick: sf_mysql-5.6 timestamp: Fri 2012-07-20 12:25:34 +0530 message: Bug#13036505 62540: TABLE LOCKS WITHIN STORED FUNCTIONS ARE BACK IN 5.5 WITH MIXED AND ROW BI.
This commit is contained in:
parent
de4a3c2a1d
commit
8867a499f7
@ -331,13 +331,14 @@ Success: 'update v2 set j= j-10 where j = 3' takes shared row locks on 't1'.
|
||||
# 4.1 SELECT/SET with a stored function which does not
|
||||
# modify data and uses SELECT in its turn.
|
||||
#
|
||||
# In theory there is no need to take row locks on the table
|
||||
# There is no need to take row locks on the table
|
||||
# being selected from in SF as the call to such function
|
||||
# won't get into the binary log. In practice, however, we
|
||||
# discover that fact too late in the process to be able to
|
||||
# affect the decision what locks should be taken.
|
||||
# Hence, strong locks are taken in this case.
|
||||
Success: 'select f1()' takes shared row locks on 't1'.
|
||||
# won't get into the binary log.
|
||||
#
|
||||
# However in practice innodb takes strong lock on tables
|
||||
# being selected from within SF, when SF is called from
|
||||
# non SELECT statements like 'set' statement below.
|
||||
Success: 'select f1()' doesn't take row locks on 't1'.
|
||||
Success: 'set @a:= f1()' takes shared row locks on 't1'.
|
||||
#
|
||||
# 4.2 INSERT (or other statement which modifies data) with
|
||||
@ -364,13 +365,15 @@ Success: 'set @a:= f2()' takes shared row locks on 't1'.
|
||||
# modify data and reads a table through subselect
|
||||
# in a control construct.
|
||||
#
|
||||
# Again, in theory a call to this function won't get to the
|
||||
# binary log and thus no locking is needed. But in practice
|
||||
# we don't detect this fact early enough (get_lock_type_for_table())
|
||||
# to avoid taking row locks.
|
||||
Success: 'select f3()' takes shared row locks on 't1'.
|
||||
# Call to this function won't get to the
|
||||
# binary log and thus no locking is needed.
|
||||
#
|
||||
# However in practice innodb takes strong lock on tables
|
||||
# being selected from within SF, when SF is called from
|
||||
# non SELECT statements like 'set' statement below.
|
||||
Success: 'select f3()' doesn't take row locks on 't1'.
|
||||
Success: 'set @a:= f3()' takes shared row locks on 't1'.
|
||||
Success: 'select f4()' takes shared row locks on 't1'.
|
||||
Success: 'select f4()' doesn't take row locks on 't1'.
|
||||
Success: 'set @a:= f4()' takes shared row locks on 't1'.
|
||||
#
|
||||
# 4.5. INSERT (or other statement which modifies data) with
|
||||
@ -398,13 +401,15 @@ Success: 'set @a:= f5()' takes shared row locks on 't1'.
|
||||
# doesn't modify data and reads tables through
|
||||
# a view.
|
||||
#
|
||||
# Once again, in theory, calls to such functions won't
|
||||
# get into the binary log and thus don't need row
|
||||
# locks. But in practice this fact is discovered
|
||||
# too late to have any effect.
|
||||
Success: 'select f6()' takes shared row locks on 't1'.
|
||||
# Calls to such functions won't get into
|
||||
# the binary log and thus don't need row locks.
|
||||
#
|
||||
# However in practice innodb takes strong lock on tables
|
||||
# being selected from within SF, when SF is called from
|
||||
# non SELECT statements like 'set' statement below.
|
||||
Success: 'select f6()' doesn't take row locks on 't1'.
|
||||
Success: 'set @a:= f6()' takes shared row locks on 't1'.
|
||||
Success: 'select f7()' takes shared row locks on 't1'.
|
||||
Success: 'select f7()' doesn't take row locks on 't1'.
|
||||
Success: 'set @a:= f7()' takes shared row locks on 't1'.
|
||||
#
|
||||
# 4.8 INSERT which uses stored function which
|
||||
@ -431,10 +436,9 @@ Success: 'select f9()' takes shared row locks on 't1'.
|
||||
# data and reads a table indirectly, by calling another
|
||||
# function.
|
||||
#
|
||||
# In theory, calls to such functions won't get into the binary
|
||||
# log and thus don't need to acquire row locks. But in practice
|
||||
# this fact is discovered too late to have any effect.
|
||||
Success: 'select f10()' takes shared row locks on 't1'.
|
||||
# Calls to such functions won't get into the binary
|
||||
# log and thus don't need to acquire row locks.
|
||||
Success: 'select f10()' doesn't take row locks on 't1'.
|
||||
#
|
||||
# 4.11 INSERT which uses a stored function which doesn't modify
|
||||
# data and reads a table indirectly, by calling another
|
||||
@ -494,10 +498,9 @@ Success: 'select f14()' takes shared row locks on 't1'.
|
||||
# 5.3 SELECT that calls a function that doesn't modify data and
|
||||
# uses a CALL statement that reads a table via SELECT.
|
||||
#
|
||||
# In theory, calls to such functions won't get into the binary
|
||||
# log and thus don't need to acquire row locks. But in practice
|
||||
# this fact is discovered too late to have any effect.
|
||||
Success: 'select f15()' takes shared row locks on 't1'.
|
||||
# Calls to such functions won't get into the binary
|
||||
# log and thus don't need to acquire row locks.
|
||||
Success: 'select f15()' doesn't take row locks on 't1'.
|
||||
#
|
||||
# 5.4 INSERT which calls function which doesn't modify data and
|
||||
# uses CALL statement which reads table through SELECT.
|
||||
|
@ -27,6 +27,7 @@ drop table if exists t0, t1, t2, t3, t4, t5;
|
||||
drop view if exists v1, v2;
|
||||
drop procedure if exists p1;
|
||||
drop procedure if exists p2;
|
||||
drop procedure if exists p3;
|
||||
drop function if exists f1;
|
||||
drop function if exists f2;
|
||||
drop function if exists f3;
|
||||
@ -42,6 +43,8 @@ drop function if exists f12;
|
||||
drop function if exists f13;
|
||||
drop function if exists f14;
|
||||
drop function if exists f15;
|
||||
drop function if exists f16;
|
||||
drop function if exists f17;
|
||||
create table t1 (i int primary key);
|
||||
insert into t1 values (1), (2), (3), (4), (5);
|
||||
create table t2 (j int primary key);
|
||||
@ -146,6 +149,26 @@ declare k int;
|
||||
call p2(k);
|
||||
return k;
|
||||
end|
|
||||
create function f16() returns int
|
||||
begin
|
||||
create temporary table if not exists temp1 (a int);
|
||||
insert into temp1 select * from t1;
|
||||
drop temporary table temp1;
|
||||
return 1;
|
||||
end|
|
||||
create function f17() returns int
|
||||
begin
|
||||
declare j int;
|
||||
select i from t1 where i = 1 into j;
|
||||
call p3;
|
||||
return 1;
|
||||
end|
|
||||
create procedure p3()
|
||||
begin
|
||||
create temporary table if not exists temp1 (a int);
|
||||
insert into temp1 select * from t1;
|
||||
drop temporary table temp1;
|
||||
end|
|
||||
create trigger t4_bi before insert on t4 for each row
|
||||
begin
|
||||
declare k int;
|
||||
@ -185,6 +208,7 @@ end|
|
||||
# once during its execution.
|
||||
show create procedure p1;
|
||||
show create procedure p2;
|
||||
show create procedure p3;
|
||||
show create function f1;
|
||||
show create function f2;
|
||||
show create function f3;
|
||||
@ -200,6 +224,8 @@ show create function f12;
|
||||
show create function f13;
|
||||
show create function f14;
|
||||
show create function f15;
|
||||
show create function f16;
|
||||
show create function f17;
|
||||
# Switch back to connection 'default'.
|
||||
#
|
||||
# 1. Statements that read tables and do not use subqueries.
|
||||
@ -359,14 +385,11 @@ Success: 'update v2 set j= j-10 where j = 3' doesn't allow concurrent inserts in
|
||||
# 4.1 SELECT/SET with a stored function which does not
|
||||
# modify data and uses SELECT in its turn.
|
||||
#
|
||||
# In theory there is no need to take strong locks on the table
|
||||
# There is no need to take strong locks on the table
|
||||
# being selected from in SF as the call to such function
|
||||
# won't get into the binary log. In practice, however, we
|
||||
# discover that fact too late in the process to be able to
|
||||
# affect the decision what locks should be taken.
|
||||
# Hence, strong locks are taken in this case.
|
||||
Success: 'select f1()' doesn't allow concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f1()' doesn't allow concurrent inserts into 't1'.
|
||||
# won't get into the binary log.
|
||||
Success: 'select f1()' allows concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f1()' allows concurrent inserts into 't1'.
|
||||
#
|
||||
# 4.2 INSERT (or other statement which modifies data) with
|
||||
# a stored function which does not modify data and uses
|
||||
@ -392,14 +415,12 @@ Success: 'set @a:= f2()' doesn't allow concurrent inserts into 't1'.
|
||||
# modify data and reads a table through subselect
|
||||
# in a control construct.
|
||||
#
|
||||
# Again, in theory a call to this function won't get to the
|
||||
# binary log and thus no strong lock is needed. But in practice
|
||||
# we don't detect this fact early enough (get_lock_type_for_table())
|
||||
# to avoid taking a strong lock.
|
||||
Success: 'select f3()' doesn't allow concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f3()' doesn't allow concurrent inserts into 't1'.
|
||||
Success: 'select f4()' doesn't allow concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f4()' doesn't allow concurrent inserts into 't1'.
|
||||
# Call to this function won't get to the
|
||||
# binary log and thus no strong lock is needed.
|
||||
Success: 'select f3()' allows concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f3()' allows concurrent inserts into 't1'.
|
||||
Success: 'select f4()' allows concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f4()' allows concurrent inserts into 't1'.
|
||||
#
|
||||
# 4.5. INSERT (or other statement which modifies data) with
|
||||
# a stored function which does not modify data and reads
|
||||
@ -426,14 +447,13 @@ Success: 'set @a:= f5()' doesn't allow concurrent inserts into 't1'.
|
||||
# doesn't modify data and reads tables through
|
||||
# a view.
|
||||
#
|
||||
# Once again, in theory, calls to such functions won't
|
||||
# get into the binary log and thus don't need strong
|
||||
# locks. But in practice this fact is discovered
|
||||
# too late to have any effect.
|
||||
Success: 'select f6()' doesn't allow concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f6()' doesn't allow concurrent inserts into 't1'.
|
||||
Success: 'select f7()' doesn't allow concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f7()' doesn't allow concurrent inserts into 't1'.
|
||||
# Calls to such functions won't get into
|
||||
# the binary log and thus don't need strong
|
||||
# locks.
|
||||
Success: 'select f6()' allows concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f6()' allows concurrent inserts into 't1'.
|
||||
Success: 'select f7()' allows concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f7()' allows concurrent inserts into 't1'.
|
||||
#
|
||||
# 4.8 INSERT which uses stored function which
|
||||
# doesn't modify data and reads a table
|
||||
@ -459,10 +479,9 @@ Success: 'select f9()' doesn't allow concurrent inserts into 't1'.
|
||||
# data and reads a table indirectly, by calling another
|
||||
# function.
|
||||
#
|
||||
# In theory, calls to such functions won't get into the binary
|
||||
# log and thus don't need to acquire strong locks. But in practice
|
||||
# this fact is discovered too late to have any effect.
|
||||
Success: 'select f10()' doesn't allow concurrent inserts into 't1'.
|
||||
# Calls to such functions won't get into the binary
|
||||
# log and thus don't need to acquire strong locks.
|
||||
Success: 'select f10()' allows concurrent inserts into 't1'.
|
||||
#
|
||||
# 4.11 INSERT which uses a stored function which doesn't modify
|
||||
# data and reads a table indirectly, by calling another
|
||||
@ -501,6 +520,26 @@ Success: 'select f12((select i+10 from t1 where i=1))' allows concurrent inserts
|
||||
# uses. Therefore it should take strong locks on the data it reads.
|
||||
Success: 'insert into t2 values (f13((select i+10 from t1 where i=1)))' doesn't allow concurrent inserts into 't1'.
|
||||
#
|
||||
# 4.15 SELECT/SET with a stored function which
|
||||
# inserts data into a temporary table using
|
||||
# SELECT on t1.
|
||||
#
|
||||
# Since this statement is written to the binary log it should
|
||||
# be serialized with concurrent statements affecting the data it
|
||||
# uses. Therefore it should take strong locks on the data it reads.
|
||||
Success: 'select f16()' doesn't allow concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f16()' doesn't allow concurrent inserts into 't1'.
|
||||
#
|
||||
# 4.16 SELECT/SET with a stored function which call procedure
|
||||
# which inserts data into a temporary table using
|
||||
# SELECT on t1.
|
||||
#
|
||||
# Since this statement is written to the binary log it should
|
||||
# be serialized with concurrent statements affecting the data it
|
||||
# uses. Therefore it should take strong locks on the data it reads.
|
||||
Success: 'select f17()' doesn't allow concurrent inserts into 't1'.
|
||||
Success: 'set @a:= f17()' doesn't allow concurrent inserts into 't1'.
|
||||
#
|
||||
# 5. Statements that read tables through stored procedures.
|
||||
#
|
||||
#
|
||||
@ -522,10 +561,9 @@ Success: 'select f14()' doesn't allow concurrent inserts into 't1'.
|
||||
# 5.3 SELECT that calls a function that doesn't modify data and
|
||||
# uses a CALL statement that reads a table via SELECT.
|
||||
#
|
||||
# In theory, calls to such functions won't get into the binary
|
||||
# log and thus don't need to acquire strong locks. But in practice
|
||||
# this fact is discovered too late to have any effect.
|
||||
Success: 'select f15()' doesn't allow concurrent inserts into 't1'.
|
||||
# Calls to such functions won't get into the binary
|
||||
# log and thus don't need to acquire strong locks.
|
||||
Success: 'select f15()' allows concurrent inserts into 't1'.
|
||||
#
|
||||
# 5.4 INSERT which calls function which doesn't modify data and
|
||||
# uses CALL statement which reads table through SELECT.
|
||||
@ -585,9 +623,12 @@ drop function f12;
|
||||
drop function f13;
|
||||
drop function f14;
|
||||
drop function f15;
|
||||
drop function f16;
|
||||
drop function f17;
|
||||
drop view v1, v2;
|
||||
drop procedure p1;
|
||||
drop procedure p2;
|
||||
drop procedure p3;
|
||||
drop table t1, t2, t3, t4, t5;
|
||||
set @@global.concurrent_insert= @old_concurrent_insert;
|
||||
#
|
||||
|
@ -440,15 +440,16 @@ let $wait_statement= $statement;
|
||||
--echo # 4.1 SELECT/SET with a stored function which does not
|
||||
--echo # modify data and uses SELECT in its turn.
|
||||
--echo #
|
||||
--echo # In theory there is no need to take row locks on the table
|
||||
--echo # There is no need to take row locks on the table
|
||||
--echo # being selected from in SF as the call to such function
|
||||
--echo # won't get into the binary log. In practice, however, we
|
||||
--echo # discover that fact too late in the process to be able to
|
||||
--echo # affect the decision what locks should be taken.
|
||||
--echo # Hence, strong locks are taken in this case.
|
||||
--echo # won't get into the binary log.
|
||||
--echo #
|
||||
--echo # However in practice innodb takes strong lock on tables
|
||||
--echo # being selected from within SF, when SF is called from
|
||||
--echo # non SELECT statements like 'set' statement below.
|
||||
let $statement= select f1();
|
||||
let $wait_statement= select i from t1 where i = 1 into j;
|
||||
--source include/check_shared_row_lock.inc
|
||||
--source include/check_no_row_lock.inc
|
||||
let $statement= set @a:= f1();
|
||||
let $wait_statement= select i from t1 where i = 1 into j;
|
||||
--source include/check_shared_row_lock.inc
|
||||
@ -486,19 +487,21 @@ let $wait_statement= select i from t1 where i = 1 into k;
|
||||
--echo # modify data and reads a table through subselect
|
||||
--echo # in a control construct.
|
||||
--echo #
|
||||
--echo # Again, in theory a call to this function won't get to the
|
||||
--echo # binary log and thus no locking is needed. But in practice
|
||||
--echo # we don't detect this fact early enough (get_lock_type_for_table())
|
||||
--echo # to avoid taking row locks.
|
||||
--echo # Call to this function won't get to the
|
||||
--echo # binary log and thus no locking is needed.
|
||||
--echo #
|
||||
--echo # However in practice innodb takes strong lock on tables
|
||||
--echo # being selected from within SF, when SF is called from
|
||||
--echo # non SELECT statements like 'set' statement below.
|
||||
let $statement= select f3();
|
||||
let $wait_statement= $statement;
|
||||
--source include/check_shared_row_lock.inc
|
||||
--source include/check_no_row_lock.inc
|
||||
let $statement= set @a:= f3();
|
||||
let $wait_statement= $statement;
|
||||
--source include/check_shared_row_lock.inc
|
||||
let $statement= select f4();
|
||||
let $wait_statement= $statement;
|
||||
--source include/check_shared_row_lock.inc
|
||||
--source include/check_no_row_lock.inc
|
||||
let $statement= set @a:= f4();
|
||||
let $wait_statement= $statement;
|
||||
--source include/check_shared_row_lock.inc
|
||||
@ -539,19 +542,21 @@ let $wait_statement= insert into t2 values ((select i from t1 where i = 1) + 5);
|
||||
--echo # doesn't modify data and reads tables through
|
||||
--echo # a view.
|
||||
--echo #
|
||||
--echo # Once again, in theory, calls to such functions won't
|
||||
--echo # get into the binary log and thus don't need row
|
||||
--echo # locks. But in practice this fact is discovered
|
||||
--echo # too late to have any effect.
|
||||
--echo # Calls to such functions won't get into
|
||||
--echo # the binary log and thus don't need row locks.
|
||||
--echo #
|
||||
--echo # However in practice innodb takes strong lock on tables
|
||||
--echo # being selected from within SF, when SF is called from
|
||||
--echo # non SELECT statements like 'set' statement below.
|
||||
let $statement= select f6();
|
||||
let $wait_statement= select i from v1 where i = 1 into k;
|
||||
--source include/check_shared_row_lock.inc
|
||||
--source include/check_no_row_lock.inc
|
||||
let $statement= set @a:= f6();
|
||||
let $wait_statement= select i from v1 where i = 1 into k;
|
||||
--source include/check_shared_row_lock.inc
|
||||
let $statement= select f7();
|
||||
let $wait_statement= select j from v2 where j = 1 into k;
|
||||
--source include/check_shared_row_lock.inc
|
||||
--source include/check_no_row_lock.inc
|
||||
let $statement= set @a:= f7();
|
||||
let $wait_statement= select j from v2 where j = 1 into k;
|
||||
--source include/check_shared_row_lock.inc
|
||||
@ -592,12 +597,11 @@ let $wait_statement= update v2 set j=j+10 where j=1;
|
||||
--echo # data and reads a table indirectly, by calling another
|
||||
--echo # function.
|
||||
--echo #
|
||||
--echo # In theory, calls to such functions won't get into the binary
|
||||
--echo # log and thus don't need to acquire row locks. But in practice
|
||||
--echo # this fact is discovered too late to have any effect.
|
||||
--echo # Calls to such functions won't get into the binary
|
||||
--echo # log and thus don't need to acquire row locks.
|
||||
let $statement= select f10();
|
||||
let $wait_statement= select i from t1 where i = 1 into j;
|
||||
--source include/check_shared_row_lock.inc
|
||||
--source include/check_no_row_lock.inc
|
||||
|
||||
--echo #
|
||||
--echo # 4.11 INSERT which uses a stored function which doesn't modify
|
||||
@ -676,12 +680,11 @@ let $wait_statement= select i from t1 where i = 1 into p;
|
||||
--echo # 5.3 SELECT that calls a function that doesn't modify data and
|
||||
--echo # uses a CALL statement that reads a table via SELECT.
|
||||
--echo #
|
||||
--echo # In theory, calls to such functions won't get into the binary
|
||||
--echo # log and thus don't need to acquire row locks. But in practice
|
||||
--echo # this fact is discovered too late to have any effect.
|
||||
--echo # Calls to such functions won't get into the binary
|
||||
--echo # log and thus don't need to acquire row locks.
|
||||
let $statement= select f15();
|
||||
let $wait_statement= select i from t1 where i = 1 into p;
|
||||
--source include/check_shared_row_lock.inc
|
||||
--source include/check_no_row_lock.inc
|
||||
|
||||
--echo #
|
||||
--echo # 5.4 INSERT which calls function which doesn't modify data and
|
||||
|
@ -49,6 +49,7 @@ drop table if exists t0, t1, t2, t3, t4, t5;
|
||||
drop view if exists v1, v2;
|
||||
drop procedure if exists p1;
|
||||
drop procedure if exists p2;
|
||||
drop procedure if exists p3;
|
||||
drop function if exists f1;
|
||||
drop function if exists f2;
|
||||
drop function if exists f3;
|
||||
@ -64,6 +65,8 @@ drop function if exists f12;
|
||||
drop function if exists f13;
|
||||
drop function if exists f14;
|
||||
drop function if exists f15;
|
||||
drop function if exists f16;
|
||||
drop function if exists f17;
|
||||
--enable_warnings
|
||||
create table t1 (i int primary key);
|
||||
insert into t1 values (1), (2), (3), (4), (5);
|
||||
@ -170,6 +173,26 @@ begin
|
||||
call p2(k);
|
||||
return k;
|
||||
end|
|
||||
create function f16() returns int
|
||||
begin
|
||||
create temporary table if not exists temp1 (a int);
|
||||
insert into temp1 select * from t1;
|
||||
drop temporary table temp1;
|
||||
return 1;
|
||||
end|
|
||||
create function f17() returns int
|
||||
begin
|
||||
declare j int;
|
||||
select i from t1 where i = 1 into j;
|
||||
call p3;
|
||||
return 1;
|
||||
end|
|
||||
create procedure p3()
|
||||
begin
|
||||
create temporary table if not exists temp1 (a int);
|
||||
insert into temp1 select * from t1;
|
||||
drop temporary table temp1;
|
||||
end|
|
||||
create trigger t4_bi before insert on t4 for each row
|
||||
begin
|
||||
declare k int;
|
||||
@ -217,6 +240,7 @@ connection con1;
|
||||
--disable_result_log
|
||||
show create procedure p1;
|
||||
show create procedure p2;
|
||||
show create procedure p3;
|
||||
show create function f1;
|
||||
show create function f2;
|
||||
show create function f3;
|
||||
@ -232,6 +256,8 @@ show create function f12;
|
||||
show create function f13;
|
||||
show create function f14;
|
||||
show create function f15;
|
||||
show create function f16;
|
||||
show create function f17;
|
||||
--enable_result_log
|
||||
--echo # Switch back to connection 'default'.
|
||||
connection default;
|
||||
@ -492,18 +518,15 @@ let $restore_table= t2;
|
||||
--echo # 4.1 SELECT/SET with a stored function which does not
|
||||
--echo # modify data and uses SELECT in its turn.
|
||||
--echo #
|
||||
--echo # In theory there is no need to take strong locks on the table
|
||||
--echo # There is no need to take strong locks on the table
|
||||
--echo # being selected from in SF as the call to such function
|
||||
--echo # won't get into the binary log. In practice, however, we
|
||||
--echo # discover that fact too late in the process to be able to
|
||||
--echo # affect the decision what locks should be taken.
|
||||
--echo # Hence, strong locks are taken in this case.
|
||||
--echo # won't get into the binary log.
|
||||
let $statement= select f1();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
let $statement= set @a:= f1();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
|
||||
--echo #
|
||||
--echo # 4.2 INSERT (or other statement which modifies data) with
|
||||
@ -538,22 +561,20 @@ let $restore_table= t2;
|
||||
--echo # modify data and reads a table through subselect
|
||||
--echo # in a control construct.
|
||||
--echo #
|
||||
--echo # Again, in theory a call to this function won't get to the
|
||||
--echo # binary log and thus no strong lock is needed. But in practice
|
||||
--echo # we don't detect this fact early enough (get_lock_type_for_table())
|
||||
--echo # to avoid taking a strong lock.
|
||||
--echo # Call to this function won't get to the
|
||||
--echo # binary log and thus no strong lock is needed.
|
||||
let $statement= select f3();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
let $statement= set @a:= f3();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
let $statement= select f4();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
let $statement= set @a:= f4();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
|
||||
--echo #
|
||||
--echo # 4.5. INSERT (or other statement which modifies data) with
|
||||
@ -591,22 +612,21 @@ let $restore_table= t2;
|
||||
--echo # doesn't modify data and reads tables through
|
||||
--echo # a view.
|
||||
--echo #
|
||||
--echo # Once again, in theory, calls to such functions won't
|
||||
--echo # get into the binary log and thus don't need strong
|
||||
--echo # locks. But in practice this fact is discovered
|
||||
--echo # too late to have any effect.
|
||||
--echo # Calls to such functions won't get into
|
||||
--echo # the binary log and thus don't need strong
|
||||
--echo # locks.
|
||||
let $statement= select f6();
|
||||
let $restore_table= t2;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
let $statement= set @a:= f6();
|
||||
let $restore_table= t2;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
let $statement= select f7();
|
||||
let $restore_table= t2;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
let $statement= set @a:= f7();
|
||||
let $restore_table= t2;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
|
||||
--echo #
|
||||
--echo # 4.8 INSERT which uses stored function which
|
||||
@ -644,12 +664,11 @@ let $restore_table= t2;
|
||||
--echo # data and reads a table indirectly, by calling another
|
||||
--echo # function.
|
||||
--echo #
|
||||
--echo # In theory, calls to such functions won't get into the binary
|
||||
--echo # log and thus don't need to acquire strong locks. But in practice
|
||||
--echo # this fact is discovered too late to have any effect.
|
||||
--echo # Calls to such functions won't get into the binary
|
||||
--echo # log and thus don't need to acquire strong locks.
|
||||
let $statement= select f10();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
|
||||
--echo #
|
||||
--echo # 4.11 INSERT which uses a stored function which doesn't modify
|
||||
@ -700,6 +719,36 @@ let $statement= insert into t2 values (f13((select i+10 from t1 where i=1)));
|
||||
let $restore_table= t2;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
|
||||
--echo #
|
||||
--echo # 4.15 SELECT/SET with a stored function which
|
||||
--echo # inserts data into a temporary table using
|
||||
--echo # SELECT on t1.
|
||||
--echo #
|
||||
--echo # Since this statement is written to the binary log it should
|
||||
--echo # be serialized with concurrent statements affecting the data it
|
||||
--echo # uses. Therefore it should take strong locks on the data it reads.
|
||||
let $statement= select f16();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
let $statement= set @a:= f16();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
|
||||
--echo #
|
||||
--echo # 4.16 SELECT/SET with a stored function which call procedure
|
||||
--echo # which inserts data into a temporary table using
|
||||
--echo # SELECT on t1.
|
||||
--echo #
|
||||
--echo # Since this statement is written to the binary log it should
|
||||
--echo # be serialized with concurrent statements affecting the data it
|
||||
--echo # uses. Therefore it should take strong locks on the data it reads.
|
||||
let $statement= select f17();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
let $statement= set @a:= f17();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # 5. Statements that read tables through stored procedures.
|
||||
@ -730,12 +779,11 @@ let $restore_table= t2;
|
||||
--echo # 5.3 SELECT that calls a function that doesn't modify data and
|
||||
--echo # uses a CALL statement that reads a table via SELECT.
|
||||
--echo #
|
||||
--echo # In theory, calls to such functions won't get into the binary
|
||||
--echo # log and thus don't need to acquire strong locks. But in practice
|
||||
--echo # this fact is discovered too late to have any effect.
|
||||
--echo # Calls to such functions won't get into the binary
|
||||
--echo # log and thus don't need to acquire strong locks.
|
||||
let $statement= select f15();
|
||||
let $restore_table= ;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
--source include/check_concurrent_insert.inc
|
||||
|
||||
--echo #
|
||||
--echo # 5.4 INSERT which calls function which doesn't modify data and
|
||||
@ -800,7 +848,6 @@ let $statement= update t5 set l= 2 where l = 1;
|
||||
let $restore_table= t5;
|
||||
--source include/check_no_concurrent_insert.inc
|
||||
|
||||
|
||||
--echo # Clean-up.
|
||||
drop function f1;
|
||||
drop function f2;
|
||||
@ -817,9 +864,12 @@ drop function f12;
|
||||
drop function f13;
|
||||
drop function f14;
|
||||
drop function f15;
|
||||
drop function f16;
|
||||
drop function f17;
|
||||
drop view v1, v2;
|
||||
drop procedure p1;
|
||||
drop procedure p2;
|
||||
drop procedure p3;
|
||||
drop table t1, t2, t3, t4, t5;
|
||||
|
||||
disconnect con1;
|
||||
|
@ -2323,6 +2323,11 @@ sp_head::restore_lex(THD *thd)
|
||||
*/
|
||||
if (sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
/* If this substatement is a update query, then mark MODIFIES_DATA */
|
||||
if (is_update_query(sublex->sql_command))
|
||||
m_flags|= MODIFIES_DATA;
|
||||
|
||||
/*
|
||||
Merge tables used by this statement (but not by its functions or
|
||||
procedures) to multiset of tables used by this routine.
|
||||
|
@ -161,7 +161,21 @@ public:
|
||||
LOG_SLOW_STATEMENTS= 256, // Used by events
|
||||
LOG_GENERAL_LOG= 512, // Used by events
|
||||
HAS_SQLCOM_RESET= 1024,
|
||||
HAS_SQLCOM_FLUSH= 2048
|
||||
HAS_SQLCOM_FLUSH= 2048,
|
||||
|
||||
/**
|
||||
Marks routines that directly (i.e. not by calling other routines)
|
||||
change tables. Note that this flag is set automatically based on
|
||||
type of statements used in the stored routine and is different
|
||||
from routine characteristic provided by user in a form of CONTAINS
|
||||
SQL, READS SQL DATA, MODIFIES SQL DATA clauses. The latter are
|
||||
accepted by parser but pretty much ignored after that.
|
||||
We don't rely on them:
|
||||
a) for compatibility reasons.
|
||||
b) because in CONTAINS SQL case they don't provide enough
|
||||
information anyway.
|
||||
*/
|
||||
MODIFIES_DATA= 4096
|
||||
};
|
||||
|
||||
stored_procedure_type m_type;
|
||||
@ -332,11 +346,17 @@ public:
|
||||
int
|
||||
add_instr(sp_instr *instr);
|
||||
|
||||
inline uint
|
||||
instructions()
|
||||
{
|
||||
return m_instr.elements;
|
||||
}
|
||||
/**
|
||||
Returns true if any substatement in the routine directly
|
||||
(not through another routine) modifies data/changes table.
|
||||
|
||||
@sa Comment for MODIFIES_DATA flag.
|
||||
*/
|
||||
bool modifies_data() const
|
||||
{ return m_flags & MODIFIES_DATA; }
|
||||
|
||||
inline uint instructions()
|
||||
{ return m_instr.elements; }
|
||||
|
||||
inline sp_instr *
|
||||
last_instruction()
|
||||
|
107
sql/sql_base.cc
107
sql/sql_base.cc
@ -3517,9 +3517,12 @@ Open_table_context::recover_from_failed_open()
|
||||
/*
|
||||
Return a appropriate read lock type given a table object.
|
||||
|
||||
@param thd Thread context
|
||||
@param prelocking_ctx Prelocking context.
|
||||
@param table_list Table list element for table to be locked.
|
||||
@param thd Thread context
|
||||
@param prelocking_ctx Prelocking context.
|
||||
@param table_list Table list element for table to be locked.
|
||||
@param routine_modifies_data
|
||||
Some routine that is invoked by statement
|
||||
modifies data.
|
||||
|
||||
@remark Due to a statement-based replication limitation, statements such as
|
||||
INSERT INTO .. SELECT FROM .. and CREATE TABLE .. SELECT FROM need
|
||||
@ -3532,9 +3535,13 @@ Open_table_context::recover_from_failed_open()
|
||||
This also applies to SELECT/SET/DO statements which use stored
|
||||
functions. Calls to such functions are going to be logged as a
|
||||
whole and thus should be serialized against concurrent changes
|
||||
to tables used by those functions. This can be avoided if functions
|
||||
only read data but doing so requires more complex analysis than it
|
||||
is done now.
|
||||
to tables used by those functions. This is avoided when functions
|
||||
do not modify data but only read it, since in this case nothing is
|
||||
written to the binary log. Argument routine_modifies_data
|
||||
denotes the same. So effectively, if the statement is not a
|
||||
update query and routine_modifies_data is false, then
|
||||
prelocking_placeholder does not take importance.
|
||||
|
||||
Furthermore, this does not apply to I_S and log tables as it's
|
||||
always unsafe to replicate such tables under statement-based
|
||||
replication as the table on the slave might contain other data
|
||||
@ -3549,7 +3556,8 @@ Open_table_context::recover_from_failed_open()
|
||||
|
||||
thr_lock_type read_lock_type_for_table(THD *thd,
|
||||
Query_tables_list *prelocking_ctx,
|
||||
TABLE_LIST *table_list)
|
||||
TABLE_LIST *table_list,
|
||||
bool routine_modifies_data)
|
||||
{
|
||||
/*
|
||||
In cases when this function is called for a sub-statement executed in
|
||||
@ -3564,7 +3572,7 @@ thr_lock_type read_lock_type_for_table(THD *thd,
|
||||
(table_list->table->s->table_category == TABLE_CATEGORY_LOG) ||
|
||||
(table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) ||
|
||||
!(is_update_query(prelocking_ctx->sql_command) ||
|
||||
table_list->prelocking_placeholder ||
|
||||
(routine_modifies_data && table_list->prelocking_placeholder) ||
|
||||
(thd->locked_tables_mode > LTM_LOCK_TABLES)))
|
||||
return TL_READ;
|
||||
else
|
||||
@ -3577,19 +3585,21 @@ thr_lock_type read_lock_type_for_table(THD *thd,
|
||||
and, if prelocking strategy prescribes so, extend the prelocking set
|
||||
with tables and routines used by it.
|
||||
|
||||
@param[in] thd Thread context.
|
||||
@param[in] prelocking_ctx Prelocking context.
|
||||
@param[in] rt Element of prelocking set to be processed.
|
||||
@param[in] prelocking_strategy Strategy which specifies how the
|
||||
prelocking set should be extended when
|
||||
one of its elements is processed.
|
||||
@param[in] has_prelocking_list Indicates that prelocking set/list for
|
||||
this statement has already been built.
|
||||
@param[in] ot_ctx Context of open_table used to recover from
|
||||
locking failures.
|
||||
@param[out] need_prelocking Set to TRUE if it was detected that this
|
||||
statement will require prelocked mode for
|
||||
its execution, not touched otherwise.
|
||||
@param[in] thd Thread context.
|
||||
@param[in] prelocking_ctx Prelocking context.
|
||||
@param[in] rt Element of prelocking set to be processed.
|
||||
@param[in] prelocking_strategy Strategy which specifies how the
|
||||
prelocking set should be extended when
|
||||
one of its elements is processed.
|
||||
@param[in] has_prelocking_list Indicates that prelocking set/list for
|
||||
this statement has already been built.
|
||||
@param[in] ot_ctx Context of open_table used to recover from
|
||||
locking failures.
|
||||
@param[out] need_prelocking Set to TRUE if it was detected that this
|
||||
statement will require prelocked mode for
|
||||
its execution, not touched otherwise.
|
||||
@param[out] routine_modifies_data Set to TRUE if it was detected that this
|
||||
routine does modify table data.
|
||||
|
||||
@retval FALSE Success.
|
||||
@retval TRUE Failure (Conflicting metadata lock, OOM, other errors).
|
||||
@ -3601,11 +3611,13 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
|
||||
Prelocking_strategy *prelocking_strategy,
|
||||
bool has_prelocking_list,
|
||||
Open_table_context *ot_ctx,
|
||||
bool *need_prelocking)
|
||||
bool *need_prelocking, bool *routine_modifies_data)
|
||||
{
|
||||
MDL_key::enum_mdl_namespace mdl_type= rt->mdl_request.key.mdl_namespace();
|
||||
DBUG_ENTER("open_and_process_routine");
|
||||
|
||||
*routine_modifies_data= false;
|
||||
|
||||
switch (mdl_type)
|
||||
{
|
||||
case MDL_key::FUNCTION:
|
||||
@ -3658,10 +3670,13 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
/* 'sp' is NULL when there is no such routine. */
|
||||
if (sp && !has_prelocking_list)
|
||||
if (sp)
|
||||
{
|
||||
prelocking_strategy->handle_routine(thd, prelocking_ctx, rt, sp,
|
||||
need_prelocking);
|
||||
*routine_modifies_data= sp->modifies_data();
|
||||
|
||||
if (!has_prelocking_list)
|
||||
prelocking_strategy->handle_routine(thd, prelocking_ctx, rt, sp,
|
||||
need_prelocking);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -4006,16 +4021,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables_mode)
|
||||
{
|
||||
if (tables->lock_type == TL_WRITE_DEFAULT)
|
||||
tables->table->reginfo.lock_type= thd->update_lock_default;
|
||||
else if (tables->lock_type == TL_READ_DEFAULT)
|
||||
tables->table->reginfo.lock_type=
|
||||
read_lock_type_for_table(thd, lex, tables);
|
||||
else
|
||||
tables->table->reginfo.lock_type= tables->lock_type;
|
||||
}
|
||||
/* Copy grant information from TABLE_LIST instance to TABLE one. */
|
||||
tables->table->grant= tables->grant;
|
||||
|
||||
/* Check and update metadata version of a base table. */
|
||||
@ -4354,6 +4360,7 @@ bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
|
||||
Open_table_context ot_ctx(thd, flags);
|
||||
bool error= FALSE;
|
||||
MEM_ROOT new_frm_mem;
|
||||
bool some_routine_modifies_data= FALSE;
|
||||
bool has_prelocking_list;
|
||||
DBUG_ENTER("open_tables");
|
||||
|
||||
@ -4526,11 +4533,16 @@ restart:
|
||||
sroutine_to_open= &rt->next, rt= rt->next)
|
||||
{
|
||||
bool need_prelocking= false;
|
||||
bool routine_modifies_data;
|
||||
TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last;
|
||||
|
||||
error= open_and_process_routine(thd, thd->lex, rt, prelocking_strategy,
|
||||
has_prelocking_list, &ot_ctx,
|
||||
&need_prelocking);
|
||||
&need_prelocking,
|
||||
&routine_modifies_data);
|
||||
|
||||
// Remember if any of SF modifies data.
|
||||
some_routine_modifies_data|= routine_modifies_data;
|
||||
|
||||
if (need_prelocking && ! thd->lex->requires_prelocking())
|
||||
thd->lex->mark_as_requiring_prelocking(save_query_tables_last);
|
||||
@ -4570,6 +4582,10 @@ restart:
|
||||
children, attach the children to their parents. At end of statement,
|
||||
the children are detached. Attaching and detaching are always done,
|
||||
even under LOCK TABLES.
|
||||
|
||||
We also convert all TL_WRITE_DEFAULT and TL_READ_DEFAULT locks to
|
||||
appropriate "real" lock types to be used for locking and to be passed
|
||||
to storage engine.
|
||||
*/
|
||||
for (tables= *start; tables; tables= tables->next_global)
|
||||
{
|
||||
@ -4586,6 +4602,19 @@ restart:
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set appropriate TABLE::lock_type. */
|
||||
if (tbl && tables->lock_type != TL_UNLOCK && !thd->locked_tables_mode)
|
||||
{
|
||||
if (tables->lock_type == TL_WRITE_DEFAULT)
|
||||
tbl->reginfo.lock_type= thd->update_lock_default;
|
||||
else if (tables->lock_type == TL_READ_DEFAULT)
|
||||
tbl->reginfo.lock_type=
|
||||
read_lock_type_for_table(thd, thd->lex, tables,
|
||||
some_routine_modifies_data);
|
||||
else
|
||||
tbl->reginfo.lock_type= tables->lock_type;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
@ -4847,11 +4876,15 @@ static bool check_lock_and_start_stmt(THD *thd,
|
||||
engine is important as, for example, InnoDB uses it to determine
|
||||
what kind of row locks should be acquired when executing statement
|
||||
in prelocked mode or under LOCK TABLES with @@innodb_table_locks = 0.
|
||||
|
||||
Last argument routine_modifies_data for read_lock_type_for_table()
|
||||
is ignored, as prelocking placeholder will never be set here.
|
||||
*/
|
||||
DBUG_ASSERT(table_list->prelocking_placeholder == false);
|
||||
if (table_list->lock_type == TL_WRITE_DEFAULT)
|
||||
lock_type= thd->update_lock_default;
|
||||
else if (table_list->lock_type == TL_READ_DEFAULT)
|
||||
lock_type= read_lock_type_for_table(thd, prelocking_ctx, table_list);
|
||||
lock_type= read_lock_type_for_table(thd, prelocking_ctx, table_list, true);
|
||||
else
|
||||
lock_type= table_list->lock_type;
|
||||
|
||||
|
@ -136,7 +136,8 @@ TABLE *find_write_locked_table(TABLE *list, const char *db,
|
||||
const char *table_name);
|
||||
thr_lock_type read_lock_type_for_table(THD *thd,
|
||||
Query_tables_list *prelocking_ctx,
|
||||
TABLE_LIST *table_list);
|
||||
TABLE_LIST *table_list,
|
||||
bool routine_modifies_data);
|
||||
|
||||
my_bool mysql_rm_tmp_tables(void);
|
||||
bool rm_temporary_table(handlerton *base, const char *path);
|
||||
|
@ -1431,11 +1431,15 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
another table instance used by this statement which is going to
|
||||
be write-locked (for example, trigger to be invoked might try
|
||||
to update this table).
|
||||
Last argument routine_modifies_data for read_lock_type_for_table()
|
||||
is ignored, as prelocking placeholder will never be set here.
|
||||
*/
|
||||
DBUG_ASSERT(tl->prelocking_placeholder == false);
|
||||
thr_lock_type lock_type= read_lock_type_for_table(thd, lex, tl, true);
|
||||
if (using_lock_tables)
|
||||
tl->lock_type= read_lock_type_for_table(thd, lex, tl);
|
||||
tl->lock_type= lock_type;
|
||||
else
|
||||
tl->set_lock_type(thd, read_lock_type_for_table(thd, lex, tl));
|
||||
tl->set_lock_type(thd, lock_type);
|
||||
tl->updating= 0;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user