summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2020-05-05 14:55:05 +0200
committerSergei Golubchik <serg@mariadb.org>2020-05-06 20:24:48 +0200
commit0fcc3abf4a0b64932dbd5fb2a3a8d466c9a5f4a9 (patch)
tree23e8c9f7566f83c2cfe5b3cb18e8d2ef8f5ec2db
parent10aaa77509869153b998898d46943ec0949b5784 (diff)
downloadmariadb-git-0fcc3abf4a0b64932dbd5fb2a3a8d466c9a5f4a9.tar.gz
MDEV-22180 Planner opens unnecessary tables when updated table is referenced by foreign keys
only MDL-prelock but do not open FK child tables for read-only (RESTRICT) FK actions. Tables still needs to be opened for CASCADE actions, see 9180e8666b8
-rw-r--r--mysql-test/suite/innodb/r/foreign-keys.result21
-rw-r--r--mysql-test/suite/innodb/t/foreign-keys.test23
-rw-r--r--sql/table.h3
3 files changed, 47 insertions, 0 deletions
diff --git a/mysql-test/suite/innodb/r/foreign-keys.result b/mysql-test/suite/innodb/r/foreign-keys.result
index 10e0b1f3d7b..3778dd082c7 100644
--- a/mysql-test/suite/innodb/r/foreign-keys.result
+++ b/mysql-test/suite/innodb/r/foreign-keys.result
@@ -124,3 +124,24 @@ SET debug_sync='reset';
SHOW OPEN TABLES FROM test;
Database Table In_use Name_locked
DROP TABLE t1, t2;
+create table t1 (pk int primary key, data int) engine=innodb;
+insert t1 values (1,1),(2,2),(3,3);
+create table t2 (t1_pk int, foreign key (t1_pk) references t1 (pk)) engine=innodb;
+insert t2 values (1),(2);
+insert t2 values (10);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`t1_pk`) REFERENCES `t1` (`pk`))
+flush tables;
+flush status;
+update t1 set data=10 where pk+1>10;
+show status like '%opened_tab%';
+Variable_name Value
+Opened_table_definitions 1
+Opened_tables 1
+flush tables;
+flush status;
+update t2 set t1_pk=11 where t1_pk+1>10;
+show status like '%opened_tab%';
+Variable_name Value
+Opened_table_definitions 1
+Opened_tables 1
+drop table t2, t1;
diff --git a/mysql-test/suite/innodb/t/foreign-keys.test b/mysql-test/suite/innodb/t/foreign-keys.test
index a19fe3876f3..b3293e88676 100644
--- a/mysql-test/suite/innodb/t/foreign-keys.test
+++ b/mysql-test/suite/innodb/t/foreign-keys.test
@@ -158,3 +158,26 @@ connection default;
SET debug_sync='reset';
SHOW OPEN TABLES FROM test;
DROP TABLE t1, t2;
+
+#
+# MDEV-22180 Planner opens unnecessary tables when updated table is referenced by foreign keys
+#
+source include/have_innodb.inc;
+
+create table t1 (pk int primary key, data int) engine=innodb;
+insert t1 values (1,1),(2,2),(3,3);
+create table t2 (t1_pk int, foreign key (t1_pk) references t1 (pk)) engine=innodb;
+insert t2 values (1),(2);
+error ER_NO_REFERENCED_ROW_2;
+insert t2 values (10);
+flush tables;
+flush status;
+# with ON UPDATE RESTRICT child tables are not opened
+update t1 set data=10 where pk+1>10;
+show status like '%opened_tab%';
+flush tables;
+flush status;
+# neither are parent tables
+update t2 set t1_pk=11 where t1_pk+1>10;
+show status like '%opened_tab%';
+drop table t2, t1;
diff --git a/sql/table.h b/sql/table.h
index 44803b5aacd..29b4cfdbcf3 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1813,6 +1813,9 @@ struct TABLE_LIST
open_type= routine ? OT_TEMPORARY_OR_BASE : OT_BASE_ONLY;
belong_to_view= belong_to_view_arg;
trg_event_map= trg_event_map_arg;
+ /* MDL is enough for read-only FK checks, we don't need the table */
+ if (prelocking_placeholder == FK && lock_type < TL_WRITE_ALLOW_WRITE)
+ open_strategy= OPEN_STUB;
**last_ptr= this;
prev_global= *last_ptr;