mirror of
https://github.com/MariaDB/server.git
synced 2025-01-24 07:44:22 +01:00
dfdbc84585
"HANDLER statements within a transaction might lead to deadlocks". Introduce a notion of a sentinel to MDL_context. A sentinel is a ticket that separates all tickets in the context into two groups: before and after it. Currently we can have (and need) only one designated sentinel -- it separates all locks taken by LOCK TABLE or HANDLER statement, which must survive COMMIT and ROLLBACK and all other locks, which must be released at COMMIT or ROLLBACK. The tricky part is maintaining the sentinel up to date when someone release its corresponding ticket. This can happen, e.g. if someone issues DROP TABLE under LOCK TABLES (generally, see all calls to release_all_locks_for_name()). MDL_context::release_ticket() is modified to take care of it. ****** A fix and a test case for Bug#46224 "HANDLER statements within a transaction might lead to deadlocks". An attempt to mix HANDLER SQL statements, which are transaction- agnostic, an open multi-statement transaction, and DDL against the involved tables (in a concurrent connection) could lead to a deadlock. The deadlock would occur when HANDLER OPEN or HANDLER READ would have to wait on a conflicting metadata lock. If the connection that issued HANDLER statement also had other metadata locks (say, acquired in scope of a transaction), a classical deadlock situation of mutual wait could occur. Incompatible change: entering LOCK TABLES mode automatically closes all open HANDLERs in the current connection. Incompatible change: previously an attempt to wait on a lock in a connection that has an open HANDLER statement could wait indefinitely/deadlock. After this patch, an error ER_LOCK_DEADLOCK is produced. The idea of the fix is to merge thd->handler_mdl_context with the main mdl_context of the connection, used for transactional locks. This makes deadlock detection possible, since all waits with locks are "visible" and available to analysis in a single MDL context of the connection. Since HANDLER locks and transactional locks have a different life cycle -- HANDLERs are explicitly open and closed, and so are HANDLER locks, explicitly acquired and released, whereas transactional locks "accumulate" till the end of a transaction and are released only with COMMIT, ROLLBACK and ROLLBACK TO SAVEPOINT, a concept of "sentinel" was introduced to MDL_context. All locks, HANDLER and others, reside in the same linked list. However, a selected element of the list separates locks with different life cycle. HANDLER locks always reside at the end of the list, after the sentinel. Transactional locks are prepended to the beginning of the list, before the sentinel. Thus, ROLLBACK, COMMIT or ROLLBACK TO SAVEPOINT, only release those locks that reside before the sentinel. HANDLER locks must be released explicitly as part of HANDLER CLOSE statement, or an implicit close. The same approach with sentinel is also employed for LOCK TABLES locks. Since HANDLER and LOCK TABLES statement has never worked together, the implementation is made simple and only maintains one sentinel, which is used either for HANDLER locks, or for LOCK TABLES locks. mysql-test/include/handler.inc: Add test coverage for Bug#46224 "HANDLER statements within a transaction might lead to deadlocks". Extended HANDLER coverage to cover a mix of HANDLER, transactions and DDL statements. mysql-test/r/handler_innodb.result: Update results (Bug#46224). mysql-test/r/handler_myisam.result: Update results (Bug#46224). sql/lock.cc: Remove thd->some_tables_deleted, it's never used. sql/log_event.cc: No need to check for thd->locked_tables_mode, it's done inside release_transactional_locks(). sql/mdl.cc: Implement the concept of HANDLER and LOCK TABLES "sentinel". Implement a method to clone an acquired ticket. Do not return tickets beyond the sentinel when acquiring locks, create a copy. Remove methods to merge and backup MDL_context, they are now not used (Hurra!). This opens a path to a proper constructor and destructor of class MDL_context (to be done in a separate patch). Modify find_ticket() to provide information about where the ticket position is with regard to the sentinel. sql/mdl.h: Add declarations necessary for the implementation of the concept of "sentinel", a dedicated ticket separating transactional and non-transactional locks. sql/mysql_priv.h: Add mark_tmp_table_for_reuse() declaration, a function to "close" a single session (temporary) table. sql/sql_base.cc: Remove thd->some_tables_deleted. Modify deadlock-prevention asserts and deadlock detection heuristics to take into account that from now on HANDLER locks reside in the same locking context. Add broadcast_refresh() to mysql_notify_thread_having_shared_lock(): this is necessary for the case when a thread having a shared lock is asleep in tdc_wait_for_old_versions(). This situation is only possible with HANDLER t1 OPEN; FLUSH TABLE (since all over code paths that lead to tdc_wait_for_old_versions() always have an empty MDL_context). Previously the server would simply deadlock in this situation. sql/sql_class.cc: Remove now unused member "THD::some_tables_deleted". Move mysql_ha_cleanup() a few lines above in THD::cleanup() to make sure that all handlers are closed when it's time to destroy the MDL_context of this connection. Remove handler_mdl_context and handler_tables. sql/sql_class.h: Remove THD::handler_tables, THD::handler_mdl_context, THD::some_tables_deleted. sql/sql_handler.cc: Remove thd->handler_tables. Remove thd->handler_mdl_context. Rewrite mysql_ha_open() to have no special provision for MERGE tables, now that we don't have to manipulate with thd->handler_tables it's easy to do. Remove dead code. Fix a bug in mysql_ha_flush() when we would always flush a temporary HANDLER when mysql_ha_flush() is called (actually mysql_ha_flush() never needs to flush temporary tables). sql/sql_insert.cc: Update a comment, no more thd->some_tables_deleted. sql/sql_parse.cc: Implement an incompatible change: entering LOCK TABLES closes active HANDLERs, if any. Now that we have a sentinel, we don't need to check for thd->locked_tables_mode when releasing metadata locks in COMMIT/ROLLBACK. sql/sql_plist.h: Add new (now necessary) methods to the list class. sql/sql_prepare.cc: Make sure we don't release HANDLER locks when rollback to a savepoint, set to not keep locks taken at PREPARE. sql/sql_servers.cc: Update to a new signature of MDL_context::release_all_locks(). sql/sql_table.cc: Remove thd->some_tables_deleted. sql/transaction.cc: Add comments. Make sure rollback to (MDL) savepoint works under LOCK TABLES and with HANDLER tables.
1359 lines
35 KiB
PHP
1359 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);
|
|
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;
|
|
--error ER_ILLEGAL_HA
|
|
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 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;
|
|
--error ER_LOCK_DEADLOCK
|
|
handler t2 open;
|
|
--error ER_LOCK_DEADLOCK
|
|
select * from t2;
|
|
handler t1 open;
|
|
commit;
|
|
--error ER_LOCK_DEADLOCK
|
|
handler t2 open;
|
|
handler t1 close;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
unlock tables;
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Reaping 'drop table t2'...
|
|
--reap
|
|
--echo # --> connection default
|
|
connection default;
|
|
handler t1 open;
|
|
handler t1 read a prev;
|
|
handler t1 close;
|
|
--echo #
|
|
--echo # Likewise, this doesn't require a multi-statement transaction.
|
|
--echo # ER_LOCK_DEADLOCK is also produced when we have an open
|
|
--echo # HANDLER and try to acquire locks for a single statement.
|
|
--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;
|
|
--error ER_LOCK_DEADLOCK
|
|
select * from t2;
|
|
--echo # --> connection con1
|
|
connection con1;
|
|
unlock tables;
|
|
--echo # --> connection con2
|
|
connection con2;
|
|
--echo # Reaping 'drop table t2'...
|
|
--reap
|
|
--echo # --> connection default
|
|
connection default;
|
|
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;
|