Skip to content

Commit 49791cb

Browse files
sjaakolajanlindstrom
authored andcommitted
10.4-MDEV-27275 CREATE TABLE with FK not safe for PA
This commit contains a fix, where the replication write set for a CREATE TABLE will contain, as certification keys, table names for all FK references. With this, all DML for the FK parent tables will conflict with the CREATE TABLE statement. There is also new test galera.MDEV-27276 to verify the fix. Reviewed-by: Jan Lindström <jan.lindstrom@mariadb.com>
1 parent 4b25790 commit 49791cb

File tree

10 files changed

+96
-10
lines changed

10 files changed

+96
-10
lines changed

include/wsrep.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
//#define WSREP_WARN(...)
6969
#define WSREP_ERROR(...)
7070
#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) do { } while(0)
71-
#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_)
71+
#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, fk_tables_)
7272
#define WSREP_TO_ISOLATION_END
7373
#define WSREP_TO_ISOLATION_BEGIN_WRTCHK(db_, table_, table_list_)
7474
#define WSREP_SYNC_WAIT(thd_, before_)

mysql-test/suite/galera/r/MDEV-22051.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ INSERT INTO t1 VALUES (1);
1818
ERROR HY000: Can't execute the query because you have a conflicting read lock
1919
UNLOCK TABLES;
2020
DROP TABLE t1;
21+
CALL mtr.add_suppression("CREATE TABLE isolation failure");
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
connection node_2;
2+
connection node_1;
3+
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
4+
connection node_1;
5+
CREATE TABLE p (id INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
6+
connection node_1;
7+
SET AUTOCOMMIT=ON;
8+
START TRANSACTION;
9+
INSERT INTO p VALUES(1,0);
10+
connection node_1a;
11+
SET SESSION wsrep_sync_wait = 0;
12+
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
13+
connection node_2;
14+
CREATE TABLE c(id INT NOT NULL PRIMARY KEY, p_id INT, FOREIGN KEY (p_id) REFERENCES p(id) ON DELETE CASCADE) ENGINE=InnoDB;
15+
connection node_1a;
16+
SET SESSION wsrep_on = 0;
17+
SET SESSION wsrep_on = 1;
18+
SET GLOBAL wsrep_provider_options = 'dbug=';
19+
SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
20+
connection node_1;
21+
COMMIT;
22+
connection node_1a;
23+
SET SESSION wsrep_on = 0;
24+
SET SESSION wsrep_on = 1;
25+
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
26+
SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
27+
SET GLOBAL wsrep_provider_options = 'dbug=';
28+
connection node_1;
29+
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
30+
connection node_2;
31+
SELECT * FROM p;
32+
id f2
33+
SELECT * FROM c;
34+
id p_id
35+
DROP TABLE c;
36+
DROP TABLE p;

mysql-test/suite/galera/r/galera_split_brain.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ connection node_1;
44
connection node_2;
55
call mtr.add_suppression("WSREP: TO isolation failed for: ");
66
connection node_1;
7+
call mtr.add_suppression("CREATE TABLE isolation failure");
78
connection node_2;
89
Killing server ...
910
connection node_1;

mysql-test/suite/galera/t/MDEV-22051.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ INSERT INTO t1 VALUES (1);
3131
UNLOCK TABLES;
3232

3333
DROP TABLE t1;
34+
CALL mtr.add_suppression("CREATE TABLE isolation failure");
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--source include/galera_cluster.inc
2+
--source include/have_innodb.inc
3+
--source include/have_debug_sync.inc
4+
--source include/galera_have_debug_sync.inc
5+
6+
#
7+
# Testing CREATE TABLE statement having foreign key constraint,
8+
# while having concurrent DML for the referenced parent table.
9+
#
10+
# The replication of CREATE TABLE should have all referenced table names
11+
# appended in the key set, and DML on the parent table should be considered as
12+
# conflicting.
13+
#
14+
# There are related test scenarios in test mysql-wsrep#332, where a regular table
15+
# is altered by adding new foreign key reference.
16+
#
17+
# We use concurrency facility of test MW-369 to setup the conflict between DDL and DML
18+
#
19+
20+
# Open connection node_1a here, MW-369.inc will use it later
21+
--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
22+
23+
# create FK parent table
24+
--connection node_1
25+
CREATE TABLE p (id INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
26+
27+
# setup conflicting queries
28+
--let $mw_369_parent_query = INSERT INTO p VALUES(1,0)
29+
--let $mw_369_child_query = CREATE TABLE c(id INT NOT NULL PRIMARY KEY, p_id INT, FOREIGN KEY (p_id) REFERENCES p(id) ON DELETE CASCADE) ENGINE=InnoDB
30+
31+
# execute above queries through separate nodes
32+
--source MW-369.inc
33+
34+
# Expect certification failure
35+
--connection node_1
36+
--error ER_LOCK_DEADLOCK
37+
--reap
38+
39+
--connection node_2
40+
SELECT * FROM p;
41+
SELECT * FROM c;
42+
43+
DROP TABLE c;
44+
DROP TABLE p;

mysql-test/suite/galera/t/galera_split_brain.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ call mtr.add_suppression("WSREP: TO isolation failed for: ");
1717

1818
--connection node_1
1919
--let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
20+
call mtr.add_suppression("CREATE TABLE isolation failure");
2021

2122
--connection node_2
2223
--source include/kill_galera.inc

mysql-test/suite/galera/t/mysql-wsrep#332.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,4 @@ SELECT * FROM c;
111111
DROP TABLE c;
112112
DROP TABLE p1;
113113
DROP TABLE p2;
114+

sql/sql_table.cc

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11624,7 +11624,14 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
1162411624
(!thd->is_current_stmt_binlog_format_row() ||
1162511625
!create_info.tmp_table()))
1162611626
{
11627-
WSREP_TO_ISOLATION_BEGIN(create_table->db.str, create_table->table_name.str, NULL);
11627+
#ifdef WITH_WSREP
11628+
WSREP_TO_ISOLATION_BEGIN_ALTER(create_table->db.str, create_table->table_name.str,
11629+
first_table, &alter_info, NULL)
11630+
{
11631+
WSREP_WARN("CREATE TABLE isolation failure");
11632+
DBUG_RETURN(true);
11633+
}
11634+
#endif /* WITH_WSREP */
1162811635
}
1162911636
/* Regular CREATE TABLE */
1163011637
res= mysql_create_table(thd, create_table, &create_info, &alter_info);
@@ -11646,9 +11653,4 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
1164611653

1164711654
end_with_restore_list:
1164811655
DBUG_RETURN(res);
11649-
11650-
#ifdef WITH_WSREP
11651-
wsrep_error_label:
11652-
DBUG_RETURN(true);
11653-
#endif
1165411656
}

