diff --git a/mysql-test/suite/galera/r/galera_multi_level_fk_ddl_delete.result b/mysql-test/suite/galera/r/galera_multi_level_fk_ddl_delete.result new file mode 100644 index 0000000000000..4199fdcd0118e --- /dev/null +++ b/mysql-test/suite/galera/r/galera_multi_level_fk_ddl_delete.result @@ -0,0 +1,362 @@ +connection node_2; +connection node_1; +# +# 1. BF-BF conflict on MDL locks between: DROP TABLE t6 and DELETE on t1 +# with foreign key references as below: +# - t1<-t2<-t3<-t4 +# - t3<-t5 +# - t2<-t6 +# +connection node_2; +SET GLOBAL wsrep_slave_threads=2; +CREATE TABLE t1 ( +id INTEGER PRIMARY KEY, +f2 INTEGER +); +CREATE TABLE t2 ( +id INT PRIMARY KEY, +t1_id INT NOT NULL, +t5_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t1_id(t1_id), +CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE, +KEY key_t5_id(t5_id) +); +CREATE TABLE t3 ( +id INT PRIMARY KEY, +t2_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t2_id(t2_id), +CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +CREATE TABLE t4 ( +id INT PRIMARY KEY, +t3_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t3_id(t3_id), +CONSTRAINT key_t3_id FOREIGN KEY (t3_id) REFERENCES t3 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +CREATE TABLE t5 ( +id INT PRIMARY KEY, +t3_id_1 INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t3_id_1(t3_id_1), +CONSTRAINT key_t3_id_1 FOREIGN KEY (t3_id_1) REFERENCES t3 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +CREATE TABLE t6 ( +id INT PRIMARY KEY, +t2_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t2_id_1(t2_id), +CONSTRAINT key_t2_id_1 FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t1 VALUES (3,0); +INSERT INTO t2 VALUES (1,1,1,1234); +INSERT INTO t2 VALUES (2,2,2,1234); +INSERT INTO t3 VALUES (1,1,1234); +INSERT INTO t3 VALUES (2,2,1234); +INSERT INTO t4 VALUES (1,1,1234); +INSERT INTO t4 VALUES (2,2,1234); +INSERT INTO t5 VALUES (1,1,1234); +INSERT INTO t5 VALUES (2,2,1234); +ALTER TABLE t2 ADD CONSTRAINT key_t5_id FOREIGN KEY (t5_id) +REFERENCES t5 (id) ON UPDATE CASCADE ON DELETE CASCADE; +connection node_1; +connection node_2; +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; +connection node_1; +DROP TABLE t6; +connection node_2; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; +SET SESSION wsrep_sync_wait = 0; +connection node_1; +SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table'; +START TRANSACTION; +DELETE FROM t1 WHERE id = 3; +COMMIT; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +include/assert_grep.inc [Foreign key referenced table found: 4 tables] +include/assert_grep.inc [Foreign key referenced table found: test.t2] +include/assert_grep.inc [Foreign key referenced table found: test.t3] +include/assert_grep.inc [Foreign key referenced table found: test.t4] +include/assert_grep.inc [Foreign key referenced table found: test.t5] +connection node_2; +select * from t1; +id f2 +1 0 +2 0 +select * from t2; +id t1_id t5_id f2 +1 1 1 1234 +2 2 2 1234 +select * from t3; +id t2_id f2 +1 1 1234 +2 2 1234 +select * from t4; +id t3_id f2 +1 1 1234 +2 2 1234 +select * from t5; +id t3_id_1 f2 +1 1 1234 +2 2 1234 +select * from t6; +ERROR 42S02: Table 'test.t6' doesn't exist +connection node_1; +select * from t1; +id f2 +1 0 +2 0 +select * from t2; +id t1_id t5_id f2 +1 1 1 1234 +2 2 2 1234 +select * from t3; +id t2_id f2 +1 1 1234 +2 2 1234 +select * from t4; +id t3_id f2 +1 1 1234 +2 2 1234 +select * from t5; +id t3_id_1 f2 +1 1 1234 +2 2 1234 +select * from t6; +ERROR 42S02: Table 'test.t6' doesn't exist +ALTER TABLE t2 DROP FOREIGN KEY key_t5_id; +DROP TABLE t5, t4, t3, t2, t1; +# +# 2. BF-BF conflict on MDL locks between: +# ALTER TABLE t3 (whose parent table are t3 -> t2 -> t1), and +# DELETE on t1 with t2 referencing t1, and t3 referencing t2. +# +connection node_2; +SET GLOBAL wsrep_slave_threads=2; +CREATE TABLE t1 ( +id INTEGER PRIMARY KEY, +f2 INTEGER +); +CREATE TABLE t2 ( +id INT PRIMARY KEY, +t1_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t1_id(t1_id), +CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +CREATE TABLE t3 ( +id INT PRIMARY KEY, +t2_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t2_id(t2_id) +); +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t1 VALUES (3,0); +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); +connection node_2; +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; +connection node_1; +ALTER TABLE t3 ADD CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE; +connection node_2; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; +SET SESSION wsrep_sync_wait = 0; +connection node_1; +SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table'; +START TRANSACTION; +DELETE FROM t1 WHERE id = 3; +COMMIT; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +include/assert_grep.inc [Foreign key referenced table found: 2 tables] +include/assert_grep.inc [Foreign key referenced table found: test.t2] +include/assert_grep.inc [Foreign key referenced table found: test.t3] +connection node_2; +select * from t1; +id f2 +1 0 +2 0 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +select * from t3; +id t2_id f2 +connection node_1; +select * from t1; +id f2 +1 0 +2 0 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +select * from t3; +id t2_id f2 +DROP TABLE t3, t2, t1; +# +# 3. BF-BF conflict on MDL locks between: +# CREATE TABLE t3 (whose parent table are t3 -> t2 -> t1), and +# DELETE on t1 with t2 referencing t1, and t3 referencing t2. +# +connection node_2; +SET GLOBAL wsrep_slave_threads=2; +CREATE TABLE t1 ( +id INTEGER PRIMARY KEY, +f2 INTEGER +); +CREATE TABLE t2 ( +id INT PRIMARY KEY, +t1_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t1_id(t1_id), +CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t1 VALUES (3,0); +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); +connection node_2; +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; +connection node_1; +CREATE TABLE t3 (id INT PRIMARY KEY, t2_id INT NOT NULL, f2 INTEGER NOT NULL, KEY key_t2_id(t2_id), CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE); +connection node_2; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; +SET SESSION wsrep_sync_wait = 0; +connection node_1; +SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table'; +START TRANSACTION; +DELETE FROM t1 WHERE id = 3; +COMMIT; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +include/assert_grep.inc [Foreign key referenced table found: 2 tables] +include/assert_grep.inc [Foreign key referenced table found: test.t2] +include/assert_grep.inc [Foreign key referenced table found: test.t3] +connection node_2; +select * from t1; +id f2 +1 0 +2 0 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +select * from t3; +id t2_id f2 +connection node_1; +select * from t1; +id f2 +1 0 +2 0 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +select * from t3; +id t2_id f2 +DROP TABLE t3, t2, t1; +# +# 4. BF-BF conflict on MDL locks between: +# OPTIMIZE TABLE t2 (whose parent table are t2 -> t1), and +# DELETE on t1. +# +connection node_2; +SET GLOBAL wsrep_slave_threads=2; +CREATE TABLE t1 ( +id INTEGER PRIMARY KEY, +f2 INTEGER +); +CREATE TABLE t2 ( +id INT PRIMARY KEY, +t1_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t1_id(t1_id), +CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t1 VALUES (3,0); +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); +connection node_2; +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; +connection node_1; +OPTIMIZE TABLE t2; +Table Op Msg_type Msg_text +test.t2 optimize note Table does not support optimize, doing recreate + analyze instead +test.t2 optimize status OK +connection node_2; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; +SET SESSION wsrep_sync_wait = 0; +connection node_1; +SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table'; +START TRANSACTION; +DELETE FROM t1 WHERE id = 3; +COMMIT; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +include/assert_grep.inc [Foreign key referenced table found: 1 tables] +include/assert_grep.inc [Foreign key referenced table found: test.t2] +connection node_2; +select * from t1; +id f2 +1 0 +2 0 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +connection node_1; +select * from t1; +id f2 +1 0 +2 0 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +DROP TABLE t2, t1; diff --git a/mysql-test/suite/galera/r/galera_multi_level_fk_ddl_update.result b/mysql-test/suite/galera/r/galera_multi_level_fk_ddl_update.result new file mode 100644 index 0000000000000..9c8a34e7dd786 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_multi_level_fk_ddl_update.result @@ -0,0 +1,358 @@ +connection node_2; +connection node_1; +# +# 1. BF-BF conflict on MDL locks between: DROP TABLE t6 and UPDATE on t1 +# with foreign key references as below: +# - t1<-t2<-t3<-t4 +# - t3<-t5 +# - t2<-t6 +# +connection node_2; +SET GLOBAL wsrep_slave_threads=2; +CREATE TABLE t1 ( +id INTEGER PRIMARY KEY, +f2 INTEGER +); +CREATE TABLE t2 ( +id INT PRIMARY KEY, +t1_id INT NOT NULL, +t5_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t1_id(t1_id), +CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE, +KEY key_t5_id(t5_id) +); +CREATE TABLE t3 ( +id INT PRIMARY KEY, +t2_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t2_id(t2_id), +CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +CREATE TABLE t4 ( +id INT PRIMARY KEY, +t3_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t3_id(t3_id), +CONSTRAINT key_t3_id FOREIGN KEY (t3_id) REFERENCES t3 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +CREATE TABLE t5 ( +id INT PRIMARY KEY, +t3_id_1 INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t3_id_1(t3_id_1), +CONSTRAINT key_t3_id_1 FOREIGN KEY (t3_id_1) REFERENCES t3 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +CREATE TABLE t6 ( +id INT PRIMARY KEY, +t2_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t2_id_1(t2_id), +CONSTRAINT key_t2_id_1 FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t2 VALUES (1,1,1,1234); +INSERT INTO t2 VALUES (2,2,2,1234); +INSERT INTO t3 VALUES (1,1,1234); +INSERT INTO t3 VALUES (2,2,1234); +INSERT INTO t4 VALUES (1,1,1234); +INSERT INTO t4 VALUES (2,2,1234); +INSERT INTO t5 VALUES (1,1,1234); +INSERT INTO t5 VALUES (2,2,1234); +ALTER TABLE t2 ADD CONSTRAINT key_t5_id FOREIGN KEY (t5_id) +REFERENCES t5 (id) ON UPDATE CASCADE ON DELETE CASCADE; +connection node_1; +connection node_2; +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; +connection node_1; +DROP TABLE t6; +connection node_2; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; +SET SESSION wsrep_sync_wait = 0; +connection node_1; +SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table'; +START TRANSACTION; +UPDATE t1 SET f2 = 1 WHERE id=2; +COMMIT; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +include/assert_grep.inc [Foreign key referenced table found: 4 tables] +include/assert_grep.inc [Foreign key referenced table found: test.t2] +include/assert_grep.inc [Foreign key referenced table found: test.t3] +include/assert_grep.inc [Foreign key referenced table found: test.t4] +include/assert_grep.inc [Foreign key referenced table found: test.t5] +connection node_2; +select * from t1; +id f2 +1 0 +2 1 +select * from t2; +id t1_id t5_id f2 +1 1 1 1234 +2 2 2 1234 +select * from t3; +id t2_id f2 +1 1 1234 +2 2 1234 +select * from t4; +id t3_id f2 +1 1 1234 +2 2 1234 +select * from t5; +id t3_id_1 f2 +1 1 1234 +2 2 1234 +select * from t6; +ERROR 42S02: Table 'test.t6' doesn't exist +connection node_1; +select * from t1; +id f2 +1 0 +2 1 +select * from t2; +id t1_id t5_id f2 +1 1 1 1234 +2 2 2 1234 +select * from t3; +id t2_id f2 +1 1 1234 +2 2 1234 +select * from t4; +id t3_id f2 +1 1 1234 +2 2 1234 +select * from t5; +id t3_id_1 f2 +1 1 1234 +2 2 1234 +select * from t6; +ERROR 42S02: Table 'test.t6' doesn't exist +ALTER TABLE t2 DROP FOREIGN KEY key_t5_id; +DROP TABLE t5, t4, t3, t2, t1; +# +# 2. BF-BF conflict on MDL locks between: +# ALTER TABLE t3 (whose parent table are t3 -> t2 -> t1), and +# UPDATE on t1 with t2 referencing t1, and t3 referencing t2. +# +connection node_2; +SET GLOBAL wsrep_slave_threads=2; +CREATE TABLE t1 ( +id INTEGER PRIMARY KEY, +f2 INTEGER +); +CREATE TABLE t2 ( +id INT PRIMARY KEY, +t1_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t1_id(t1_id), +CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +CREATE TABLE t3 ( +id INT PRIMARY KEY, +t2_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t2_id(t2_id) +); +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); +connection node_2; +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; +connection node_1; +ALTER TABLE t3 ADD CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE; +connection node_2; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; +SET SESSION wsrep_sync_wait = 0; +connection node_1; +SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table'; +START TRANSACTION; +UPDATE t1 SET f2 = 1 WHERE id=2; +COMMIT; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +include/assert_grep.inc [Foreign key referenced table found: 2 tables] +include/assert_grep.inc [Foreign key referenced table found: test.t2] +include/assert_grep.inc [Foreign key referenced table found: test.t3] +connection node_2; +select * from t1; +id f2 +1 0 +2 1 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +select * from t3; +id t2_id f2 +connection node_1; +select * from t1; +id f2 +1 0 +2 1 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +select * from t3; +id t2_id f2 +DROP TABLE t3, t2, t1; +# +# 3. BF-BF conflict on MDL locks between: +# CREATE TABLE t3 (whose parent table are t3 -> t2 -> t1), and +# UPDATE on t1 with t2 referencing t1, and t3 referencing t2. +# +connection node_2; +SET GLOBAL wsrep_slave_threads=2; +CREATE TABLE t1 ( +id INTEGER PRIMARY KEY, +f2 INTEGER +); +CREATE TABLE t2 ( +id INT PRIMARY KEY, +t1_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t1_id(t1_id), +CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); +connection node_2; +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; +connection node_1; +CREATE TABLE t3 (id INT PRIMARY KEY, t2_id INT NOT NULL, f2 INTEGER NOT NULL, KEY key_t2_id(t2_id), CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE); +connection node_2; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; +SET SESSION wsrep_sync_wait = 0; +connection node_1; +SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table'; +START TRANSACTION; +UPDATE t1 SET f2 = 1 WHERE id=2; +COMMIT; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +include/assert_grep.inc [Foreign key referenced table found: 2 tables] +include/assert_grep.inc [Foreign key referenced table found: test.t2] +include/assert_grep.inc [Foreign key referenced table found: test.t3] +connection node_2; +select * from t1; +id f2 +1 0 +2 1 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +select * from t3; +id t2_id f2 +connection node_1; +select * from t1; +id f2 +1 0 +2 1 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +select * from t3; +id t2_id f2 +DROP TABLE t3, t2, t1; +# +# 4. BF-BF conflict on MDL locks between: +# OPTIMIZE TABLE t2 (whose parent table are t2 -> t1), and +# UPDATE on t1. +# +connection node_2; +SET GLOBAL wsrep_slave_threads=2; +CREATE TABLE t1 ( +id INTEGER PRIMARY KEY, +f2 INTEGER +); +CREATE TABLE t2 ( +id INT PRIMARY KEY, +t1_id INT NOT NULL, +f2 INTEGER NOT NULL, +KEY key_t1_id(t1_id), +CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); +connection node_2; +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; +connection node_1; +OPTIMIZE TABLE t2; +Table Op Msg_type Msg_text +test.t2 optimize note Table does not support optimize, doing recreate + analyze instead +test.t2 optimize status OK +connection node_2; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; +SET SESSION wsrep_sync_wait = 0; +connection node_1; +SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table'; +START TRANSACTION; +UPDATE t1 SET f2 = 1 WHERE id=2; +COMMIT; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; +connection node_1; +include/assert_grep.inc [Foreign key referenced table found: 1 tables] +include/assert_grep.inc [Foreign key referenced table found: test.t2] +connection node_2; +select * from t1; +id f2 +1 0 +2 1 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +connection node_1; +select * from t1; +id f2 +1 0 +2 1 +select * from t2; +id t1_id f2 +1 1 1234 +2 2 1234 +DROP TABLE t2, t1; diff --git a/mysql-test/suite/galera/t/galera_multi_level_fk_ddl_delete.test b/mysql-test/suite/galera/t/galera_multi_level_fk_ddl_delete.test new file mode 100644 index 0000000000000..b1c3e6d53526a --- /dev/null +++ b/mysql-test/suite/galera/t/galera_multi_level_fk_ddl_delete.test @@ -0,0 +1,452 @@ +# +# BF-BF conflict on MDL locks between DDL and delete query +# when multi-level foreign key like t3 -> t2 -> t1 +# are present. +# +# If bug is present, expect the wait condition +# to timeout and when the DELETE applies, it +# will be granted a MDL lock of type SHARED_READ +# for table t1. When resumed, the DROP TABLE will +# also try to MDL lock t1, causing a BF-BF conflict +# on that MDL lock. + +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--echo # +--echo # 1. BF-BF conflict on MDL locks between: DROP TABLE t6 and DELETE on t1 +--echo # with foreign key references as below: +--echo # - t1<-t2<-t3<-t4 +--echo # - t3<-t5 +--echo # - t2<-t6 +--echo # + + +# +# Setup +# +--connection node_2 +SET GLOBAL wsrep_slave_threads=2; + +CREATE TABLE t1 ( + id INTEGER PRIMARY KEY, + f2 INTEGER +); + +CREATE TABLE t2 ( + id INT PRIMARY KEY, + t1_id INT NOT NULL, + t5_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t1_id(t1_id), + CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE, + KEY key_t5_id(t5_id) +); + +CREATE TABLE t3 ( + id INT PRIMARY KEY, + t2_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t2_id(t2_id), + CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE t4 ( + id INT PRIMARY KEY, + t3_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t3_id(t3_id), + CONSTRAINT key_t3_id FOREIGN KEY (t3_id) REFERENCES t3 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE t5 ( + id INT PRIMARY KEY, + t3_id_1 INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t3_id_1(t3_id_1), + CONSTRAINT key_t3_id_1 FOREIGN KEY (t3_id_1) REFERENCES t3 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE t6 ( + id INT PRIMARY KEY, + t2_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t2_id_1(t2_id), + CONSTRAINT key_t2_id_1 FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + + +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t1 VALUES (3,0); + +INSERT INTO t2 VALUES (1,1,1,1234); +INSERT INTO t2 VALUES (2,2,2,1234); + +INSERT INTO t3 VALUES (1,1,1234); +INSERT INTO t3 VALUES (2,2,1234); + +INSERT INTO t4 VALUES (1,1,1234); +INSERT INTO t4 VALUES (2,2,1234); + +INSERT INTO t5 VALUES (1,1,1234); +INSERT INTO t5 VALUES (2,2,1234); + +ALTER TABLE t2 ADD CONSTRAINT key_t5_id FOREIGN KEY (t5_id) +REFERENCES t5 (id) ON UPDATE CASCADE ON DELETE CASCADE; + +--connection node_1 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = "t2" AND CONSTRAINT_TYPE = "FOREIGN KEY" AND CONSTRAINT_NAME="key_t5_id" +--source include/wait_condition.inc + + +--let $fk_parent_query = DROP TABLE t6 +--let $fk_child_query = DELETE FROM t1 WHERE id = 3 +--let $fk_mdl_lock_num = 5 +--source galera_multi_level_foreign_key.inc + + +# +# Verify Foreign key for referenced table added. +# +--connection node_1 +--let assert_text= Foreign key referenced table found: 4 tables +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 4 +--let assert_select= Foreign key referenced table found: +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t2 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 1 +--let assert_select= Foreign key referenced table found: test.t2 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t3 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 1 +--let assert_select= Foreign key referenced table found: test.t3 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t4 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 1 +--let assert_select= Foreign key referenced table found: test.t4 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t5 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 1 +--let assert_select= Foreign key referenced table found: test.t5 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + + +# +# Verify delete and drop table has succeded. +# +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 2 FROM test.t1 +--source include/wait_condition.inc + +select * from t1; +select * from t2; +select * from t3; +select * from t4; +select * from t5; +--error ER_NO_SUCH_TABLE +select * from t6; + +--connection node_1 +select * from t1; +select * from t2; +select * from t3; +select * from t4; +select * from t5; +--error ER_NO_SUCH_TABLE +select * from t6; + + +# +# Cleanup +# +ALTER TABLE t2 DROP FOREIGN KEY key_t5_id; +DROP TABLE t5, t4, t3, t2, t1; + + +--echo # +--echo # 2. BF-BF conflict on MDL locks between: +--echo # ALTER TABLE t3 (whose parent table are t3 -> t2 -> t1), and +--echo # DELETE on t1 with t2 referencing t1, and t3 referencing t2. +--echo # + +# +# Setup +# +--connection node_2 +SET GLOBAL wsrep_slave_threads=2; + +CREATE TABLE t1 ( + id INTEGER PRIMARY KEY, + f2 INTEGER +); + +CREATE TABLE t2 ( + id INT PRIMARY KEY, + t1_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t1_id(t1_id), + CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE t3 ( + id INT PRIMARY KEY, + t2_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t2_id(t2_id) +); + +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t1 VALUES (3,0); + +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); + + +# +# ALTER TABLE t3 and wait for it to reach node_2 +# +--let $fk_parent_query = ALTER TABLE t3 ADD CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE +# +# Issue a DELETE to table that references t1 +# +--let $fk_child_query = DELETE FROM t1 WHERE id = 3 +--let $fk_mdl_lock_num = 3 +--source galera_multi_level_foreign_key.inc + + +# +# Verify Foreign key for referenced table added. +# +--connection node_1 +--let assert_text= Foreign key referenced table found: 2 tables +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 6 +--let assert_select= Foreign key referenced table found: +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t2 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 2 +--let assert_select= Foreign key referenced table found: test.t2 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t3 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 2 +--let assert_select= Foreign key referenced table found: test.t3 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + + +# +# Verify delete and alter table has succeded. +# +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 2 FROM test.t1 +--source include/wait_condition.inc + +select * from t1; +select * from t2; +select * from t3; + +--connection node_1 +select * from t1; +select * from t2; +select * from t3; + + +# +# Cleanup +# +DROP TABLE t3, t2, t1; + + +--echo # +--echo # 3. BF-BF conflict on MDL locks between: +--echo # CREATE TABLE t3 (whose parent table are t3 -> t2 -> t1), and +--echo # DELETE on t1 with t2 referencing t1, and t3 referencing t2. +--echo # + +# +# Setup +# +--connection node_2 +SET GLOBAL wsrep_slave_threads=2; + +CREATE TABLE t1 ( + id INTEGER PRIMARY KEY, + f2 INTEGER +); + +CREATE TABLE t2 ( + id INT PRIMARY KEY, + t1_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t1_id(t1_id), + CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + + +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t1 VALUES (3,0); + +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); + + +--let $fk_parent_query = CREATE TABLE t3 (id INT PRIMARY KEY, t2_id INT NOT NULL, f2 INTEGER NOT NULL, KEY key_t2_id(t2_id), CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE) +--let $fk_child_query = DELETE FROM t1 WHERE id = 3 +--let $fk_mdl_lock_num = 3 +--source galera_multi_level_foreign_key.inc + + +# +# Verify Foreign key for referenced table added. +# +--connection node_1 +--let assert_text= Foreign key referenced table found: 2 tables +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 8 +--let assert_select= Foreign key referenced table found: +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t2 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 3 +--let assert_select= Foreign key referenced table found: test.t2 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t3 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 3 +--let assert_select= Foreign key referenced table found: test.t3 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + + +# +# Verify delete and create table has succeded. +# +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 2 FROM test.t1 +--source include/wait_condition.inc + +select * from t1; +select * from t2; +select * from t3; + +--connection node_1 +select * from t1; +select * from t2; +select * from t3; + + +# +# Cleanup +# +DROP TABLE t3, t2, t1; + + +--echo # +--echo # 4. BF-BF conflict on MDL locks between: +--echo # OPTIMIZE TABLE t2 (whose parent table are t2 -> t1), and +--echo # DELETE on t1. +--echo # + +# +# Setup +# +--connection node_2 +SET GLOBAL wsrep_slave_threads=2; + +CREATE TABLE t1 ( + id INTEGER PRIMARY KEY, + f2 INTEGER +); + +CREATE TABLE t2 ( + id INT PRIMARY KEY, + t1_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t1_id(t1_id), + CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + + +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); +INSERT INTO t1 VALUES (3,0); + +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); + + +--let $fk_parent_query = OPTIMIZE TABLE t2 +--let $fk_child_query = DELETE FROM t1 WHERE id = 3 +--let $fk_mdl_lock_num = 2 +--source galera_multi_level_foreign_key.inc + + +# +# Verify Foreign key for referenced table added. +# +--connection node_1 +--let assert_text= Foreign key referenced table found: 1 tables +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 9 +--let assert_select= Foreign key referenced table found: +--let $assert_only_after = CURRENT_TEST: +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t2 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 4 +--let assert_select= Foreign key referenced table found: test.t2 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_delete +--source include/assert_grep.inc + + +# +# Verify delete and create table has succeded. +# +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 2 FROM test.t1 +--source include/wait_condition.inc + + +select * from t1; +select * from t2; + +--connection node_1 +select * from t1; +select * from t2; + + +# +# Cleanup +# +DROP TABLE t2, t1; diff --git a/mysql-test/suite/galera/t/galera_multi_level_fk_ddl_update.test b/mysql-test/suite/galera/t/galera_multi_level_fk_ddl_update.test new file mode 100644 index 0000000000000..1dea0021901fd --- /dev/null +++ b/mysql-test/suite/galera/t/galera_multi_level_fk_ddl_update.test @@ -0,0 +1,451 @@ +# +# BF-BF conflict on MDL locks between DDL and update query +# when multi-level foreign key like t3 -> t2 -> t1 +# are present. +# +# If bug is present, expect the wait condition +# to timeout and when the UPDATE applies, it +# will be granted a MDL lock of type SHARED_READ +# for table t1. When resumed, the DROP TABLE will +# also try to MDL lock t1, causing a BF-BF conflict +# on that MDL lock. + +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--echo # +--echo # 1. BF-BF conflict on MDL locks between: DROP TABLE t6 and UPDATE on t1 +--echo # with foreign key references as below: +--echo # - t1<-t2<-t3<-t4 +--echo # - t3<-t5 +--echo # - t2<-t6 +--echo # + + +# +# Setup +# +--connection node_2 +SET GLOBAL wsrep_slave_threads=2; + +CREATE TABLE t1 ( + id INTEGER PRIMARY KEY, + f2 INTEGER +); + +CREATE TABLE t2 ( + id INT PRIMARY KEY, + t1_id INT NOT NULL, + t5_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t1_id(t1_id), + CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE, + KEY key_t5_id(t5_id) +); + +CREATE TABLE t3 ( + id INT PRIMARY KEY, + t2_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t2_id(t2_id), + CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE t4 ( + id INT PRIMARY KEY, + t3_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t3_id(t3_id), + CONSTRAINT key_t3_id FOREIGN KEY (t3_id) REFERENCES t3 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE t5 ( + id INT PRIMARY KEY, + t3_id_1 INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t3_id_1(t3_id_1), + CONSTRAINT key_t3_id_1 FOREIGN KEY (t3_id_1) REFERENCES t3 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE t6 ( + id INT PRIMARY KEY, + t2_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t2_id_1(t2_id), + CONSTRAINT key_t2_id_1 FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + + +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); + +INSERT INTO t2 VALUES (1,1,1,1234); +INSERT INTO t2 VALUES (2,2,2,1234); + +INSERT INTO t3 VALUES (1,1,1234); +INSERT INTO t3 VALUES (2,2,1234); + +INSERT INTO t4 VALUES (1,1,1234); +INSERT INTO t4 VALUES (2,2,1234); + +INSERT INTO t5 VALUES (1,1,1234); +INSERT INTO t5 VALUES (2,2,1234); + +ALTER TABLE t2 ADD CONSTRAINT key_t5_id FOREIGN KEY (t5_id) +REFERENCES t5 (id) ON UPDATE CASCADE ON DELETE CASCADE; + +--connection node_1 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = "t2" AND CONSTRAINT_TYPE = "FOREIGN KEY" AND CONSTRAINT_NAME="key_t5_id" +--source include/wait_condition.inc + + +--let $fk_parent_query = DROP TABLE t6 +--let $fk_child_query = UPDATE t1 SET f2 = 1 WHERE id=2 +--let $fk_mdl_lock_num = 5 +--source galera_multi_level_foreign_key.inc + + +# +# Verify Foreign key for referenced table added. +# +--connection node_1 +--let assert_text= Foreign key referenced table found: 4 tables +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 4 +--let assert_select= Foreign key referenced table found: +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t2 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 1 +--let assert_select= Foreign key referenced table found: test.t2 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t3 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 1 +--let assert_select= Foreign key referenced table found: test.t3 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t4 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 1 +--let assert_select= Foreign key referenced table found: test.t4 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t5 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 1 +--let assert_select= Foreign key referenced table found: test.t5 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + + +# +# Verify update and drop table has succeded. +# +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM test.t1 where id=2 and f2=1; +--source include/wait_condition.inc + +select * from t1; +select * from t2; +select * from t3; +select * from t4; +select * from t5; +--error ER_NO_SUCH_TABLE +select * from t6; + +--connection node_1 +select * from t1; +select * from t2; +select * from t3; +select * from t4; +select * from t5; +--error ER_NO_SUCH_TABLE +select * from t6; + + +# +# Cleanup +# +ALTER TABLE t2 DROP FOREIGN KEY key_t5_id; +DROP TABLE t5, t4, t3, t2, t1; + + +--echo # +--echo # 2. BF-BF conflict on MDL locks between: +--echo # ALTER TABLE t3 (whose parent table are t3 -> t2 -> t1), and +--echo # UPDATE on t1 with t2 referencing t1, and t3 referencing t2. +--echo # + +# +# Setup +# +--connection node_2 +SET GLOBAL wsrep_slave_threads=2; + +CREATE TABLE t1 ( + id INTEGER PRIMARY KEY, + f2 INTEGER +); + +CREATE TABLE t2 ( + id INT PRIMARY KEY, + t1_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t1_id(t1_id), + CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE TABLE t3 ( + id INT PRIMARY KEY, + t2_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t2_id(t2_id) +); + +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); + +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); + + +# +# ALTER TABLE t3 and wait for it to reach node_2 +# +--let $fk_parent_query = ALTER TABLE t3 ADD CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE +# +# Issue a UPDATE to table that references t1 +# Notice that we update field f2, not the primary key, +# and not foreign key. Bug does not manifest if we update +# one of those fields (because FK keys appended in those cases). +# +--let $fk_child_query = UPDATE t1 SET f2 = 1 WHERE id=2 +--let $fk_mdl_lock_num = 3 +--source galera_multi_level_foreign_key.inc + + +# +# Verify Foreign key for referenced table added. +# +--connection node_1 +--let assert_text= Foreign key referenced table found: 2 tables +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 6 +--let assert_select= Foreign key referenced table found: +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t2 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 2 +--let assert_select= Foreign key referenced table found: test.t2 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t3 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 2 +--let assert_select= Foreign key referenced table found: test.t3 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + + +# +# Verify update and drop table has succeded. +# +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM test.t1 where id=2 and f2=1; +--source include/wait_condition.inc + +select * from t1; +select * from t2; +select * from t3; + +--connection node_1 +select * from t1; +select * from t2; +select * from t3; + + +# +# Cleanup +# +DROP TABLE t3, t2, t1; + + +--echo # +--echo # 3. BF-BF conflict on MDL locks between: +--echo # CREATE TABLE t3 (whose parent table are t3 -> t2 -> t1), and +--echo # UPDATE on t1 with t2 referencing t1, and t3 referencing t2. +--echo # + +# +# Setup +# +--connection node_2 +SET GLOBAL wsrep_slave_threads=2; + +CREATE TABLE t1 ( + id INTEGER PRIMARY KEY, + f2 INTEGER +); + +CREATE TABLE t2 ( + id INT PRIMARY KEY, + t1_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t1_id(t1_id), + CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + + +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); + +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); + + +--let $fk_parent_query = CREATE TABLE t3 (id INT PRIMARY KEY, t2_id INT NOT NULL, f2 INTEGER NOT NULL, KEY key_t2_id(t2_id), CONSTRAINT key_t2_id FOREIGN KEY (t2_id) REFERENCES t2 (id) ON UPDATE CASCADE ON DELETE CASCADE) +--let $fk_child_query = UPDATE t1 SET f2 = 1 WHERE id=2 +--let $fk_mdl_lock_num = 3 +--source galera_multi_level_foreign_key.inc + + +# +# Verify Foreign key for referenced table added. +# +--connection node_1 +--let assert_text= Foreign key referenced table found: 2 tables +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 8 +--let assert_select= Foreign key referenced table found: +--let $assert_only_after = CURRENT_TEST: +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t2 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 3 +--let assert_select= Foreign key referenced table found: test.t2 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t3 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 3 +--let assert_select= Foreign key referenced table found: test.t3 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + + +# +# Verify update and drop table has succeded. +# +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM test.t1 where id=2 and f2=1; +--source include/wait_condition.inc + +select * from t1; +select * from t2; +select * from t3; + +--connection node_1 +select * from t1; +select * from t2; +select * from t3; + + +# +# Cleanup +# +DROP TABLE t3, t2, t1; + + +--echo # +--echo # 4. BF-BF conflict on MDL locks between: +--echo # OPTIMIZE TABLE t2 (whose parent table are t2 -> t1), and +--echo # UPDATE on t1. +--echo # + +# +# Setup +# +--connection node_2 +SET GLOBAL wsrep_slave_threads=2; + +CREATE TABLE t1 ( + id INTEGER PRIMARY KEY, + f2 INTEGER +); + +CREATE TABLE t2 ( + id INT PRIMARY KEY, + t1_id INT NOT NULL, + f2 INTEGER NOT NULL, + KEY key_t1_id(t1_id), + CONSTRAINT key_t1_id FOREIGN KEY (t1_id) REFERENCES t1 (id) ON UPDATE CASCADE ON DELETE CASCADE +); + + +INSERT INTO t1 VALUES (1,0); +INSERT INTO t1 VALUES (2,0); + +INSERT INTO t2 VALUES (1,1,1234); +INSERT INTO t2 VALUES (2,2,1234); + + +--let $fk_parent_query = OPTIMIZE TABLE t2 +--let $fk_child_query = UPDATE t1 SET f2 = 1 WHERE id=2 +--let $fk_mdl_lock_num = 2 +--source galera_multi_level_foreign_key.inc + + +# +# Verify Foreign key for referenced table added. +# +--connection node_1 +--let assert_text= Foreign key referenced table found: 1 tables +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 9 +--let assert_select= Foreign key referenced table found: +--let $assert_only_after = CURRENT_TEST: +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + +--let assert_text= Foreign key referenced table found: test.t2 +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let assert_count= 4 +--let assert_select= Foreign key referenced table found: test.t2 +--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_update +--source include/assert_grep.inc + + +# +# Verify update has succeded. +# +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM test.t1 where id=2 and f2=1; +--source include/wait_condition.inc + +select * from t1; +select * from t2; + +--connection node_1 +select * from t1; +select * from t2; + + +# +# Cleanup +# +DROP TABLE t2, t1; diff --git a/mysql-test/suite/galera/t/galera_multi_level_foreign_key.inc b/mysql-test/suite/galera/t/galera_multi_level_foreign_key.inc new file mode 100644 index 0000000000000..2eb31f7e57783 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_multi_level_foreign_key.inc @@ -0,0 +1,61 @@ +# +# Execute parent query on node_1 and wait for it to reach node_2 +# +--connection node_2 +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; + +--connection node_1 +--eval $fk_parent_query + +--connection node_2 +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; + +SET SESSION wsrep_sync_wait = 0; +--let $expected_apply_waits = query_get_value("SHOW STATUS LIKE 'wsrep_apply_waits'", Value, 1) +--let $expected_apply_waits = `select $expected_apply_waits + 1` + + +# +# Execute child query on node_1. +# If bug is present, expect the wait condition +# to timeout and when the child query applies, it +# will be granted a MDL lock on parent table. +# When resumed, the parent query will +# also try to acquire MDL lock on parent table, +# causing a BF-BF conflict on that MDL lock. +# +--connection node_1 +SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table'; +START TRANSACTION; +--eval $fk_child_query +--let $wait_condition = SELECT COUNT(*) = $fk_mdl_lock_num FROM performance_schema.metadata_locks WHERE OBJECT_SCHEMA='test' AND LOCK_STATUS="GRANTED" +--source include/wait_condition.inc +COMMIT; + + +# +# Expect the child query to depend on the parent query, +# therefore it should wait for the parent query to +# finish before it can be applied. +# +--connection node_2 +--let $status_var = wsrep_apply_waits +--let $status_var_value = $expected_apply_waits +--source include/wait_for_status_var.inc + +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; + + +# +# Cleanup +# +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; + +--connection node_1 +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL DEBUG_DBUG = ""; +SET GLOBAL wsrep_slave_threads=DEFAULT; + diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 53663a6b90ea1..5f7ee9fca853c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4718,6 +4718,7 @@ prepare_fk_prelocking_list(THD *thd, Query_tables_list *prelocking_ctx, FOREIGN_KEY_INFO *fk; Query_arena *arena, backup; TABLE *table= table_list->table; + bool error= FALSE; arena= thd->activate_stmt_arena_if_needed(&backup); @@ -4755,10 +4756,24 @@ prepare_fk_prelocking_list(THD *thd, Query_tables_list *prelocking_ctx, table_list->belong_to_view, op, &prelocking_ctx->query_tables_last, table_list->for_insert_data); + +#ifdef WITH_WSREP + /* + Append table level shared key for the referenced/foreign table for: + - statement that updates existing rows (UPDATE, multi-update) + - statement that deletes existing rows (DELETE, DELETE_MULTI) + This is done to avoid potential MDL conflicts with concurrent DDLs. + */ + if (wsrep_foreign_key_append(thd, fk)) + { + error= TRUE; + break; + } +#endif // WITH_WSREP } if (arena) thd->restore_active_arena(arena, &backup); - DBUG_RETURN(FALSE); + DBUG_RETURN(error); } /** diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 28e734105cd2a..823e544828cf6 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2355,18 +2355,8 @@ static bool check_prepared_statement(Prepared_statement *stmt) } #ifdef WITH_WSREP - if (wsrep_sync_wait(thd, sql_command)) - goto error; - if (!stmt->is_sql_prepare()) - { - wsrep_after_command_before_result(thd); - if (wsrep_current_error(thd)) - { - wsrep_override_error(thd, wsrep_current_error(thd), - wsrep_current_error_status(thd)); - goto error; - } - } + if (wsrep_sync_wait(thd, sql_command)) + goto error; #endif switch (sql_command) { case SQLCOM_REPLACE: @@ -2612,6 +2602,20 @@ static bool check_prepared_statement(Prepared_statement *stmt) } break; } + +#ifdef WITH_WSREP + if (!stmt->is_sql_prepare()) + { + wsrep_after_command_before_result(thd); + if (wsrep_current_error(thd)) + { + wsrep_override_error(thd, wsrep_current_error(thd), + wsrep_current_error_status(thd)); + goto error; + } + } +#endif + if (res == 0) { if (!stmt->is_sql_prepare()) diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 22d66379835f9..582313e9bc589 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -3664,3 +3664,36 @@ bool wsrep_table_list_has_non_temp_tables(THD *thd, TABLE_LIST *tables) } return false; } + +bool wsrep_foreign_key_append(THD *thd, FOREIGN_KEY_INFO *fk) +{ + if (WSREP(thd) && !thd->wsrep_applier && + wsrep_is_active(thd) && + (sql_command_flags[thd->lex->sql_command] & + (CF_UPDATES_DATA | CF_DELETES_DATA))) + { + wsrep::key key(wsrep::key::shared); + key.append_key_part(fk->foreign_db->str, fk->foreign_db->length); + key.append_key_part(fk->foreign_table->str, fk->foreign_table->length); + + if (thd->wsrep_cs().append_key(key)) + { + WSREP_ERROR("Appending table key failed: %s", + wsrep_thd_query(thd)); + sql_print_information("Failed Foreign key referenced table found: " + "%s.%s", + fk->foreign_db->str, + fk->foreign_table->str); + return true; + } + + DBUG_EXECUTE_IF( + "wsrep_print_foreign_keys_table", + sql_print_information("Foreign key referenced table found: %s.%s", + fk->foreign_db->str, + fk->foreign_table->str); + ); + } + + return false; +} diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 1c8220fd035a0..57bae6fe8ad46 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -583,6 +583,16 @@ void wsrep_ready_set(bool ready_value); */ bool wsrep_table_list_has_non_temp_tables(THD *thd, TABLE_LIST *tables); +/** + * Append foreign key to wsrep. + * + * @param thd Thread object + * @param fk Foreign Key Info + * + * @return true if error, otherwise false. + */ +bool wsrep_foreign_key_append(THD *thd, FOREIGN_KEY_INFO *fk); + #else /* !WITH_WSREP */ /* These macros are needed to compile MariaDB without WSREP support