summaryrefslogtreecommitdiff
path: root/mysql-test/r/sp-lock.result
diff options
context:
space:
mode:
authorKonstantin Osipov <kostja@sun.com>2009-12-29 15:19:05 +0300
committerKonstantin Osipov <kostja@sun.com>2009-12-29 15:19:05 +0300
commitbf9c1b7353d59f4c875c50dabd62dfd9765caf05 (patch)
tree50d75982e824c58225970afc69d0794daebfd8bd /mysql-test/r/sp-lock.result
parentdfdbc84585a154d056fdef3878172e383117354b (diff)
downloadmariadb-git-bf9c1b7353d59f4c875c50dabd62dfd9765caf05.tar.gz
Apply and review:
3655 Jon Olav Hauglid 2009-10-19 Bug #30977 Concurrent statement using stored function and DROP FUNCTION breaks SBR Bug #48246 assert in close_thread_table Implement a fix for: Bug #41804 purge stored procedure cache causes mysterious hang for many minutes Bug #49972 Crash in prepared statements The problem was that concurrent execution of DML statements that use stored functions and DDL statements that drop/modify the same function might result in incorrect binary log in statement (and mixed) mode and therefore break replication. This patch fixes the problem by introducing metadata locking for stored procedures and functions. This is similar to what is done in Bug#25144 for views. Procedures and functions now are locked using metadata locks until the transaction is either committed or rolled back. This prevents other statements from modifying the procedure/function while it is being executed. This provides commit ordering - guaranteeing serializability across multiple transactions and thus fixes the reported binlog problem. Note that we do not take locks for top-level CALLs. This means that procedures called directly are not protected from changes by simultaneous DDL operations so they are executed at the state they had at the time of the CALL. By not taking locks for top-level CALLs, we still allow transactions to be started inside procedures. This patch also changes stored procedure cache invalidation. Upon a change of cache version, we no longer invalidate the entire cache, but only those routines which we use, only when a statement is executed that uses them. This patch also changes the logic of prepared statement validation. A stored procedure used by a prepared statement is now validated only once a metadata lock has been acquired. A version mismatch causes a flush of the obsolete routine from the cache and statement reprepare. Incompatible changes: 1) ER_LOCK_DEADLOCK is reported for a transaction trying to access a procedure/function that is locked by a DDL operation in another connection. 2) Procedure/function DDL operations are now prohibited in LOCK TABLES mode as exclusive locks must be taken all at once and LOCK TABLES provides no way to specifiy procedures/functions to be locked. Test cases have been added to sp-lock.test and rpl_sp.test. Work on this bug has very much been a team effort and this patch includes and is based on contributions from Davi Arnaut, Dmitry Lenev, Magne Mæhre and Konstantin Osipov. mysql-test/r/ps_ddl.result: Update results (Bug#30977). mysql-test/r/ps_ddl1.result: Update results (Bug#30977). mysql-test/r/sp-error.result: Update results (Bug#30977). mysql-test/r/sp-lock.result: Update results (Bug#30977). mysql-test/suite/rpl/r/rpl_sp.result: Update results (Bug#30977). mysql-test/suite/rpl/t/rpl_sp.test: Add a test case for Bug#30977. mysql-test/t/ps_ddl.test: Update comments. We no longer re-prepare a prepared statement when a stored procedure used in top-level CALL is changed. mysql-test/t/ps_ddl1.test: Modifying stored procedure p1 no longer invalidates prepared statement "call p1" -- we can re-use the prepared statement without invalidation. mysql-test/t/sp-error.test: Use a constant for an error value. mysql-test/t/sp-lock.test: Add test coverage for Bug#30977. sql/lock.cc: Implement lock_routine_name() - a way to acquire an exclusive metadata lock (ex- name-lock) on stored procedure/function. sql/sp.cc: Change semantics of sp_cache_routine() -- now it has an option to make sure that the routine that is cached is up to date (has the latest sp cache version). Add sp_cache_invalidate() to sp_drop_routine(), where it was missing (a bug!). Acquire metadata locks for SP DDL (ALTER/CREATE/DROP). This is the core of the fix for Bug#30977. Since caching and cache invalidation scheme was changed, make sure we don't invalidate the SP cache in the middle of a stored routine execution. At the same time, make sure we don't access stale data due to lack of invalidation. For that, change ALTER FUNCTION/PROCEDURE to not use the cache, and SHOW PROCEDURE CODE/SHOW CREATE PROCEDURE/FUNCTION to always read an up to date version of the routine from the cache. sql/sp.h: Add a helper wrapper around sp_cache_routine(). sql/sp_cache.cc: Implement new sp_cache_version() and sp_cache_flush_obsolete(). Now we flush stale routines individually, rather than all at once. sql/sp_cache.h: Update signatures of sp_cache_version() and sp_cache_flush_obsolete(). sql/sp_head.cc: Add a default initialization of sp_head::m_sp_cache_version. Remove a redundant sp_head::create(). sql/sp_head.h: Add m_sp_cache_version to sp_head class - we now keep track of every routine in the stored procedure cache, rather than of the entire cache. sql/sql_base.cc: Implement prelocking for stored routines. Validate stored routines after they were locked. Flush obsolete routines upon next access, one by one, not all at once (Bug#41804). Style fixes. sql/sql_class.h: Rename a Open_table_context method. sql/sql_parse.cc: Make sure stored procedures DDL commits the active transaction (issues an implicit commit before and after). Remove sp_head::create(), a pure redundancy. Move the semantical check during alter routine inside sp_update_routine() code in order to: - avoid using SP cache during update, it may be obsolete. - speed up and simplify the update procedure. Remove sp_cache_flush_obsolete() calls, we no longer flush the entire cache, ever, stale routines are flushed before next use, one at a time. sql/sql_prepare.cc: Move routine metadata validation to open_and_process_routine(). Fix Bug#49972 (don't swap flags at reprepare). Reset Sroutine_hash_entries in reinit_stmt_before_use(). Remove SP cache invalidation, it's now done by open_tables(). sql/sql_show.cc: Fix a warning: remove an unused label. sql/sql_table.cc: Reset mdl_request.ticket for tickets acquired for routines inlined through a view, in CHECK TABLE statement, to satisfy an MDL assert. sql/sql_update.cc: Move the cleanup of "translation items" to close_tables_for_reopen(), since it's needed in all cases when we back off, not just the back-off in multi-update. This fixes a bug when the server would crash on attempt to back off when opening tables for a statement that uses information_schema tables.
Diffstat (limited to 'mysql-test/r/sp-lock.result')
-rw-r--r--mysql-test/r/sp-lock.result697
1 files changed, 697 insertions, 0 deletions
diff --git a/mysql-test/r/sp-lock.result b/mysql-test/r/sp-lock.result
new file mode 100644
index 00000000000..65524d02d08
--- /dev/null
+++ b/mysql-test/r/sp-lock.result
@@ -0,0 +1,697 @@
+#
+# Test coverage for changes performed by the fix
+# for Bug#30977 "Concurrent statement using stored function
+# and DROP FUNCTION breaks SBR.
+#
+#
+# 1) Verify that the preceding transaction is
+# (implicitly) committed before CREATE/ALTER/DROP
+# PROCEDURE. Note, that this is already tested
+# in implicit_commit.test, but here we use an alternative
+# approach.
+#
+# Start a transaction, create a savepoint,
+# then call a DDL operation on a procedure, and then check
+# that the savepoint is no longer present.
+drop table if exists t1;
+drop procedure if exists p1;
+drop procedure if exists p2;
+drop procedure if exists p3;
+drop procedure if exists p4;
+drop function if exists f1;
+create table t1 (a int);
+#
+# Test 'CREATE PROCEDURE'.
+#
+begin;
+savepoint sv;
+create procedure p1() begin end;
+rollback to savepoint sv;
+ERROR 42000: SAVEPOINT sv does not exist
+#
+# Test 'ALTER PROCEDURE'.
+#
+begin;
+savepoint sv;
+alter procedure p1 comment 'changed comment';
+rollback to savepoint sv;
+ERROR 42000: SAVEPOINT sv does not exist
+#
+# Test 'DROP PROCEDURE'.
+#
+begin;
+savepoint sv;
+drop procedure p1;
+rollback to savepoint sv;
+ERROR 42000: SAVEPOINT sv does not exist
+#
+# Test 'CREATE FUNCTION'.
+#
+begin;
+savepoint sv;
+create function f1() returns int return 1;
+rollback to savepoint sv;
+ERROR 42000: SAVEPOINT sv does not exist
+#
+# Test 'ALTER FUNCTION'.
+#
+begin;
+savepoint sv;
+alter function f1 comment 'new comment';
+rollback to savepoint sv;
+ERROR 42000: SAVEPOINT sv does not exist
+#
+# Test 'DROP FUNCTION'.
+#
+begin;
+savepoint sv;
+drop function f1;
+rollback to savepoint sv;
+ERROR 42000: SAVEPOINT sv does not exist
+#
+# 2) Verify that procedure DDL operations fail
+# under lock tables.
+#
+# Auxiliary routines to test ALTER.
+create procedure p1() begin end;
+create function f1() returns int return 1;
+lock table t1 write;
+create procedure p2() begin end;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+alter procedure p1 comment 'changed comment';
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+drop procedure p1;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+create function f2() returns int return 1;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+alter function f1 comment 'changed comment';
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+lock table t1 read;
+create procedure p2() begin end;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+alter procedure p1 comment 'changed comment';
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+drop procedure p1;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+create function f2() returns int return 1;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+alter function f1 comment 'changed comment';
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+unlock tables;
+#
+# Even if we locked a temporary table.
+# Todo: this is a restriction we could possibly lift.
+#
+drop table t1;
+create temporary table t1 (a int);
+lock table t1 read;
+create procedure p2() begin end;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+alter procedure p1 comment 'changed comment';
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+drop procedure p1;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+create function f2() returns int return 1;
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+alter function f1 comment 'changed comment';
+ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
+unlock tables;
+drop function f1;
+drop procedure p1;
+drop temporary table t1;
+#
+# 3) Verify that CREATE/ALTER/DROP routine grab an
+# exclusive lock.
+#
+# For that, start a transaction, use a routine. In a concurrent
+# connection, try to drop or alter the routine. It should place
+# a pending or exlusive lock and block. In a concurrnet
+# connection, try to use the routine under LOCK TABLES.
+# That should yield ER_LOCK_DEADLOCK.
+#
+# Establish helper connections.
+#
+# Test DROP PROCEDURE.
+#
+# --> connection default
+create table t1 (a int);
+create procedure p1() begin end;
+create function f1() returns int
+begin
+call p1();
+return 1;
+end|
+begin;
+select f1();
+f1()
+1
+# --> connection con1
+# Sending 'drop procedure p1'...
+drop procedure p1;
+# --> connection con2
+# Waitng for 'drop procedure t1' to get blocked on MDL lock...
+# Demonstrate that there is a pending exclusive lock.
+lock table t1 read;
+select f1();
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+unlock tables;
+# --> connection default
+commit;
+# --> connection con1
+# Reaping 'drop procedure p1'...
+# --> connection default
+#
+# Test CREATE PROCEDURE.
+#
+create procedure p1() begin end;
+begin;
+select f1();
+f1()
+1
+# --> connection con1
+# Sending 'create procedure p1'...
+create procedure p1() begin end;
+# --> connection con2
+# Waitng for 'create procedure t1' to get blocked on MDL lock...
+# Demonstrate that there is a pending exclusive lock.
+lock table t1 read;
+select f1();
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+unlock tables;
+# --> connection default
+commit;
+# --> connection con1
+# Reaping 'create procedure p1'...
+ERROR 42000: PROCEDURE p1 already exists
+#
+# Test ALTER PROCEDURE.
+begin;
+select f1();
+f1()
+1
+# --> connection con1
+# Sending 'alter procedure p1'...
+alter procedure p1 contains sql;
+# --> connection con2
+# Waitng for 'alter procedure t1' to get blocked on MDL lock...
+# Demonstrate that there is a pending exclusive lock.
+lock table t1 read;
+select f1();
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+unlock tables;
+# --> connection default
+commit;
+# --> connection con1
+# Reaping 'alter procedure p1'...
+# --> connection default
+#
+# Test DROP FUNCTION.
+#
+begin;
+select f1();
+f1()
+1
+# --> connection con1
+# Sending 'drop function f1'...
+drop function f1;
+# --> connection con2
+# Waitng for 'drop function f1' to get blocked on MDL lock...
+# Demonstrate that there is a pending exclusive lock.
+lock table t1 read;
+select f1();
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+unlock tables;
+# --> connection default
+commit;
+# --> connection con1
+# Reaping 'drop function f1'...
+# --> connection default
+#
+# Test CREATE FUNCTION.
+#
+create function f1() returns int return 1;
+begin;
+select f1();
+f1()
+1
+# --> connection con1
+# Sending 'create function f1'...
+create function f1() returns int return 2;
+# --> connection con2
+# Waitng for 'create function f1' to get blocked on MDL lock...
+# Demonstrate that there is a pending exclusive lock.
+lock table t1 read;
+select f1();
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+unlock tables;
+# --> connection default
+commit;
+# --> connection con1
+# Reaping 'create function f1'...
+ERROR 42000: FUNCTION f1 already exists
+# --> connection default
+#
+# Test ALTER FUNCTION.
+begin;
+select f1();
+f1()
+1
+# --> connection con1
+# Sending 'alter function f1'...
+alter function f1 contains sql;
+# --> connection con2
+# Waitng for 'alter function f1' to get blocked on MDL lock...
+# Demonstrate that there is a pending exclusive lock.
+lock table t1 read;
+select f1();
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+unlock tables;
+# --> connection default
+commit;
+# --> connection con1
+# Reaping 'alter function f1'...
+# --> connection default
+drop function f1;
+drop procedure p1;
+#
+# 4) MDL lock should not be taken for
+# unrolled CALL statements.
+# The primary goal of metadata locks is a consistent binary log.
+# When a call statement is unrolled, it doesn't get to the
+# binary log, instead the statements that are contained
+# in the procedure body do. This can nest to any level.
+#
+create procedure p1() begin end;
+create procedure p2() begin end;
+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|
+begin;
+select * from t1;
+a
+savepoint sv;
+call p4();
+# 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
+# This is to verify there was no implicit commit.
+rollback to savepoint sv;
+call p4();
+ERROR 42000: PROCEDURE test.p4 does not exist
+commit;
+drop table t1;
+#
+# 5) Locks should be taken on routines
+# used indirectly by views or triggers.
+#
+#
+# A function is used from a trigger.
+#
+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
+# Sending 'drop function f1'
+drop function f1;
+# --> connection con2
+# Waitng for 'drop function f1' to get blocked on MDL lock...
+# --> connnection default
+commit;
+# --> connection con1
+# Reaping 'drop function f1'...
+# --> connection default
+#
+# A function is used from a view.
+#
+create function f1() returns int return 1;
+create view v1 as select f1() as a;
+begin;
+select * from v1;
+a
+1
+# --> connection con1
+# Sending 'drop function f1'
+drop function f1;
+# --> connection con2
+# Waitng for 'drop function f1' to get blocked on MDL lock...
+# --> connnection default
+commit;
+# --> connection con1
+# Reaping 'drop function f1'...
+# --> connection default
+#
+# A procedure is used from a function.
+#
+create function f1() returns int
+begin
+declare v_out int;
+call p1(v_out);
+return v_out;
+end|
+create procedure p1(out v_out int) set v_out=3;
+begin;
+select * from v1;
+a
+3
+# --> connection con1
+# Sending 'drop procedure p1'
+drop procedure p1;
+# --> connection con2
+# Waitng for 'drop procedure p1' to get blocked on MDL lock...
+# --> connnection default
+commit;
+# --> connection con1
+# Reaping 'drop procedure p1'...
+# --> connection default
+#
+# Deep nesting: a function is used from a procedure used
+# from a function used from a view used in a trigger.
+#
+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
+# Sending 'drop function f2'
+drop function f2;
+# --> connection con2
+# Waitng for 'drop function f2' to get blocked on MDL lock...
+# --> connnection default
+commit;
+# --> connection con1
+# Reaping 'drop function f2'...
+# --> connection default
+drop view v1;
+drop function f1;
+drop procedure p1;
+drop table t1, t2;
+#
+# 6) Check that ER_LOCK_DEADLOCK is reported if
+# acquisition of a shared lock fails during a transaction or
+# we need to back off to flush the sp cache.
+#
+# a) A back off due to a lock conflict.
+#
+create table t1 (a int);
+create function f1() returns int return 6;
+begin;
+select f1();
+f1()
+6
+# --> connection con1
+# Sending 'drop function f1'...
+drop function f1;
+# --> connection con2
+# Waitng for 'drop function f1' to get blocked on MDL lock...
+begin;
+select * from t1;
+a
+select f1();
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+commit;
+# --> connection default
+commit;
+# --> connection con1
+# Reaping 'drop function f1'...
+# --> connection default
+#
+# b) A back off to flush the cache.
+# Sic: now this situation does not require a back off since we
+# flush the cache on the fly.
+#
+create function f1() returns int return 7;
+begin;
+select * from t1;
+a
+select f1();
+f1()
+7
+commit;
+drop table t1;
+drop function f1;
+#
+# 7) Demonstrate that under LOCK TABLES we accumulate locks
+# on stored routines, and release metadata locks in
+# ROLLBACK TO SAVEPOINT. That is done only for those stored
+# routines that are not part of LOCK TABLES prelocking list.
+# Those stored routines that are part of LOCK TABLES
+# prelocking list are implicitly locked when entering
+# LOCK TABLES, and ROLLBACK TO SAVEPOINT has no effect on
+# them.
+#
+create function f1() returns varchar(20) return "f1()";
+create function f2() returns varchar(20) return "f2()";
+create view v1 as select f1() as a;
+set @@session.autocommit=0;
+lock table v1 read;
+select * from v1;
+a
+f1()
+savepoint sv;
+select f2();
+f2()
+f2()
+# --> connection con1
+# Sending 'drop function f1'...
+drop function f1;
+# --> connection con2
+# Waitng for 'drop function f1' to get blocked on MDL lock...
+# Sending 'drop function f2'...
+drop function f2;
+# --> connection default
+# Waitng for 'drop function f2' to get blocked on MDL lock...
+rollback to savepoint sv;
+# --> connection con2
+# Reaping 'drop function f2'...
+# --> connection default
+unlock tables;
+# --> connection con1
+# Reaping 'drop function f1'...
+# --> connection default
+drop function f1;
+ERROR 42000: FUNCTION test.f1 does not exist
+drop function f2;
+ERROR 42000: FUNCTION test.f2 does not exist
+drop view v1;
+set @@session.autocommit=default;
+#
+# 8) Check the situation when we're preparing or executing a
+# prepared statement, and as part of that try to flush the
+# session sp cache. However, one of the procedures that
+# needs a flush is in use. Verify that there is no infinite
+# reprepare loop and no crash.
+#
+create function f1() returns int return 1;
+#
+# We just mention p1() in the body of f2() to make
+# sure that p1() metadata is validated when validating
+# 'select f2()'.
+# Recursion is not allowed in stored functions, so
+# an attempt to just invoke p1() from f2() which is in turn
+# called from p1() would have given a run-time error.
+#
+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|
+# --> connection con2
+prepare stmt from "select f2()";
+# --> connection default
+begin;
+select f1();
+f1()
+1
+# --> connection con1
+# Sending 'alter function f1 ...'...
+alter function f1 comment "comment";
+# --> connection con2
+# Waitng for 'alter function f1 ...' to get blocked on MDL lock...
+# Sending 'call p1()'...
+call p1();
+# Waitng for 'call p1()' to get blocked on MDL lock on f1...
+# Let 'alter function f1 ...' go through...
+commit;
+# --> connection con1
+# Reaping 'alter function f1 ...'
+# --> connection con2
+# Reaping 'call p1()'...
+f2()
+1
+deallocate prepare stmt;
+# --> connection default
+drop function f1;
+drop function f2;
+drop procedure p1;
+#
+# 9) Check the situation when a stored function is invoked
+# from a stored procedure, and recursively invokes the
+# stored procedure that is in use. But for the second
+# invocation, a cache flush is requested. We can't
+# flush the procedure that's in use, and are forced
+# to use an old version. It is not a violation of
+# consistency, since we unroll top-level calls.
+# Just verify the code works.
+#
+create function f1() returns int return 1;
+begin;
+select f1();
+f1()
+1
+# --> connection con1
+# Sending 'alter function f1 ...'...
+alter function f1 comment "comment";
+# --> connection con2
+# Waitng for 'alter function f1 ...' to get blocked on MDL lock...
+#
+# We just mention p1() in the body of f2() to make
+# sure that p1() is prelocked for f2().
+# Recursion is not allowed in stored functions, so
+# an attempt to just invoke p1() from f2() which is in turn
+# called from p1() would have given a run-time error.
+#
+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|
+# Sending 'call p1()'...
+call p1();
+# Waitng for 'call p1()' to get blocked on MDL lock on f1...
+# Let 'alter function f1 ...' go through...
+commit;
+# --> connection con1
+# Reaping 'alter function f1 ...'
+# --> connection con2
+# Reaping 'call p1()'...
+# --> connection default
+drop function f1;
+drop function f2;
+drop procedure p1;
+#
+# 10) A select from information_schema.routines now
+# flushes the stored routines caches. Test that this
+# does not remove from the cache a stored routine
+# that is already prelocked.
+#
+create function f1() returns int return get_lock("30977", 100000);
+create function f2() returns int return 2;
+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|
+# --> connection con1
+select get_lock("30977", 0);
+get_lock("30977", 0)
+1
+# --> connection default
+# Sending 'select f3()'...
+select f3();
+# --> connection con1
+# Waitng for 'select f3()' to get blocked on the user level lock...
+# Do something to change the cache version.
+create function f4() returns int return 4;
+drop function f4;
+select release_lock("30977");
+release_lock("30977")
+1
+# --> connection default
+# Reaping 'select f3()'...
+# Routine 'f2()' should exist and get executed successfully.
+f3()
+f1
+select @var;
+@var
+2
+drop function f1;
+drop function f2;
+drop function f3;
+# 11) Check the situation when the connection is flushing the
+# SP cache which contains a procedure that is being executed.
+#
+# Function f1() calls p1(). Procedure p1() has a DROP
+# VIEW statement, which, we know, invalidates the routines cache.
+# During cache flush p1() must not be flushed since it's in
+# use.
+#
+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|
+set @exec_count=0;
+call p1();
+ERROR HY000: Recursive limit 0 (as set by the max_sp_recursion_depth variable) was exceeded for routine p1
+select @exec_count;
+@exec_count
+0
+set @@session.max_sp_recursion_depth=5;
+set @exec_count=0;
+call p1();
+ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
+select @exec_count;
+@exec_count
+0
+drop procedure p1;
+drop function f1;
+set @@session.max_sp_recursion_depth=default;
+# --> connection con1
+# --> connection con2
+# --> connection default
+#
+# End of 5.5 tests
+#