mirror of
https://github.com/MariaDB/server.git
synced 2025-01-24 07:44:22 +01:00
0228c98936
This change is supposed to reduce number of ER_LOCK_DEADLOCK errors which occur when multi-statement transaction encounters conflicting metadata lock in cases when waiting is possible. The idea is not to fail ER_LOCK_DEADLOCK error immediately when we encounter conflicting metadata lock. Instead we release all metadata locks acquired by current statement and start to wait until conflicting lock go away. To avoid deadlocks we use simple empiric which aborts waiting with ER_LOCK_DEADLOCK error if it turns out that somebody is waiting for metadata locks owned by this transaction. This patch also fixes bug #46273 "MySQL 5.4.4 new MDL: Bug#989 is not fully fixed in case of ALTER". The bug was that concurrent execution of UPDATE or MULTI-UPDATE statement as a part of multi-statement transaction that already has used table being updated and ALTER TABLE statement might have resulted of loss of isolation between this transaction and ALTER TABLE statement, which manifested itself as changes performed by ALTER TABLE becoming visible in transaction and wrong binary log order as a consequence. This problem occurred when UPDATE or MULTI-UPDATE's wait in mysql_lock_tables() call was aborted due to metadata lock upgrade performed by concurrent ALTER TABLE. After such abort all metadata locks held by transaction were released but transaction silently continued to be executed as if nothing has happened. We solve this problem by changing our code not to release all locks in such case. Instead we release only locks which were acquired by current statement and then try to reacquire them by restarting open/lock tables process. We piggyback on simple deadlock detector implementation since this change has to be done anyway for it. mysql-test/include/handler.inc: After introduction of basic deadlock detector for metadata locks it became necessary to change parts of test for HANDLER statements which covered some of scenarios in which ER_LOCK_DEADLOCK error was detected in absence of real deadlock (with new deadlock detector this no longer happens). Also adjusted test to the fact that HANDLER READ for the table no longer will be blocked by ALTER TABLE for the same table which awaits for metadata lock upgrade (this is due to removal of mysql_lock_abort() from wait_while_table_is_used()). mysql-test/r/handler_innodb.result: After introduction of basic deadlock detector for metadata locks it became necessary to change parts of test for HANDLER statements which covered some of scenarios in which ER_LOCK_DEADLOCK error was detected in absence of real deadlock (with new deadlock detector this no longer happens). Also adjusted test to the fact that HANDLER READ for the table no longer will be blocked by ALTER TABLE for the same table which awaits for metadata lock upgrade (this is due to removal of mysql_lock_abort() from wait_while_table_is_used()). mysql-test/r/handler_myisam.result: After introduction of basic deadlock detector for metadata locks it became necessary to change parts of test for HANDLER statements which covered some of scenarios in which ER_LOCK_DEADLOCK error was detected in absence of real deadlock (with new deadlock detector this no longer happens). Also adjusted test to the fact that HANDLER READ for the table no longer will be blocked by ALTER TABLE for the same table which awaits for metadata lock upgrade (this is due to removal of mysql_lock_abort() from wait_while_table_is_used()). mysql-test/r/mdl_sync.result: Added test coverage for basic deadlock detection in metadata locking subsystem and for bug #46273 "MySQL 5.4.4 new MDL: Bug#989 is not fully fixed in case of ALTER". mysql-test/r/sp-lock.result: Adjusted test coverage for metadata locking for stored routines since after introduction of basic deadlock detector for metadata locks number of scenarios in which ER_LOCK_DEADLOCK error in absence of deadlock has decreased. mysql-test/t/mdl_sync.test: Added test coverage for basic deadlock detection in metadata locking subsystem and for bug #46273 "MySQL 5.4.4 new MDL: Bug#989 is not fully fixed in case of ALTER". mysql-test/t/sp-lock.test: Adjusted test coverage for metadata locking for stored routines since after introduction of basic deadlock detector for metadata locks number of scenarios in which ER_LOCK_DEADLOCK error in absence of deadlock has decreased. sql/log_event_old.cc: close_tables_for_reopen() now takes one more argument which specifies at which point it should stop releasing metadata locks acquired by this connection. sql/mdl.cc: Changed metadata locking subsystem to support basic deadlock detection with a help of the following simple empiric -- we assume that there is a deadlock if there is a connection which has to wait for a metadata lock which is currently acquired by some connection which is itself waiting to be able to acquire some shared metadata lock. To implement this change: - Added MDL_context::can_wait_lead_to_deadlock()/_impl() methods which allow to find out if there is someone waiting for metadata lock which is held by the connection and therefore deadlocks are possible if this connection is going to wait for some metadata lock. To do this added version of MDL_ticket::has_pending_conflicting_lock() method which assumes that its caller already owns LOCK_mdl mutex. - Changed MDL_context::wait_for_locks() to use one of the above methods to check if somebody is waiting for metadata lock owned by this context (and therefore deadlock is possible) and emit ER_LOCK_DEADLOCK error in this case. Also now we mark context of connections waiting inside of this method by setting MDL_context::m_is_waiting_in_mdl member. Thanks to this such connection could be waken up if some other connection starts waiting for one of its metadata locks and so a deadlock can occur. - Adjusted notify_shared_lock() to wake up connections which wait inside MDL_context::wait_for_locks() while holding shared metadata lock. - Changed MDL_ticket::upgrade_shared_lock_to_exclusive() to add temporary ticket for exclusive lock to MDL_lock::waiting queue, so request for metadata lock upgrade can be properly detected by our empiric. Also now this method invokes a callback which forces transactions holding shared metadata lock on the table to call MDL_context:: can_wait_lead_to_deadlock() method even if they don't need any new metadata locks. Thanks to this such transactions can detect deadlocks/ livelocks between MDL and table-level locks. Also reduced timeouts between calls to notify_shared_lock() in MDL_ticket::upgrade_shared_lock_to_exclusive() and MDL_context::acquire_exclusive_locks(). This was necessary to get rid of call to mysql_lock_abort() in wait_while_table_is_used(). (Now we instead rely on notify_shared_lock() timely calling mysql_lock_abort_for_thread() for the table on which lock is being upgraded/acquired). sql/mdl.h: - Added a version of MDL_ticket::has_pending_conflicting_lock() method to be used in situations when caller already has acquired LOCK_mdl mutex. - Added MDL_context::can_wait_lead_to_deadlock()/_impl() methods which allow to find out if there is someone waiting for metadata lock which is held by this connection and thus deadlocks are possible if this connections will start waiting for some metadata lock. - Added MDL_context::m_is_waiting_in_mdl member to mark connections waiting in MDL_context::wait_for_locks() method of metadata locking subsystem. Added getter method for this private member to make it accessible in notify_shared_lock() auxiliary so we can wake-up such connections if they hold shared metadata locks. - Finally, added mysql_abort_transactions_with_shared_lock() callback to be able force transactions which don't need any new metadata locks still call MDL_context::can_wait_lead_to_deadlock() and detect some of deadlocks between metadata locks and table-level locks. sql/mysql_priv.h: close_tables_for_reopen() now takes one more argument which specifies at which point it should stop releasing metadata locks acquired by this connection. sql/sql_base.cc: Changed approach to metadata locking for multi-statement transactions. We no longer fail ER_LOCK_DEADLOCK error immediately when we encounter conflicting metadata lock. Instead we release all metadata locks acquired by current statement and start to wait until conflicting locks to go away by calling MDL_context::wait_for_locks() method. To avoid deadlocks the latter implements simple empiric which aborts waiting with ER_LOCK_DEADLOCK error if it turns out that somebody is waiting for metadata locks owned by this transaction. To implement the change described above: - Introduced Open_table_context::m_start_of_statement_svp member to store state of metadata locks at the start of the statement. - Changed Open_table_context::request_backoff_action() not to fail with ER_LOCK_DEADLOCK immediately if back-off is requested due to conflicting metadata lock. - Added new argument for close_tables_for_reopen() procedure which allows to specify subset of metadata locks to be released. - Changed open_tables() not to release all metadata locks acquired by current transaction when metadata lock conflict is discovered. Instead we release only locks acquired by current statement. - Changed open_ltable() and open_and_lock_tables_derived() not to emit ER_LOCK_DEADLOCK error when mysql_lock_tables() is aborted in multi-statement transaction when somebody tries to acquire exclusive metadata lock on the table. Instead we release metadata locks acquired by current statement and try to wait until they can be re-acquired. - Adjusted tdc_wait_for_old_versions() to check if there is someone waiting for one of metadata locks held by this connection and run deadlock detection in order to avoid deadlocks in some situations. - Added mysql_abort_transactions_with_shared_lock() callback which allows to force transactions holding shared metadata lock on the table to call MDL_context::can_wait_lead_to_deadlock() even if they don't need any new metadata locks so they can detect potential deadlocks between metadata locking subsystem and table-level locks. - Adjusted wait_while_table_is_used() not to set TABLE::version to 0 as it is now done only when necessary by the above-mentioned callback. Also removed unnecessary call to mysql_lock_abort(). Instead we rely on code performing metadata lock upgrade aborting waits on the table-level lock for this table by calling mysql_lock_abort_for_thread() (invoked by mysql_notify_thread_having_shared_lock()). In future this should allow to reduce number of scenarios in which we produce ER_LOCK_DEADLOCK error even though no real deadlock exists. sql/sql_class.h: Introduced Open_table_context::m_start_of_statement_svp member to store state of metadata locks at the start of the statement. Replaced Open_table_context::m_can_deadlock member with m_has_locks member to reflect the fact that we no longer unconditionally emit ER_LOCK_DEADLOCK error for transaction having some metadata locks when conflicting metadata lock is discovered. sql/sql_insert.cc: close_tables_for_reopen() now takes one more argument which specifies at which point it should stop releasing metadata locks acquired by this connection. sql/sql_plist.h: Made I_P_List_iterator<T, B> usable with const lists. sql/sql_show.cc: close_tables_for_reopen() now takes one more argument which specifies at which point it should stop releasing metadata locks acquired by this connection. sql/sql_update.cc: Changed UPDATE and MULTI-UPDATE code not to release all metadata locks when calls to mysql_lock_tables() are aborted. Instead we release only locks which are acquired by this statement and then try to reacquire them by calling open_tables(). This solves bug #46273 "MySQL 5.4.4 new MDL: Bug#989 is not fully fixed in case of ALTER".
1365 lines
35 KiB
PHP
1365 lines
35 KiB
PHP
# include/handler.inc
|
|
#
|
|
# The variables
|
|
# $engine_type -- storage engine to be tested
|
|
# $other_engine_type -- storage engine <> $engine_type
|
|
# $other_handler_engine_type -- storage engine <> $engine_type, if possible
|
|
# 1. $other_handler_engine_type must support handler
|
|
# 2. $other_handler_engine_type must point to an all
|
|
# time available storage engine
|
|
# 2006-08 MySQL 5.1 MyISAM and MEMORY only
|
|
# have to be set before sourcing this script.
|
|
-- source include/not_embedded.inc
|
|
#
|
|
# test of HANDLER ...
|
|
#
|
|
# Last update:
|
|
# 2006-07-31 ML test refactored (MySQL 5.1)
|
|
# code of t/handler.test and t/innodb_handler.test united
|
|
# main testing code put into include/handler.inc
|
|
#
|
|
|
|
eval SET SESSION STORAGE_ENGINE = $engine_type;
|
|
|
|
--disable_warnings
|
|
drop table if exists t1,t3,t4,t5;
|
|
--enable_warnings
|
|
|
|
create table t1 (a int, b char(10), key a(a), key b(a,b));
|
|
insert into t1 values
|
|
(17,"ddd"),(18,"eee"),(19,"fff"),(19,"yyy"),
|
|
(14,"aaa"),(15,"bbb"),(16,"ccc"),(16,"xxx"),
|
|
(20,"ggg"),(21,"hhh"),(22,"iii");
|
|
handler t1 open as t2;
|
|
-- error 1064
|
|
handler t2 read a=(SELECT 1);
|
|
handler t2 read a first;
|
|
handler t2 read a next;
|
|
handler t2 read a next;
|
|
handler t2 read a prev;
|
|
handler t2 read a last;
|
|
handler t2 read a prev;
|
|
handler t2 read a prev;
|
|
|
|
handler t2 read a first;
|
|
handler t2 read a prev;
|
|
|
|
handler t2 read a last;
|
|
handler t2 read a prev;
|
|
handler t2 read a next;
|
|
handler t2 read a next;
|
|
|
|
handler t2 read a=(15);
|
|
handler t2 read a=(16);
|
|
|
|
--error 1070
|
|
handler t2 read a=(19,"fff");
|
|
|
|
handler t2 read b=(19,"fff");
|
|
handler t2 read b=(19,"yyy");
|
|
handler t2 read b=(19);
|
|
|
|
--error 1109
|
|
handler t1 read a last;
|
|
|
|
handler t2 read a=(11);
|
|
handler t2 read a>=(11);
|
|
|
|
handler t2 read a=(18);
|
|
handler t2 read a>=(18);
|
|
handler t2 read a>(18);
|
|
handler t2 read a<=(18);
|
|
handler t2 read a<(18);
|
|
|
|
handler t2 read a first limit 5;
|
|
handler t2 read a next limit 3;
|
|
handler t2 read a prev limit 10;
|
|
|
|
handler t2 read a>=(16) limit 4;
|
|
handler t2 read a>=(16) limit 2,2;
|
|
handler t2 read a last limit 3;
|
|
|
|
handler t2 read a=(19);
|
|
handler t2 read a=(19) where b="yyy";
|
|
|
|
handler t2 read first;
|
|
handler t2 read next;
|
|
handler t2 read next;
|
|
--error 1064
|
|
handler t2 read last;
|
|
handler t2 close;
|
|
|
|
handler t1 open;
|
|
handler t1 read a next; # this used to crash as a bug#5373
|
|
handler t1 read a next;
|
|
handler t1 close;
|
|
|
|
handler t1 open;
|
|
handler t1 read a prev; # this used to crash as a bug#5373
|
|
handler t1 read a prev;
|
|
handler t1 close;
|
|
|
|
handler t1 open as t2;
|
|
handler t2 read first;
|
|
eval alter table t1 engine = $engine_type;
|
|
--error 1109
|
|
handler t2 read first;
|
|
|
|
#
|
|
# DROP TABLE / ALTER TABLE
|
|
#
|
|
handler t1 open as t2;
|
|
drop table t1;
|
|
create table t1 (a int);
|
|
insert into t1 values (17);
|
|
--error 1109
|
|
handler t2 read first;
|
|
handler t1 open as t2;
|
|
eval alter table t1 engine=$other_engine_type;
|
|
--error 1109
|
|
handler t2 read first;
|
|
drop table t1;
|
|
|
|
#
|
|
# Test case for the bug #787
|
|
#
|
|
create table t1 (a int);
|
|
insert into t1 values (1),(2),(3),(4),(5),(6);
|
|
delete from t1 limit 2;
|
|
handler t1 open;
|
|
handler t1 read first;
|
|
handler t1 read first limit 1,1;
|
|
handler t1 read first limit 2,2;
|
|
delete from t1 limit 3;
|
|
handler t1 read first;
|
|
drop table t1;
|
|
|
|
#
|
|
# Test for #751
|
|
#
|
|
create table t1(a int, index(a));
|
|
insert into t1 values (1), (2), (3);
|
|
handler t1 open;
|
|
--error 1054
|
|
handler t1 read a=(W);
|
|
--error 1210
|
|
handler t1 read a=(a);
|
|
drop table t1;
|
|
#
|
|
# BUG#2304
|
|
#
|
|
create table t1 (a char(5));
|
|
insert into t1 values ("Ok");
|
|
handler t1 open as t;
|
|
handler t read first;
|
|
use mysql;
|
|
handler t read first;
|
|
handler t close;
|
|
handler test.t1 open as t;
|
|
handler t read first;
|
|
handler t close;
|
|
use test;
|
|
drop table t1;
|
|
|
|
#
|
|
# BUG#3649
|
|
#
|
|
create table t1 ( a int, b int, INDEX a (a) );
|
|
insert into t1 values (1,2), (2,1);
|
|
handler t1 open;
|
|
handler t1 read a=(1) where b=2;
|
|
handler t1 read a=(1) where b=3;
|
|
handler t1 read a=(1) where b=1;
|
|
handler t1 close;
|
|
drop table t1;
|
|
|
|
#
|
|
# Check if two database names beginning the same are seen as different.
|
|
#
|
|
# This database begins like the usual 'test' database.
|
|
#
|
|
--disable_warnings
|
|
drop database if exists test_test;
|
|
--enable_warnings
|
|
create database test_test;
|
|
use test_test;
|
|
create table t1(table_id char(20) primary key);
|
|
insert into t1 values ('test_test.t1');
|
|
insert into t1 values ('');
|
|
handler t1 open;
|
|
handler t1 read first limit 9;
|
|
create table t2(table_id char(20) primary key);
|
|
insert into t2 values ('test_test.t2');
|
|
insert into t2 values ('');
|
|
handler t2 open;
|
|
handler t2 read first limit 9;
|
|
#
|
|
# This is the usual 'test' database.
|
|
#
|
|
use test;
|
|
--disable_warnings
|
|
drop table if exists t1;
|
|
--enable_warnings
|
|
create table t1(table_id char(20) primary key);
|
|
insert into t1 values ('test.t1');
|
|
insert into t1 values ('');
|
|
--error 1066
|
|
handler t1 open;
|
|
#
|
|
# Check accesibility of all the tables.
|
|
#
|
|
use test;
|
|
--error 1064
|
|
handler test.t1 read first limit 9;
|
|
--error 1064
|
|
handler test_test.t1 read first limit 9;
|
|
handler t1 read first limit 9;
|
|
--error 1064
|
|
handler test_test.t2 read first limit 9;
|
|
handler t2 read first limit 9;
|
|
|
|
#
|
|
# Cleanup.
|
|
#
|
|
|
|
--error 1064
|
|
handler test_test.t1 close;
|
|
handler t1 close;
|
|
drop table test_test.t1;
|
|
--error 1064
|
|
handler test_test.t2 close;
|
|
handler t2 close;
|
|
drop table test_test.t2;
|
|
drop database test_test;
|
|
|
|
#
|
|
use test;
|
|
--error 1064
|
|
handler test.t1 close;
|
|
--error 1109
|
|
handler t1 close;
|
|
drop table test.t1;
|
|
|
|
#
|
|
# BUG#4335
|
|
#
|
|
--disable_warnings
|
|
drop database if exists test_test;
|
|
drop table if exists t1;
|
|
drop table if exists t2;
|
|
drop table if exists t3;
|
|
--enable_warnings
|
|
create database test_test;
|
|
use test_test;
|
|
create table t1 (c1 char(20));
|
|
insert into t1 values ('test_test.t1');
|
|
create table t3 (c1 char(20));
|
|
insert into t3 values ('test_test.t3');
|
|
handler t1 open;
|
|
handler t1 read first limit 9;
|
|
handler t1 open h1;
|
|
handler h1 read first limit 9;
|
|
use test;
|
|
create table t1 (c1 char(20));
|
|
create table t2 (c1 char(20));
|
|
create table t3 (c1 char(20));
|
|
insert into t1 values ('t1');
|
|
insert into t2 values ('t2');
|
|
insert into t3 values ('t3');
|
|
--error 1066
|
|
handler t1 open;
|
|
--error 1066
|
|
handler t2 open t1;
|
|
--error 1066
|
|
handler t3 open t1;
|
|
handler t1 read first limit 9;
|
|
--error 1064
|
|
handler test.t1 close;
|
|
--error 1066
|
|
handler test.t1 open h1;
|
|
--error 1066
|
|
handler test_test.t1 open h1;
|
|
handler test_test.t3 open h3;
|
|
handler test.t1 open h2;
|
|
handler t1 read first limit 9;
|
|
handler h1 read first limit 9;
|
|
handler h2 read first limit 9;
|
|
handler h3 read first limit 9;
|
|
handler h2 read first limit 9;
|
|
--error 1064
|
|
handler test.h1 close;
|
|
handler t1 close;
|
|
handler h1 close;
|
|
handler h2 close;
|
|
--error 1109
|
|
handler t1 read first limit 9;
|
|
--error 1109
|
|
handler h1 read first limit 9;
|
|
--error 1109
|
|
handler h2 read first limit 9;
|
|
handler h3 read first limit 9;
|
|
handler h3 read first limit 9;
|
|
use test_test;
|
|
handler h3 read first limit 9;
|
|
--error 1064
|
|
handler test.h3 read first limit 9;
|
|
handler h3 close;
|
|
use test;
|
|
drop table t3;
|
|
drop table t2;
|
|
drop table t1;
|
|
drop database test_test;
|
|
|
|
#
|
|
# Test if fix for BUG#4286 correctly closes handler tables.
|
|
#
|
|
create table t1 (c1 char(20));
|
|
insert into t1 values ("t1");
|
|
handler t1 open as h1;
|
|
handler h1 read first limit 9;
|
|
create table t2 (c1 char(20));
|
|
insert into t2 values ("t2");
|
|
handler t2 open as h2;
|
|
handler h2 read first limit 9;
|
|
create table t3 (c1 char(20));
|
|
insert into t3 values ("t3");
|
|
handler t3 open as h3;
|
|
handler h3 read first limit 9;
|
|
create table t4 (c1 char(20));
|
|
insert into t4 values ("t4");
|
|
handler t4 open as h4;
|
|
handler h4 read first limit 9;
|
|
create table t5 (c1 char(20));
|
|
insert into t5 values ("t5");
|
|
handler t5 open as h5;
|
|
handler h5 read first limit 9;
|
|
# close first
|
|
eval alter table t1 engine=$other_handler_engine_type;
|
|
--error 1109
|
|
handler h1 read first limit 9;
|
|
handler h2 read first limit 9;
|
|
handler h3 read first limit 9;
|
|
handler h4 read first limit 9;
|
|
handler h5 read first limit 9;
|
|
# close last
|
|
eval alter table t5 engine=$other_handler_engine_type;
|
|
--error 1109
|
|
handler h1 read first limit 9;
|
|
handler h2 read first limit 9;
|
|
handler h3 read first limit 9;
|
|
handler h4 read first limit 9;
|
|
--error 1109
|
|
handler h5 read first limit 9;
|
|
# close middle
|
|
eval alter table t3 engine=$other_handler_engine_type;
|
|
--error 1109
|
|
handler h1 read first limit 9;
|
|
handler h2 read first limit 9;
|
|
--error 1109
|
|
handler h3 read first limit 9;
|
|
handler h4 read first limit 9;
|
|
--error 1109
|
|
handler h5 read first limit 9;
|
|
handler h2 close;
|
|
handler h4 close;
|
|
# close all depending handler tables
|
|
handler t1 open as h1_1;
|
|
handler t1 open as h1_2;
|
|
handler t1 open as h1_3;
|
|
handler h1_1 read first limit 9;
|
|
handler h1_2 read first limit 9;
|
|
handler h1_3 read first limit 9;
|
|
eval alter table t1 engine=$engine_type;
|
|
--error 1109
|
|
handler h1_1 read first limit 9;
|
|
--error 1109
|
|
handler h1_2 read first limit 9;
|
|
--error 1109
|
|
handler h1_3 read first limit 9;
|
|
drop table t1;
|
|
drop table t2;
|
|
drop table t3;
|
|
drop table t4;
|
|
drop table t5;
|
|
|
|
#
|
|
# Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash
|
|
#
|
|
create table t1 (c1 int);
|
|
insert into t1 values (1);
|
|
# client 1
|
|
handler t1 open;
|
|
handler t1 read first;
|
|
# client 2
|
|
connect (con2,localhost,root,,);
|
|
connection con2;
|
|
--exec echo send the below to another connection, do not wait for the result
|
|
send optimize table t1;
|
|
--sleep 1
|
|
# client 1
|
|
--exec echo proceed with the normal connection
|
|
connection default;
|
|
handler t1 read next;
|
|
handler t1 close;
|
|
# client 2
|
|
--exec echo read the result from the other connection
|
|
connection con2;
|
|
reap;
|
|
# client 1
|
|
--exec echo proceed with the normal connection
|
|
connection default;
|
|
drop table t1;
|
|
|
|
CREATE TABLE t1 ( no1 smallint(5) NOT NULL default '0', no2 int(10) NOT NULL default '0', PRIMARY KEY (no1,no2));
|
|
INSERT INTO t1 VALUES (1,274),(1,275),(2,6),(2,8),(4,1),(4,2);
|
|
HANDLER t1 OPEN;
|
|
HANDLER t1 READ `primary` = (1, 1000);
|
|
HANDLER t1 READ `primary` PREV;
|
|
DROP TABLE t1;
|
|
|
|
# End of 4.1 tests
|
|
|
|
#
|
|
# Addendum to Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash
|
|
# Show that DROP TABLE can no longer deadlock against
|
|
# FLUSH TABLES WITH READ LOCK. This is a 5.0 issue.
|
|
#
|
|
create table t1 (c1 int);
|
|
insert into t1 values (14397);
|
|
flush tables with read lock;
|
|
# The thread with the global read lock cannot drop the table itself:
|
|
--error 1223
|
|
drop table t1;
|
|
#
|
|
# client 2
|
|
# We need a second connection to try the drop.
|
|
# The drop waits for the global read lock to go away.
|
|
# Without the addendum fix it locked LOCK_open before entering the wait loop.
|
|
connection con2;
|
|
--exec echo send the below to another connection, do not wait for the result
|
|
send drop table t1;
|
|
--sleep 1
|
|
#
|
|
# client 1
|
|
# Now we need something that wants LOCK_open. A simple table access which
|
|
# opens the table does the trick.
|
|
--exec echo proceed with the normal connection
|
|
connection default;
|
|
# This would hang on LOCK_open without the 5.0 addendum fix.
|
|
select * from t1;
|
|
# Release the read lock. This should make the DROP go through.
|
|
unlock tables;
|
|
#
|
|
# client 2
|
|
# Read the result of the drop command.
|
|
connection con2;
|
|
--exec echo read the result from the other connection
|
|
reap;
|
|
#
|
|
# client 1
|
|
# Now back to normal operation. The table should not exist any more.
|
|
--exec echo proceed with the normal connection
|
|
connection default;
|
|
--error 1146
|
|
select * from t1;
|
|
# Just to be sure and not confuse the next test case writer.
|
|
drop table if exists t1;
|
|
|
|
#
|
|
# Bug#25856 - HANDLER table OPEN in one connection lock DROP TABLE in another one
|
|
#
|
|
--disable_warnings
|
|
drop table if exists t1;
|
|
--enable_warnings
|
|
eval create table t1 (a int) ENGINE=$other_engine_type;
|
|
--echo --> client 2
|
|
connection con2;
|
|
--error 1031
|
|
handler t1 open;
|
|
--echo --> client 1
|
|
connection default;
|
|
drop table t1;
|
|
disconnect con2;
|
|
|
|
#
|
|
# Bug#30632 HANDLER read failure causes hang
|
|
#
|
|
--disable_warnings
|
|
drop table if exists t1;
|
|
--enable_warnings
|
|
create table t1 (a int);
|
|
handler t1 open as t1_alias;
|
|
--error 1176
|
|
handler t1_alias read a next;
|
|
--error 1054
|
|
handler t1_alias READ a next where inexistent > 0;
|
|
--error 1176
|
|
handler t1_alias read a next;
|
|
--error 1054
|
|
handler t1_alias READ a next where inexistent > 0;
|
|
handler t1_alias close;
|
|
drop table t1;
|
|
|
|
#
|
|
# Bug#21587 FLUSH TABLES causes server crash when used with HANDLER statements
|
|
#
|
|
|
|
--disable_warnings
|
|
drop table if exists t1,t2;
|
|
--enable_warnings
|
|
create table t1 (c1 int);
|
|
create table t2 (c1 int);
|
|
insert into t1 values (1);
|
|
insert into t2 values (2);
|
|
--echo connection: default
|
|
handler t1 open;
|
|
handler t1 read first;
|
|
connect (flush,localhost,root,,);
|
|
connection flush;
|
|
--echo connection: flush
|
|
--send flush tables;
|
|
connect (waiter,localhost,root,,);
|
|
connection waiter;
|
|
--echo connection: waiter
|
|
let $wait_condition=
|
|
select count(*) = 1 from information_schema.processlist
|
|
where state = "Flushing tables";
|
|
--source include/wait_condition.inc
|
|
connection default;
|
|
--echo connection: default
|
|
handler t2 open;
|
|
handler t2 read first;
|
|
handler t1 read next;
|
|
handler t1 close;
|
|
handler t2 close;
|
|
connection flush;
|
|
reap;
|
|
connection default;
|
|
drop table t1,t2;
|
|
disconnect flush;
|
|
|
|
#
|
|
# Bug#31409 RENAME TABLE causes server crash or deadlock when used with HANDLER statements
|
|
#
|
|
|
|
--disable_warnings
|
|
drop table if exists t1,t2;
|
|
--enable_warnings
|
|
create table t1 (c1 int);
|
|
--echo connection: default
|
|
handler t1 open;
|
|
handler t1 read first;
|
|
connect (flush,localhost,root,,);
|
|
connection flush;
|
|
--echo connection: flush
|
|
--send rename table t1 to t2;
|
|
connection waiter;
|
|
--echo connection: waiter
|
|
let $wait_condition=
|
|
select count(*) = 1 from information_schema.processlist
|
|
where state = "Waiting for table" and info = "rename table t1 to t2";
|
|
--source include/wait_condition.inc
|
|
connection default;
|
|
--echo connection: default
|
|
--echo #
|
|
--echo # RENAME placed two pending locks and waits.
|
|
--echo # When HANDLER t2 OPEN does open_tables(), it calls
|
|
--echo # mysql_ha_flush(), which in turn closes the open HANDLER for t1.
|
|
--echo # RENAME TABLE gets unblocked. If it gets scheduled quickly
|
|
--echo # and manages to complete before open_tables()
|
|
--echo # of HANDLER t2 OPEN, open_tables() and therefore the whole
|
|
--echo # HANDLER t2 OPEN succeeds. Otherwise open_tables()
|
|
--echo # notices a pending or active exclusive metadata lock on t2
|
|
--echo # and the whole HANDLER t2 OPEN fails with ER_LOCK_DEADLOCK
|
|
--echo # error.
|
|
--echo #
|
|
--error 0, ER_LOCK_DEADLOCK
|
|
handler t2 open;
|
|
--error 0, ER_UNKNOWN_TABLE
|
|
handler t2 close;
|
|
--echo connection: flush
|
|
connection flush;
|
|
reap;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 close;
|
|
connection default;
|
|
drop table t2;
|
|
connection flush;
|
|
disconnect flush;
|
|
--source include/wait_until_disconnected.inc
|
|
connection waiter;
|
|
disconnect waiter;
|
|
--source include/wait_until_disconnected.inc
|
|
connection default;
|
|
|
|
#
|
|
# Bug#30882 Dropping a temporary table inside a stored function may cause a server crash
|
|
#
|
|
# Test HANDLER statements in conjunction with temporary tables. While the temporary table
|
|
# is open by a HANDLER, no other statement can access it.
|
|
#
|
|
|
|
--disable_warnings
|
|
drop table if exists t1;
|
|
--enable_warnings
|
|
create temporary table t1 (a int, b char(1), key a(a), key b(a,b));
|
|
insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"),
|
|
(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j");
|
|
select a,b from t1;
|
|
handler t1 open as a1;
|
|
handler a1 read a first;
|
|
handler a1 read a next;
|
|
handler a1 read a next;
|
|
--error ER_CANT_REOPEN_TABLE
|
|
select a,b from t1;
|
|
handler a1 read a prev;
|
|
handler a1 read a prev;
|
|
handler a1 read a=(6) where b="g";
|
|
handler a1 close;
|
|
select a,b from t1;
|
|
handler t1 open as a2;
|
|
handler a2 read a first;
|
|
handler a2 read a last;
|
|
handler a2 read a prev;
|
|
handler a2 close;
|
|
drop table t1;
|
|
|
|
#
|
|
# Bug#31397 Inconsistent drop table behavior of handler tables.
|
|
#
|
|
|
|
--disable_warnings
|
|
drop table if exists t1,t2;
|
|
--enable_warnings
|
|
create table t1 (a int);
|
|
handler t1 open as t1_alias;
|
|
drop table t1;
|
|
create table t1 (a int);
|
|
handler t1 open as t1_alias;
|
|
flush tables;
|
|
drop table t1;
|
|
create table t1 (a int);
|
|
handler t1 open as t1_alias;
|
|
handler t1_alias close;
|
|
drop table t1;
|
|
create table t1 (a int);
|
|
handler t1 open as t1_alias;
|
|
handler t1_alias read first;
|
|
drop table t1;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1_alias read next;
|
|
|
|
# Test that temporary tables associated with handlers are properly dropped.
|
|
|
|
create table t1 (a int);
|
|
create temporary table t2 (a int, key(a));
|
|
handler t1 open as a1;
|
|
handler t2 open as a2;
|
|
handler a2 read a first;
|
|
drop table t1, t2;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler a2 read a next;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler a1 close;
|
|
|
|
# Alter table drop handlers
|
|
|
|
create table t1 (a int, key(a));
|
|
create table t2 like t1;
|
|
handler t1 open as a1;
|
|
handler t2 open as a2;
|
|
handler a1 read a first;
|
|
handler a2 read a first;
|
|
alter table t1 add b int;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler a1 close;
|
|
handler a2 close;
|
|
drop table t1, t2;
|
|
|
|
# Rename table drop handlers
|
|
|
|
create table t1 (a int, key(a));
|
|
handler t1 open as a1;
|
|
handler a1 read a first;
|
|
rename table t1 to t2;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler a1 read a first;
|
|
drop table t2;
|
|
|
|
# Optimize table drop handlers
|
|
|
|
create table t1 (a int, key(a));
|
|
create table t2 like t1;
|
|
handler t1 open as a1;
|
|
handler t2 open as a2;
|
|
handler a1 read a first;
|
|
handler a2 read a first;
|
|
optimize table t1;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler a1 close;
|
|
handler a2 close;
|
|
drop table t1, t2;
|
|
|
|
# Flush tables causes handlers reopen
|
|
|
|
create table t1 (a int, b char(1), key a(a), key b(a,b));
|
|
insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"),
|
|
(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j");
|
|
handler t1 open;
|
|
handler t1 read a first;
|
|
handler t1 read a next;
|
|
flush tables;
|
|
handler t1 read a next;
|
|
handler t1 read a next;
|
|
flush tables with read lock;
|
|
handler t1 read a next;
|
|
unlock tables;
|
|
drop table t1;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read a next;
|
|
|
|
#
|
|
# Bug#41110: crash with handler command when used concurrently with alter table
|
|
# Bug#41112: crash in mysql_ha_close_table/get_lock_data with alter table
|
|
#
|
|
|
|
connect(con1,localhost,root,,);
|
|
connect(con2,localhost,root,,);
|
|
|
|
connection default;
|
|
--disable_warnings
|
|
drop table if exists t1;
|
|
--enable_warnings
|
|
create table t1 (a int, key a (a));
|
|
insert into t1 values (1);
|
|
handler t1 open;
|
|
connection con1;
|
|
send alter table t1 engine=memory;
|
|
connection con2;
|
|
let $wait_condition=
|
|
select count(*) = 1 from information_schema.processlist
|
|
where state = "Waiting for table" and info = "alter table t1 engine=memory";
|
|
--source include/wait_condition.inc
|
|
connection default;
|
|
handler t1 read a next;
|
|
handler t1 close;
|
|
connection con1;
|
|
--reap
|
|
drop table t1;
|
|
disconnect con1;
|
|
--source include/wait_until_disconnected.inc
|
|
connection con2;
|
|
disconnect con2;
|
|
--source include/wait_until_disconnected.inc
|
|
connection default;
|
|
|
|
#
|
|
# Bug#44151 using handler commands on information_schema tables crashes server
|
|
#
|
|
USE information_schema;
|
|
--error ER_WRONG_USAGE
|
|
HANDLER COLUMNS OPEN;
|
|
USE test;
|
|
|
|
--echo #
|
|
--echo # Add test coverage for HANDLER and LOCK TABLES, HANDLER and DDL.
|
|
--echo #
|
|
--disable_warnings
|
|
drop table if exists t1, t2, t3;
|
|
--enable_warnings
|
|
create table t1 (a int, key a (a));
|
|
insert into t1 (a) values (1), (2), (3), (4), (5);
|
|
create table t2 (a int, key a (a)) select * from t1;
|
|
create temporary table t3 (a int, key a (a)) select * from t2;
|
|
handler t1 open;
|
|
handler t2 open;
|
|
handler t3 open;
|
|
--echo #
|
|
--echo # LOCK TABLES implicitly closes all handlers.
|
|
--echo #
|
|
lock table t3 read;
|
|
--echo #
|
|
--echo # No HANDLER sql is available under lock tables anyway.
|
|
--echo #
|
|
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
|
handler t1 open;
|
|
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
|
handler t1 read next;
|
|
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
|
handler t2 close;
|
|
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
|
handler t3 open;
|
|
--echo # After UNLOCK TABLES no handlers are around, they were
|
|
--echo # implicitly closed.
|
|
unlock tables;
|
|
drop temporary table t3;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t2 close;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t3 read next;
|
|
--echo #
|
|
--echo # Other operations also implicitly close handler:
|
|
--echo #
|
|
--echo # TRUNCATE
|
|
--echo #
|
|
handler t1 open;
|
|
truncate table t1;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
handler t1 open;
|
|
--echo #
|
|
--echo # CREATE TRIGGER
|
|
--echo #
|
|
create trigger t1_ai after insert on t1 for each row set @a=1;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
--echo #
|
|
--echo # DROP TRIGGER
|
|
--echo #
|
|
handler t1 open;
|
|
drop trigger t1_ai;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
--echo #
|
|
--echo # ALTER TABLE
|
|
--echo #
|
|
handler t1 open;
|
|
alter table t1 add column b int;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
--echo #
|
|
--echo # ANALYZE TABLE
|
|
--echo #
|
|
handler t1 open;
|
|
analyze table t1;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
--echo #
|
|
--echo # OPTIMIZE TABLE
|
|
--echo #
|
|
handler t1 open;
|
|
optimize table t1;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
--echo #
|
|
--echo # REPAIR TABLE
|
|
--echo #
|
|
handler t1 open;
|
|
repair table t1;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
--echo #
|
|
--echo # DROP TABLE, naturally.
|
|
--echo #
|
|
handler t1 open;
|
|
drop table t1;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
create table t1 (a int, b int, key a (a)) select a from t2;
|
|
--echo #
|
|
--echo # RENAME TABLE, naturally
|
|
--echo #
|
|
handler t1 open;
|
|
rename table t1 to t3;
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t1 read next;
|
|
--echo #
|
|
--echo # CREATE TABLE (even with IF NOT EXISTS clause,
|
|
--echo # and the table exists).
|
|
--echo #
|
|
handler t2 open;
|
|
create table if not exists t2 (a int);
|
|
--error ER_UNKNOWN_TABLE
|
|
handler t2 read next;
|
|
rename table t3 to t1;
|
|
drop table t2;
|
|
--echo #
|
|
--echo # FLUSH TABLE doesn't close the table but loses the position
|
|
--echo #
|
|
handler t1 open;
|
|
handler t1 read a prev;
|
|
flush table t1;
|
|
handler t1 read a prev;
|
|
handler t1 close;
|
|
--echo #
|
|
--echo # FLUSH TABLES WITH READ LOCK behaves like FLUSH TABLE.
|
|
--echo #
|
|
handler t1 open;
|
|
handler t1 read a prev;
|
|
flush tables with read lock;
|
|
handler t1 read a prev;
|
|
handler t1 close;
|
|
unlock tables;
|
|
--echo #
|
|
--echo # Explore the effect of HANDLER locks on concurrent DDL
|
|
--echo #
|
|
handler t1 open;
|
|
--echo # Establishing auxiliary connections con1, con2, con3
|
|
connect(con1, localhost, root,,);
|
|
connect(con2, localhost, root,,);
|
|
connect(con3, localhost, root,,);
|
|
--echo # --> connection con1;
|
|
connection con1;
|
|
--echo # Sending:
|
|
--send drop table t1
|
|
--echo # We can't use connection 'default' as wait_condition will
|
|
--echo # autoclose handlers.
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Waitng for 'drop table t1' to get blocked...
|
|
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t1';
|
|
--source include/wait_condition.inc
|
|
--echo # --> connection default
|
|
connection default;
|
|
handler t1 read a prev;
|
|
handler t1 read a prev;
|
|
handler t1 close;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
--echo # Reaping 'drop table t1'...
|
|
--reap
|
|
--echo # --> connection default
|
|
connection default;
|
|
--echo #
|
|
--echo # Explore the effect of HANDLER locks in parallel with SELECT
|
|
--echo #
|
|
create table t1 (a int, key a (a));
|
|
insert into t1 (a) values (1), (2), (3), (4), (5);
|
|
begin;
|
|
select * from t1;
|
|
handler t1 open;
|
|
handler t1 read a prev;
|
|
handler t1 read a prev;
|
|
handler t1 close;
|
|
--echo # --> connection con1;
|
|
connection con1;
|
|
--echo # Sending:
|
|
--send drop table t1
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Waiting for 'drop table t1' to get blocked...
|
|
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t1';
|
|
--source include/wait_condition.inc
|
|
--echo # --> connection default
|
|
connection default;
|
|
--echo # We can still use the table, it's part of the transaction
|
|
select * from t1;
|
|
--echo # Such are the circumstances that t1 is a part of transaction,
|
|
--echo # thus we can reopen it in the handler
|
|
handler t1 open;
|
|
--echo # We can commit the transaction, it doesn't close the handler
|
|
--echo # and doesn't let DROP to proceed.
|
|
commit;
|
|
handler t1 read a prev;
|
|
handler t1 read a prev;
|
|
handler t1 read a prev;
|
|
handler t1 close;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
--echo # Now drop can proceed
|
|
--echo # Reaping 'drop table t1'...
|
|
--reap
|
|
--echo # --> connection default
|
|
connection default;
|
|
--echo #
|
|
--echo # Demonstrate that HANDLER locks and transaction locks
|
|
--echo # reside in the same context, and we don't back-off
|
|
--echo # when have transaction or handler locks.
|
|
--echo #
|
|
create table t1 (a int, key a (a));
|
|
insert into t1 (a) values (1), (2), (3), (4), (5);
|
|
create table t2 (a int, key a (a));
|
|
insert into t2 (a) values (1), (2), (3), (4), (5);
|
|
begin;
|
|
select * from t1;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
lock table t2 read;
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Sending:
|
|
send rename table t2 to t3, t1 to t2, t3 to t1;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
--echo # Waiting for 'rename table ...' to get blocked...
|
|
let $wait_condition=select count(*)=1 from information_schema.processlist
|
|
where state='Waiting for table' and info='rename table t2 to t3, t1 to t2, t3 to t1';
|
|
--source include/wait_condition.inc
|
|
--echo # --> connection default
|
|
connection default;
|
|
--error ER_LOCK_DEADLOCK
|
|
handler t2 open;
|
|
--error ER_LOCK_DEADLOCK
|
|
select * from t2;
|
|
handler t1 open;
|
|
commit;
|
|
handler t1 close;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
unlock tables;
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Reaping 'rename table ...'...
|
|
--reap
|
|
--echo # --> connection default
|
|
connection default;
|
|
handler t1 open;
|
|
handler t1 read a prev;
|
|
handler t1 close;
|
|
drop table t2;
|
|
--echo #
|
|
--echo # Originally there was a deadlock error in this test.
|
|
--echo # With implementation of deadlock detector
|
|
--echo # we no longer deadlock, but block and wait on a lock.
|
|
--echo # The HANDLER is auto-closed as soon as the connection
|
|
--echo # sees a pending conflicting lock against it.
|
|
--echo #
|
|
create table t2 (a int, key a (a));
|
|
handler t1 open;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
lock tables t2 read;
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Sending 'drop table t2'...
|
|
--send drop table t2
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
--echo # Waiting for 'drop table t2' to get blocked...
|
|
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t2';
|
|
--source include/wait_condition.inc
|
|
--echo # --> connection default
|
|
connection default;
|
|
--echo # Sending 'select * from t2'
|
|
send select * from t2;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
--echo # Waiting for 'select * from t2' to get blocked...
|
|
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='select * from t2';
|
|
unlock tables;
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Reaping 'drop table t2'...
|
|
--reap
|
|
--echo # --> connection default
|
|
connection default;
|
|
--echo # Reaping 'select * from t2'
|
|
--error ER_NO_SUCH_TABLE
|
|
reap;
|
|
handler t1 close;
|
|
|
|
--echo #
|
|
--echo # ROLLBACK TO SAVEPOINT releases transactional locks,
|
|
--echo # but has no effect on open HANDLERs
|
|
--echo #
|
|
create table t2 like t1;
|
|
create table t3 like t1;
|
|
begin;
|
|
--echo # Have something before the savepoint
|
|
select * from t3;
|
|
savepoint sv;
|
|
handler t1 open;
|
|
handler t1 read a first;
|
|
handler t1 read a next;
|
|
select * from t2;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
--echo # Sending:
|
|
--send drop table t1
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Sending:
|
|
--send drop table t2
|
|
--echo # --> connection default
|
|
connection default;
|
|
--echo # Let DROP TABLE statements sync in. We must use
|
|
--echo # a separate connection for that, because otherwise SELECT
|
|
--echo # will auto-close the HANDLERs, becaues there are pending
|
|
--echo # exclusive locks against them.
|
|
--echo # --> connection con3
|
|
connection con3;
|
|
--echo # Waiting for 'drop table t1' to get blocked...
|
|
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t1';
|
|
--source include/wait_condition.inc
|
|
--echo # Waiting for 'drop table t2' to get blocked...
|
|
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t2';
|
|
--source include/wait_condition.inc
|
|
--echo # Demonstrate that t2 lock was released and t2 was dropped
|
|
--echo # after ROLLBACK TO SAVEPOINT
|
|
--echo # --> connection default
|
|
connection default;
|
|
rollback to savepoint sv;
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Reaping 'drop table t2'...
|
|
--reap
|
|
--echo # Demonstrate that ROLLBACK TO SAVEPOINT didn't release the handler
|
|
--echo # lock.
|
|
--echo # --> connection default
|
|
connection default;
|
|
handler t1 read a next;
|
|
handler t1 read a next;
|
|
--echo # Demonstrate that the drop will go through as soon as we close the
|
|
--echo # HANDLER
|
|
handler t1 close;
|
|
--echo # connection con1
|
|
connection con1;
|
|
--echo # Reaping 'drop table t1'...
|
|
--reap
|
|
--echo # --> connection default
|
|
connection default;
|
|
commit;
|
|
drop table t3;
|
|
--echo #
|
|
--echo # A few special cases when using SAVEPOINT/ROLLBACK TO
|
|
--echo # SAVEPOINT and HANDLER.
|
|
--echo #
|
|
--echo # Show that rollback to the savepoint taken in the beginning
|
|
--echo # of the transaction doesn't release mdl lock on
|
|
--echo # the HANDLER that was opened later.
|
|
--echo #
|
|
create table t1 (a int, key a(a));
|
|
insert into t1 (a) values (1), (2), (3), (4), (5);
|
|
create table t2 like t1;
|
|
begin;
|
|
savepoint sv;
|
|
handler t1 open;
|
|
handler t1 read a first;
|
|
handler t1 read a next;
|
|
select * from t2;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
--echo # Sending:
|
|
--send drop table t1
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Sending:
|
|
--send drop table t2
|
|
--echo # --> connection default
|
|
connection default;
|
|
--echo # Let DROP TABLE statements sync in. We must use
|
|
--echo # a separate connection for that, because otherwise SELECT
|
|
--echo # will auto-close the HANDLERs, becaues there are pending
|
|
--echo # exclusive locks against them.
|
|
--echo # --> connection con3
|
|
connection con3;
|
|
--echo # Waiting for 'drop table t1' to get blocked...
|
|
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t1';
|
|
--source include/wait_condition.inc
|
|
--echo # Waiting for 'drop table t2' to get blocked...
|
|
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t2';
|
|
--source include/wait_condition.inc
|
|
--echo # Demonstrate that t2 lock was released and t2 was dropped
|
|
--echo # after ROLLBACK TO SAVEPOINT
|
|
--echo # --> connection default
|
|
connection default;
|
|
rollback to savepoint sv;
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Reaping 'drop table t2'...
|
|
--reap
|
|
--echo # Demonstrate that ROLLBACK TO SAVEPOINT didn't release the handler
|
|
--echo # lock.
|
|
--echo # --> connection default
|
|
connection default;
|
|
handler t1 read a next;
|
|
handler t1 read a next;
|
|
--echo # Demonstrate that the drop will go through as soon as we close the
|
|
--echo # HANDLER
|
|
handler t1 close;
|
|
--echo # connection con1
|
|
connection con1;
|
|
--echo # Reaping 'drop table t1'...
|
|
--reap
|
|
--echo # --> connection default
|
|
connection default;
|
|
commit;
|
|
--echo #
|
|
--echo # Show that rollback to the savepoint taken in the beginning
|
|
--echo # of the transaction works properly (no valgrind warnins, etc),
|
|
--echo # even though it's done after the HANDLER mdl lock that was there
|
|
--echo # at the beginning is released and added again.
|
|
--echo #
|
|
create table t1 (a int, key a(a));
|
|
insert into t1 (a) values (1), (2), (3), (4), (5);
|
|
create table t2 like t1;
|
|
create table t3 like t1;
|
|
insert into t3 (a) select a from t1;
|
|
begin;
|
|
handler t1 open;
|
|
savepoint sv;
|
|
handler t1 read a first;
|
|
select * from t2;
|
|
handler t1 close;
|
|
handler t3 open;
|
|
handler t3 read a first;
|
|
rollback to savepoint sv;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
drop table t1, t2;
|
|
--echo # Sending:
|
|
--send drop table t3
|
|
--echo # Let DROP TABLE statement sync in.
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Waiting for 'drop table t3' to get blocked...
|
|
let $wait_condition=select count(*)=1 from information_schema.processlist where state='Waiting for table' and info='drop table t3';
|
|
--source include/wait_condition.inc
|
|
--echo # Demonstrate that ROLLBACK TO SAVEPOINT didn't release the handler
|
|
--echo # lock.
|
|
--echo # --> connection default
|
|
connection default;
|
|
handler t3 read a next;
|
|
--echo # Demonstrate that the drop will go through as soon as we close the
|
|
--echo # HANDLER
|
|
handler t3 close;
|
|
--echo # connection con1
|
|
connection con1;
|
|
--echo # Reaping 'drop table t3'...
|
|
--reap
|
|
--echo # --> connection default
|
|
connection default;
|
|
commit;
|
|
|
|
--echo #
|
|
--echo # If we have to wait on an exclusive locks while having
|
|
--echo # an open HANDLER, ER_LOCK_DEADLOCK is reported.
|
|
--echo #
|
|
create table t1 (a int, key a(a));
|
|
create table t2 like t1;
|
|
handler t1 open;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
lock table t2 read;
|
|
--echo # --> connection default
|
|
connection default;
|
|
--error ER_LOCK_DEADLOCK
|
|
drop table t2;
|
|
--error ER_LOCK_DEADLOCK
|
|
rename table t2 to t3;
|
|
--echo # Demonstrate that there is no deadlock with FLUSH TABLE,
|
|
--echo # even though it is waiting for the other table to go away
|
|
--echo # Sending:
|
|
--send flush table t2
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
drop table t1;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
unlock tables;
|
|
--echo # --> connection default
|
|
connection default;
|
|
--echo # Reaping 'flush table t2'...
|
|
--reap
|
|
drop table t2;
|
|
|
|
--echo #
|
|
--echo # Bug #46224 HANDLER statements within a transaction might
|
|
--echo # lead to deadlocks
|
|
--echo #
|
|
create table t1 (a int, key a(a));
|
|
|
|
--echo # --> connection default
|
|
connection default;
|
|
begin;
|
|
select * from t1;
|
|
handler t1 open;
|
|
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
lock tables t1 write;
|
|
|
|
--echo # --> connection default
|
|
connection default;
|
|
--echo # Sending:
|
|
--send handler t1 read a next
|
|
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
--echo # Waiting for 'handler t1 read a next' to get blocked...
|
|
let $wait_condition=
|
|
select count(*) = 1 from information_schema.processlist
|
|
where state = "Table lock" and info = "handler t1 read a next";
|
|
--source include/wait_condition.inc
|
|
--echo # Sending:
|
|
--send drop table t1
|
|
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Waiting for 'drop table t1' to get blocked...
|
|
let $wait_condition=
|
|
select count(*) = 1 from information_schema.processlist
|
|
where state = "Waiting for table" and info = "drop table t1";
|
|
--source include/wait_condition.inc
|
|
|
|
--echo # --> connection default
|
|
connection default;
|
|
--echo # Reaping 'handler t1 read a next'...
|
|
--error ER_LOCK_DEADLOCK
|
|
--reap
|
|
handler t1 close;
|
|
commit;
|
|
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
--echo # Reaping 'drop table t1'...
|
|
--reap
|
|
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
disconnect con1;
|
|
--source include/wait_until_disconnected.inc
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
disconnect con2;
|
|
--source include/wait_until_disconnected.inc
|
|
--echo # --> connection con3
|
|
connection con3;
|
|
disconnect con3;
|
|
--source include/wait_until_disconnected.inc
|
|
connection default;
|
|
|
|
--echo #
|
|
--echo # A temporary table test.
|
|
--echo # Check that we don't loose positions of HANDLER opened
|
|
--echo # against a temporary table.
|
|
--echo #
|
|
create table t1 (a int, b int, key a (a));
|
|
insert into t1 (a) values (1), (2), (3), (4), (5);
|
|
create temporary table t2 (a int, b int, key a (a));
|
|
insert into t2 (a) select a from t1;
|
|
handler t1 open;
|
|
handler t1 read a next;
|
|
handler t2 open;
|
|
handler t2 read a next;
|
|
flush table t1;
|
|
handler t2 read a next;
|
|
--echo # Sic: the position is lost
|
|
handler t1 read a next;
|
|
select * from t1;
|
|
--echo # Sic: the position is not lost
|
|
handler t2 read a next;
|
|
--error ER_CANT_REOPEN_TABLE
|
|
select * from t2;
|
|
handler t2 read a next;
|
|
drop table t1;
|
|
drop temporary table t2;
|
|
|
|
--echo #
|
|
--echo # A test for lock_table_names()/unlock_table_names() function.
|
|
--echo # It should work properly in presence of open HANDLER.
|
|
--echo #
|
|
create table t1 (a int, b int, key a (a));
|
|
create table t2 like t1;
|
|
create table t3 like t1;
|
|
create table t4 like t1;
|
|
handler t1 open;
|
|
handler t2 open;
|
|
rename table t4 to t5, t3 to t4, t5 to t3;
|
|
handler t1 read first;
|
|
handler t2 read first;
|
|
drop table t1, t2, t3, t4;
|