Commit 5d1c0d00 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-13331 FK DELETE CASCADE does not honor innodb_lock_wait_timeout

row_ins_check_foreign_constraint(): On timeout,
return DB_LOCK_WAIT_TIMEOUT instead of DB_LOCK_WAIT,
so that the lock wait will be properly terminated.
Also, replace some redundant assignments.

It looks like this bug was introduced in MySQL 5.7.8 by:

    commit a97f6b91227c7e0fc3151cfe5421891e79c12d19
    Author: Annamalai Gurusami <annamalai.gurusami@oracle.com>
    Date:   Tue Jun 9 16:02:31 2015 +0530

        Bug #20953265 INNODB: FAILING ASSERTION: RESULT != FTS_INVALID
parent 2f342c45
Branches unavailable
Tags unavailable
No related merge requests found
......@@ -209,7 +209,6 @@ UPDATE users SET name = 'qux' WHERE id = 1;
connect con1,localhost,root,,;
SET innodb_lock_wait_timeout= 1;
DELETE FROM matchmaking_groups WHERE id = 10;
disconnect con1;
connection default;
COMMIT;
SELECT * FROM matchmaking_group_users WHERE matchmaking_group_id NOT IN (SELECT id FROM matchmaking_groups);
......@@ -222,3 +221,45 @@ id name
2 bar
DROP TABLE
matchmaking_group_maps, matchmaking_group_users, matchmaking_groups, users;
#
# MDEV-13331 FK DELETE CASCADE does not honor innodb_lock_wait_timeout
#
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
CREATE TABLE t2 (
id INT NOT NULL PRIMARY KEY,
ref_id INT NOT NULL DEFAULT 0,
f INT NULL,
FOREIGN KEY (ref_id) REFERENCES t1 (id) ON DELETE CASCADE
) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2);
INSERT INTO t2 VALUES (1,1,10),(2,2,20);
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`id` int(11) NOT NULL,
`ref_id` int(11) NOT NULL DEFAULT 0,
`f` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `ref_id` (`ref_id`),
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`ref_id`) REFERENCES `t1` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
connection con1;
BEGIN;
UPDATE t2 SET f = 11 WHERE id = 1;
connection default;
SET innodb_lock_wait_timeout= 1;
DELETE FROM t1 WHERE id = 1;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
connection con1;
COMMIT;
disconnect con1;
connection default;
SELECT * FROM t2;
id ref_id f
1 1 11
2 2 20
DELETE FROM t1 WHERE id = 1;
SELECT * FROM t2;
id ref_id f
2 2 20
DROP TABLE t2, t1;
......@@ -186,7 +186,6 @@ UPDATE users SET name = 'qux' WHERE id = 1;
--connect (con1,localhost,root,,)
SET innodb_lock_wait_timeout= 1;
DELETE FROM matchmaking_groups WHERE id = 10;
--disconnect con1
--connection default
COMMIT;
......@@ -200,4 +199,41 @@ SELECT * FROM users;
DROP TABLE
matchmaking_group_maps, matchmaking_group_users, matchmaking_groups, users;
--echo #
--echo # MDEV-13331 FK DELETE CASCADE does not honor innodb_lock_wait_timeout
--echo #
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB;
CREATE TABLE t2 (
id INT NOT NULL PRIMARY KEY,
ref_id INT NOT NULL DEFAULT 0,
f INT NULL,
FOREIGN KEY (ref_id) REFERENCES t1 (id) ON DELETE CASCADE
) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2);
INSERT INTO t2 VALUES (1,1,10),(2,2,20);
SHOW CREATE TABLE t2;
--connection con1
BEGIN;
UPDATE t2 SET f = 11 WHERE id = 1;
--connection default
SET innodb_lock_wait_timeout= 1;
--error ER_LOCK_WAIT_TIMEOUT
DELETE FROM t1 WHERE id = 1;
--connection con1
COMMIT;
--disconnect con1
--connection default
SELECT * FROM t2;
DELETE FROM t1 WHERE id = 1;
SELECT * FROM t2;
DROP TABLE t2, t1;
--source include/wait_until_count_sessions.inc
......@@ -1759,13 +1759,6 @@ row_ins_check_foreign_constraint(
cmp = cmp_dtuple_rec(entry, rec, offsets);
if (cmp == 0) {
ulint lock_type;
lock_type = skip_gap_lock
? LOCK_REC_NOT_GAP
: LOCK_ORDINARY;
if (rec_get_deleted_flag(rec,
rec_offs_comp(offsets))) {
/* In delete-marked records, DB_TRX_ID must
......@@ -1775,7 +1768,9 @@ row_ins_check_foreign_constraint(
offsets));
err = row_ins_set_shared_rec_lock(
lock_type, block,
skip_gap_lock
? LOCK_REC_NOT_GAP
: LOCK_ORDINARY, block,
rec, check_index, offsets, thr);
switch (err) {
case DB_SUCCESS_LOCKED_REC:
......@@ -1857,23 +1852,21 @@ row_ins_check_foreign_constraint(
} else {
ut_a(cmp < 0);
err = DB_SUCCESS;
if (!skip_gap_lock) {
err = row_ins_set_shared_rec_lock(
err = skip_gap_lock
? DB_SUCCESS
: row_ins_set_shared_rec_lock(
LOCK_GAP, block,
rec, check_index, offsets, thr);
}
switch (err) {
case DB_SUCCESS_LOCKED_REC:
err = DB_SUCCESS;
/* fall through */
case DB_SUCCESS:
if (check_ref) {
err = DB_NO_REFERENCED_ROW;
row_ins_foreign_report_add_err(
trx, foreign, rec, entry);
} else {
err = DB_SUCCESS;
}
default:
break;
......@@ -1921,19 +1914,11 @@ row_ins_check_foreign_constraint(
thr->lock_state = QUE_THR_LOCK_NOLOCK;
DBUG_PRINT("to_be_dropped",
("table: %s", check_table->name.m_name));
if (check_table->to_be_dropped) {
/* The table is being dropped. We shall timeout
this operation */
err = DB_LOCK_WAIT_TIMEOUT;
goto exit_func;
}
err = check_table->to_be_dropped
? DB_LOCK_WAIT_TIMEOUT
: trx->error_state;
}
exit_func:
if (heap != NULL) {
mem_heap_free(heap);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment