diff options
Diffstat (limited to 'mysql-test/main/sp-lock.test')
-rw-r--r-- | mysql-test/main/sp-lock.test | 994 |
1 files changed, 994 insertions, 0 deletions
diff --git a/mysql-test/main/sp-lock.test b/mysql-test/main/sp-lock.test new file mode 100644 index 00000000..9ca07107 --- /dev/null +++ b/mysql-test/main/sp-lock.test @@ -0,0 +1,994 @@ +# +# Metadata lock handling for stored procedures and +# functions. +# +--echo # +--echo # Test coverage for changes performed by the fix +--echo # for Bug#30977 "Concurrent statement using stored function +--echo # and DROP FUNCTION breaks SBR. +--echo # + +--echo # +--echo # 1) Verify that the preceding transaction is +--echo # (implicitly) committed before CREATE/ALTER/DROP +--echo # PROCEDURE. Note, that this is already tested +--echo # in implicit_commit.test, but here we use an alternative +--echo # approach. +--echo # + +--echo # Start a transaction, create a savepoint, +--echo # then call a DDL operation on a procedure, and then check +--echo # that the savepoint is no longer present. + +# Tests will be skipped for the view protocol +-- source include/no_view_protocol.inc + +create table t1 (a int); +--echo # +--echo # Test 'CREATE PROCEDURE'. +--echo # +begin; +savepoint sv; +create procedure p1() begin end; +--error ER_SP_DOES_NOT_EXIST +rollback to savepoint sv; +--echo # +--echo # Test 'ALTER PROCEDURE'. +--echo # +begin; +savepoint sv; +alter procedure p1 comment 'changed comment'; +--error ER_SP_DOES_NOT_EXIST +rollback to savepoint sv; +--echo # +--echo # Test 'DROP PROCEDURE'. +--echo # +begin; +savepoint sv; +drop procedure p1; +--error ER_SP_DOES_NOT_EXIST +rollback to savepoint sv; +--echo # +--echo # Test 'CREATE FUNCTION'. +--echo # +begin; +savepoint sv; +create function f1() returns int return 1; +--error ER_SP_DOES_NOT_EXIST +rollback to savepoint sv; +--echo # +--echo # Test 'ALTER FUNCTION'. +--echo # +begin; +savepoint sv; +alter function f1 comment 'new comment'; +--error ER_SP_DOES_NOT_EXIST +rollback to savepoint sv; +--echo # +--echo # Test 'DROP FUNCTION'. +--echo # +begin; +savepoint sv; +drop function f1; +--error ER_SP_DOES_NOT_EXIST +rollback to savepoint sv; + +--echo # +--echo # 2) Verify that procedure DDL operations fail +--echo # under lock tables. +--echo # +--echo # Auxiliary routines to test ALTER. +create procedure p1() begin end; +create function f1() returns int return 1; + +lock table t1 write; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +create procedure p2() begin end; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +alter procedure p1 comment 'changed comment'; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +drop procedure p1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +create function f2() returns int return 1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +alter function f1 comment 'changed comment'; +lock table t1 read; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +create procedure p2() begin end; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +alter procedure p1 comment 'changed comment'; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +drop procedure p1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +create function f2() returns int return 1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +alter function f1 comment 'changed comment'; +unlock tables; +--echo # +--echo # Even if we locked a temporary table. +--echo # Todo: this is a restriction we could possibly lift. +--echo # +drop table t1; +create temporary table t1 (a int); +lock table t1 read; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +create procedure p2() begin end; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +alter procedure p1 comment 'changed comment'; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +drop procedure p1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +create function f2() returns int return 1; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +alter function f1 comment 'changed comment'; +unlock tables; + +drop function f1; +drop procedure p1; +drop temporary table t1; + +--echo # +--echo # 3) Verify that CREATE/ALTER/DROP routine grab an +--echo # exclusive lock. +--echo # +--echo # For that, start a transaction, use a routine. In a concurrent +--echo # connection, try to drop or alter the routine. It should place +--echo # a pending or exclusive lock and block. In another concurrnet +--echo # connection, try to use the routine. +--echo # That should block on the pending exclusive lock. +--echo # +connect(con1, localhost, root,,); +connect(con2, localhost, root,,); +connect(con3, localhost, root,,); + +--echo # +--echo # Test DROP PROCEDURE. +--echo # +connection default; +create procedure p1() begin end; +delimiter |; +create function f1() returns int +begin + call p1(); + return 1; +end| +delimiter ;| +begin; +select f1(); +connection con1; +--echo # Sending 'drop procedure p1'... +send drop procedure p1; +connection con2; +--echo # Waiting for 'drop procedure t1' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored procedure metadata lock' and +info='drop procedure p1'; +--source include/wait_condition.inc +--echo # Demonstrate that there is a pending exclusive lock. +--echo # Sending 'select f1()'... +send select f1(); +connection con3; +--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored procedure metadata lock' and info='select f1()'; +connection default; +commit; +connection con1; +--echo # Reaping 'drop procedure p1'... +reap; +connection con2; +--echo # Reaping 'select f1()' +--error ER_SP_DOES_NOT_EXIST +reap; +connection default; + +--echo # +--echo # Test CREATE PROCEDURE. +--echo # +create procedure p1() begin end; +begin; +select f1(); +connection con1; +--echo # Sending 'create procedure p1'... +send create procedure p1() begin end; +connection con2; +--echo # Waiting for 'create procedure t1' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored procedure metadata lock' and +info='create procedure p1() begin end'; +--source include/wait_condition.inc +--echo # Demonstrate that there is a pending exclusive lock. +--echo # Sending 'select f1()'... +send select f1(); +connection con3; +--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored procedure metadata lock' and info='select f1()'; +connection default; +commit; +connection con1; +--echo # Reaping 'create procedure p1'... +--error ER_SP_ALREADY_EXISTS +reap; +connection con2; +--echo # Reaping 'select f1()' +reap; +connection default; + +--echo # +--echo # Test ALTER PROCEDURE. +--echo # +begin; +select f1(); +connection con1; +--echo # Sending 'alter procedure p1'... +send alter procedure p1 contains sql; +connection con2; +--echo # Waiting for 'alter procedure t1' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored procedure metadata lock' and +info='alter procedure p1 contains sql'; +--source include/wait_condition.inc +--echo # Demonstrate that there is a pending exclusive lock. +--echo # Sending 'select f1()'... +send select f1(); +connection con3; +--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored procedure metadata lock' and info='select f1()'; +connection default; +commit; +connection con1; +--echo # Reaping 'alter procedure p1'... +reap; +connection con2; +--echo # Reaping 'select f1()' +reap; +connection default; + +--echo # +--echo # Test DROP FUNCTION. +--echo # +begin; +select f1(); +connection con1; +--echo # Sending 'drop function f1'... +send drop function f1; +connection con2; +--echo # Waiting for 'drop function f1' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info='drop function f1'; +--source include/wait_condition.inc +--echo # Demonstrate that there is a pending exclusive lock. +--echo # Sending 'select f1()'... +send select f1(); +connection con3; +--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and info='select f1()'; +connection default; +commit; +connection con1; +--echo # Reaping 'drop function f1'... +reap; +connection con2; +--echo # Reaping 'select f1()' +--error ER_SP_DOES_NOT_EXIST +reap; +connection default; + +--echo # +--echo # Test CREATE FUNCTION. +--echo # +create function f1() returns int return 1; +begin; +select f1(); +connection con1; +--echo # Sending 'create function f1'... +send create function f1() returns int return 2; +connection con2; +--echo # Waiting for 'create function f1' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info='create function f1() returns int return 2'; +--source include/wait_condition.inc +--echo # Demonstrate that there is a pending exclusive lock. +--echo # Sending 'select f1()'... +send select f1(); +connection con3; +--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and info='select f1()'; +connection default; +commit; +connection con1; +--echo # Reaping 'create function f1'... +--error ER_SP_ALREADY_EXISTS +reap; +connection con2; +--echo # Reaping 'select f1()' +reap; +connection default; + +--echo # +--echo # Test ALTER FUNCTION. +--echo # +begin; +select f1(); +connection con1; +--echo # Sending 'alter function f1'... +send alter function f1 contains sql; +connection con2; +--echo # Waiting for 'alter function f1' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info='alter function f1 contains sql'; +--source include/wait_condition.inc +--echo # Demonstrate that there is a pending exclusive lock. +--echo # Sending 'select f1()'... +send select f1(); +connection con3; +--echo # Waiting for 'select f1()' to get blocked by a pending MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and info='select f1()'; +connection default; +commit; +connection con1; +--echo # Reaping 'alter function f1'... +reap; +connection con2; +--echo # Reaping 'select f1()' +reap; +connection default; +drop function f1; +drop procedure p1; + +--echo # +--echo # 4) MDL lock should not be taken for +--echo # unrolled CALL statements. +--echo # The primary goal of metadata locks is a consistent binary log. +--echo # When a call statement is unrolled, it doesn't get to the +--echo # binary log, instead the statements that are contained +--echo # in the procedure body do. This can nest to any level. +--echo # +create procedure p1() begin end; +create procedure p2() begin end; +create table t1 (a int); +delimiter |; +create procedure p3() +begin + call p1(); + call p1(); + call p2(); +end| +create procedure p4() +begin + call p1(); + call p1(); + call p2(); + call p2(); + call p3(); +end| +delimiter ;| +begin; +select * from t1; +savepoint sv; +call p4(); +--echo # Prepared statement should not add any locks either. +prepare stmt from "call p4()"; +execute stmt; +execute stmt; +connection con1; +drop procedure p1; +drop procedure p2; +drop procedure p3; +drop procedure p4; +connection default; +--echo # This is to verify there was no implicit commit. +rollback to savepoint sv; +--error ER_SP_DOES_NOT_EXIST +call p4(); +commit; +drop table t1; + +--echo # +--echo # 5) Locks should be taken on routines +--echo # used indirectly by views or triggers. +--echo # +--echo # +--echo # A function is used from a trigger. +--echo # +create function f1() returns int return 1; +create table t1 (a int); +create table t2 (a int, b int); +create trigger t1_ai after insert on t1 for each row + insert into t2 (a, b) values (new.a, f1()); +begin; +insert into t1 (a) values (1); +connection con1; +--echo # Sending 'drop function f1' +send drop function f1; +connection con2; +--echo # Waiting for 'drop function f1' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info='drop function f1'; +--source include/wait_condition.inc +connection default; +commit; +connection con1; +--echo # Reaping 'drop function f1'... +reap; +connection default; +--echo # +--echo # A function is used from a view. +--echo # +create function f1() returns int return 1; +create view v1 as select f1() as a; +begin; +select * from v1; +connection con1; +--echo # Sending 'drop function f1' +send drop function f1; +connection con2; +--echo # Waiting for 'drop function f1' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info='drop function f1'; +--source include/wait_condition.inc +connection default; +commit; +connection con1; +--echo # Reaping 'drop function f1'... +reap; +connection default; +--echo # +--echo # A procedure is used from a function. +--echo # +delimiter |; +create function f1() returns int +begin + declare v_out int; + call p1(v_out); + return v_out; +end| +delimiter ;| +create procedure p1(out v_out int) set v_out=3; +begin; +select * from v1; +connection con1; +--echo # Sending 'drop procedure p1' +send drop procedure p1; +connection con2; +--echo # Waiting for 'drop procedure p1' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored procedure metadata lock' and +info='drop procedure p1'; +--source include/wait_condition.inc +connection default; +commit; +connection con1; +--echo # Reaping 'drop procedure p1'... +reap; +connection default; + +--echo # +--echo # Deep nesting: a function is used from a procedure used +--echo # from a function used from a view used in a trigger. +--echo # +create function f2() returns int return 4; +create procedure p1(out v_out int) set v_out=f2(); +drop trigger t1_ai; +create trigger t1_ai after insert on t1 for each row + insert into t2 (a, b) values (new.a, (select max(a) from v1)); +begin; +insert into t1 (a) values (3); +connection con1; +--echo # Sending 'drop function f2' +send drop function f2; +connection con2; +--echo # Waiting for 'drop function f2' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info='drop function f2'; +--source include/wait_condition.inc +connection default; +commit; +connection con1; +--echo # Reaping 'drop function f2'... +reap; +connection default; + +drop view v1; +drop function f1; +drop procedure p1; +drop table t1, t2; + +--echo # +--echo # 6) Check that ER_LOCK_DEADLOCK is reported if +--echo # acquisition of a shared lock fails during a transaction or +--echo # we need to back off to flush the sp cache. +--echo # +--echo # Sic: now this situation does not require a back off since we +--echo # flush the cache on the fly. +--echo # +create function f1() returns int return 7; +create table t1 (a int); +begin; +select * from t1; +# Used to have a back-off here, with optional ER_LOCK_DEADLOCK +#--error ER_LOCK_DEADLOCK +select f1(); +commit; +drop table t1; +drop function f1; + +--echo # +--echo # 7) Demonstrate that under LOCK TABLES we accumulate locks +--echo # on stored routines, and release metadata locks in +--echo # ROLLBACK TO SAVEPOINT. That is done only for those stored +--echo # routines that are not part of LOCK TABLES prelocking list. +--echo # Those stored routines that are part of LOCK TABLES +--echo # prelocking list are implicitly locked when entering +--echo # LOCK TABLES, and ROLLBACK TO SAVEPOINT has no effect on +--echo # them. +--echo # +create function f1() returns varchar(20) return "f1()"; +create function f2() returns varchar(20) return "f2()"; +create view v1 as select f1() as a; +lock table v1 read; +start transaction; +select * from v1; +savepoint sv; +select f2(); +connection con1; +--echo # Sending 'drop function f1'... +send drop function f1; +connection con2; +--echo # Waiting for 'drop function f1' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info='drop function f1'; +--source include/wait_condition.inc +--echo # Sending 'drop function f2'... +send drop function f2; +connection default; +--echo # Waiting for 'drop function f2' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info='drop function f2'; +--source include/wait_condition.inc +rollback to savepoint sv; +connection con2; +--echo # Reaping 'drop function f2'... +reap; +connection default; +unlock tables; +commit; +connection con1; +--echo # Reaping 'drop function f1'... +reap; +connection default; +--error ER_SP_DOES_NOT_EXIST +drop function f1; +--error ER_SP_DOES_NOT_EXIST +drop function f2; +drop view v1; + +--echo # +--echo # 8) Check the situation when we're preparing or executing a +--echo # prepared statement, and as part of that try to flush the +--echo # session sp cache. However, one of the procedures that +--echo # needs a flush is in use. Verify that there is no infinite +--echo # reprepare loop and no crash. +--echo # +create function f1() returns int return 1; +delimiter |; +--echo # +--echo # We just mention p1() in the body of f2() to make +--echo # sure that p1() metadata is validated when validating +--echo # 'select f2()'. +--echo # Recursion is not allowed in stored functions, so +--echo # an attempt to just invoke p1() from f2() which is in turn +--echo # called from p1() would have given a run-time error. +--echo # +create function f2() returns int +begin + if @var is null then + call p1(); + end if; + return 1; +end| +create procedure p1() +begin + select f1() into @var; + execute stmt; +end| +delimiter ;| +connection con2; +prepare stmt from "select f2()"; +connection default; +begin; +select f1(); +connection con1; +--echo # Sending 'alter function f1 ...'... +send alter function f1 comment "comment"; +connection con2; +--echo # Waiting for 'alter function f1 ...' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info like 'alter function f1 comment%'; +--source include/wait_condition.inc +--echo # Sending 'call p1()'... +send call p1(); +connection default; +--echo # Waiting for 'call p1()' to get blocked on MDL lock on f1... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info='select f1() into @var'; +--source include/wait_condition.inc +--echo # Let 'alter function f1 ...' go through... +commit; +connection con1; +--echo # Reaping 'alter function f1 ...' +reap; +connection con2; +--echo # Reaping 'call p1()'... +reap; +deallocate prepare stmt; +connection default; +drop function f1; +drop function f2; +drop procedure p1; + +--echo # +--echo # 9) Check the situation when a stored function is invoked +--echo # from a stored procedure, and recursively invokes the +--echo # stored procedure that is in use. But for the second +--echo # invocation, a cache flush is requested. We can't +--echo # flush the procedure that's in use, and are forced +--echo # to use an old version. It is not a violation of +--echo # consistency, since we unroll top-level calls. +--echo # Just verify the code works. +--echo # +create function f1() returns int return 1; +begin; +select f1(); +connection con1; +--echo # Sending 'alter function f1 ...'... +send alter function f1 comment "comment"; +connection con2; +--echo # Waiting for 'alter function f1 ...' to get blocked on MDL lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info like 'alter function f1 comment%'; +--source include/wait_condition.inc +delimiter |; +--echo # +--echo # We just mention p1() in the body of f2() to make +--echo # sure that p1() is prelocked for f2(). +--echo # Recursion is not allowed in stored functions, so +--echo # an attempt to just invoke p1() from f2() which is in turn +--echo # called from p1() would have given a run-time error. +--echo # +create function f2() returns int +begin + if @var is null then + call p1(); + end if; + return 1; +end| +create procedure p1() +begin + select f1() into @var; + select f2() into @var; +end| +delimiter ;| +--echo # Sending 'call p1()'... +send call p1(); +connection default; +--echo # Waiting for 'call p1()' to get blocked on MDL lock on f1... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='Waiting for stored function metadata lock' and +info='select f1() into @var'; +--source include/wait_condition.inc +--echo # Let 'alter function f1 ...' go through... +commit; +connection con1; +--echo # Reaping 'alter function f1 ...' +reap; +connection con2; +--echo # Reaping 'call p1()'... +reap; +connection default; +drop function f1; +drop function f2; +drop procedure p1; + +--echo # +--echo # 10) A select from information_schema.routines now +--echo # flushes the stored routines caches. Test that this +--echo # does not remove from the cache a stored routine +--echo # that is already prelocked. +--echo # +create function f1() returns int return get_lock("30977", 100000); +create function f2() returns int return 2; +delimiter |; +create function f3() returns varchar(255) +begin + declare res varchar(255); + declare c cursor for select routine_name from + information_schema.routines where routine_name='f1'; + select f1() into @var; + open c; + fetch c into res; + close c; + select f2() into @var; + return res; +end| +delimiter ;| +connection con1; +select get_lock("30977", 0); +connection default; +--echo # Sending 'select f3()'... +send select f3(); +connection con1; +--echo # Waiting for 'select f3()' to get blocked on the user level lock... +let $wait_condition=select count(*)=1 from information_schema.processlist +where state='User lock' and info='select f1() into @var'; +--source include/wait_condition.inc +--echo # Do something to change the cache version. +create function f4() returns int return 4; +drop function f4; +select release_lock("30977"); +connection default; +--echo # Reaping 'select f3()'... +--echo # Routine 'f2()' should exist and get executed successfully. +reap; +select @var; +drop function f1; +drop function f2; +drop function f3; + + +--echo # 11) Check the situation when the connection is flushing the +--echo # SP cache which contains a procedure that is being executed. +--echo # +--echo # Function f1() calls p1(). Procedure p1() has a DROP +--echo # VIEW statement, which, we know, invalidates the routines cache. +--echo # During cache flush p1() must not be flushed since it's in +--echo # use. +--echo # +delimiter |; +create function f1() returns int +begin + call p1(); + return 1; +end| +create procedure p1() +begin + create view v1 as select 1; + drop view v1; + select f1() into @var; + set @exec_count=@exec_count+1; +end| +delimiter ;| +set @exec_count=0; +--error ER_SP_RECURSION_LIMIT +call p1(); +select @exec_count; +set @@session.max_sp_recursion_depth=5; +set @exec_count=0; +--error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +call p1(); +select @exec_count; +drop procedure p1; +drop function f1; +set @@session.max_sp_recursion_depth=default; + +connection con1; +disconnect con1; +--source include/wait_until_disconnected.inc +connection con2; +disconnect con2; +--source include/wait_until_disconnected.inc +connection con3; +disconnect con3; +--source include/wait_until_disconnected.inc +connection default; + + +--echo # +--echo # SHOW CREATE PROCEDURE p1 called from p1, after p1 was altered +--echo # + +delimiter |; +CREATE PROCEDURE p1() +BEGIN + SELECT get_lock("test", 10); + SHOW CREATE PROCEDURE p1; +END| +delimiter ;| + +connect (con2, localhost, root); +connect (con3, localhost, root); + +connection default; +SELECT get_lock("test", 10); + +connection con2; +--echo # Will halt before executing SHOW CREATE PROCEDURE p1 +--echo # Sending: +--send CALL p1() + +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='User lock' and info='SELECT get_lock("test", 10)'; +--source include/wait_condition.inc +--echo # Alter p1 +DROP PROCEDURE p1; +CREATE PROCEDURE p1() BEGIN END; + +connection default; +--echo # Resume CALL p1, now with new p1 +SELECT release_lock("test"); + +connection con2; +--echo # Reaping: CALL p1() +--reap + +connection con3; +disconnect con3; +--source include/wait_until_disconnected.inc +connection con2; +disconnect con2; +--source include/wait_until_disconnected.inc +connection default; +DROP PROCEDURE p1; + + +--echo # +--echo # Bug#57663 Concurrent statement using stored function and DROP DATABASE +--echo # breaks SBR +--echo # + +connect(con1, localhost, root); +connect(con2, localhost, root); + +--echo # Test 1: Check that DROP DATABASE block if a function is used +--echo # by an active transaction. + +connection default; +CREATE DATABASE db1; +CREATE FUNCTION db1.f1() RETURNS INTEGER RETURN 1; +START TRANSACTION; +SELECT db1.f1(); + +connection con1; +--echo # Sending: +--send DROP DATABASE db1 + +connection default; +--echo # Waiting for DROP DATABASE to be blocked by the lock on f1() +let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist + WHERE state= 'Waiting for stored function metadata lock' + AND info='DROP DATABASE db1'; +--source include/wait_condition.inc +COMMIT; + +connection con1; +--echo # Reaping: DROP DATABASE db1 +--reap + +--echo # Test 2: Check that DROP DATABASE blocks if a procedure is +--echo # used by an active transaction. + +connection default; +CREATE DATABASE db1; +CREATE PROCEDURE db1.p1() BEGIN END; +delimiter |; +CREATE FUNCTION f1() RETURNS INTEGER +BEGIN + CALL db1.p1(); + RETURN 1; +END| +delimiter ;| +START TRANSACTION; +SELECT f1(); + +connection con1; +--echo # Sending: +--send DROP DATABASE db1 + +connection default; +--echo # Waiting for DROP DATABASE to be blocked by the lock on p1() +let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist + WHERE state= 'Waiting for stored procedure metadata lock' + AND info='DROP DATABASE db1'; +--source include/wait_condition.inc +COMMIT; + +connection con1; +--echo # Reaping: DROP DATABASE db1 +--reap + +--echo # Test 3: Check that DROP DATABASE is not selected as a victim if a +--echo # deadlock is discovered with DML statements. + +connection default; +CREATE DATABASE db1; +CREATE TABLE db1.t1 (a INT); +CREATE FUNCTION db1.f1() RETURNS INTEGER RETURN 1; +START TRANSACTION; +# DROP DATABASE will lock tables (t1) before functions (f1) +SELECT db1.f1(); + +connection con1; +--echo # Sending: +--send DROP DATABASE db1 + +connection default; +--echo # Waiting for DROP DATABASE to be blocked by the lock on f1() +let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist + WHERE state= 'Waiting for stored function metadata lock' + AND info='DROP DATABASE db1'; +--source include/wait_condition.inc +--error ER_LOCK_DEADLOCK +SELECT * FROM db1.t1; +COMMIT; + +connection con1; +--echo # Reaping: DROP DATABASE db1 +--reap + +--echo # Test 4: Check that active DROP DATABASE blocks stored routine DDL. + +connection default; +CREATE DATABASE db1; +CREATE FUNCTION db1.f1() RETURNS INTEGER RETURN 1; +CREATE FUNCTION db1.f2() RETURNS INTEGER RETURN 2; +START TRANSACTION; +SELECT db1.f2(); + +connection con1; +--echo # Sending: +--send DROP DATABASE db1 + +connection con2; +--echo # Waiting for DROP DATABASE to be blocked by the lock on f2() +let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist + WHERE state= 'Waiting for stored function metadata lock' + AND info='DROP DATABASE db1'; +--source include/wait_condition.inc +--echo # Sending: +--send ALTER FUNCTION db1.f1 COMMENT "test" + +connection default; +--echo # Waiting for ALTER FUNCTION to be blocked by the schema lock on db1 +let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist + WHERE state= 'Waiting for schema metadata lock' + AND info='ALTER FUNCTION db1.f1 COMMENT "test"'; +--source include/wait_condition.inc +COMMIT; + +connection con1; +--echo # Reaping: DROP DATABASE db1 +--reap +disconnect con1; +--source include/wait_until_disconnected.inc + +connection con2; +--echo # Reaping: ALTER FUNCTION f1 COMMENT 'test' +--error ER_SP_DOES_NOT_EXIST +--reap +disconnect con2; +--source include/wait_until_disconnected.inc + +connection default; +DROP FUNCTION f1; + + +--echo # +--echo # End of 5.5 tests +--echo # |