mirror of
https://github.com/MariaDB/server.git
synced 2025-02-01 19:41:47 +01:00
3c279d9a5a
The problem was that TRUNCATE TABLE didn't take a exclusive lock on a table if it resorted to truncating via delete of all rows in the table. Specifically for InnoDB tables, this could break proper isolation as InnoDB ends up aborting some granted locks when truncating a table. The solution is to take a exclusive metadata lock before TRUNCATE TABLE can proceed. This guarantees that no other transaction is using the table. Incompatible change: Truncate via delete no longer fails if sql_safe_updates is activated (this was a undocumented side effect).
200 lines
4.1 KiB
Text
200 lines
4.1 KiB
Text
-- source include/have_partition.inc
|
|
-- source include/not_embedded.inc
|
|
-- source include/have_innodb.inc
|
|
|
|
--disable_warnings
|
|
drop table if exists t1;
|
|
--enable_warnings
|
|
|
|
# basic tests of semi-consistent reads
|
|
# for verifying Bug#40595: Non-matching rows not released with READ-COMMITTED
|
|
# on tables with partitions
|
|
|
|
connect (a,localhost,root,,);
|
|
connect (b,localhost,root,,);
|
|
connection a;
|
|
set binlog_format=mixed;
|
|
set session transaction isolation level repeatable read;
|
|
create table t1(a int not null)
|
|
engine=innodb
|
|
DEFAULT CHARSET=latin1
|
|
PARTITION BY RANGE(a)
|
|
(PARTITION p0 VALUES LESS THAN (20),
|
|
PARTITION p1 VALUES LESS THAN MAXVALUE);
|
|
insert into t1 values (1),(2),(3),(4),(5),(6),(7);
|
|
set autocommit=0;
|
|
# this should lock the entire table
|
|
select * from t1 where a=3 lock in share mode;
|
|
connection b;
|
|
set binlog_format=mixed;
|
|
set session transaction isolation level repeatable read;
|
|
set autocommit=0;
|
|
-- error ER_LOCK_WAIT_TIMEOUT
|
|
update t1 set a=10 where a=5;
|
|
connection a;
|
|
#DELETE FROM t1 WHERE a=5;
|
|
commit;
|
|
connection b;
|
|
# perform a semi-consisent read (and unlock non-matching rows)
|
|
set session transaction isolation level read committed;
|
|
update t1 set a=10 where a=5;
|
|
connection a;
|
|
-- error ER_LOCK_WAIT_TIMEOUT
|
|
select * from t1 where a=2 for update;
|
|
# this should lock the records (1),(2)
|
|
select * from t1 where a=2 limit 1 for update;
|
|
connection b;
|
|
# semi-consistent read will skip non-matching locked rows a=1, a=2
|
|
update t1 set a=11 where a=6;
|
|
-- error ER_LOCK_WAIT_TIMEOUT
|
|
update t1 set a=12 where a=2;
|
|
-- error ER_LOCK_WAIT_TIMEOUT
|
|
update t1 set a=13 where a=1;
|
|
connection a;
|
|
commit;
|
|
connection b;
|
|
update t1 set a=14 where a=1;
|
|
commit;
|
|
connection a;
|
|
--sorted_result
|
|
select * from t1;
|
|
drop table t1;
|
|
|
|
connection default;
|
|
disconnect a;
|
|
disconnect b;
|
|
|
|
#
|
|
# Bug #31310: Locked rows silently skipped in read-committed isolation level.
|
|
# (This also tests the '*_semi_consistent*' functions in partitioning)
|
|
# Copied from include/mix1.inc
|
|
|
|
connect (con1,localhost,root,,);
|
|
connect (con2,localhost,root,,);
|
|
SET SESSION AUTOCOMMIT = 0;
|
|
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
|
set binlog_format=mixed;
|
|
--echo # Switch to connection con1
|
|
connection con1;
|
|
|
|
eval
|
|
CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(256))
|
|
ENGINE = InnoDB
|
|
PARTITION BY RANGE (a)
|
|
(PARTITION p0 VALUES LESS THAN (300),
|
|
PARTITION p1 VALUES LESS THAN MAXVALUE);
|
|
INSERT INTO t1 VALUES (1,2);
|
|
|
|
--echo # 1. test for locking:
|
|
|
|
BEGIN;
|
|
--enable_info
|
|
UPDATE t1 SET b = 12 WHERE a = 1;
|
|
--disable_info
|
|
SELECT * FROM t1;
|
|
|
|
--echo # Switch to connection con2
|
|
connection con2;
|
|
|
|
--enable_info
|
|
--disable_abort_on_error
|
|
--error ER_LOCK_WAIT_TIMEOUT
|
|
UPDATE t1 SET b = 21 WHERE a = 1;
|
|
--disable_info
|
|
ROLLBACK;
|
|
|
|
--echo # Switch to connection con1
|
|
connection con1;
|
|
SELECT * FROM t1;
|
|
ROLLBACK;
|
|
|
|
--echo # 2. test for serialized update:
|
|
|
|
CREATE TABLE t2 (a INT);
|
|
|
|
TRUNCATE t1;
|
|
INSERT INTO t1 VALUES (1,'init');
|
|
|
|
DELIMITER |;
|
|
CREATE PROCEDURE p1()
|
|
BEGIN
|
|
UPDATE t1 SET b = CONCAT(b, '+con2') WHERE a = 1;
|
|
INSERT INTO t2 VALUES ();
|
|
END|
|
|
DELIMITER ;|
|
|
|
|
BEGIN;
|
|
--enable_info
|
|
UPDATE t1 SET b = CONCAT(b, '+con1') WHERE a = 1;
|
|
--disable_info
|
|
SELECT * FROM t1;
|
|
|
|
--echo # Switch to connection con2
|
|
connection con2;
|
|
|
|
--send CALL p1;
|
|
|
|
--echo # Switch to connection con1
|
|
connection con1;
|
|
SELECT * FROM t1;
|
|
COMMIT;
|
|
|
|
let $bug31310 = 1;
|
|
while ($bug31310)
|
|
{
|
|
let $bug31310= `SELECT 1 - COUNT(*) FROM t2`;
|
|
}
|
|
|
|
SELECT * FROM t1;
|
|
|
|
--echo # Switch to connection con2
|
|
connection con2;
|
|
--reap
|
|
SELECT * FROM t1;
|
|
COMMIT;
|
|
|
|
--echo # Switch to connection con1
|
|
connection con1;
|
|
|
|
--echo # 3. test for updated key column:
|
|
|
|
TRUNCATE t1;
|
|
DELETE FROM t2;
|
|
|
|
INSERT INTO t1 VALUES (1,'init');
|
|
|
|
BEGIN;
|
|
--enable_info
|
|
UPDATE t1 SET a = 2, b = CONCAT(b, '+con1') WHERE a = 1;
|
|
--disable_info
|
|
SELECT * FROM t1;
|
|
|
|
--echo # Switch to connection con2
|
|
connection con2;
|
|
|
|
--send CALL p1;
|
|
|
|
--echo # Switch to connection con1
|
|
connection con1;
|
|
SELECT * FROM t1;
|
|
COMMIT;
|
|
|
|
let $bug31310 = 1;
|
|
while ($bug31310)
|
|
{
|
|
let $bug31310= `SELECT 1 - COUNT(*) FROM t2`;
|
|
}
|
|
|
|
SELECT * FROM t1;
|
|
|
|
--echo # Switch to connection con2
|
|
connection con2;
|
|
reap;
|
|
SELECT * FROM t1;
|
|
|
|
connection default;
|
|
disconnect con1;
|
|
disconnect con2;
|
|
DROP PROCEDURE p1;
|
|
DROP TABLE t1, t2;
|
|
|