MDEV-26077 Assertion err != DB_DUPLICATE_KEY or unexpected ER_TABLE_EXISTS_ERROR
This is a backport of 161e4bfafd261aa5204827086637d4d7dcceb949.
trans_rollback_to_savepoint(): Only release metadata locks (MDL)
if the storage engines agree, after the changes were already rolled back.
Ever since commit 3792693f311a90cf195ec6d2f9b3762255a249c7
and mysql/mysql-server@55ceedbc3feb911505dcba6cee8080d55ce86dda
we used to cheat here and always release MDL if the binlog is disabled.
MDL are supposed to prevent race conditions between DML and DDL also
when no replication is in use. MDL are supposed to be a superset of
InnoDB table locks: InnoDB table lock may only exist if the thread
also holds MDL on the table name.
In the included test case, ROLLBACK TO SAVEPOINT would wrongly release
the MDL on both tables and let ALTER TABLE proceed, even though the DML
transaction is actually holding locks on the table.
Until commit 1bd681c8b3c5213ce1f7976940a7dc38b48a0d39 (MDEV-25506)
in MariaDB 10.6, InnoDB would often work around the locking violation
in a blatantly non-ACID way: If locks exist on a table that is being
dropped (in this case, actually a partition of a table that is being
rebuilt by ALTER TABLE), InnoDB could move the table (or partition)
into a queue, to be dropped after the locks and references had been
released. If the lock is not released and the original copy of the
table not dropped quickly enough, a name conflict could occur on
a subsequent ALTER TABLE.
The scenario of commit 3792693f311a90cf195ec6d2f9b3762255a249c7
is unaffected by this fix, because mysqldump
would use non-locking reads, and the transaction would not be holding
any InnoDB locks during the execution of ROLLBACK TO SAVEPOINT.
MVCC reads inside InnoDB are only covered by MDL and page latches,
not by any table or record locks.
FIXME: It would be nice if storage engines were specifically asked
which MDL can be released, instead of only offering a choice
between all or nothing. InnoDB should be able to release any
locks for tables that are no longer in trx_t::mod_tables, except
if another transaction had converted some implicit record locks
to explicit ones, before the ROLLBACK TO SAVEPOINT had been completed.
Reviewed by: Sergei Golubchik
2021-07-02 11:15:35 +03:00
|
|
|
#
|
|
|
|
# MDEV-26077 Assertion failure err != DB_DUPLICATE_KEY
|
|
|
|
# or unexpected ER_TABLE_EXISTS_ERROR
|
|
|
|
#
|
|
|
|
CREATE TABLE t1 (pk INT PRIMARY KEY) ENGINE=InnoDB;
|
|
|
|
CREATE TABLE t2 (pk INT PRIMARY KEY) ENGINE=InnoDB;
|
|
|
|
connect con1,localhost,root,,test;
|
|
|
|
START TRANSACTION;
|
|
|
|
INSERT INTO t2 (pk) VALUES (1);
|
|
|
|
SAVEPOINT sp;
|
|
|
|
INSERT INTO t1 (pk) VALUES (1);
|
|
|
|
ROLLBACK TO SAVEPOINT sp;
|
|
|
|
connection default;
|
2021-09-11 11:12:11 +03:00
|
|
|
SET @save_timeout=@@lock_wait_timeout;
|
|
|
|
SET @save_innodb_timeout=@@innodb_lock_wait_timeout;
|
MDEV-26077 Assertion err != DB_DUPLICATE_KEY or unexpected ER_TABLE_EXISTS_ERROR
This is a backport of 161e4bfafd261aa5204827086637d4d7dcceb949.
trans_rollback_to_savepoint(): Only release metadata locks (MDL)
if the storage engines agree, after the changes were already rolled back.
Ever since commit 3792693f311a90cf195ec6d2f9b3762255a249c7
and mysql/mysql-server@55ceedbc3feb911505dcba6cee8080d55ce86dda
we used to cheat here and always release MDL if the binlog is disabled.
MDL are supposed to prevent race conditions between DML and DDL also
when no replication is in use. MDL are supposed to be a superset of
InnoDB table locks: InnoDB table lock may only exist if the thread
also holds MDL on the table name.
In the included test case, ROLLBACK TO SAVEPOINT would wrongly release
the MDL on both tables and let ALTER TABLE proceed, even though the DML
transaction is actually holding locks on the table.
Until commit 1bd681c8b3c5213ce1f7976940a7dc38b48a0d39 (MDEV-25506)
in MariaDB 10.6, InnoDB would often work around the locking violation
in a blatantly non-ACID way: If locks exist on a table that is being
dropped (in this case, actually a partition of a table that is being
rebuilt by ALTER TABLE), InnoDB could move the table (or partition)
into a queue, to be dropped after the locks and references had been
released. If the lock is not released and the original copy of the
table not dropped quickly enough, a name conflict could occur on
a subsequent ALTER TABLE.
The scenario of commit 3792693f311a90cf195ec6d2f9b3762255a249c7
is unaffected by this fix, because mysqldump
would use non-locking reads, and the transaction would not be holding
any InnoDB locks during the execution of ROLLBACK TO SAVEPOINT.
MVCC reads inside InnoDB are only covered by MDL and page latches,
not by any table or record locks.
FIXME: It would be nice if storage engines were specifically asked
which MDL can be released, instead of only offering a choice
between all or nothing. InnoDB should be able to release any
locks for tables that are no longer in trx_t::mod_tables, except
if another transaction had converted some implicit record locks
to explicit ones, before the ROLLBACK TO SAVEPOINT had been completed.
Reviewed by: Sergei Golubchik
2021-07-02 11:15:35 +03:00
|
|
|
SET lock_wait_timeout=0;
|
|
|
|
SET innodb_lock_wait_timeout=0;
|
|
|
|
ALTER TABLE t1 PARTITION BY HASH(pk);
|
|
|
|
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
2021-09-11 11:12:11 +03:00
|
|
|
SET lock_wait_timeout=@save_timeout;
|
|
|
|
SET innodb_lock_wait_timeout=@save_innodb_timeout;
|
MDEV-26077 Assertion err != DB_DUPLICATE_KEY or unexpected ER_TABLE_EXISTS_ERROR
This is a backport of 161e4bfafd261aa5204827086637d4d7dcceb949.
trans_rollback_to_savepoint(): Only release metadata locks (MDL)
if the storage engines agree, after the changes were already rolled back.
Ever since commit 3792693f311a90cf195ec6d2f9b3762255a249c7
and mysql/mysql-server@55ceedbc3feb911505dcba6cee8080d55ce86dda
we used to cheat here and always release MDL if the binlog is disabled.
MDL are supposed to prevent race conditions between DML and DDL also
when no replication is in use. MDL are supposed to be a superset of
InnoDB table locks: InnoDB table lock may only exist if the thread
also holds MDL on the table name.
In the included test case, ROLLBACK TO SAVEPOINT would wrongly release
the MDL on both tables and let ALTER TABLE proceed, even though the DML
transaction is actually holding locks on the table.
Until commit 1bd681c8b3c5213ce1f7976940a7dc38b48a0d39 (MDEV-25506)
in MariaDB 10.6, InnoDB would often work around the locking violation
in a blatantly non-ACID way: If locks exist on a table that is being
dropped (in this case, actually a partition of a table that is being
rebuilt by ALTER TABLE), InnoDB could move the table (or partition)
into a queue, to be dropped after the locks and references had been
released. If the lock is not released and the original copy of the
table not dropped quickly enough, a name conflict could occur on
a subsequent ALTER TABLE.
The scenario of commit 3792693f311a90cf195ec6d2f9b3762255a249c7
is unaffected by this fix, because mysqldump
would use non-locking reads, and the transaction would not be holding
any InnoDB locks during the execution of ROLLBACK TO SAVEPOINT.
MVCC reads inside InnoDB are only covered by MDL and page latches,
not by any table or record locks.
FIXME: It would be nice if storage engines were specifically asked
which MDL can be released, instead of only offering a choice
between all or nothing. InnoDB should be able to release any
locks for tables that are no longer in trx_t::mod_tables, except
if another transaction had converted some implicit record locks
to explicit ones, before the ROLLBACK TO SAVEPOINT had been completed.
Reviewed by: Sergei Golubchik
2021-07-02 11:15:35 +03:00
|
|
|
SHOW CREATE TABLE t1;
|
|
|
|
Table Create Table
|
|
|
|
t1 CREATE TABLE `t1` (
|
|
|
|
`pk` int(11) NOT NULL,
|
|
|
|
PRIMARY KEY (`pk`)
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
|
|
|
connection con1;
|
|
|
|
COMMIT;
|
|
|
|
connection default;
|
|
|
|
ALTER TABLE t2 PARTITION BY HASH(pk);
|
|
|
|
disconnect con1;
|
|
|
|
connection default;
|
|
|
|
DROP TABLE t1, t2;
|
|
|
|
# End of 10.2 tests
|
2018-05-17 22:03:53 +05:30
|
|
|
CREATE TABLE t1(a INT, b VARCHAR(10), INDEX(a))ENGINE=InnoDB
|
|
|
|
PARTITION BY RANGE(a)
|
|
|
|
(PARTITION pa VALUES LESS THAN (3),
|
|
|
|
PARTITION pb VALUES LESS THAN (5));
|
|
|
|
CREATE TABLE t2(a INT, FOREIGN KEY(a) REFERENCES t1(a))ENGINE=INNODB
|
|
|
|
PARTITION BY RANGE(a)
|
|
|
|
(PARTITION pa VALUES LESS THAN (2),
|
|
|
|
PARTITION pb VALUES LESS THAN (4));
|
2020-01-10 23:17:38 +10:00
|
|
|
ERROR HY000: Partitioned tables do not support FOREIGN KEY
|
2018-05-17 22:03:53 +05:30
|
|
|
DROP TABLE t1;
|
2021-07-02 11:44:51 +03:00
|
|
|
# End of 10.3 tests
|
2021-02-01 18:43:07 +02:00
|
|
|
#
|
|
|
|
# MDEV-24754 Server crash in
|
|
|
|
# ha_partition_inplace_ctx::~ha_partition_inplace_ctx
|
|
|
|
#
|
|
|
|
CREATE TABLE t1 (id INT PRIMARY KEY, a INT, va INT AS (a) VIRTUAL)
|
|
|
|
ENGINE=InnoDB PARTITION BY HASH(id) PARTITIONS 2;
|
|
|
|
ALTER TABLE t1 ADD b INT, ALGORITHM=INSTANT;
|
|
|
|
DROP TABLE t1;
|
2021-07-02 13:02:26 +03:00
|
|
|
# End of 10.5 tests
|