Skip to content

Commit a21e01a

Browse files
committed
MDEV-17541 KILL QUERY during lock wait in FOREIGN KEY check causes hang
row_ins_check_foreign_constraint(): Do not overwrite hard errors with the soft error DB_LOCK_WAIT. This prevents an infinite wait loop when DB_INTERRUPTED was returned. For DB_LOCK_WAIT, row_insert_for_mysql() would keep invoking row_ins_step() and the transaction would remain active until the server shutdown is initiated.
1 parent ab1ce22 commit a21e01a

File tree

3 files changed

+59
-8
lines changed

3 files changed

+59
-8
lines changed

mysql-test/suite/innodb/r/foreign_key.result

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,6 @@ DELETE FROM t1 WHERE id = 1;
252252
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
253253
connection con1;
254254
COMMIT;
255-
disconnect con1;
256255
connection default;
257256
SELECT * FROM t2;
258257
id ref_id f
@@ -332,7 +331,25 @@ PRIMARY KEY (store_id),
332331
UNIQUE KEY idx_unique_manager (manager_staff_id),
333332
CONSTRAINT fk_store_staff FOREIGN KEY (manager_staff_id) REFERENCES staff (staff_id) ON DELETE RESTRICT ON UPDATE CASCADE
334333
) ENGINE=InnoDB;
335-
SET FOREIGN_KEY_CHECKS=DEFAULT;
336334
LOCK TABLE staff WRITE;
337335
UNLOCK TABLES;
338336
DROP TABLES staff, store;
337+
SET FOREIGN_KEY_CHECKS=1;
338+
#
339+
# MDEV-17541 KILL QUERY during lock wait in FOREIGN KEY check hangs
340+
#
341+
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
342+
CREATE TABLE t2 (a INT PRIMARY KEY, FOREIGN KEY (a) REFERENCES t1(a))
343+
ENGINE=InnoDB;
344+
connection con1;
345+
INSERT INTO t1 SET a=1;
346+
BEGIN;
347+
DELETE FROM t1;
348+
connection default;
349+
INSERT INTO t2 SET a=1;
350+
connection con1;
351+
kill query @id;
352+
connection default;
353+
ERROR 70100: Query execution was interrupted
354+
disconnect con1;
355+
DROP TABLE t2,t1;

mysql-test/suite/innodb/t/foreign_key.test

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,6 @@ DELETE FROM t1 WHERE id = 1;
228228

229229
--connection con1
230230
COMMIT;
231-
--disconnect con1
232231

233232
--connection default
234233
SELECT * FROM t2;
@@ -288,8 +287,6 @@ insert into t1 values(1, 1);
288287
insert into t2(f1) values(1);
289288
drop table t2, t1;
290289

291-
--source include/wait_until_count_sessions.inc
292-
293290
#
294291
# MDEV-12669 Circular foreign keys cause a loop and OOM upon LOCK TABLE
295292
#
@@ -308,8 +305,42 @@ CREATE TABLE store (
308305
UNIQUE KEY idx_unique_manager (manager_staff_id),
309306
CONSTRAINT fk_store_staff FOREIGN KEY (manager_staff_id) REFERENCES staff (staff_id) ON DELETE RESTRICT ON UPDATE CASCADE
310307
) ENGINE=InnoDB;
311-
SET FOREIGN_KEY_CHECKS=DEFAULT;
312308

313309
LOCK TABLE staff WRITE;
314310
UNLOCK TABLES;
315311
DROP TABLES staff, store;
312+
SET FOREIGN_KEY_CHECKS=1;
313+
314+
--echo #
315+
--echo # MDEV-17541 KILL QUERY during lock wait in FOREIGN KEY check hangs
316+
--echo #
317+
318+
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
319+
CREATE TABLE t2 (a INT PRIMARY KEY, FOREIGN KEY (a) REFERENCES t1(a))
320+
ENGINE=InnoDB;
321+
322+
connection con1;
323+
INSERT INTO t1 SET a=1;
324+
BEGIN;
325+
DELETE FROM t1;
326+
327+
connection default;
328+
let $ID= `SELECT @id := CONNECTION_ID()`;
329+
send INSERT INTO t2 SET a=1;
330+
331+
connection con1;
332+
let $wait_condition=
333+
select count(*) = 1 from information_schema.processlist
334+
where state = 'update' and info = 'INSERT INTO t2 SET a=1';
335+
--source include/wait_condition.inc
336+
let $ignore= `SELECT @id := $ID`;
337+
kill query @id;
338+
339+
connection default;
340+
--error ER_QUERY_INTERRUPTED
341+
reap;
342+
disconnect con1;
343+
344+
DROP TABLE t2,t1;
345+
346+
--source include/wait_until_count_sessions.inc

storage/innobase/row/row0ins.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,9 +1871,12 @@ row_ins_check_foreign_constraint(
18711871

18721872
thr->lock_state = QUE_THR_LOCK_NOLOCK;
18731873

1874-
if (check_table->to_be_dropped
1875-
|| trx->error_state == DB_LOCK_WAIT_TIMEOUT) {
1874+
err = trx->error_state;
1875+
if (err != DB_SUCCESS) {
1876+
} else if (check_table->to_be_dropped) {
18761877
err = DB_LOCK_WAIT_TIMEOUT;
1878+
} else {
1879+
err = DB_LOCK_WAIT;
18771880
}
18781881

18791882
my_atomic_addlint(&check_table->n_foreign_key_checks_running,

0 commit comments

Comments
 (0)