sql/wsrep_mysqld.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,7 @@ static bool wsrep_prepare_keys_for_isolation(THD* thd,
14051405
goto err;
14061406
}
14071407

1408-
if (alter_info && (alter_info->flags & (ALTER_ADD_FOREIGN_KEY)))
1408+
if (alter_info)
14091409
{
14101410
if (!wsrep_prepare_keys_for_alter_add_fk(table_list->db.str, alter_info, ka))
14111411
goto err;
@@ -1538,7 +1538,7 @@ wsrep::key_array wsrep_prepare_keys_for_toi(const char* db,
15381538
ret.push_back(wsrep_prepare_key_for_toi(table->db.str, table->table_name.str,
15391539
wsrep::key::exclusive));
15401540
}
1541-
if (alter_info && (alter_info->flags & ALTER_ADD_FOREIGN_KEY))
1541+
if (alter_info)
15421542
{
15431543
wsrep::key_array fk(wsrep_prepare_keys_for_alter_add_fk(table_list->db.str, alter_info));
15441544
if (!fk.empty())
@@ -1803,7 +1803,6 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
18031803
switch (lex->sql_command)
18041804
{
18051805
case SQLCOM_CREATE_TABLE:
1806-
DBUG_ASSERT(!table_list);
18071806
if (thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
18081807
{
18091808
return false;

0 commit comments

Comments
 (0)