mariadb/mysql-test/suite/galera/t/galera_fk_cascade_delete.test
sjaakola c1846c4fcf MDEV-26803 PA unsafety with FK cascade delete operation
This commit has a mtr test where two two transactions delete a row from
two separate tables, which will cascade a FK delete for the same row in
a third table. Second replica node is configured with 2 applier threads,
and the test will fail if these two transactions are applied in parallel.

The actual fix, in this commit, is to mark a transaction as unsafe for
parallel applying when it traverses into cascade delete operation.

Reviewed-by: Jan Lindström <jan.lindstrom@mariadb.com>
2021-12-17 09:38:23 +02:00

256 lines
7.2 KiB
Text

#
# Test Foreign Key Cascading DELETEs
#
--source include/galera_cluster.inc
--echo #
--echo # test phase with cascading foreign key through 3 tables
--echo #
--connection node_1
CREATE TABLE grandparent (
id INT NOT NULL PRIMARY KEY
) ENGINE=InnoDB;
CREATE TABLE parent (
id INT NOT NULL PRIMARY KEY,
grandparent_id INT,
FOREIGN KEY (grandparent_id)
REFERENCES grandparent(id)
ON DELETE CASCADE
) ENGINE=InnoDB;
CREATE TABLE child (
id INT NOT NULL PRIMARY KEY,
parent_id INT,
FOREIGN KEY (parent_id)
REFERENCES parent(id)
ON DELETE CASCADE
) ENGINE=InnoDB;
INSERT INTO grandparent VALUES (1),(2);
INSERT INTO parent VALUES (1,1), (2,2);
INSERT INTO child VALUES (1,1), (2,2);
--connection node_2
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'grandparent'
--source include/wait_condition.inc
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'parent'
--source include/wait_condition.inc
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'child'
--source include/wait_condition.inc
--let $wait_condition = SELECT COUNT(*) = 2 FROM child;
--source include/wait_condition.inc
--let $wait_condition = SELECT COUNT(*) = 2 FROM parent;
--source include/wait_condition.inc
--let $wait_condition = SELECT COUNT(*) = 2 FROM grandparent;
--source include/wait_condition.inc
DELETE FROM grandparent WHERE id = 1;
SELECT * FROM grandparent;
SELECT * FROM parent;
SELECT * FROM child;
--connection node_1
--let $wait_condition = SELECT COUNT(*) = 1 FROM child;
--source include/wait_condition.inc
--let $wait_condition = SELECT COUNT(*) = 1 FROM parent;
--source include/wait_condition.inc
--let $wait_condition = SELECT COUNT(*) = 1 FROM grandparent;
--source include/wait_condition.inc
SELECT * FROM grandparent;
SELECT * FROM parent;
SELECT * FROM child;
DROP TABLE child;
DROP TABLE parent;
DROP TABLE grandparent;
--echo
--echo Scenario 2, testing PA applying with FK cascade delete
--echo
CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
f2 INTEGER,
CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
ON DELETE CASCADE,
CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1)
ON DELETE CASCADE);
--let $count = 100
--disable_query_log
while ($count)
{
--eval INSERT INTO p1 VALUES ($count, 0);
--eval INSERT INTO p2 VALUES ($count, 0);
--eval INSERT INTO c VALUES ($count, $count, $count, 0);
--dec $count
}
--connection node_2
set global wsrep_slave_threads=2;
--connection node_1
--let $count = 100
while ($count)
{
--eval DELETE FROM p2 WHERE f1=$count;
--eval DELETE FROM p1 WHERE f1=$count;
--dec $count
}
--enable_query_log
--connection node_2
set global wsrep_slave_threads=DEFAULT;
SELECT * FROM p1;
SELECT * FROM p2;
SELECT * FROM c;
--connection node_1
DROP TABLE c;
DROP TABLE p1,p2;
--echo
--echo Scenario 4, testing PA applying with FK cascade delete on
--echo more than one level
--echo
CREATE TABLE gp1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE gp2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
f2 INTEGER,
CONSTRAINT pfk_3 FOREIGN KEY (p1_id) REFERENCES gp1 (f1)
ON DELETE CASCADE
) ENGINE=INNODB;
CREATE TABLE p2 (f1 INTEGER PRIMARY KEY,p1_id INTEGER, p2_id INTEGER,
f2 INTEGER,
CONSTRAINT pfk_4 FOREIGN KEY (p1_id) REFERENCES gp2 (f1)
ON DELETE CASCADE
) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
f2 INTEGER,
CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
ON DELETE CASCADE,
CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1)
ON DELETE CASCADE) ENGINE=INNODB;
--let $count = 100
--disable_query_log
while ($count)
{
--eval INSERT INTO gp1 VALUES ($count, 0);
--eval INSERT INTO gp2 VALUES ($count, 0);
--eval INSERT INTO p1 VALUES ($count, $count, $count, 0);
--eval INSERT INTO p2 VALUES ($count, $count, $count, 0);
--eval INSERT INTO c VALUES ($count, $count, $count, 0);
--dec $count
}
--connection node_2
set global wsrep_slave_threads=2;
--connection node_1
--let $count = 100
while ($count)
{
--eval DELETE FROM gp1 WHERE f1=$count;
--eval DELETE FROM gp2 WHERE f1=$count;
--dec $count
}
--enable_query_log
--connection node_2
set global wsrep_slave_threads=DEFAULT;
SELECT * FROM gp1;
SELECT * FROM gp2;
SELECT * FROM p1;
SELECT * FROM p2;
SELECT * FROM c;
--connection node_1
DROP TABLE c;
DROP TABLE p1,p2;
DROP TABLE gp1,gp2;
--echo
--echo Scenario 3, testing PA applying with FK cascade delete on
--echo more than one level in a diamond topology
--echo
CREATE TABLE ggp1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE gp1 (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
f2 INTEGER,
CONSTRAINT pfk_6 FOREIGN KEY (p1_id) REFERENCES ggp1 (f1)
ON DELETE CASCADE
) ENGINE=INNODB;
CREATE TABLE gp2 (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
f2 INTEGER,
CONSTRAINT pfk_5 FOREIGN KEY (p1_id) REFERENCES ggp1 (f1)
ON DELETE CASCADE
) ENGINE=INNODB;
CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
f2 INTEGER,
CONSTRAINT pfk_3 FOREIGN KEY (p1_id) REFERENCES gp1 (f1)
ON DELETE CASCADE
) ENGINE=INNODB;
CREATE TABLE p2 (f1 INTEGER PRIMARY KEY,p1_id INTEGER, p2_id INTEGER,
f2 INTEGER,
CONSTRAINT pfk_4 FOREIGN KEY (p1_id) REFERENCES gp2 (f1)
ON DELETE CASCADE
) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
f2 INTEGER,
CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
ON DELETE CASCADE,
CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1)
ON DELETE CASCADE) ENGINE=INNODB;
--let $count = 100
--disable_query_log
while ($count)
{
--eval INSERT INTO ggp1 VALUES ($count, 0);
--eval INSERT INTO gp1 VALUES ($count, $count, $count, 0);
--eval INSERT INTO gp2 VALUES ($count, $count, $count, 0);
--eval INSERT INTO p1 VALUES ($count, $count, $count, 0);
--eval INSERT INTO p2 VALUES ($count, $count, $count, 0);
--eval INSERT INTO c VALUES ($count, $count, $count, 0);
--dec $count
}
--connection node_2
set global wsrep_slave_threads=2;
--connection node_1
--let $count = 100
while ($count)
{
--eval DELETE FROM ggp1 WHERE f1=$count;
--dec $count
}
--enable_query_log
--connection node_2
set global wsrep_slave_threads=DEFAULT;
SELECT * FROM ggp1;
SELECT * FROM gp2;
SELECT * FROM gp1;
SELECT * FROM p1;
SELECT * FROM p2;
SELECT * FROM c;
--connection node_1
DROP TABLE c;
DROP TABLE p1,p2;
DROP TABLE gp1,gp2;
DROP TABLE ggp1;