Skip to content

Commit dd74332

Browse files
committed
MDEV-12669 Circular foreign keys cause a loop and OOM upon LOCK TABLE
table_already_fk_prelocked() was looking for a table in the wrong list (not the complete list of prelocked tables, but only in its tail, starting from the current table - which is always empty for the last added table), so for circular FKs it kept adding same tables to the list indefinitely. Backport of d6d7e16
1 parent 710093c commit dd74332

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
SET FOREIGN_KEY_CHECKS=0;
2+
CREATE TABLE staff (
3+
staff_id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
4+
store_id TINYINT UNSIGNED NOT NULL,
5+
PRIMARY KEY (staff_id),
6+
KEY idx_fk_store_id (store_id),
7+
CONSTRAINT fk_staff_store FOREIGN KEY (store_id) REFERENCES store (store_id) ON DELETE RESTRICT ON UPDATE CASCADE
8+
) ENGINE=InnoDB;
9+
CREATE TABLE store (
10+
store_id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
11+
manager_staff_id TINYINT UNSIGNED NOT NULL,
12+
PRIMARY KEY (store_id),
13+
UNIQUE KEY idx_unique_manager (manager_staff_id),
14+
CONSTRAINT fk_store_staff FOREIGN KEY (manager_staff_id) REFERENCES staff (staff_id) ON DELETE RESTRICT ON UPDATE CASCADE
15+
) ENGINE=InnoDB;
16+
SET FOREIGN_KEY_CHECKS=DEFAULT;
17+
LOCK TABLE staff WRITE;
18+
UNLOCK TABLES;
19+
DROP TABLES staff, store;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--source include/have_innodb.inc
2+
3+
#
4+
# MDEV-12669 Circular foreign keys cause a loop and OOM upon LOCK TABLE
5+
#
6+
SET FOREIGN_KEY_CHECKS=0;
7+
CREATE TABLE staff (
8+
staff_id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
9+
store_id TINYINT UNSIGNED NOT NULL,
10+
PRIMARY KEY (staff_id),
11+
KEY idx_fk_store_id (store_id),
12+
CONSTRAINT fk_staff_store FOREIGN KEY (store_id) REFERENCES store (store_id) ON DELETE RESTRICT ON UPDATE CASCADE
13+
) ENGINE=InnoDB;
14+
CREATE TABLE store (
15+
store_id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
16+
manager_staff_id TINYINT UNSIGNED NOT NULL,
17+
PRIMARY KEY (store_id),
18+
UNIQUE KEY idx_unique_manager (manager_staff_id),
19+
CONSTRAINT fk_store_staff FOREIGN KEY (manager_staff_id) REFERENCES staff (staff_id) ON DELETE RESTRICT ON UPDATE CASCADE
20+
) ENGINE=InnoDB;
21+
SET FOREIGN_KEY_CHECKS=DEFAULT;
22+
23+
LOCK TABLE staff WRITE;
24+
UNLOCK TABLES;
25+
DROP TABLES staff, store;

sql/sql_base.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4893,8 +4893,9 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
48934893
else
48944894
lock_type= TL_READ;
48954895

4896-
if (table_already_fk_prelocked(table_list, fk->foreign_db,
4897-
fk->foreign_table, lock_type))
4896+
if (table_already_fk_prelocked(prelocking_ctx->query_tables,
4897+
fk->foreign_db, fk->foreign_table,
4898+
lock_type))
48984899
continue;
48994900

49004901
TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));

0 commit comments

Comments
 (0)