summaryrefslogtreecommitdiff
path: root/mysql-test
diff options
context:
space:
mode:
Diffstat (limited to 'mysql-test')
-rw-r--r--mysql-test/include/check_concurrent_insert.inc96
-rw-r--r--mysql-test/include/check_no_concurrent_insert.inc81
-rw-r--r--mysql-test/include/check_no_row_lock.inc71
-rw-r--r--mysql-test/include/check_shared_row_lock.inc61
-rw-r--r--mysql-test/r/bug39022.result6
-rw-r--r--mysql-test/r/innodb_mysql_lock2.result601
-rw-r--r--mysql-test/r/lock_sync.result631
-rw-r--r--mysql-test/t/bug39022.test6
-rw-r--r--mysql-test/t/innodb_mysql_lock2.test803
-rw-r--r--mysql-test/t/lock_sync.test867
10 files changed, 3217 insertions, 6 deletions
diff --git a/mysql-test/include/check_concurrent_insert.inc b/mysql-test/include/check_concurrent_insert.inc
new file mode 100644
index 00000000000..f4bec3c9cdb
--- /dev/null
+++ b/mysql-test/include/check_concurrent_insert.inc
@@ -0,0 +1,96 @@
+#
+# SUMMARY
+# Check if statement reading table '$table' allows concurrent
+# inserts in it.
+#
+# PARAMETERS
+# $table Table in which concurrent inserts should be allowed.
+# $con_aux1 Name of the first auxiliary connection to be used by this
+# script.
+# $con_aux2 Name of the second auxiliary connection to be used by this
+# script.
+# $statement Statement to be checked.
+# $restore_table Table which might be modified by statement to be checked
+# and thus needs backing up before its execution and
+# restoring after it (can be empty).
+#
+# EXAMPLE
+# lock_sync.test
+#
+--disable_result_log
+--disable_query_log
+
+# Reset DEBUG_SYNC facility for safety.
+set debug_sync= "RESET";
+
+if (`SELECT '$restore_table' <> ''`)
+{
+--eval create temporary table t_backup select * from $restore_table;
+}
+
+connection $con_aux1;
+set debug_sync='after_lock_tables_takes_lock SIGNAL parked WAIT_FOR go';
+--send_eval $statement;
+
+connection $con_aux2;
+set debug_sync='now WAIT_FOR parked';
+--send_eval insert into $table (i) values (0);
+
+--enable_result_log
+--enable_query_log
+connection default;
+# Wait until concurrent insert is successfully executed while
+# statement being checked has its tables locked.
+# We use wait_condition.inc instead of simply reaping
+# concurrent insert here in order to avoid deadlocks if test
+# fails and to time out gracefully instead.
+let $wait_condition=
+ select count(*) = 0 from information_schema.processlist
+ where info = "insert into $table (i) values (0)";
+--source include/wait_condition.inc
+
+--disable_result_log
+--disable_query_log
+
+if ($success)
+{
+# Apparently concurrent insert was successfully executed.
+# To be safe against wait_condition.inc succeeding due to
+# races let us first reap concurrent insert to ensure that
+# it has really been successfully executed.
+connection $con_aux2;
+--reap
+connection default;
+set debug_sync= 'now SIGNAL go';
+connection $con_aux1;
+--reap
+connection default;
+--echo Success: '$statement' allows concurrent inserts into '$table'.
+}
+if (!$success)
+{
+# Waiting has timed out. Apparently concurrent insert was blocked.
+# So to be able to continue we need to end our statement first.
+set debug_sync= 'now SIGNAL go';
+connection $con_aux1;
+--reap
+connection $con_aux2;
+--reap
+connection default;
+--echo Error: '$statement' doesn't allow concurrent inserts into '$table'!
+}
+
+--eval delete from $table where i = 0;
+
+if (`SELECT '$restore_table' <> ''`)
+{
+--eval truncate table $restore_table;
+--eval insert into $restore_table select * from t_backup;
+drop temporary table t_backup;
+}
+
+# Clean-up. Reset DEBUG_SYNC facility after use.
+set debug_sync= "RESET";
+
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/include/check_no_concurrent_insert.inc b/mysql-test/include/check_no_concurrent_insert.inc
new file mode 100644
index 00000000000..f60401bcad1
--- /dev/null
+++ b/mysql-test/include/check_no_concurrent_insert.inc
@@ -0,0 +1,81 @@
+#
+# SUMMARY
+# Check that statement reading table '$table' doesn't allow concurrent
+# inserts in it.
+#
+# PARAMETERS
+# $table Table in which concurrent inserts should be disallowed.
+# $con_aux1 Name of the first auxiliary connection to be used by this
+# script.
+# $con_aux2 Name of the second auxiliary connection to be used by this
+# script.
+# $statement Statement to be checked.
+# $restore_table Table which might be modified by statement to be checked
+# and thus needs backing up before its execution and
+# restoring after it (can be empty).
+#
+# EXAMPLE
+# lock_sync.test
+#
+--disable_result_log
+--disable_query_log
+
+# Reset DEBUG_SYNC facility for safety.
+set debug_sync= "RESET";
+
+if (`SELECT '$restore_table' <> ''`)
+{
+--eval create temporary table t_backup select * from $restore_table;
+}
+
+connection $con_aux1;
+set debug_sync='after_lock_tables_takes_lock SIGNAL parked WAIT_FOR go';
+--send_eval $statement;
+
+connection $con_aux2;
+set debug_sync='now WAIT_FOR parked';
+--send_eval insert into $table (i) values (0);
+
+--enable_result_log
+--enable_query_log
+connection default;
+# Wait until concurrent insert is successfully blocked because
+# of our statement.
+let $wait_condition=
+ select count(*) = 1 from information_schema.processlist
+ where state = "Locked" and info = "insert into $table (i) values (0)";
+--source include/wait_condition.inc
+
+--disable_result_log
+--disable_query_log
+
+set debug_sync= 'now SIGNAL go';
+connection $con_aux1;
+--reap
+connection $con_aux2;
+--reap
+connection default;
+
+if ($success)
+{
+--echo Success: '$statement' doesn't allow concurrent inserts into '$table'.
+}
+if (!$success)
+{
+--echo Error: '$statement' allows concurrent inserts into '$table'!
+}
+
+--eval delete from $table where i = 0;
+
+if (`SELECT '$restore_table' <> ''`)
+{
+--eval truncate table $restore_table;
+--eval insert into $restore_table select * from t_backup;
+drop temporary table t_backup;
+}
+
+# Clean-up. Reset DEBUG_SYNC facility after use.
+set debug_sync= "RESET";
+
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/include/check_no_row_lock.inc b/mysql-test/include/check_no_row_lock.inc
new file mode 100644
index 00000000000..c08e7f35b10
--- /dev/null
+++ b/mysql-test/include/check_no_row_lock.inc
@@ -0,0 +1,71 @@
+#
+# SUMMARY
+# Check if statement affecting or reading table '$table' doesn't
+# take any kind of locks on its rows.
+#
+# PARAMETERS
+# $table Table for which presence of row locks should be checked.
+# $con_aux Name of auxiliary connection to be used by this script.
+# $statement Statement to be checked.
+#
+# EXAMPLE
+# innodb_mysql_lock2.test
+#
+--disable_result_log
+--disable_query_log
+
+connection default;
+begin;
+--eval select * from $table for update;
+
+connection $con_aux;
+begin;
+--send_eval $statement;
+
+--enable_result_log
+--enable_query_log
+
+connection default;
+# Wait until statement is successfully executed while
+# all rows in table are X-locked. This means that it
+# does not acquire any row locks.
+# We use wait_condition.inc instead of simply reaping
+# statement here in order to avoid deadlocks if test
+# fails and to time out gracefully instead.
+let $wait_condition=
+ select count(*) = 0 from information_schema.processlist
+ where info = "$statement";
+--source include/wait_condition.inc
+
+--disable_result_log
+--disable_query_log
+
+if ($success)
+{
+# Apparently statement was successfully executed and thus it
+# has not required any row locks.
+# To be safe against wait_condition.inc succeeding due to
+# races let us first reap the statement being checked to
+# ensure that it has been successfully executed.
+connection $con_aux;
+--reap
+rollback;
+connection default;
+rollback;
+--echo Success: '$statement' doesn't take row locks on '$table'.
+}
+if (!$success)
+{
+# Waiting has timed out. Apparently statement was blocked on
+# some row lock. So to be able to continue we need to unlock
+# rows first.
+rollback;
+connection $con_aux;
+--reap
+rollback;
+connection default;
+--echo Error: '$statement' takes some row locks on '$table'!
+}
+
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/include/check_shared_row_lock.inc b/mysql-test/include/check_shared_row_lock.inc
new file mode 100644
index 00000000000..efc7e13b3aa
--- /dev/null
+++ b/mysql-test/include/check_shared_row_lock.inc
@@ -0,0 +1,61 @@
+#
+# SUMMARY
+# Check if statement reading table '$table' takes shared locks
+# on some of its rows.
+#
+# PARAMETERS
+# $table Table for which presence of row locks should be checked.
+# $con_aux Name of auxiliary connection to be used by this script.
+# $statement Statement to be checked.
+# $wait_statement Sub-statement which is supposed to acquire locks (should
+# be the same as $statement for ordinary statements).
+#
+# EXAMPLE
+# innodb_mysql_lock2.test
+#
+--disable_result_log
+--disable_query_log
+
+connection default;
+begin;
+--eval select * from $table for update;
+
+connection $con_aux;
+begin;
+--send_eval $statement;
+
+--enable_result_log
+--enable_query_log
+
+connection default;
+# Wait until statement is successfully blocked because
+# all rows in table are X-locked. This means that at
+# least it acquires S-locks on some of rows.
+let $wait_condition=
+ select count(*) = 1 from information_schema.processlist
+ where state in ("Sending data","statistics", "preparing") and
+ info = "$wait_statement";
+--source include/wait_condition.inc
+
+--disable_result_log
+--disable_query_log
+
+rollback;
+
+connection $con_aux;
+--reap
+rollback;
+
+connection default;
+--enable_result_log
+--enable_query_log
+
+if ($success)
+{
+--echo Success: '$statement' takes shared row locks on '$table'.
+}
+
+if (!$success)
+{
+--echo Error: '$statement' hasn't taken shared row locks on '$table'!
+}
diff --git a/mysql-test/r/bug39022.result b/mysql-test/r/bug39022.result
index 5963709aa2a..75899ed686b 100644
--- a/mysql-test/r/bug39022.result
+++ b/mysql-test/r/bug39022.result
@@ -12,7 +12,7 @@ INSERT INTO t2 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),
START TRANSACTION;
# in thread2
REPLACE INTO t2 VALUES (-17);
-SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d);
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE;
d
# in thread1
REPLACE INTO t1(a,b) VALUES (67,20);
@@ -21,10 +21,10 @@ COMMIT;
START TRANSACTION;
REPLACE INTO t1(a,b) VALUES (65,-50);
REPLACE INTO t2 VALUES (-91);
-SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d);
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE;
# in thread1
# should not crash
-SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d);
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
# in thread2
d
diff --git a/mysql-test/r/innodb_mysql_lock2.result b/mysql-test/r/innodb_mysql_lock2.result
new file mode 100644
index 00000000000..79606ea8bdc
--- /dev/null
+++ b/mysql-test/r/innodb_mysql_lock2.result
@@ -0,0 +1,601 @@
+#
+# Test how do we handle locking in various cases when
+# we read data from InnoDB tables.
+#
+# In fact by performing this test we check two things:
+# 1) That SQL-layer correctly determine type of thr_lock.c
+# lock to be acquired/passed to InnoDB engine.
+# 2) That InnoDB engine correctly interprets this lock
+# type and takes necessary row locks or does not
+# take them if they are not necessary.
+#
+# This test makes sense only in REPEATABLE-READ mode as
+# in SERIALIZABLE mode all statements that read data take
+# shared lock on them to enforce its semantics.
+select @@session.tx_isolation;
+@@session.tx_isolation
+REPEATABLE-READ
+# Prepare playground by creating tables, views,
+# routines and triggers used in tests.
+drop table if exists t0, t1, t2, t3, t4, t5, te;
+drop view if exists v1, v2;
+drop procedure if exists p1;
+drop procedure if exists p2;
+drop function if exists f1;
+drop function if exists f2;
+drop function if exists f3;
+drop function if exists f4;
+drop function if exists f5;
+drop function if exists f6;
+drop function if exists f7;
+drop function if exists f8;
+drop function if exists f9;
+drop function if exists f10;
+drop function if exists f11;
+drop function if exists f12;
+drop function if exists f13;
+drop function if exists f14;
+drop function if exists f15;
+create table t1 (i int primary key) engine=innodb;
+insert into t1 values (1), (2), (3), (4), (5);
+create table t2 (j int primary key) engine=innodb;
+insert into t2 values (1), (2), (3), (4), (5);
+create table t3 (k int primary key) engine=innodb;
+insert into t3 values (1), (2), (3);
+create table t4 (l int primary key) engine=innodb;
+insert into t4 values (1);
+create table t5 (l int primary key) engine=innodb;
+insert into t5 values (1);
+create table te(e int primary key);
+insert into te values (1);
+create view v1 as select i from t1;
+create view v2 as select j from t2 where j in (select i from t1);
+create procedure p1(k int) insert into t2 values (k);
+create function f1() returns int
+begin
+declare j int;
+select i from t1 where i = 1 into j;
+return j;
+end|
+create function f2() returns int
+begin
+declare k int;
+select i from t1 where i = 1 into k;
+insert into t2 values (k + 5);
+return 0;
+end|
+create function f3() returns int
+begin
+return (select i from t1 where i = 3);
+end|
+create function f4() returns int
+begin
+if (select i from t1 where i = 3) then
+return 1;
+else
+return 0;
+end if;
+end|
+create function f5() returns int
+begin
+insert into t2 values ((select i from t1 where i = 1) + 5);
+return 0;
+end|
+create function f6() returns int
+begin
+declare k int;
+select i from v1 where i = 1 into k;
+return k;
+end|
+create function f7() returns int
+begin
+declare k int;
+select j from v2 where j = 1 into k;
+return k;
+end|
+create function f8() returns int
+begin
+declare k int;
+select i from v1 where i = 1 into k;
+insert into t2 values (k+5);
+return k;
+end|
+create function f9() returns int
+begin
+update v2 set j=j+10 where j=1;
+return 1;
+end|
+create function f10() returns int
+begin
+return f1();
+end|
+create function f11() returns int
+begin
+declare k int;
+set k= f1();
+insert into t2 values (k+5);
+return k;
+end|
+create function f12(p int) returns int
+begin
+insert into t2 values (p);
+return p;
+end|
+create function f13(p int) returns int
+begin
+return p;
+end|
+create procedure p2(inout p int)
+begin
+select i from t1 where i = 1 into p;
+end|
+create function f14() returns int
+begin
+declare k int;
+call p2(k);
+insert into t2 values (k+5);
+return k;
+end|
+create function f15() returns int
+begin
+declare k int;
+call p2(k);
+return k;
+end|
+create trigger t4_bi before insert on t4 for each row
+begin
+declare k int;
+select i from t1 where i=1 into k;
+set new.l= k+1;
+end|
+create trigger t4_bu before update on t4 for each row
+begin
+if (select i from t1 where i=1) then
+set new.l= 2;
+end if;
+end|
+# Trigger below uses insertion of duplicate key in 'te'
+# table as a way to abort delete operation.
+create trigger t4_bd before delete on t4 for each row
+begin
+if !(select i from v1 where i=1) then
+insert into te values (1);
+end if;
+end|
+create trigger t5_bi before insert on t5 for each row
+begin
+set new.l= f1()+1;
+end|
+create trigger t5_bu before update on t5 for each row
+begin
+declare j int;
+call p2(j);
+set new.l= j + 1;
+end|
+#
+# Set common variables to be used by scripts called below.
+#
+#
+# 1. Statements that read tables and do not use subqueries.
+#
+#
+# 1.1 Simple SELECT statement.
+#
+# No locks are necessary as this statement won't be written
+# to the binary log and InnoDB supports snapshots.
+Success: 'select * from t1' doesn't take row locks on 't1'.
+#
+# 1.2 Multi-UPDATE statement.
+#
+# Has to take shared locks on rows in the table being read as this
+# statement will be written to the binary log and therefore should
+# be serialized with concurrent statements.
+Success: 'update t2, t1 set j= j - 1 where i = j' takes shared row locks on 't1'.
+#
+# 1.3 Multi-DELETE statement.
+#
+# The above is true for this statement as well.
+Success: 'delete t2 from t1, t2 where i = j' takes shared row locks on 't1'.
+#
+# 1.4 DESCRIBE statement.
+#
+# This statement does not really read data from the
+# target table and thus does not take any lock on it.
+# We check this for completeness of coverage.
+Success: 'describe t1' doesn't take row locks on 't1'.
+#
+# 1.5 SHOW statements.
+#
+# The above is true for SHOW statements as well.
+Success: 'show create table t1' doesn't take row locks on 't1'.
+Success: 'show keys from t1' doesn't take row locks on 't1'.
+#
+# 2. Statements which read tables through subqueries.
+#
+#
+# 2.1 CALL with a subquery.
+#
+# A strong lock is not necessary as this statement is not
+# written to the binary log as a whole (it is written
+# statement-by-statement) and thanks to MVCC we can always get
+# versions of rows prior to the update that has locked them.
+# But in practice InnoDB does locking reads for all statements
+# other than SELECT (unless it is a READ-COMITTED mode or
+# innodb_locks_unsafe_for_binlog is ON).
+Success: 'call p1((select i + 5 from t1 where i = 1))' takes shared row locks on 't1'.
+#
+# 2.2 CREATE TABLE with a subquery.
+#
+# Has to take shared locks on rows in the table being read as
+# this statement is written to the binary log and therefore
+# should be serialized with concurrent statements.
+Success: 'create table t0 engine=innodb select * from t1' takes shared row locks on 't1'.
+drop table t0;
+Success: 'create table t0 engine=innodb select j from t2 where j in (select i from t1)' takes shared row locks on 't1'.
+drop table t0;
+#
+# 2.3 DELETE with a subquery.
+#
+# The above is true for this statement as well.
+Success: 'delete from t2 where j in (select i from t1)' takes shared row locks on 't1'.
+#
+# 2.4 MULTI-DELETE with a subquery.
+#
+# Same is true for this statement as well.
+Success: 'delete t2 from t3, t2 where k = j and j in (select i from t1)' takes shared row locks on 't1'.
+#
+# 2.5 DO with a subquery.
+#
+# In theory should not take row locks as it is not logged.
+# In practice InnoDB takes shared row locks.
+Success: 'do (select i from t1 where i = 1)' takes shared row locks on 't1'.
+#
+# 2.6 INSERT with a subquery.
+#
+# Has to take shared locks on rows in the table being read as
+# this statement is written to the binary log and therefore
+# should be serialized with concurrent statements.
+Success: 'insert into t2 select i+5 from t1' takes shared row locks on 't1'.
+Success: 'insert into t2 values ((select i+5 from t1 where i = 4))' takes shared row locks on 't1'.
+#
+# 2.7 LOAD DATA with a subquery.
+#
+# The above is true for this statement as well.
+Success: 'load data infile '../../std_data/rpl_loaddata.dat' into table t2 (@a, @b) set j= @b + (select i from t1 where i = 1)' takes shared row locks on 't1'.
+#
+# 2.8 REPLACE with a subquery.
+#
+# Same is true for this statement as well.
+Success: 'replace into t2 select i+5 from t1' takes shared row locks on 't1'.
+Success: 'replace into t2 values ((select i+5 from t1 where i = 4))' takes shared row locks on 't1'.
+#
+# 2.9 SELECT with a subquery.
+#
+# Locks are not necessary as this statement is not written
+# to the binary log and thanks to MVCC we can always get
+# versions of rows prior to the update that has locked them.
+#
+# Also serves as a test case for bug #46947 "Embedded SELECT
+# without FOR UPDATE is causing a lock".
+Success: 'select * from t2 where j in (select i from t1)' doesn't take row locks on 't1'.
+#
+# 2.10 SET with a subquery.
+#
+# In theory should not require locking as it is not written
+# to the binary log. In practice InnoDB acquires shared row
+# locks.
+Success: 'set @a:= (select i from t1 where i = 1)' takes shared row locks on 't1'.
+#
+# 2.11 SHOW with a subquery.
+#
+# Similarly to the previous case, in theory should not require locking
+# as it is not written to the binary log. In practice InnoDB
+# acquires shared row locks.
+Success: 'show tables from test where Tables_in_test = 't2' and (select i from t1 where i = 1)' takes shared row locks on 't1'.
+Success: 'show columns from t2 where (select i from t1 where i = 1)' takes shared row locks on 't1'.
+#
+# 2.12 UPDATE with a subquery.
+#
+# Has to take shared locks on rows in the table being read as
+# this statement is written to the binary log and therefore
+# should be serialized with concurrent statements.
+Success: 'update t2 set j= j-10 where j in (select i from t1)' takes shared row locks on 't1'.
+#
+# 2.13 MULTI-UPDATE with a subquery.
+#
+# Same is true for this statement as well.
+Success: 'update t2, t3 set j= j -10 where j=k and j in (select i from t1)' takes shared row locks on 't1'.
+#
+# 3. Statements which read tables through a view.
+#
+#
+# 3.1 SELECT statement which uses some table through a view.
+#
+# Since this statement is not written to the binary log
+# and old version of rows are accessible thanks to MVCC,
+# no locking is necessary.
+Success: 'select * from v1' doesn't take row locks on 't1'.
+Success: 'select * from v2' doesn't take row locks on 't1'.
+Success: 'select * from t2 where j in (select i from v1)' doesn't take row locks on 't1'.
+Success: 'select * from t3 where k in (select j from v2)' doesn't take row locks on 't1'.
+#
+# 3.2 Statements which modify a table and use views.
+#
+# Since such statements are going to be written to the binary
+# log they need to be serialized against concurrent statements
+# and therefore should take shared row locks on data read.
+Success: 'update t2 set j= j-10 where j in (select i from v1)' takes shared row locks on 't1'.
+Success: 'update t3 set k= k-10 where k in (select j from v2)' takes shared row locks on 't1'.
+Success: 'update t2, v1 set j= j-10 where j = i' takes shared row locks on 't1'.
+Success: 'update v2 set j= j-10 where j = 3' takes shared row locks on 't1'.
+#
+# 4. Statements which read tables through stored functions.
+#
+#
+# 4.1 SELECT/SET with a stored function which does not
+# modify data and uses SELECT in its turn.
+#
+# Calls to such functions won't get into the binary log and
+# thus don't need to acquire strong locks.
+# In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+# used stored functions may lead to broken SBR" strong locks
+# are taken (we accepted it as a trade-off for this fix).
+Success: 'select f1()' doesn't take row locks on 't1'.
+Success: 'set @a:= f1()' doesn't take row locks on 't1'.
+#
+# 4.2 INSERT (or other statement which modifies data) with
+# a stored function which does not modify data and uses
+# SELECT.
+#
+# Since such statement is written to the binary log it should
+# be serialized with concurrent statements affecting the data
+# it uses. Therefore it should take row locks on the data
+# it reads.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken.
+Success: 'insert into t2 values (f1() + 5)' doesn't take row locks on 't1'.
+#
+# 4.3 SELECT/SET with a stored function which
+# reads and modifies data.
+#
+# Since a call to such function is written to the binary log,
+# it should be serialized with concurrent statements affecting
+# the data it uses. Hence, row locks on the data read
+# should be taken.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken.
+Success: 'select f2()' doesn't take row locks on 't1'.
+Success: 'set @a:= f2()' doesn't take row locks on 't1'.
+#
+# 4.4. SELECT/SET with a stored function which does not
+# 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'.
+Success: 'set @a:= f3()' takes shared row locks on 't1'.
+Success: 'select f4()' takes shared row locks on 't1'.
+Success: 'set @a:= f4()' takes shared row locks on 't1'.
+#
+# 4.5. INSERT (or other statement which modifies data) with
+# a stored function which does not modify data and reads
+# the table through a subselect in one of its control
+# constructs.
+#
+# Since such statement is written to the binary log it should
+# be serialized with concurrent statements affecting data it
+# uses. Therefore it should take row locks on the data
+# it reads.
+Success: 'insert into t2 values (f3() + 5)' takes shared row locks on 't1'.
+Success: 'insert into t2 values (f4() + 6)' takes shared row locks on 't1'.
+#
+# 4.6 SELECT/SET which uses a stored function with
+# DML which reads a table via a subquery.
+#
+# Since call to such function is written to the binary log
+# it should be serialized with concurrent statements.
+# Hence reads should take row locks.
+Success: 'select f5()' takes shared row locks on 't1'.
+Success: 'set @a:= f5()' takes shared row locks on 't1'.
+#
+# 4.7 SELECT/SET which uses a stored function which
+# 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. In practice this fact is discovered
+# too late to have any effect.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken
+# in case of simple SELECT.
+Success: 'select f6()' doesn't take row locks on 't1'.
+Success: 'set @a:= f6()' doesn't take row locks on 't1'.
+Success: 'select f7()' takes shared row locks on 't1'.
+Success: 'set @a:= f7()' takes shared row locks on 't1'.
+#
+# 4.8 INSERT which uses stored function which
+# doesn't modify data and reads a table
+# through a view.
+#
+# Since such statement is written to the binary log and
+# should be serialized with concurrent statements affecting
+# the data it uses. Therefore it should take row locks on
+# the rows it reads.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken
+# in case of simple SELECT.
+Success: 'insert into t3 values (f6() + 5)' doesn't take row locks on 't1'.
+Success: 'insert into t3 values (f7() + 5)' takes shared row locks on 't1'.
+#
+# 4.9 SELECT which uses a stored function which
+# modifies data and reads tables through a view.
+#
+# Since a call to such function is written to the binary log
+# it should be serialized with concurrent statements.
+# Hence, reads should take row locks.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken
+# in case of simple SELECT.
+Success: 'select f8()' doesn't take row locks on 't1'.
+Success: 'select f9()' takes shared row locks on 't1'.
+#
+# 4.10 SELECT which uses stored function which doesn't modify
+# data and reads a table indirectly, by calling another
+# function.
+#
+# Calls to such functions won't get into the binary log and
+# thus don't need to acquire strong locks.
+# In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+# used stored functions may lead to broken SBR" strong locks
+# are taken (we accepted it as a trade-off for this fix).
+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
+# function.
+#
+# Since such statement is written to the binary log, it should
+# be serialized with concurrent statements affecting the data it
+# uses. Therefore it should take row locks on data it reads.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken.
+Success: 'insert into t2 values (f10() + 5)' doesn't take row locks on 't1'.
+#
+# 4.12 SELECT which uses a stored function which modifies
+# data and reads a table indirectly, by calling another
+# function.
+#
+# Since a call to such function is written to the binary log
+# it should be serialized from concurrent statements.
+# Hence, reads should take row locks.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken.
+Success: 'select f11()' doesn't take row locks on 't1'.
+#
+# 4.13 SELECT that reads a table through a subquery passed
+# as a parameter to a stored function which modifies
+# data.
+#
+# Even though a call to this function is written to the
+# binary log, values of its parameters are written as literals.
+# So there is no need to acquire row locks on rows used in
+# the subquery.
+# But due to the fact that in 5.1 for prelocked statements
+# THD::in_lock_tables is set to TRUE we acquire strong locks
+# (see also bug#44613 "SELECT statement inside FUNCTION takes
+# a shared lock" [sic!!!]).
+Success: 'select f12((select i+10 from t1 where i=1))' takes shared row locks on 't1'.
+#
+# 4.14 INSERT that reads a table via a subquery passed
+# as a parameter to a stored function which doesn't
+# modify data.
+#
+# 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 row locks on the data it reads.
+Success: 'insert into t2 values (f13((select i+10 from t1 where i=1)))' takes shared row locks on 't1'.
+#
+# 5. Statements that read tables through stored procedures.
+#
+#
+# 5.1 CALL statement which reads a table via SELECT.
+#
+# Since neither this statement nor its components are
+# written to the binary log, there is no need to take
+# row locks on the data it reads.
+Success: 'call p2(@a)' doesn't take row locks on 't1'.
+#
+# 5.2 Function that modifies data and uses CALL,
+# which reads a table through SELECT.
+#
+# Since a call to such function is written to the binary
+# log, it should be serialized with concurrent statements.
+# Hence, in this case reads should take row locks on data.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken.
+Success: 'select f14()' doesn't take 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.
+#
+# Calls to such functions won't get into the binary log and
+# thus don't need to acquire strong locks.
+# In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+# used stored functions may lead to broken SBR" strong locks
+# are taken (we accepted it as a trade-off for this fix).
+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.
+#
+# Since such statement is written to the binary log it should
+# be serialized with concurrent statements affecting data it
+# uses. Therefore it should take row locks on data it reads.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken.
+Success: 'insert into t2 values (f15()+5)' doesn't take row locks on 't1'.
+#
+# 6. Statements that use triggers.
+#
+#
+# 6.1 Statement invoking a trigger that reads table via SELECT.
+#
+# 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 row locks on the data
+# it reads.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken.
+Success: 'insert into t4 values (2)' doesn't take row locks on 't1'.
+#
+# 6.2 Statement invoking a trigger that reads table through
+# a subquery in a control construct.
+#
+# The above is true for this statement as well.
+Success: 'update t4 set l= 2 where l = 1' takes shared row locks on 't1'.
+#
+# 6.3 Statement invoking a trigger that reads a table through
+# a view.
+#
+# And for this statement.
+Success: 'delete from t4 where l = 1' takes shared row locks on 't1'.
+#
+# 6.4 Statement invoking a trigger that reads a table through
+# a stored function.
+#
+# And for this statement.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken.
+Success: 'insert into t5 values (2)' doesn't take row locks on 't1'.
+#
+# 6.5 Statement invoking a trigger that reads a table through
+# stored procedure.
+#
+# And for this statement.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" no lock is taken.
+Success: 'update t5 set l= 2 where l = 1' doesn't take row locks on 't1'.
+# Clean-up.
+drop function f1;
+drop function f2;
+drop function f3;
+drop function f4;
+drop function f5;
+drop function f6;
+drop function f7;
+drop function f8;
+drop function f9;
+drop function f10;
+drop function f11;
+drop function f12;
+drop function f13;
+drop function f14;
+drop function f15;
+drop view v1, v2;
+drop procedure p1;
+drop procedure p2;
+drop table t1, t2, t3, t4, t5, te;
diff --git a/mysql-test/r/lock_sync.result b/mysql-test/r/lock_sync.result
new file mode 100644
index 00000000000..752f278a2b4
--- /dev/null
+++ b/mysql-test/r/lock_sync.result
@@ -0,0 +1,631 @@
+#
+# Test how we handle locking in various cases when
+# we read data from MyISAM tables.
+#
+# In this test we mostly check that the SQL-layer correctly
+# determines the type of thr_lock.c lock for a table being
+# read.
+# I.e. that it disallows concurrent inserts when the statement
+# is going to be written to the binary log and therefore
+# should be serialized, and allows concurrent inserts when
+# such serialization is not necessary (e.g. when
+# the statement is not written to binary log).
+#
+# Force concurrent inserts to be performed even if the table
+# has gaps. This allows to simplify clean up in scripts
+# used below (instead of backing up table being inserted
+# into and then restoring it from backup at the end of the
+# script we can simply delete rows which were inserted).
+set @old_concurrent_insert= @@global.concurrent_insert;
+set @@global.concurrent_insert= 2;
+select @@global.concurrent_insert;
+@@global.concurrent_insert
+2
+# Prepare playground by creating tables, views,
+# routines and triggers used in tests.
+drop table if exists t0, t1, t2, t3, t4, t5, te;
+drop view if exists v1, v2;
+drop procedure if exists p1;
+drop procedure if exists p2;
+drop function if exists f1;
+drop function if exists f2;
+drop function if exists f3;
+drop function if exists f4;
+drop function if exists f5;
+drop function if exists f6;
+drop function if exists f7;
+drop function if exists f8;
+drop function if exists f9;
+drop function if exists f10;
+drop function if exists f11;
+drop function if exists f12;
+drop function if exists f13;
+drop function if exists f14;
+drop function if exists f15;
+create table t1 (i int primary key);
+insert into t1 values (1), (2), (3), (4), (5);
+create table t2 (j int primary key);
+insert into t2 values (1), (2), (3), (4), (5);
+create table t3 (k int primary key);
+insert into t3 values (1), (2), (3);
+create table t4 (l int primary key);
+insert into t4 values (1);
+create table t5 (l int primary key);
+insert into t5 values (1);
+create table te(e int primary key);
+insert into te values (1);
+create view v1 as select i from t1;
+create view v2 as select j from t2 where j in (select i from t1);
+create procedure p1(k int) insert into t2 values (k);
+create function f1() returns int
+begin
+declare j int;
+select i from t1 where i = 1 into j;
+return j;
+end|
+create function f2() returns int
+begin
+declare k int;
+select i from t1 where i = 1 into k;
+insert into t2 values (k + 5);
+return 0;
+end|
+create function f3() returns int
+begin
+return (select i from t1 where i = 3);
+end|
+create function f4() returns int
+begin
+if (select i from t1 where i = 3) then
+return 1;
+else
+return 0;
+end if;
+end|
+create function f5() returns int
+begin
+insert into t2 values ((select i from t1 where i = 1) + 5);
+return 0;
+end|
+create function f6() returns int
+begin
+declare k int;
+select i from v1 where i = 1 into k;
+return k;
+end|
+create function f7() returns int
+begin
+declare k int;
+select j from v2 where j = 1 into k;
+return k;
+end|
+create function f8() returns int
+begin
+declare k int;
+select i from v1 where i = 1 into k;
+insert into t2 values (k+5);
+return k;
+end|
+create function f9() returns int
+begin
+update v2 set j=j+10 where j=1;
+return 1;
+end|
+create function f10() returns int
+begin
+return f1();
+end|
+create function f11() returns int
+begin
+declare k int;
+set k= f1();
+insert into t2 values (k+5);
+return k;
+end|
+create function f12(p int) returns int
+begin
+insert into t2 values (p);
+return p;
+end|
+create function f13(p int) returns int
+begin
+return p;
+end|
+create procedure p2(inout p int)
+begin
+select i from t1 where i = 1 into p;
+end|
+create function f14() returns int
+begin
+declare k int;
+call p2(k);
+insert into t2 values (k+5);
+return k;
+end|
+create function f15() returns int
+begin
+declare k int;
+call p2(k);
+return k;
+end|
+create trigger t4_bi before insert on t4 for each row
+begin
+declare k int;
+select i from t1 where i=1 into k;
+set new.l= k+1;
+end|
+create trigger t4_bu before update on t4 for each row
+begin
+if (select i from t1 where i=1) then
+set new.l= 2;
+end if;
+end|
+# Trigger below uses insertion of duplicate key in 'te'
+# table as a way to abort delete operation.
+create trigger t4_bd before delete on t4 for each row
+begin
+if !(select i from v1 where i=1) then
+insert into te values (1);
+end if;
+end|
+create trigger t5_bi before insert on t5 for each row
+begin
+set new.l= f1()+1;
+end|
+create trigger t5_bu before update on t5 for each row
+begin
+declare j int;
+call p2(j);
+set new.l= j + 1;
+end|
+#
+# Set common variables to be used by the scripts
+# called below.
+#
+# Switch to connection 'con1'.
+# Cache all functions used in the tests below so statements
+# calling them won't need to open and lock mysql.proc table
+# and we can assume that each statement locks its tables
+# once during its execution.
+show create procedure p1;
+show create procedure p2;
+show create function f1;
+show create function f2;
+show create function f3;
+show create function f4;
+show create function f5;
+show create function f6;
+show create function f7;
+show create function f8;
+show create function f9;
+show create function f10;
+show create function f11;
+show create function f12;
+show create function f13;
+show create function f14;
+show create function f15;
+# Switch back to connection 'default'.
+#
+# 1. Statements that read tables and do not use subqueries.
+#
+#
+# 1.1 Simple SELECT statement.
+#
+# No locks are necessary as this statement won't be written
+# to the binary log and thanks to how MyISAM works SELECT
+# will see version of the table prior to concurrent insert.
+Success: 'select * from t1' allows concurrent inserts into 't1'.
+#
+# 1.2 Multi-UPDATE statement.
+#
+# Has to take shared locks on rows in the table being read as this
+# statement will be written to the binary log and therefore should
+# be serialized with concurrent statements.
+Success: 'update t2, t1 set j= j - 1 where i = j' doesn't allow concurrent inserts into 't1'.
+#
+# 1.3 Multi-DELETE statement.
+#
+# The above is true for this statement as well.
+Success: 'delete t2 from t1, t2 where i = j' doesn't allow concurrent inserts into 't1'.
+#
+# 1.4 DESCRIBE statement.
+#
+# This statement does not really read data from the
+# target table and thus does not take any lock on it.
+# We check this for completeness of coverage.
+lock table t1 write;
+# Switching to connection 'con1'.
+# This statement should not be blocked.
+describe t1;
+# Switching to connection 'default'.
+unlock tables;
+#
+# 1.5 SHOW statements.
+#
+# The above is true for SHOW statements as well.
+lock table t1 write;
+# Switching to connection 'con1'.
+# These statements should not be blocked.
+show keys from t1;
+# Switching to connection 'default'.
+unlock tables;
+#
+# 2. Statements which read tables through subqueries.
+#
+#
+# 2.1 CALL with a subquery.
+#
+# In theory strong lock is not necessary as this statement
+# is not written to the binary log as a whole (it is written
+# statement-by-statement). But in practice in 5.1 for
+# almost everything except SELECT we take strong lock.
+Success: 'call p1((select i + 5 from t1 where i = 1))' doesn't allow concurrent inserts into 't1'.
+#
+# 2.2 CREATE TABLE with a subquery.
+#
+# Has to take a strong lock on the table being read as
+# this statement is written to the binary log and therefore
+# should be serialized with concurrent statements.
+Success: 'create table t0 select * from t1' doesn't allow concurrent inserts into 't1'.
+drop table t0;
+Success: 'create table t0 select j from t2 where j in (select i from t1)' doesn't allow concurrent inserts into 't1'.
+drop table t0;
+#
+# 2.3 DELETE with a subquery.
+#
+# The above is true for this statement as well.
+Success: 'delete from t2 where j in (select i from t1)' doesn't allow concurrent inserts into 't1'.
+#
+# 2.4 MULTI-DELETE with a subquery.
+#
+# Same is true for this statement as well.
+Success: 'delete t2 from t3, t2 where k = j and j in (select i from t1)' doesn't allow concurrent inserts into 't1'.
+#
+# 2.5 DO with a subquery.
+#
+# In theory strong lock is not necessary as it is not logged.
+# But in practice in 5.1 for almost everything except SELECT
+# we take strong lock.
+Success: 'do (select i from t1 where i = 1)' doesn't allow concurrent inserts into 't1'.
+#
+# 2.6 INSERT with a subquery.
+#
+# Has to take a strong lock on the table being read as
+# this statement is written to the binary log and therefore
+# should be serialized with concurrent inserts.
+Success: 'insert into t2 select i+5 from t1' doesn't allow concurrent inserts into 't1'.
+Success: 'insert into t2 values ((select i+5 from t1 where i = 4))' doesn't allow concurrent inserts into 't1'.
+#
+# 2.7 LOAD DATA with a subquery.
+#
+# The above is true for this statement as well.
+Success: 'load data infile '../../std_data/rpl_loaddata.dat' into table t2 (@a, @b) set j= @b + (select i from t1 where i = 1)' doesn't allow concurrent inserts into 't1'.
+#
+# 2.8 REPLACE with a subquery.
+#
+# Same is true for this statement as well.
+Success: 'replace into t2 select i+5 from t1' doesn't allow concurrent inserts into 't1'.
+Success: 'replace into t2 values ((select i+5 from t1 where i = 4))' doesn't allow concurrent inserts into 't1'.
+#
+# 2.9 SELECT with a subquery.
+#
+# Strong locks are not necessary as this statement is not written
+# to the binary log and thanks to how MyISAM works this statement
+# sees a version of the table prior to the concurrent insert.
+Success: 'select * from t2 where j in (select i from t1)' allows concurrent inserts into 't1'.
+#
+# 2.10 SET with a subquery.
+#
+# In theory the same is true for this statement as well.
+# But in practice in 5.1 we acquire strong lock in this
+# case as well.
+Success: 'set @a:= (select i from t1 where i = 1)' doesn't allow concurrent inserts into 't1'.
+#
+# 2.11 SHOW with a subquery.
+#
+# The same is true for this statement too.
+Success: 'show tables from test where Tables_in_test = 't2' and (select i from t1 where i = 1)' doesn't allow concurrent inserts into 't1'.
+Success: 'show columns from t2 where (select i from t1 where i = 1)' doesn't allow concurrent inserts into 't1'.
+#
+# 2.12 UPDATE with a subquery.
+#
+# Has to take a strong lock on the table being read as
+# this statement is written to the binary log and therefore
+# should be serialized with concurrent inserts.
+Success: 'update t2 set j= j-10 where j in (select i from t1)' doesn't allow concurrent inserts into 't1'.
+#
+# 2.13 MULTI-UPDATE with a subquery.
+#
+# Same is true for this statement as well.
+Success: 'update t2, t3 set j= j -10 where j=k and j in (select i from t1)' doesn't allow concurrent inserts into 't1'.
+#
+# 3. Statements which read tables through a view.
+#
+#
+# 3.1 SELECT statement which uses some table through a view.
+#
+# Since this statement is not written to the binary log and
+# an old version of the table is accessible thanks to how MyISAM
+# handles concurrent insert, no locking is necessary.
+Success: 'select * from v1' allows concurrent inserts into 't1'.
+Success: 'select * from v2' allows concurrent inserts into 't1'.
+Success: 'select * from t2 where j in (select i from v1)' allows concurrent inserts into 't1'.
+Success: 'select * from t3 where k in (select j from v2)' allows concurrent inserts into 't1'.
+#
+# 3.2 Statements which modify a table and use views.
+#
+# Since such statements are going to be written to the binary
+# log they need to be serialized against concurrent statements
+# and therefore should take strong locks on the data read.
+Success: 'update t2 set j= j-10 where j in (select i from v1)' doesn't allow concurrent inserts into 't1'.
+Success: 'update t3 set k= k-10 where k in (select j from v2)' doesn't allow concurrent inserts into 't1'.
+Success: 'update t2, v1 set j= j-10 where j = i' doesn't allow concurrent inserts into 't1'.
+Success: 'update v2 set j= j-10 where j = 3' doesn't allow concurrent inserts into 't1'.
+#
+# 4. Statements which read tables through stored functions.
+#
+#
+# 4.1 SELECT/SET with a stored function which does not
+# modify data and uses SELECT in its turn.
+#
+# Calls to such functions won't get into the binary log and
+# thus don't need to acquire strong locks.
+# In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+# used stored functions may lead to broken SBR" strong locks
+# are taken (we accepted it as a trade-off for this fix).
+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
+# SELECT.
+#
+# Since such statement is written to the binary log it should
+# be serialized with concurrent statements affecting the data
+# it uses. Therefore it should take strong lock on the data
+# it reads.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken.
+Success: 'insert into t2 values (f1() + 5)' allows concurrent inserts into 't1'.
+#
+# 4.3 SELECT/SET with a stored function which
+# reads and modifies data.
+#
+# Since a call to such function is written to the binary log,
+# it should be serialized with concurrent statements affecting
+# the data it uses. Hence, a strong lock on the data read
+# should be taken.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken.
+Success: 'select f2()' allows concurrent inserts into 't1'.
+Success: 'set @a:= f2()' allows concurrent inserts into 't1'.
+#
+# 4.4. SELECT/SET with a stored function which does not
+# 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'.
+#
+# 4.5. INSERT (or other statement which modifies data) with
+# a stored function which does not modify data and reads
+# the table through a subselect in one of its control
+# constructs.
+#
+# Since such statement is written to the binary log it should
+# be serialized with concurrent statements affecting data it
+# uses. Therefore it should take a strong lock on the data
+# it reads.
+Success: 'insert into t2 values (f3() + 5)' doesn't allow concurrent inserts into 't1'.
+Success: 'insert into t2 values (f4() + 6)' doesn't allow concurrent inserts into 't1'.
+#
+# 4.6 SELECT/SET which uses a stored function with
+# DML which reads a table via a subquery.
+#
+# Since call to such function is written to the binary log
+# it should be serialized with concurrent statements.
+# Hence reads should take a strong lock.
+Success: 'select f5()' doesn't allow concurrent inserts into 't1'.
+Success: 'set @a:= f5()' doesn't allow concurrent inserts into 't1'.
+#
+# 4.7 SELECT/SET which uses a stored function which
+# 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. In practice this fact is discovered
+# too late to have any effect.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken
+# in case when simple SELECT is used.
+Success: 'select f6()' allows concurrent inserts into 't1'.
+Success: 'set @a:= f6()' allows 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'.
+#
+# 4.8 INSERT which uses stored function which
+# doesn't modify data and reads a table
+# through a view.
+#
+# Since such statement is written to the binary log and
+# should be serialized with concurrent statements affecting
+# the data it uses. Therefore it should take a strong lock on
+# the table it reads.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken
+# in case when simple SELECT is used.
+Success: 'insert into t3 values (f6() + 5)' allows concurrent inserts into 't1'.
+Success: 'insert into t3 values (f7() + 5)' doesn't allow concurrent inserts into 't1'.
+#
+# 4.9 SELECT which uses a stored function which
+# modifies data and reads tables through a view.
+#
+# Since a call to such function is written to the binary log
+# it should be serialized with concurrent statements.
+# Hence, reads should take strong locks.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken
+# in case when simple SELECT is used.
+Success: 'select f8()' allows concurrent inserts into 't1'.
+Success: 'select f9()' doesn't allow concurrent inserts into 't1'.
+#
+# 4.10 SELECT which uses a stored function which doesn't modify
+# data and reads a table indirectly, by calling another
+# function.
+#
+# Calls to such functions won't get into the binary log and
+# thus don't need to acquire strong locks.
+# In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+# used stored functions may lead to broken SBR" strong locks
+# are taken (we accepted it as a trade-off for this fix).
+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
+# function.
+#
+# Since such 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 data it reads.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken.
+Success: 'insert into t2 values (f10() + 5)' allows concurrent inserts into 't1'.
+#
+# 4.12 SELECT which uses a stored function which modifies
+# data and reads a table indirectly, by calling another
+# function.
+#
+# Since a call to such function is written to the binary log
+# it should be serialized from concurrent statements.
+# Hence, read should take a strong lock.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken.
+Success: 'select f11()' allows concurrent inserts into 't1'.
+#
+# 4.13 SELECT that reads a table through a subquery passed
+# as a parameter to a stored function which modifies
+# data.
+#
+# Even though a call to this function is written to the
+# binary log, values of its parameters are written as literals.
+# So there is no need to acquire strong locks for tables used in
+# the subquery.
+Success: 'select f12((select i+10 from t1 where i=1))' allows concurrent inserts into 't1'.
+#
+# 4.14 INSERT that reads a table via a subquery passed
+# as a parameter to a stored function which doesn't
+# modify data.
+#
+# 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: 'insert into t2 values (f13((select i+10 from t1 where i=1)))' doesn't allow concurrent inserts into 't1'.
+#
+# 5. Statements that read tables through stored procedures.
+#
+#
+# 5.1 CALL statement which reads a table via SELECT.
+#
+# Since neither this statement nor its components are
+# written to the binary log, there is no need to take
+# strong locks on the data it reads.
+Success: 'call p2(@a)' allows concurrent inserts into 't1'.
+#
+# 5.2 Function that modifies data and uses CALL,
+# which reads a table through SELECT.
+#
+# Since a call to such function is written to the binary
+# log, it should be serialized with concurrent statements.
+# Hence, in this case reads should take strong locks on data.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken.
+Success: 'select f14()' allows 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.
+#
+# Calls to such functions won't get into the binary log and
+# thus don't need to acquire strong locks.
+# In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+# used stored functions may lead to broken SBR" strong locks
+# are taken (we accepted it as a trade-off for this fix).
+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.
+#
+# Since such statement is written to the binary log it should
+# be serialized with concurrent statements affecting data it
+# uses. Therefore it should take strong locks on data it reads.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken.
+Success: 'insert into t2 values (f15()+5)' allows concurrent inserts into 't1'.
+#
+# 6. Statements that use triggers.
+#
+#
+# 6.1 Statement invoking a trigger that reads table via SELECT.
+#
+# 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.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken.
+Success: 'insert into t4 values (2)' allows concurrent inserts into 't1'.
+#
+# 6.2 Statement invoking a trigger that reads table through
+# a subquery in a control construct.
+#
+# The above is true for this statement as well.
+Success: 'update t4 set l= 2 where l = 1' doesn't allow concurrent inserts into 't1'.
+#
+# 6.3 Statement invoking a trigger that reads a table through
+# a view.
+#
+# And for this statement.
+Success: 'delete from t4 where l = 1' doesn't allow concurrent inserts into 't1'.
+#
+# 6.4 Statement invoking a trigger that reads a table through
+# a stored function.
+#
+# And for this statement.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken.
+Success: 'insert into t5 values (2)' allows concurrent inserts into 't1'.
+#
+# 6.5 Statement invoking a trigger that reads a table through
+# stored procedure.
+#
+# And for this statement.
+# But due to bug #53921 "Wrong locks for SELECTs used stored
+# functions may lead to broken SBR" weak locks are taken.
+Success: 'update t5 set l= 2 where l = 1' allows concurrent inserts into 't1'.
+# Clean-up.
+drop function f1;
+drop function f2;
+drop function f3;
+drop function f4;
+drop function f5;
+drop function f6;
+drop function f7;
+drop function f8;
+drop function f9;
+drop function f10;
+drop function f11;
+drop function f12;
+drop function f13;
+drop function f14;
+drop function f15;
+drop view v1, v2;
+drop procedure p1;
+drop procedure p2;
+drop table t1, t2, t3, t4, t5, te;
+set @@global.concurrent_insert= @old_concurrent_insert;
diff --git a/mysql-test/t/bug39022.test b/mysql-test/t/bug39022.test
index 268b207e0e5..6056dbf0e7b 100644
--- a/mysql-test/t/bug39022.test
+++ b/mysql-test/t/bug39022.test
@@ -24,7 +24,7 @@ START TRANSACTION;
connection thread2;
--echo # in thread2
REPLACE INTO t2 VALUES (-17);
-SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d);
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE;
connection thread1;
--echo # in thread1
@@ -37,14 +37,14 @@ START TRANSACTION;
REPLACE INTO t1(a,b) VALUES (65,-50);
REPLACE INTO t2 VALUES (-91);
send;
-SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d); #waits
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE; #waits
connection thread1;
--echo # in thread1
--echo # should not crash
--error ER_LOCK_DEADLOCK
-SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d); #crashes
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE; #crashes
connection thread2;
--echo # in thread2
diff --git a/mysql-test/t/innodb_mysql_lock2.test b/mysql-test/t/innodb_mysql_lock2.test
new file mode 100644
index 00000000000..79698bcd898
--- /dev/null
+++ b/mysql-test/t/innodb_mysql_lock2.test
@@ -0,0 +1,803 @@
+# This test covers behavior for InnoDB tables.
+--source include/have_innodb.inc
+# This test requires statement/mixed mode binary logging.
+# Row-based mode puts weaker serializability requirements
+# so weaker locks are acquired for it.
+--source include/have_binlog_format_mixed_or_statement.inc
+# Save the initial number of concurrent sessions.
+--source include/count_sessions.inc
+
+--echo #
+--echo # Test how do we handle locking in various cases when
+--echo # we read data from InnoDB tables.
+--echo #
+--echo # In fact by performing this test we check two things:
+--echo # 1) That SQL-layer correctly determine type of thr_lock.c
+--echo # lock to be acquired/passed to InnoDB engine.
+--echo # 2) That InnoDB engine correctly interprets this lock
+--echo # type and takes necessary row locks or does not
+--echo # take them if they are not necessary.
+--echo #
+
+--echo # This test makes sense only in REPEATABLE-READ mode as
+--echo # in SERIALIZABLE mode all statements that read data take
+--echo # shared lock on them to enforce its semantics.
+select @@session.tx_isolation;
+
+--echo # Prepare playground by creating tables, views,
+--echo # routines and triggers used in tests.
+connect (con1, localhost, root,,);
+connection default;
+--disable_warnings
+drop table if exists t0, t1, t2, t3, t4, t5, te;
+drop view if exists v1, v2;
+drop procedure if exists p1;
+drop procedure if exists p2;
+drop function if exists f1;
+drop function if exists f2;
+drop function if exists f3;
+drop function if exists f4;
+drop function if exists f5;
+drop function if exists f6;
+drop function if exists f7;
+drop function if exists f8;
+drop function if exists f9;
+drop function if exists f10;
+drop function if exists f11;
+drop function if exists f12;
+drop function if exists f13;
+drop function if exists f14;
+drop function if exists f15;
+--enable_warnings
+create table t1 (i int primary key) engine=innodb;
+insert into t1 values (1), (2), (3), (4), (5);
+create table t2 (j int primary key) engine=innodb;
+insert into t2 values (1), (2), (3), (4), (5);
+create table t3 (k int primary key) engine=innodb;
+insert into t3 values (1), (2), (3);
+create table t4 (l int primary key) engine=innodb;
+insert into t4 values (1);
+create table t5 (l int primary key) engine=innodb;
+insert into t5 values (1);
+create table te(e int primary key);
+insert into te values (1);
+create view v1 as select i from t1;
+create view v2 as select j from t2 where j in (select i from t1);
+create procedure p1(k int) insert into t2 values (k);
+delimiter |;
+create function f1() returns int
+begin
+ declare j int;
+ select i from t1 where i = 1 into j;
+ return j;
+end|
+create function f2() returns int
+begin
+ declare k int;
+ select i from t1 where i = 1 into k;
+ insert into t2 values (k + 5);
+ return 0;
+end|
+create function f3() returns int
+begin
+ return (select i from t1 where i = 3);
+end|
+create function f4() returns int
+begin
+ if (select i from t1 where i = 3) then
+ return 1;
+ else
+ return 0;
+ end if;
+end|
+create function f5() returns int
+begin
+ insert into t2 values ((select i from t1 where i = 1) + 5);
+ return 0;
+end|
+create function f6() returns int
+begin
+ declare k int;
+ select i from v1 where i = 1 into k;
+ return k;
+end|
+create function f7() returns int
+begin
+ declare k int;
+ select j from v2 where j = 1 into k;
+ return k;
+end|
+create function f8() returns int
+begin
+ declare k int;
+ select i from v1 where i = 1 into k;
+ insert into t2 values (k+5);
+ return k;
+end|
+create function f9() returns int
+begin
+ update v2 set j=j+10 where j=1;
+ return 1;
+end|
+create function f10() returns int
+begin
+ return f1();
+end|
+create function f11() returns int
+begin
+ declare k int;
+ set k= f1();
+ insert into t2 values (k+5);
+ return k;
+end|
+create function f12(p int) returns int
+begin
+ insert into t2 values (p);
+ return p;
+end|
+create function f13(p int) returns int
+begin
+ return p;
+end|
+create procedure p2(inout p int)
+begin
+ select i from t1 where i = 1 into p;
+end|
+create function f14() returns int
+begin
+ declare k int;
+ call p2(k);
+ insert into t2 values (k+5);
+ return k;
+end|
+create function f15() returns int
+begin
+ declare k int;
+ call p2(k);
+ return k;
+end|
+create trigger t4_bi before insert on t4 for each row
+begin
+ declare k int;
+ select i from t1 where i=1 into k;
+ set new.l= k+1;
+end|
+create trigger t4_bu before update on t4 for each row
+begin
+ if (select i from t1 where i=1) then
+ set new.l= 2;
+ end if;
+end|
+--echo # Trigger below uses insertion of duplicate key in 'te'
+--echo # table as a way to abort delete operation.
+create trigger t4_bd before delete on t4 for each row
+begin
+ if !(select i from v1 where i=1) then
+ insert into te values (1);
+ end if;
+end|
+create trigger t5_bi before insert on t5 for each row
+begin
+ set new.l= f1()+1;
+end|
+create trigger t5_bu before update on t5 for each row
+begin
+ declare j int;
+ call p2(j);
+ set new.l= j + 1;
+end|
+delimiter ;|
+
+--echo #
+--echo # Set common variables to be used by scripts called below.
+--echo #
+let $con_aux= con1;
+let $table= t1;
+
+
+--echo #
+--echo # 1. Statements that read tables and do not use subqueries.
+--echo #
+
+--echo #
+--echo # 1.1 Simple SELECT statement.
+--echo #
+--echo # No locks are necessary as this statement won't be written
+--echo # to the binary log and InnoDB supports snapshots.
+let $statement= select * from t1;
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 1.2 Multi-UPDATE statement.
+--echo #
+--echo # Has to take shared locks on rows in the table being read as this
+--echo # statement will be written to the binary log and therefore should
+--echo # be serialized with concurrent statements.
+let $statement= update t2, t1 set j= j - 1 where i = j;
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 1.3 Multi-DELETE statement.
+--echo #
+--echo # The above is true for this statement as well.
+let $statement= delete t2 from t1, t2 where i = j;
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 1.4 DESCRIBE statement.
+--echo #
+--echo # This statement does not really read data from the
+--echo # target table and thus does not take any lock on it.
+--echo # We check this for completeness of coverage.
+let $statement= describe t1;
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 1.5 SHOW statements.
+--echo #
+--echo # The above is true for SHOW statements as well.
+let $statement= show create table t1;
+--source include/check_no_row_lock.inc
+let $statement= show keys from t1;
+--source include/check_no_row_lock.inc
+
+
+--echo #
+--echo # 2. Statements which read tables through subqueries.
+--echo #
+
+--echo #
+--echo # 2.1 CALL with a subquery.
+--echo #
+--echo # A strong lock is not necessary as this statement is not
+--echo # written to the binary log as a whole (it is written
+--echo # statement-by-statement) and thanks to MVCC we can always get
+--echo # versions of rows prior to the update that has locked them.
+--echo # But in practice InnoDB does locking reads for all statements
+--echo # other than SELECT (unless it is a READ-COMITTED mode or
+--echo # innodb_locks_unsafe_for_binlog is ON).
+let $statement= call p1((select i + 5 from t1 where i = 1));
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 2.2 CREATE TABLE with a subquery.
+--echo #
+--echo # Has to take shared locks on rows in the table being read as
+--echo # this statement is written to the binary log and therefore
+--echo # should be serialized with concurrent statements.
+let $statement= create table t0 engine=innodb select * from t1;
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+drop table t0;
+let $statement= create table t0 engine=innodb select j from t2 where j in (select i from t1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+drop table t0;
+
+--echo #
+--echo # 2.3 DELETE with a subquery.
+--echo #
+--echo # The above is true for this statement as well.
+let $statement= delete from t2 where j in (select i from t1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 2.4 MULTI-DELETE with a subquery.
+--echo #
+--echo # Same is true for this statement as well.
+let $statement= delete t2 from t3, t2 where k = j and j in (select i from t1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 2.5 DO with a subquery.
+--echo #
+--echo # In theory should not take row locks as it is not logged.
+--echo # In practice InnoDB takes shared row locks.
+let $statement= do (select i from t1 where i = 1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 2.6 INSERT with a subquery.
+--echo #
+--echo # Has to take shared locks on rows in the table being read as
+--echo # this statement is written to the binary log and therefore
+--echo # should be serialized with concurrent statements.
+let $statement= insert into t2 select i+5 from t1;
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+let $statement= insert into t2 values ((select i+5 from t1 where i = 4));
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 2.7 LOAD DATA with a subquery.
+--echo #
+--echo # The above is true for this statement as well.
+let $statement= load data infile '../../std_data/rpl_loaddata.dat' into table t2 (@a, @b) set j= @b + (select i from t1 where i = 1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 2.8 REPLACE with a subquery.
+--echo #
+--echo # Same is true for this statement as well.
+let $statement= replace into t2 select i+5 from t1;
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+let $statement= replace into t2 values ((select i+5 from t1 where i = 4));
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 2.9 SELECT with a subquery.
+--echo #
+--echo # Locks are not necessary as this statement is not written
+--echo # to the binary log and thanks to MVCC we can always get
+--echo # versions of rows prior to the update that has locked them.
+--echo #
+--echo # Also serves as a test case for bug #46947 "Embedded SELECT
+--echo # without FOR UPDATE is causing a lock".
+let $statement= select * from t2 where j in (select i from t1);
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 2.10 SET with a subquery.
+--echo #
+--echo # In theory should not require locking as it is not written
+--echo # to the binary log. In practice InnoDB acquires shared row
+--echo # locks.
+let $statement= set @a:= (select i from t1 where i = 1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 2.11 SHOW with a subquery.
+--echo #
+--echo # Similarly to the previous case, in theory should not require locking
+--echo # as it is not written to the binary log. In practice InnoDB
+--echo # acquires shared row locks.
+let $statement= show tables from test where Tables_in_test = 't2' and (select i from t1 where i = 1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+let $statement= show columns from t2 where (select i from t1 where i = 1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 2.12 UPDATE with a subquery.
+--echo #
+--echo # Has to take shared locks on rows in the table being read as
+--echo # this statement is written to the binary log and therefore
+--echo # should be serialized with concurrent statements.
+let $statement= update t2 set j= j-10 where j in (select i from t1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 2.13 MULTI-UPDATE with a subquery.
+--echo #
+--echo # Same is true for this statement as well.
+let $statement= update t2, t3 set j= j -10 where j=k and j in (select i from t1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+
+--echo #
+--echo # 3. Statements which read tables through a view.
+--echo #
+
+--echo #
+--echo # 3.1 SELECT statement which uses some table through a view.
+--echo #
+--echo # Since this statement is not written to the binary log
+--echo # and old version of rows are accessible thanks to MVCC,
+--echo # no locking is necessary.
+let $statement= select * from v1;
+--source include/check_no_row_lock.inc
+let $statement= select * from v2;
+--source include/check_no_row_lock.inc
+let $statement= select * from t2 where j in (select i from v1);
+--source include/check_no_row_lock.inc
+let $statement= select * from t3 where k in (select j from v2);
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 3.2 Statements which modify a table and use views.
+--echo #
+--echo # Since such statements are going to be written to the binary
+--echo # log they need to be serialized against concurrent statements
+--echo # and therefore should take shared row locks on data read.
+let $statement= update t2 set j= j-10 where j in (select i from v1);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+let $statement= update t3 set k= k-10 where k in (select j from v2);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+let $statement= update t2, v1 set j= j-10 where j = i;
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+let $statement= update v2 set j= j-10 where j = 3;
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+
+--echo #
+--echo # 4. Statements which read tables through stored functions.
+--echo #
+
+--echo #
+--echo # 4.1 SELECT/SET with a stored function which does not
+--echo # modify data and uses SELECT in its turn.
+--echo #
+--echo # Calls to such functions won't get into the binary log and
+--echo # thus don't need to acquire strong locks.
+--echo # In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+--echo # used stored functions may lead to broken SBR" strong locks
+--echo # are taken (we accepted it as a trade-off for this fix).
+let $statement= select f1();
+let $wait_statement= select i from t1 where i = 1 into j;
+--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_no_row_lock.inc
+
+--echo #
+--echo # 4.2 INSERT (or other statement which modifies data) with
+--echo # a stored function which does not modify data and uses
+--echo # SELECT.
+--echo #
+--echo # Since such statement is written to the binary log it should
+--echo # be serialized with concurrent statements affecting the data
+--echo # it uses. Therefore it should take row locks on the data
+--echo # it reads.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken.
+let $statement= insert into t2 values (f1() + 5);
+let $wait_statement= select i from t1 where i = 1 into j;
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 4.3 SELECT/SET with a stored function which
+--echo # reads and modifies data.
+--echo #
+--echo # Since a call to such function is written to the binary log,
+--echo # it should be serialized with concurrent statements affecting
+--echo # the data it uses. Hence, row locks on the data read
+--echo # should be taken.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken.
+let $statement= select f2();
+let $wait_statement= select i from t1 where i = 1 into k;
+--source include/check_no_row_lock.inc
+let $statement= set @a:= f2();
+let $wait_statement= select i from t1 where i = 1 into k;
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 4.4. SELECT/SET with a stored function which does not
+--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.
+let $statement= select f3();
+let $wait_statement= $statement;
+--source include/check_shared_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
+let $statement= set @a:= f4();
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 4.5. INSERT (or other statement which modifies data) with
+--echo # a stored function which does not modify data and reads
+--echo # the table through a subselect in one of its control
+--echo # constructs.
+--echo #
+--echo # Since such statement is written to the binary log it should
+--echo # be serialized with concurrent statements affecting data it
+--echo # uses. Therefore it should take row locks on the data
+--echo # it reads.
+let $statement= insert into t2 values (f3() + 5);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+let $statement= insert into t2 values (f4() + 6);
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 4.6 SELECT/SET which uses a stored function with
+--echo # DML which reads a table via a subquery.
+--echo #
+--echo # Since call to such function is written to the binary log
+--echo # it should be serialized with concurrent statements.
+--echo # Hence reads should take row locks.
+let $statement= select f5();
+let $wait_statement= insert into t2 values ((select i from t1 where i = 1) + 5);
+--source include/check_shared_row_lock.inc
+let $statement= set @a:= f5();
+let $wait_statement= insert into t2 values ((select i from t1 where i = 1) + 5);
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 4.7 SELECT/SET which uses a stored function which
+--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. In practice this fact is discovered
+--echo # too late to have any effect.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken
+--echo # in case of simple SELECT.
+let $statement= select f6();
+let $wait_statement= select i from v1 where i = 1 into k;
+--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_no_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
+let $statement= set @a:= f7();
+let $wait_statement= select j from v2 where j = 1 into k;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 4.8 INSERT which uses stored function which
+--echo # doesn't modify data and reads a table
+--echo # through a view.
+--echo #
+--echo # Since such statement is written to the binary log and
+--echo # should be serialized with concurrent statements affecting
+--echo # the data it uses. Therefore it should take row locks on
+--echo # the rows it reads.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken
+--echo # in case of simple SELECT.
+let $statement= insert into t3 values (f6() + 5);
+let $wait_statement= select i from v1 where i = 1 into k;
+--source include/check_no_row_lock.inc
+let $statement= insert into t3 values (f7() + 5);
+let $wait_statement= select j from v2 where j = 1 into k;
+--source include/check_shared_row_lock.inc
+
+
+--echo #
+--echo # 4.9 SELECT which uses a stored function which
+--echo # modifies data and reads tables through a view.
+--echo #
+--echo # Since a call to such function is written to the binary log
+--echo # it should be serialized with concurrent statements.
+--echo # Hence, reads should take row locks.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken
+--echo # in case of simple SELECT.
+let $statement= select f8();
+let $wait_statement= select i from v1 where i = 1 into k;
+--source include/check_no_row_lock.inc
+let $statement= select f9();
+let $wait_statement= update v2 set j=j+10 where j=1;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 4.10 SELECT which uses stored function which doesn't modify
+--echo # data and reads a table indirectly, by calling another
+--echo # function.
+--echo #
+--echo # Calls to such functions won't get into the binary log and
+--echo # thus don't need to acquire strong locks.
+--echo # In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+--echo # used stored functions may lead to broken SBR" strong locks
+--echo # are taken (we accepted it as a trade-off for this fix).
+let $statement= select f10();
+let $wait_statement= select i from t1 where i = 1 into j;
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 4.11 INSERT which uses a stored function which doesn't modify
+--echo # data and reads a table indirectly, by calling another
+--echo # function.
+--echo #
+--echo # Since such 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 row locks on data it reads.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken.
+let $statement= insert into t2 values (f10() + 5);
+let $wait_statement= select i from t1 where i = 1 into j;
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 4.12 SELECT which uses a stored function which modifies
+--echo # data and reads a table indirectly, by calling another
+--echo # function.
+--echo #
+--echo # Since a call to such function is written to the binary log
+--echo # it should be serialized from concurrent statements.
+--echo # Hence, reads should take row locks.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken.
+let $statement= select f11();
+let $wait_statement= select i from t1 where i = 1 into j;
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 4.13 SELECT that reads a table through a subquery passed
+--echo # as a parameter to a stored function which modifies
+--echo # data.
+--echo #
+--echo # Even though a call to this function is written to the
+--echo # binary log, values of its parameters are written as literals.
+--echo # So there is no need to acquire row locks on rows used in
+--echo # the subquery.
+--echo # But due to the fact that in 5.1 for prelocked statements
+--echo # THD::in_lock_tables is set to TRUE we acquire strong locks
+--echo # (see also bug#44613 "SELECT statement inside FUNCTION takes
+--echo # a shared lock" [sic!!!]).
+let $statement= select f12((select i+10 from t1 where i=1));
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 4.14 INSERT that reads a table via a subquery passed
+--echo # as a parameter to a stored function which doesn't
+--echo # modify data.
+--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 row locks on the data it reads.
+let $statement= insert into t2 values (f13((select i+10 from t1 where i=1)));
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+
+--echo #
+--echo # 5. Statements that read tables through stored procedures.
+--echo #
+
+--echo #
+--echo # 5.1 CALL statement which reads a table via SELECT.
+--echo #
+--echo # Since neither this statement nor its components are
+--echo # written to the binary log, there is no need to take
+--echo # row locks on the data it reads.
+let $statement= call p2(@a);
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 5.2 Function that modifies data and uses CALL,
+--echo # which reads a table through SELECT.
+--echo #
+--echo # Since a call to such function is written to the binary
+--echo # log, it should be serialized with concurrent statements.
+--echo # Hence, in this case reads should take row locks on data.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken.
+let $statement= select f14();
+let $wait_statement= select i from t1 where i = 1 into p;
+--source include/check_no_row_lock.inc
+
+--echo #
+--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 # Calls to such functions won't get into the binary log and
+--echo # thus don't need to acquire strong locks.
+--echo # In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+--echo # used stored functions may lead to broken SBR" strong locks
+--echo # are taken (we accepted it as a trade-off for this fix).
+let $statement= select f15();
+let $wait_statement= select i from t1 where i = 1 into p;
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 5.4 INSERT which calls function which doesn't modify data and
+--echo # uses CALL statement which reads table through SELECT.
+--echo #
+--echo # Since such statement is written to the binary log it should
+--echo # be serialized with concurrent statements affecting data it
+--echo # uses. Therefore it should take row locks on data it reads.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken.
+let $statement= insert into t2 values (f15()+5);
+let $wait_statement= select i from t1 where i = 1 into p;
+--source include/check_no_row_lock.inc
+
+
+--echo #
+--echo # 6. Statements that use triggers.
+--echo #
+
+--echo #
+--echo # 6.1 Statement invoking a trigger that reads table via SELECT.
+--echo #
+--echo # Since this statement is written to the binary log it should
+--echo # be serialized with concurrent statements affecting the data
+--echo # it uses. Therefore, it should take row locks on the data
+--echo # it reads.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken.
+let $statement= insert into t4 values (2);
+let $wait_statement= select i from t1 where i=1 into k;
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 6.2 Statement invoking a trigger that reads table through
+--echo # a subquery in a control construct.
+--echo #
+--echo # The above is true for this statement as well.
+let $statement= update t4 set l= 2 where l = 1;
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 6.3 Statement invoking a trigger that reads a table through
+--echo # a view.
+--echo #
+--echo # And for this statement.
+let $statement= delete from t4 where l = 1;
+let $wait_statement= $statement;
+--source include/check_shared_row_lock.inc
+
+--echo #
+--echo # 6.4 Statement invoking a trigger that reads a table through
+--echo # a stored function.
+--echo #
+--echo # And for this statement.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken.
+let $statement= insert into t5 values (2);
+let $wait_statement= select i from t1 where i = 1 into j;
+--source include/check_no_row_lock.inc
+
+--echo #
+--echo # 6.5 Statement invoking a trigger that reads a table through
+--echo # stored procedure.
+--echo #
+--echo # And for this statement.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" no lock is taken.
+let $statement= update t5 set l= 2 where l = 1;
+let $wait_statement= select i from t1 where i = 1 into p;
+--source include/check_no_row_lock.inc
+
+--echo # Clean-up.
+drop function f1;
+drop function f2;
+drop function f3;
+drop function f4;
+drop function f5;
+drop function f6;
+drop function f7;
+drop function f8;
+drop function f9;
+drop function f10;
+drop function f11;
+drop function f12;
+drop function f13;
+drop function f14;
+drop function f15;
+drop view v1, v2;
+drop procedure p1;
+drop procedure p2;
+drop table t1, t2, t3, t4, t5, te;
+disconnect con1;
+
+# Check that all connections opened by test cases in this file are really
+# gone so execution of other tests won't be affected by their presence.
+--source include/wait_until_count_sessions.inc
diff --git a/mysql-test/t/lock_sync.test b/mysql-test/t/lock_sync.test
new file mode 100644
index 00000000000..17f8abb75f3
--- /dev/null
+++ b/mysql-test/t/lock_sync.test
@@ -0,0 +1,867 @@
+#
+# Locking related tests which use DEBUG_SYNC facility.
+#
+--source include/have_debug_sync.inc
+# This test requires statement/mixed mode binary logging.
+# Row-based mode puts weaker serializability requirements
+# so weaker locks are acquired for it.
+--source include/have_binlog_format_mixed_or_statement.inc
+
+# Save the initial number of concurrent sessions.
+--source include/count_sessions.inc
+
+
+--echo #
+--echo # Test how we handle locking in various cases when
+--echo # we read data from MyISAM tables.
+--echo #
+--echo # In this test we mostly check that the SQL-layer correctly
+--echo # determines the type of thr_lock.c lock for a table being
+--echo # read.
+--echo # I.e. that it disallows concurrent inserts when the statement
+--echo # is going to be written to the binary log and therefore
+--echo # should be serialized, and allows concurrent inserts when
+--echo # such serialization is not necessary (e.g. when
+--echo # the statement is not written to binary log).
+--echo #
+
+--echo # Force concurrent inserts to be performed even if the table
+--echo # has gaps. This allows to simplify clean up in scripts
+--echo # used below (instead of backing up table being inserted
+--echo # into and then restoring it from backup at the end of the
+--echo # script we can simply delete rows which were inserted).
+set @old_concurrent_insert= @@global.concurrent_insert;
+set @@global.concurrent_insert= 2;
+select @@global.concurrent_insert;
+
+--echo # Prepare playground by creating tables, views,
+--echo # routines and triggers used in tests.
+connect (con1, localhost, root,,);
+connect (con2, localhost, root,,);
+connection default;
+--disable_warnings
+drop table if exists t0, t1, t2, t3, t4, t5, te;
+drop view if exists v1, v2;
+drop procedure if exists p1;
+drop procedure if exists p2;
+drop function if exists f1;
+drop function if exists f2;
+drop function if exists f3;
+drop function if exists f4;
+drop function if exists f5;
+drop function if exists f6;
+drop function if exists f7;
+drop function if exists f8;
+drop function if exists f9;
+drop function if exists f10;
+drop function if exists f11;
+drop function if exists f12;
+drop function if exists f13;
+drop function if exists f14;
+drop function if exists f15;
+--enable_warnings
+create table t1 (i int primary key);
+insert into t1 values (1), (2), (3), (4), (5);
+create table t2 (j int primary key);
+insert into t2 values (1), (2), (3), (4), (5);
+create table t3 (k int primary key);
+insert into t3 values (1), (2), (3);
+create table t4 (l int primary key);
+insert into t4 values (1);
+create table t5 (l int primary key);
+insert into t5 values (1);
+create table te(e int primary key);
+insert into te values (1);
+create view v1 as select i from t1;
+create view v2 as select j from t2 where j in (select i from t1);
+create procedure p1(k int) insert into t2 values (k);
+delimiter |;
+create function f1() returns int
+begin
+ declare j int;
+ select i from t1 where i = 1 into j;
+ return j;
+end|
+create function f2() returns int
+begin
+ declare k int;
+ select i from t1 where i = 1 into k;
+ insert into t2 values (k + 5);
+ return 0;
+end|
+create function f3() returns int
+begin
+ return (select i from t1 where i = 3);
+end|
+create function f4() returns int
+begin
+ if (select i from t1 where i = 3) then
+ return 1;
+ else
+ return 0;
+ end if;
+end|
+create function f5() returns int
+begin
+ insert into t2 values ((select i from t1 where i = 1) + 5);
+ return 0;
+end|
+create function f6() returns int
+begin
+ declare k int;
+ select i from v1 where i = 1 into k;
+ return k;
+end|
+create function f7() returns int
+begin
+ declare k int;
+ select j from v2 where j = 1 into k;
+ return k;
+end|
+create function f8() returns int
+begin
+ declare k int;
+ select i from v1 where i = 1 into k;
+ insert into t2 values (k+5);
+ return k;
+end|
+create function f9() returns int
+begin
+ update v2 set j=j+10 where j=1;
+ return 1;
+end|
+create function f10() returns int
+begin
+ return f1();
+end|
+create function f11() returns int
+begin
+ declare k int;
+ set k= f1();
+ insert into t2 values (k+5);
+ return k;
+end|
+create function f12(p int) returns int
+begin
+ insert into t2 values (p);
+ return p;
+end|
+create function f13(p int) returns int
+begin
+ return p;
+end|
+create procedure p2(inout p int)
+begin
+ select i from t1 where i = 1 into p;
+end|
+create function f14() returns int
+begin
+ declare k int;
+ call p2(k);
+ insert into t2 values (k+5);
+ return k;
+end|
+create function f15() returns int
+begin
+ declare k int;
+ call p2(k);
+ return k;
+end|
+create trigger t4_bi before insert on t4 for each row
+begin
+ declare k int;
+ select i from t1 where i=1 into k;
+ set new.l= k+1;
+end|
+create trigger t4_bu before update on t4 for each row
+begin
+ if (select i from t1 where i=1) then
+ set new.l= 2;
+ end if;
+end|
+--echo # Trigger below uses insertion of duplicate key in 'te'
+--echo # table as a way to abort delete operation.
+create trigger t4_bd before delete on t4 for each row
+begin
+ if !(select i from v1 where i=1) then
+ insert into te values (1);
+ end if;
+end|
+create trigger t5_bi before insert on t5 for each row
+begin
+ set new.l= f1()+1;
+end|
+create trigger t5_bu before update on t5 for each row
+begin
+ declare j int;
+ call p2(j);
+ set new.l= j + 1;
+end|
+delimiter ;|
+
+--echo #
+--echo # Set common variables to be used by the scripts
+--echo # called below.
+--echo #
+let $con_aux1= con1;
+let $con_aux2= con2;
+let $table= t1;
+
+--echo # Switch to connection 'con1'.
+connection con1;
+--echo # Cache all functions used in the tests below so statements
+--echo # calling them won't need to open and lock mysql.proc table
+--echo # and we can assume that each statement locks its tables
+--echo # once during its execution.
+--disable_result_log
+show create procedure p1;
+show create procedure p2;
+show create function f1;
+show create function f2;
+show create function f3;
+show create function f4;
+show create function f5;
+show create function f6;
+show create function f7;
+show create function f8;
+show create function f9;
+show create function f10;
+show create function f11;
+show create function f12;
+show create function f13;
+show create function f14;
+show create function f15;
+--enable_result_log
+--echo # Switch back to connection 'default'.
+connection default;
+
+--echo #
+--echo # 1. Statements that read tables and do not use subqueries.
+--echo #
+
+--echo #
+--echo # 1.1 Simple SELECT statement.
+--echo #
+--echo # No locks are necessary as this statement won't be written
+--echo # to the binary log and thanks to how MyISAM works SELECT
+--echo # will see version of the table prior to concurrent insert.
+let $statement= select * from t1;
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 1.2 Multi-UPDATE statement.
+--echo #
+--echo # Has to take shared locks on rows in the table being read as this
+--echo # statement will be written to the binary log and therefore should
+--echo # be serialized with concurrent statements.
+let $statement= update t2, t1 set j= j - 1 where i = j;
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 1.3 Multi-DELETE statement.
+--echo #
+--echo # The above is true for this statement as well.
+let $statement= delete t2 from t1, t2 where i = j;
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 1.4 DESCRIBE statement.
+--echo #
+--echo # This statement does not really read data from the
+--echo # target table and thus does not take any lock on it.
+--echo # We check this for completeness of coverage.
+lock table t1 write;
+--echo # Switching to connection 'con1'.
+connection con1;
+--echo # This statement should not be blocked.
+--disable_result_log
+describe t1;
+--enable_result_log
+--echo # Switching to connection 'default'.
+connection default;
+unlock tables;
+
+--echo #
+--echo # 1.5 SHOW statements.
+--echo #
+--echo # The above is true for SHOW statements as well.
+lock table t1 write;
+--echo # Switching to connection 'con1'.
+connection con1;
+--echo # These statements should not be blocked.
+# The below test for SHOW CREATE TABLE is disabled until bug 52593
+# "SHOW CREATE TABLE is blocked if table is locked for write by another
+# connection" is fixed.
+--disable_parsing
+show create table t1;
+--enable_parsing
+--disable_result_log
+show keys from t1;
+--enable_result_log
+--echo # Switching to connection 'default'.
+connection default;
+unlock tables;
+
+
+--echo #
+--echo # 2. Statements which read tables through subqueries.
+--echo #
+
+--echo #
+--echo # 2.1 CALL with a subquery.
+--echo #
+--echo # In theory strong lock is not necessary as this statement
+--echo # is not written to the binary log as a whole (it is written
+--echo # statement-by-statement). But in practice in 5.1 for
+--echo # almost everything except SELECT we take strong lock.
+let $statement= call p1((select i + 5 from t1 where i = 1));
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 2.2 CREATE TABLE with a subquery.
+--echo #
+--echo # Has to take a strong lock on the table being read as
+--echo # this statement is written to the binary log and therefore
+--echo # should be serialized with concurrent statements.
+let $statement= create table t0 select * from t1;
+let $restore_table= ;
+--source include/check_no_concurrent_insert.inc
+drop table t0;
+let $statement= create table t0 select j from t2 where j in (select i from t1);
+let $restore_table= ;
+--source include/check_no_concurrent_insert.inc
+drop table t0;
+
+--echo #
+--echo # 2.3 DELETE with a subquery.
+--echo #
+--echo # The above is true for this statement as well.
+let $statement= delete from t2 where j in (select i from t1);
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 2.4 MULTI-DELETE with a subquery.
+--echo #
+--echo # Same is true for this statement as well.
+let $statement= delete t2 from t3, t2 where k = j and j in (select i from t1);
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+
+--echo #
+--echo # 2.5 DO with a subquery.
+--echo #
+--echo # In theory strong lock is not necessary as it is not logged.
+--echo # But in practice in 5.1 for almost everything except SELECT
+--echo # we take strong lock.
+let $statement= do (select i from t1 where i = 1);
+let $restore_table= ;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 2.6 INSERT with a subquery.
+--echo #
+--echo # Has to take a strong lock on the table being read as
+--echo # this statement is written to the binary log and therefore
+--echo # should be serialized with concurrent inserts.
+let $statement= insert into t2 select i+5 from t1;
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+let $statement= insert into t2 values ((select i+5 from t1 where i = 4));
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 2.7 LOAD DATA with a subquery.
+--echo #
+--echo # The above is true for this statement as well.
+let $statement= load data infile '../../std_data/rpl_loaddata.dat' into table t2 (@a, @b) set j= @b + (select i from t1 where i = 1);
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 2.8 REPLACE with a subquery.
+--echo #
+--echo # Same is true for this statement as well.
+let $statement= replace into t2 select i+5 from t1;
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+let $statement= replace into t2 values ((select i+5 from t1 where i = 4));
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 2.9 SELECT with a subquery.
+--echo #
+--echo # Strong locks are not necessary as this statement is not written
+--echo # to the binary log and thanks to how MyISAM works this statement
+--echo # sees a version of the table prior to the concurrent insert.
+let $statement= select * from t2 where j in (select i from t1);
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 2.10 SET with a subquery.
+--echo #
+--echo # In theory the same is true for this statement as well.
+--echo # But in practice in 5.1 we acquire strong lock in this
+--echo # case as well.
+let $statement= set @a:= (select i from t1 where i = 1);
+let $restore_table= ;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 2.11 SHOW with a subquery.
+--echo #
+--echo # The same is true for this statement too.
+let $statement= show tables from test where Tables_in_test = 't2' and (select i from t1 where i = 1);
+let $restore_table= ;
+--source include/check_no_concurrent_insert.inc
+let $statement= show columns from t2 where (select i from t1 where i = 1);
+let $restore_table= ;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 2.12 UPDATE with a subquery.
+--echo #
+--echo # Has to take a strong lock on the table being read as
+--echo # this statement is written to the binary log and therefore
+--echo # should be serialized with concurrent inserts.
+let $statement= update t2 set j= j-10 where j in (select i from t1);
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 2.13 MULTI-UPDATE with a subquery.
+--echo #
+--echo # Same is true for this statement as well.
+let $statement= update t2, t3 set j= j -10 where j=k and j in (select i from t1);
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+
+--echo #
+--echo # 3. Statements which read tables through a view.
+--echo #
+
+--echo #
+--echo # 3.1 SELECT statement which uses some table through a view.
+--echo #
+--echo # Since this statement is not written to the binary log and
+--echo # an old version of the table is accessible thanks to how MyISAM
+--echo # handles concurrent insert, no locking is necessary.
+let $statement= select * from v1;
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+let $statement= select * from v2;
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+let $statement= select * from t2 where j in (select i from v1);
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+let $statement= select * from t3 where k in (select j from v2);
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 3.2 Statements which modify a table and use views.
+--echo #
+--echo # Since such statements are going to be written to the binary
+--echo # log they need to be serialized against concurrent statements
+--echo # and therefore should take strong locks on the data read.
+let $statement= update t2 set j= j-10 where j in (select i from v1);
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+let $statement= update t3 set k= k-10 where k in (select j from v2);
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+let $statement= update t2, v1 set j= j-10 where j = i;
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+let $statement= update v2 set j= j-10 where j = 3;
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+
+--echo #
+--echo # 4. Statements which read tables through stored functions.
+--echo #
+
+--echo #
+--echo # 4.1 SELECT/SET with a stored function which does not
+--echo # modify data and uses SELECT in its turn.
+--echo #
+--echo # Calls to such functions won't get into the binary log and
+--echo # thus don't need to acquire strong locks.
+--echo # In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+--echo # used stored functions may lead to broken SBR" strong locks
+--echo # are taken (we accepted it as a trade-off for this fix).
+let $statement= select f1();
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+let $statement= set @a:= f1();
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 4.2 INSERT (or other statement which modifies data) with
+--echo # a stored function which does not modify data and uses
+--echo # SELECT.
+--echo #
+--echo # Since such statement is written to the binary log it should
+--echo # be serialized with concurrent statements affecting the data
+--echo # it uses. Therefore it should take strong lock on the data
+--echo # it reads.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken.
+let $statement= insert into t2 values (f1() + 5);
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 4.3 SELECT/SET with a stored function which
+--echo # reads and modifies data.
+--echo #
+--echo # Since a call to such function is written to the binary log,
+--echo # it should be serialized with concurrent statements affecting
+--echo # the data it uses. Hence, a strong lock on the data read
+--echo # should be taken.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken.
+let $statement= select f2();
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+let $statement= set @a:= f2();
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 4.4. SELECT/SET with a stored function which does not
+--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.
+let $statement= select f3();
+let $restore_table= ;
+--source include/check_no_concurrent_insert.inc
+let $statement= set @a:= f3();
+let $restore_table= ;
+--source include/check_no_concurrent_insert.inc
+let $statement= select f4();
+let $restore_table= ;
+--source include/check_no_concurrent_insert.inc
+let $statement= set @a:= f4();
+let $restore_table= ;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 4.5. INSERT (or other statement which modifies data) with
+--echo # a stored function which does not modify data and reads
+--echo # the table through a subselect in one of its control
+--echo # constructs.
+--echo #
+--echo # Since such statement is written to the binary log it should
+--echo # be serialized with concurrent statements affecting data it
+--echo # uses. Therefore it should take a strong lock on the data
+--echo # it reads.
+let $statement= insert into t2 values (f3() + 5);
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+let $statement= insert into t2 values (f4() + 6);
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 4.6 SELECT/SET which uses a stored function with
+--echo # DML which reads a table via a subquery.
+--echo #
+--echo # Since call to such function is written to the binary log
+--echo # it should be serialized with concurrent statements.
+--echo # Hence reads should take a strong lock.
+let $statement= select f5();
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+let $statement= set @a:= f5();
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 4.7 SELECT/SET which uses a stored function which
+--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. In practice this fact is discovered
+--echo # too late to have any effect.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken
+--echo # in case when simple SELECT is used.
+let $statement= select f6();
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+let $statement= set @a:= f6();
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+let $statement= select f7();
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+let $statement= set @a:= f7();
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 4.8 INSERT which uses stored function which
+--echo # doesn't modify data and reads a table
+--echo # through a view.
+--echo #
+--echo # Since such statement is written to the binary log and
+--echo # should be serialized with concurrent statements affecting
+--echo # the data it uses. Therefore it should take a strong lock on
+--echo # the table it reads.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken
+--echo # in case when simple SELECT is used.
+let $statement= insert into t3 values (f6() + 5);
+let $restore_table= t3;
+--source include/check_concurrent_insert.inc
+let $statement= insert into t3 values (f7() + 5);
+let $restore_table= t3;
+--source include/check_no_concurrent_insert.inc
+
+
+--echo #
+--echo # 4.9 SELECT which uses a stored function which
+--echo # modifies data and reads tables through a view.
+--echo #
+--echo # Since a call to such function is written to the binary log
+--echo # it should be serialized with concurrent statements.
+--echo # Hence, reads should take strong locks.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken
+--echo # in case when simple SELECT is used.
+let $statement= select f8();
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+let $statement= select f9();
+let $restore_table= t2;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 4.10 SELECT which uses a stored function which doesn't modify
+--echo # data and reads a table indirectly, by calling another
+--echo # function.
+--echo #
+--echo # Calls to such functions won't get into the binary log and
+--echo # thus don't need to acquire strong locks.
+--echo # In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+--echo # used stored functions may lead to broken SBR" strong locks
+--echo # are taken (we accepted it as a trade-off for this fix).
+let $statement= select f10();
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 4.11 INSERT which uses a stored function which doesn't modify
+--echo # data and reads a table indirectly, by calling another
+--echo # function.
+--echo #
+--echo # Since such 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 data it reads.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken.
+let $statement= insert into t2 values (f10() + 5);
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 4.12 SELECT which uses a stored function which modifies
+--echo # data and reads a table indirectly, by calling another
+--echo # function.
+--echo #
+--echo # Since a call to such function is written to the binary log
+--echo # it should be serialized from concurrent statements.
+--echo # Hence, read should take a strong lock.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken.
+let $statement= select f11();
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 4.13 SELECT that reads a table through a subquery passed
+--echo # as a parameter to a stored function which modifies
+--echo # data.
+--echo #
+--echo # Even though a call to this function is written to the
+--echo # binary log, values of its parameters are written as literals.
+--echo # So there is no need to acquire strong locks for tables used in
+--echo # the subquery.
+let $statement= select f12((select i+10 from t1 where i=1));
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 4.14 INSERT that reads a table via a subquery passed
+--echo # as a parameter to a stored function which doesn't
+--echo # modify data.
+--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= 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 # 5. Statements that read tables through stored procedures.
+--echo #
+
+--echo #
+--echo # 5.1 CALL statement which reads a table via SELECT.
+--echo #
+--echo # Since neither this statement nor its components are
+--echo # written to the binary log, there is no need to take
+--echo # strong locks on the data it reads.
+let $statement= call p2(@a);
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 5.2 Function that modifies data and uses CALL,
+--echo # which reads a table through SELECT.
+--echo #
+--echo # Since a call to such function is written to the binary
+--echo # log, it should be serialized with concurrent statements.
+--echo # Hence, in this case reads should take strong locks on data.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken.
+let $statement= select f14();
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--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 # Calls to such functions won't get into the binary log and
+--echo # thus don't need to acquire strong locks.
+--echo # In 5.5 due to fix for bug #53921 "Wrong locks for SELECTs
+--echo # used stored functions may lead to broken SBR" strong locks
+--echo # are taken (we accepted it as a trade-off for this fix).
+let $statement= select f15();
+let $restore_table= ;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 5.4 INSERT which calls function which doesn't modify data and
+--echo # uses CALL statement which reads table through SELECT.
+--echo #
+--echo # Since such statement is written to the binary log it should
+--echo # be serialized with concurrent statements affecting data it
+--echo # uses. Therefore it should take strong locks on data it reads.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken.
+let $statement= insert into t2 values (f15()+5);
+let $restore_table= t2;
+--source include/check_concurrent_insert.inc
+
+
+--echo #
+--echo # 6. Statements that use triggers.
+--echo #
+
+--echo #
+--echo # 6.1 Statement invoking a trigger that reads table via SELECT.
+--echo #
+--echo # Since this statement is written to the binary log it should
+--echo # be serialized with concurrent statements affecting the data
+--echo # it uses. Therefore, it should take strong locks on the data
+--echo # it reads.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken.
+let $statement= insert into t4 values (2);
+let $restore_table= t4;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 6.2 Statement invoking a trigger that reads table through
+--echo # a subquery in a control construct.
+--echo #
+--echo # The above is true for this statement as well.
+let $statement= update t4 set l= 2 where l = 1;
+let $restore_table= t4;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 6.3 Statement invoking a trigger that reads a table through
+--echo # a view.
+--echo #
+--echo # And for this statement.
+let $statement= delete from t4 where l = 1;
+let $restore_table= t4;
+--source include/check_no_concurrent_insert.inc
+
+--echo #
+--echo # 6.4 Statement invoking a trigger that reads a table through
+--echo # a stored function.
+--echo #
+--echo # And for this statement.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken.
+let $statement= insert into t5 values (2);
+let $restore_table= t5;
+--source include/check_concurrent_insert.inc
+
+--echo #
+--echo # 6.5 Statement invoking a trigger that reads a table through
+--echo # stored procedure.
+--echo #
+--echo # And for this statement.
+--echo # But due to bug #53921 "Wrong locks for SELECTs used stored
+--echo # functions may lead to broken SBR" weak locks are taken.
+let $statement= update t5 set l= 2 where l = 1;
+let $restore_table= t5;
+--source include/check_concurrent_insert.inc
+
+
+--echo # Clean-up.
+drop function f1;
+drop function f2;
+drop function f3;
+drop function f4;
+drop function f5;
+drop function f6;
+drop function f7;
+drop function f8;
+drop function f9;
+drop function f10;
+drop function f11;
+drop function f12;
+drop function f13;
+drop function f14;
+drop function f15;
+drop view v1, v2;
+drop procedure p1;
+drop procedure p2;
+drop table t1, t2, t3, t4, t5, te;
+
+disconnect con1;
+disconnect con2;
+
+set @@global.concurrent_insert= @old_concurrent_insert;
+
+
+# Check that all connections opened by test cases in this file are really
+# gone so execution of other tests won't be affected by their presence.
+--source include/wait_until_count_sessions.inc