Backport of:
------------------------------------------------------------ 2599.161.3 Ingo Struewing 2009-07-21 Bug#20667 - Truncate table fails for a write locked table TRUNCATE TABLE was not allowed under LOCK TABLES. The patch removes this restriction. mysql_truncate() does now handle that case.
This commit is contained in:
parent
a3814e3635
commit
700a361a6a
@ -1046,18 +1046,21 @@ c1
|
|||||||
LOCK TABLE t1 WRITE, t2 WRITE, t3 WRITE;
|
LOCK TABLE t1 WRITE, t2 WRITE, t3 WRITE;
|
||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
TRUNCATE TABLE t3;
|
TRUNCATE TABLE t3;
|
||||||
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
|
||||||
SELECT * FROM t3;
|
SELECT * FROM t3;
|
||||||
c1
|
c1
|
||||||
1
|
UNLOCK TABLES;
|
||||||
2
|
SELECT * FROM t1;
|
||||||
|
c1
|
||||||
|
SELECT * FROM t2;
|
||||||
|
c1
|
||||||
#
|
#
|
||||||
# Truncate child table under locked tables.
|
# Truncate child table under locked tables.
|
||||||
|
LOCK TABLE t1 WRITE, t2 WRITE, t3 WRITE;
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
TRUNCATE TABLE t1;
|
TRUNCATE TABLE t1;
|
||||||
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
|
||||||
SELECT * FROM t3;
|
SELECT * FROM t3;
|
||||||
c1
|
c1
|
||||||
1
|
|
||||||
2
|
2
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
DROP TABLE t1, t2, t3;
|
DROP TABLE t1, t2, t3;
|
||||||
@ -1089,18 +1092,24 @@ INSERT INTO t1 VALUES (1);
|
|||||||
CREATE TABLE t4 (c1 INT, INDEX(c1));
|
CREATE TABLE t4 (c1 INT, INDEX(c1));
|
||||||
LOCK TABLE t4 WRITE;
|
LOCK TABLE t4 WRITE;
|
||||||
TRUNCATE TABLE t3;
|
TRUNCATE TABLE t3;
|
||||||
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
|
||||||
SELECT * FROM t3;
|
SELECT * FROM t3;
|
||||||
c1
|
c1
|
||||||
1
|
SELECT * FROM t1;
|
||||||
2
|
c1
|
||||||
|
SELECT * FROM t2;
|
||||||
|
c1
|
||||||
#
|
#
|
||||||
# Truncate temporary child table under locked tables.
|
# Truncate temporary child table under locked tables.
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
TRUNCATE TABLE t1;
|
TRUNCATE TABLE t1;
|
||||||
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
|
|
||||||
SELECT * FROM t3;
|
SELECT * FROM t3;
|
||||||
c1
|
c1
|
||||||
1
|
2
|
||||||
|
SELECT * FROM t1;
|
||||||
|
c1
|
||||||
|
SELECT * FROM t2;
|
||||||
|
c1
|
||||||
2
|
2
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
DROP TABLE t1, t2, t3, t4;
|
DROP TABLE t1, t2, t3, t4;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
drop table if exists t1;
|
drop table if exists t1, t2;
|
||||||
create table t1 (a integer, b integer,c1 CHAR(10));
|
create table t1 (a integer, b integer,c1 CHAR(10));
|
||||||
insert into t1 (a) values (1),(2);
|
insert into t1 (a) values (1),(2);
|
||||||
truncate table t1;
|
truncate table t1;
|
||||||
@ -61,6 +61,91 @@ ERROR 42S02: Table 'test.v1' doesn't exist
|
|||||||
drop view v1;
|
drop view v1;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
#
|
#
|
||||||
|
# Bug#20667 - Truncate table fails for a write locked table
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (c1 INT);
|
||||||
|
LOCK TABLE t1 WRITE;
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
SELECT * FROM t1;
|
||||||
|
c1
|
||||||
|
1
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
c1
|
||||||
|
UNLOCK TABLES;
|
||||||
|
LOCK TABLE t1 READ;
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
|
||||||
|
UNLOCK TABLES;
|
||||||
|
CREATE TABLE t2 (c1 INT);
|
||||||
|
LOCK TABLE t2 WRITE;
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
ERROR HY000: Table 't1' was not locked with LOCK TABLES
|
||||||
|
UNLOCK TABLES;
|
||||||
|
CREATE VIEW v1 AS SELECT t1.c1 FROM t1,t2 WHERE t1.c1 = t2.c1;
|
||||||
|
INSERT INTO t1 VALUES (1), (2), (3);
|
||||||
|
INSERT INTO t2 VALUES (1), (3), (4);
|
||||||
|
SELECT * FROM v1;
|
||||||
|
c1
|
||||||
|
1
|
||||||
|
3
|
||||||
|
TRUNCATE v1;
|
||||||
|
ERROR 42S02: Table 'test.v1' doesn't exist
|
||||||
|
SELECT * FROM v1;
|
||||||
|
c1
|
||||||
|
1
|
||||||
|
3
|
||||||
|
LOCK TABLE t1 WRITE;
|
||||||
|
SELECT * FROM v1;
|
||||||
|
ERROR HY000: Table 'v1' was not locked with LOCK TABLES
|
||||||
|
TRUNCATE v1;
|
||||||
|
ERROR 42S02: Table 'test.v1' doesn't exist
|
||||||
|
SELECT * FROM v1;
|
||||||
|
ERROR HY000: Table 'v1' was not locked with LOCK TABLES
|
||||||
|
UNLOCK TABLES;
|
||||||
|
LOCK TABLE t1 WRITE, t2 WRITE;
|
||||||
|
SELECT * FROM v1;
|
||||||
|
ERROR HY000: Table 'v1' was not locked with LOCK TABLES
|
||||||
|
TRUNCATE v1;
|
||||||
|
ERROR 42S02: Table 'test.v1' doesn't exist
|
||||||
|
SELECT * FROM v1;
|
||||||
|
ERROR HY000: Table 'v1' was not locked with LOCK TABLES
|
||||||
|
UNLOCK TABLES;
|
||||||
|
LOCK TABLE v1 WRITE;
|
||||||
|
SELECT * FROM v1;
|
||||||
|
c1
|
||||||
|
1
|
||||||
|
3
|
||||||
|
TRUNCATE v1;
|
||||||
|
ERROR 42S02: Table 'test.v1' doesn't exist
|
||||||
|
SELECT * FROM v1;
|
||||||
|
c1
|
||||||
|
1
|
||||||
|
3
|
||||||
|
UNLOCK TABLES;
|
||||||
|
LOCK TABLE t1 WRITE, t2 WRITE, v1 WRITE;
|
||||||
|
SELECT * FROM v1;
|
||||||
|
c1
|
||||||
|
1
|
||||||
|
3
|
||||||
|
TRUNCATE v1;
|
||||||
|
ERROR 42S02: Table 'test.v1' doesn't exist
|
||||||
|
SELECT * FROM v1;
|
||||||
|
c1
|
||||||
|
1
|
||||||
|
3
|
||||||
|
UNLOCK TABLES;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
CREATE PROCEDURE p1() SET @a = 5;
|
||||||
|
TRUNCATE p1;
|
||||||
|
ERROR 42S02: Table 'test.p1' doesn't exist
|
||||||
|
SHOW CREATE PROCEDURE p1;
|
||||||
|
Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
|
||||||
|
p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`()
|
||||||
|
SET @a = 5 latin1 latin1_swedish_ci latin1_swedish_ci
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
#
|
||||||
# Bug#46452 Crash in MDL, HANDLER OPEN + TRUNCATE TABLE
|
# Bug#46452 Crash in MDL, HANDLER OPEN + TRUNCATE TABLE
|
||||||
#
|
#
|
||||||
DROP TABLE IF EXISTS t1;
|
DROP TABLE IF EXISTS t1;
|
||||||
|
70
mysql-test/r/truncate_coverage.result
Normal file
70
mysql-test/r/truncate_coverage.result
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
DROP TABLE IF EXISTS t1;
|
||||||
|
#
|
||||||
|
# Bug#20667 - Truncate table fails for a write locked table
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (c1 INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
#
|
||||||
|
# connection con1
|
||||||
|
START TRANSACTION;
|
||||||
|
INSERT INTO t1 VALUES (2);
|
||||||
|
#
|
||||||
|
# connection default
|
||||||
|
LOCK TABLE t1 WRITE;
|
||||||
|
SET DEBUG_SYNC='mdl_upgrade_shared_lock_to_exclusive SIGNAL waiting';
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
#
|
||||||
|
# connection con1
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||||
|
KILL QUERY @id;
|
||||||
|
COMMIT;
|
||||||
|
#
|
||||||
|
# connection default
|
||||||
|
ERROR 70100: Query execution was interrupted
|
||||||
|
UNLOCK TABLES;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
CREATE TABLE t1 (c1 INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
#
|
||||||
|
# connection con1
|
||||||
|
START TRANSACTION;
|
||||||
|
INSERT INTO t1 VALUES (2);
|
||||||
|
#
|
||||||
|
# connection default
|
||||||
|
LOCK TABLE t1 WRITE;
|
||||||
|
SET DEBUG_SYNC='mdl_upgrade_shared_lock_to_exclusive SIGNAL waiting';
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
#
|
||||||
|
# connection con1
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||||
|
COMMIT;
|
||||||
|
#
|
||||||
|
# connection default
|
||||||
|
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||||
|
UNLOCK TABLES;
|
||||||
|
DROP TABLE t1;
|
||||||
|
ERROR 42S02: Unknown table 't1'
|
||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
CREATE TABLE t1 (c1 INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
#
|
||||||
|
# connection con1
|
||||||
|
START TRANSACTION;
|
||||||
|
INSERT INTO t1 VALUES (2);
|
||||||
|
#
|
||||||
|
# connection default
|
||||||
|
SET DEBUG_SYNC='mdl_acquire_exclusive_locks_wait SIGNAL waiting';
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
#
|
||||||
|
# connection con1
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||||
|
KILL QUERY @id;
|
||||||
|
COMMIT;
|
||||||
|
#
|
||||||
|
# connection default
|
||||||
|
ERROR 70100: Query execution was interrupted
|
||||||
|
UNLOCK TABLES;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET DEBUG_SYNC='RESET';
|
@ -675,12 +675,16 @@ SELECT * FROM t3;
|
|||||||
--echo # Truncate MERGE table under locked tables.
|
--echo # Truncate MERGE table under locked tables.
|
||||||
LOCK TABLE t1 WRITE, t2 WRITE, t3 WRITE;
|
LOCK TABLE t1 WRITE, t2 WRITE, t3 WRITE;
|
||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
|
||||||
TRUNCATE TABLE t3;
|
TRUNCATE TABLE t3;
|
||||||
SELECT * FROM t3;
|
SELECT * FROM t3;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
SELECT * FROM t2;
|
||||||
--echo #
|
--echo #
|
||||||
--echo # Truncate child table under locked tables.
|
--echo # Truncate child table under locked tables.
|
||||||
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
LOCK TABLE t1 WRITE, t2 WRITE, t3 WRITE;
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
TRUNCATE TABLE t1;
|
TRUNCATE TABLE t1;
|
||||||
SELECT * FROM t3;
|
SELECT * FROM t3;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
@ -706,14 +710,18 @@ SELECT * FROM t3;
|
|||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
CREATE TABLE t4 (c1 INT, INDEX(c1));
|
CREATE TABLE t4 (c1 INT, INDEX(c1));
|
||||||
LOCK TABLE t4 WRITE;
|
LOCK TABLE t4 WRITE;
|
||||||
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
|
||||||
TRUNCATE TABLE t3;
|
TRUNCATE TABLE t3;
|
||||||
SELECT * FROM t3;
|
SELECT * FROM t3;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
SELECT * FROM t2;
|
||||||
--echo #
|
--echo #
|
||||||
--echo # Truncate temporary child table under locked tables.
|
--echo # Truncate temporary child table under locked tables.
|
||||||
--error ER_LOCK_OR_ACTIVE_TRANSACTION
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
TRUNCATE TABLE t1;
|
TRUNCATE TABLE t1;
|
||||||
SELECT * FROM t3;
|
SELECT * FROM t3;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
SELECT * FROM t2;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
DROP TABLE t1, t2, t3, t4;
|
DROP TABLE t1, t2, t3, t4;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# Test of truncate
|
# Test of truncate
|
||||||
#
|
#
|
||||||
--disable_warnings
|
--disable_warnings
|
||||||
drop table if exists t1;
|
drop table if exists t1, t2;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
|
|
||||||
create table t1 (a integer, b integer,c1 CHAR(10));
|
create table t1 (a integer, b integer,c1 CHAR(10));
|
||||||
@ -69,6 +69,77 @@ drop table t1;
|
|||||||
|
|
||||||
# End of 5.0 tests
|
# End of 5.0 tests
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug#20667 - Truncate table fails for a write locked table
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (c1 INT);
|
||||||
|
LOCK TABLE t1 WRITE;
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
SELECT * FROM t1;
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
#
|
||||||
|
LOCK TABLE t1 READ;
|
||||||
|
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
#
|
||||||
|
CREATE TABLE t2 (c1 INT);
|
||||||
|
LOCK TABLE t2 WRITE;
|
||||||
|
--error ER_TABLE_NOT_LOCKED
|
||||||
|
TRUNCATE TABLE t1;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
#
|
||||||
|
CREATE VIEW v1 AS SELECT t1.c1 FROM t1,t2 WHERE t1.c1 = t2.c1;
|
||||||
|
INSERT INTO t1 VALUES (1), (2), (3);
|
||||||
|
INSERT INTO t2 VALUES (1), (3), (4);
|
||||||
|
SELECT * FROM v1;
|
||||||
|
--error ER_NO_SUCH_TABLE
|
||||||
|
TRUNCATE v1;
|
||||||
|
SELECT * FROM v1;
|
||||||
|
#
|
||||||
|
LOCK TABLE t1 WRITE;
|
||||||
|
--error ER_TABLE_NOT_LOCKED
|
||||||
|
SELECT * FROM v1;
|
||||||
|
--error ER_NO_SUCH_TABLE
|
||||||
|
TRUNCATE v1;
|
||||||
|
--error ER_TABLE_NOT_LOCKED
|
||||||
|
SELECT * FROM v1;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
#
|
||||||
|
LOCK TABLE t1 WRITE, t2 WRITE;
|
||||||
|
--error ER_TABLE_NOT_LOCKED
|
||||||
|
SELECT * FROM v1;
|
||||||
|
--error ER_NO_SUCH_TABLE
|
||||||
|
TRUNCATE v1;
|
||||||
|
--error ER_TABLE_NOT_LOCKED
|
||||||
|
SELECT * FROM v1;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
#
|
||||||
|
LOCK TABLE v1 WRITE;
|
||||||
|
SELECT * FROM v1;
|
||||||
|
--error ER_NO_SUCH_TABLE
|
||||||
|
TRUNCATE v1;
|
||||||
|
SELECT * FROM v1;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
#
|
||||||
|
LOCK TABLE t1 WRITE, t2 WRITE, v1 WRITE;
|
||||||
|
SELECT * FROM v1;
|
||||||
|
--error ER_NO_SUCH_TABLE
|
||||||
|
TRUNCATE v1;
|
||||||
|
SELECT * FROM v1;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
#
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1, t2;
|
||||||
|
#
|
||||||
|
CREATE PROCEDURE p1() SET @a = 5;
|
||||||
|
--error ER_NO_SUCH_TABLE
|
||||||
|
TRUNCATE p1;
|
||||||
|
SHOW CREATE PROCEDURE p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # Bug#46452 Crash in MDL, HANDLER OPEN + TRUNCATE TABLE
|
--echo # Bug#46452 Crash in MDL, HANDLER OPEN + TRUNCATE TABLE
|
||||||
--echo #
|
--echo #
|
||||||
|
155
mysql-test/t/truncate_coverage.test
Normal file
155
mysql-test/t/truncate_coverage.test
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#
|
||||||
|
# Code coverage testing of TRUNCATE TABLE.
|
||||||
|
#
|
||||||
|
# Ingo Struewing, 2009-07-20
|
||||||
|
#
|
||||||
|
|
||||||
|
--source include/have_debug_sync.inc
|
||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
|
||||||
|
--let $MYSQLD_DATADIR= `SELECT @@datadir`
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
DROP TABLE IF EXISTS t1;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug#20667 - Truncate table fails for a write locked table
|
||||||
|
--echo #
|
||||||
|
########
|
||||||
|
# Attack wait_while_table_is_used(). Kill query while trying to
|
||||||
|
# upgrade MDL.
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (c1 INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
#
|
||||||
|
# Start a transaction and execute a DML in it. Since 5.4.4 this leaves
|
||||||
|
# a shared meta data lock (MDL) behind. TRUNCATE shall block on it.
|
||||||
|
#
|
||||||
|
--echo #
|
||||||
|
--echo # connection con1
|
||||||
|
--connect (con1, localhost, root,,)
|
||||||
|
START TRANSACTION;
|
||||||
|
INSERT INTO t1 VALUES (2);
|
||||||
|
#
|
||||||
|
# Get connection id of default connection.
|
||||||
|
# Lock the table and start TRUNCATE, which will block on MDL upgrade.
|
||||||
|
#
|
||||||
|
--echo #
|
||||||
|
--echo # connection default
|
||||||
|
--connection default
|
||||||
|
let $ID= `SELECT @id := CONNECTION_ID()`;
|
||||||
|
LOCK TABLE t1 WRITE;
|
||||||
|
SET DEBUG_SYNC='mdl_upgrade_shared_lock_to_exclusive SIGNAL waiting';
|
||||||
|
send TRUNCATE TABLE t1;
|
||||||
|
#
|
||||||
|
# Get the default connection ID into a variable in an invisible statement.
|
||||||
|
# Kill the TRUNCATE query. This shall result in an error return
|
||||||
|
# from wait_while_table_is_used().
|
||||||
|
#
|
||||||
|
--echo #
|
||||||
|
--echo # connection con1
|
||||||
|
--connection con1
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||||
|
let $invisible_assignment_in_select = `SELECT @id := $ID`;
|
||||||
|
KILL QUERY @id;
|
||||||
|
COMMIT;
|
||||||
|
--disconnect con1
|
||||||
|
--echo #
|
||||||
|
--echo # connection default
|
||||||
|
--connection default
|
||||||
|
--error ER_QUERY_INTERRUPTED
|
||||||
|
reap;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
########
|
||||||
|
# Attack reopen_tables(). Remove form file.
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (c1 INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
#
|
||||||
|
# Start a transaction and execute a DML in it. Since 5.4.4 this leaves
|
||||||
|
# a shared meta data lock (MDL) behind. TRUNCATE shall block on it.
|
||||||
|
#
|
||||||
|
--echo #
|
||||||
|
--echo # connection con1
|
||||||
|
--connect (con1, localhost, root,,)
|
||||||
|
START TRANSACTION;
|
||||||
|
INSERT INTO t1 VALUES (2);
|
||||||
|
#
|
||||||
|
# Lock the table and start TRUNCATE, which will block on MDL upgrade.
|
||||||
|
#
|
||||||
|
--echo #
|
||||||
|
--echo # connection default
|
||||||
|
--connection default
|
||||||
|
LOCK TABLE t1 WRITE;
|
||||||
|
SET DEBUG_SYNC='mdl_upgrade_shared_lock_to_exclusive SIGNAL waiting';
|
||||||
|
send TRUNCATE TABLE t1;
|
||||||
|
#
|
||||||
|
# Remove datafile.
|
||||||
|
# Commit to let TRUNCATE continue.
|
||||||
|
#
|
||||||
|
--echo #
|
||||||
|
--echo # connection con1
|
||||||
|
--connection con1
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||||
|
--remove_file $MYSQLD_DATADIR/test/t1.frm
|
||||||
|
COMMIT;
|
||||||
|
--disconnect con1
|
||||||
|
--echo #
|
||||||
|
--echo # connection default
|
||||||
|
--connection default
|
||||||
|
--error ER_NO_SUCH_TABLE
|
||||||
|
reap;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
--error ER_BAD_TABLE_ERROR
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
########
|
||||||
|
# Attack acquire_exclusive_locks(). Hold a global read lock.
|
||||||
|
# Non-LOCK TABLE case.
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (c1 INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
#
|
||||||
|
# Start a transaction and execute a DML in it. Since 5.4.4 this leaves
|
||||||
|
# a shared meta data lock (MDL) behind. TRUNCATE shall block on it.
|
||||||
|
#
|
||||||
|
--echo #
|
||||||
|
--echo # connection con1
|
||||||
|
--connect (con1, localhost, root,,)
|
||||||
|
START TRANSACTION;
|
||||||
|
INSERT INTO t1 VALUES (2);
|
||||||
|
#
|
||||||
|
# Get connection id of default connection.
|
||||||
|
# Start TRUNCATE, which will block on acquire_exclusive_locks().
|
||||||
|
#
|
||||||
|
--echo #
|
||||||
|
--echo # connection default
|
||||||
|
--connection default
|
||||||
|
let $ID= `SELECT @id := CONNECTION_ID()`;
|
||||||
|
SET DEBUG_SYNC='mdl_acquire_exclusive_locks_wait SIGNAL waiting';
|
||||||
|
send TRUNCATE TABLE t1;
|
||||||
|
#
|
||||||
|
# Get the default connection ID into a variable in an invisible statement.
|
||||||
|
# Kill the TRUNCATE query. This shall result in an error return
|
||||||
|
# from wait_while_table_is_used().
|
||||||
|
#
|
||||||
|
--echo #
|
||||||
|
--echo # connection con1
|
||||||
|
--connection con1
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||||
|
let $invisible_assignment_in_select = `SELECT @id := $ID`;
|
||||||
|
KILL QUERY @id;
|
||||||
|
COMMIT;
|
||||||
|
--disconnect con1
|
||||||
|
--echo #
|
||||||
|
--echo # connection default
|
||||||
|
--connection default
|
||||||
|
--error ER_QUERY_INTERRUPTED
|
||||||
|
reap;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET DEBUG_SYNC='RESET';
|
||||||
|
|
@ -1098,9 +1098,15 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
|
|||||||
HA_CREATE_INFO create_info;
|
HA_CREATE_INFO create_info;
|
||||||
char path[FN_REFLEN + 1];
|
char path[FN_REFLEN + 1];
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
bool error;
|
bool error= TRUE;
|
||||||
uint path_length;
|
uint path_length;
|
||||||
MDL_request mdl_request;
|
MDL_request mdl_request;
|
||||||
|
/*
|
||||||
|
Is set if we're under LOCK TABLES, and used
|
||||||
|
to downgrade the exclusive lock after the
|
||||||
|
table was truncated.
|
||||||
|
*/
|
||||||
|
MDL_ticket *mdl_ticket= NULL;
|
||||||
bool has_mdl_lock= FALSE;
|
bool has_mdl_lock= FALSE;
|
||||||
DBUG_ENTER("mysql_truncate");
|
DBUG_ENTER("mysql_truncate");
|
||||||
|
|
||||||
@ -1119,7 +1125,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
|
|||||||
goto trunc_by_del;
|
goto trunc_by_del;
|
||||||
|
|
||||||
table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
|
table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
|
||||||
|
|
||||||
close_temporary_table(thd, table, 0, 0); // Don't free share
|
close_temporary_table(thd, table, 0, 0); // Don't free share
|
||||||
ha_create_table(thd, share->normalized_path.str,
|
ha_create_table(thd, share->normalized_path.str,
|
||||||
share->db.str, share->table_name.str, &create_info, 1);
|
share->db.str, share->table_name.str, &create_info, 1);
|
||||||
@ -1177,21 +1183,47 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
|
|||||||
thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION)
|
thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION)
|
||||||
goto trunc_by_del;
|
goto trunc_by_del;
|
||||||
|
|
||||||
mdl_request.init(MDL_key::TABLE, table_list->db, table_list->table_name, MDL_EXCLUSIVE);
|
|
||||||
if (thd->mdl_context.acquire_exclusive_lock(&mdl_request))
|
|
||||||
DBUG_RETURN(TRUE);
|
|
||||||
|
|
||||||
has_mdl_lock= TRUE;
|
if (thd->locked_tables_mode)
|
||||||
|
{
|
||||||
|
if (!(table= find_write_locked_table(thd->open_tables, table_list->db,
|
||||||
|
table_list->table_name)))
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
mdl_ticket= table->mdl_ticket;
|
||||||
|
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
||||||
|
goto end;
|
||||||
|
close_all_tables_for_name(thd, table->s, FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Even though we could use the previous execution branch
|
||||||
|
here just as well, we must not try to open the table:
|
||||||
|
MySQL manual documents that TRUNCATE can be used to
|
||||||
|
repair a damaged table, i.e. a table that can not be
|
||||||
|
fully "opened". In particular MySQL manual says:
|
||||||
|
|
||||||
pthread_mutex_lock(&LOCK_open);
|
As long as the table format file tbl_name.frm is valid,
|
||||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_list->db,
|
the table can be re-created as an empty table with TRUNCATE
|
||||||
table_list->table_name);
|
TABLE, even if the data or index files have become corrupted.
|
||||||
pthread_mutex_unlock(&LOCK_open);
|
*/
|
||||||
|
mdl_request.init(MDL_key::TABLE, table_list->db, table_list->table_name,
|
||||||
|
MDL_EXCLUSIVE);
|
||||||
|
if (thd->mdl_context.acquire_exclusive_lock(&mdl_request))
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
has_mdl_lock= TRUE;
|
||||||
|
pthread_mutex_lock(&LOCK_open);
|
||||||
|
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_list->db,
|
||||||
|
table_list->table_name);
|
||||||
|
pthread_mutex_unlock(&LOCK_open);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
|
/*
|
||||||
// crashes, replacement works. *(path + path_length - reg_ext_length)=
|
Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
|
||||||
// '\0';
|
crashes, replacement works. *(path + path_length - reg_ext_length)=
|
||||||
|
'\0';
|
||||||
|
*/
|
||||||
path[path_length - reg_ext_length] = 0;
|
path[path_length - reg_ext_length] = 0;
|
||||||
pthread_mutex_lock(&LOCK_open);
|
pthread_mutex_lock(&LOCK_open);
|
||||||
error= ha_create_table(thd, path, table_list->db, table_list->table_name,
|
error= ha_create_table(thd, path, table_list->db, table_list->table_name,
|
||||||
@ -1202,6 +1234,12 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
|
|||||||
end:
|
end:
|
||||||
if (!dont_send_ok)
|
if (!dont_send_ok)
|
||||||
{
|
{
|
||||||
|
if (thd->locked_tables_mode && thd->locked_tables_list.reopen_tables(thd))
|
||||||
|
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
|
||||||
|
/*
|
||||||
|
Even if we failed to reopen some tables,
|
||||||
|
the operation itself succeeded, write the binlog.
|
||||||
|
*/
|
||||||
if (!error)
|
if (!error)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -1213,12 +1251,11 @@ end:
|
|||||||
}
|
}
|
||||||
if (has_mdl_lock)
|
if (has_mdl_lock)
|
||||||
thd->mdl_context.release_lock(mdl_request.ticket);
|
thd->mdl_context.release_lock(mdl_request.ticket);
|
||||||
|
if (mdl_ticket)
|
||||||
|
mdl_ticket->downgrade_exclusive_lock();
|
||||||
}
|
}
|
||||||
else if (error)
|
|
||||||
{
|
DBUG_PRINT("exit", ("error: %d", error));
|
||||||
if (has_mdl_lock)
|
|
||||||
thd->mdl_context.release_lock(mdl_request.ticket);
|
|
||||||
}
|
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
|
|
||||||
trunc_by_del:
|
trunc_by_del:
|
||||||
|
@ -3078,7 +3078,7 @@ end_with_restore_list:
|
|||||||
Don't allow this within a transaction because we want to use
|
Don't allow this within a transaction because we want to use
|
||||||
re-generate table
|
re-generate table
|
||||||
*/
|
*/
|
||||||
if (thd->locked_tables_mode || thd->active_transaction())
|
if (thd->active_transaction())
|
||||||
{
|
{
|
||||||
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
|
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
|
||||||
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
|
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user