summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsjaakola <seppo.jaakola@iki.fi>2021-12-15 22:29:32 +0200
committerJan Lindström <jan.lindstrom@mariadb.com>2021-12-20 13:34:54 +0200
commit49791cbc6f76c4f4c1bb436dbe26cec6177ee279 (patch)
tree53e914744200b518e5ba751de70001c0b660819f
parent4b25790eb3d09404230bb873d3e963b1eb600974 (diff)
downloadmariadb-git-49791cbc6f76c4f4c1bb436dbe26cec6177ee279.tar.gz
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>
-rw-r--r--include/wsrep.h2
-rw-r--r--mysql-test/suite/galera/r/MDEV-22051.result1
-rw-r--r--mysql-test/suite/galera/r/MDEV-27276.result36
-rw-r--r--mysql-test/suite/galera/r/galera_split_brain.result1
-rw-r--r--mysql-test/suite/galera/t/MDEV-22051.test1
-rw-r--r--mysql-test/suite/galera/t/MDEV-27276.test44
-rw-r--r--mysql-test/suite/galera/t/galera_split_brain.test1
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#332.test1
-rw-r--r--sql/sql_table.cc14
-rw-r--r--sql/wsrep_mysqld.cc5
10 files changed, 96 insertions, 10 deletions
diff --git a/include/wsrep.h b/include/wsrep.h
index 2a9036956cc..1b645207f00 100644
--- a/include/wsrep.h
+++ b/include/wsrep.h
@@ -68,7 +68,7 @@
//#define WSREP_WARN(...)
#define WSREP_ERROR(...)
#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) do { } while(0)
-#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_)
+#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_, fk_tables_)
#define WSREP_TO_ISOLATION_END
#define WSREP_TO_ISOLATION_BEGIN_WRTCHK(db_, table_, table_list_)
#define WSREP_SYNC_WAIT(thd_, before_)
diff --git a/mysql-test/suite/galera/r/MDEV-22051.result b/mysql-test/suite/galera/r/MDEV-22051.result
index 0e9756dd20e..229e26fd32a 100644
--- a/mysql-test/suite/galera/r/MDEV-22051.result
+++ b/mysql-test/suite/galera/r/MDEV-22051.result
@@ -18,3 +18,4 @@ INSERT INTO t1 VALUES (1);
ERROR HY000: Can't execute the query because you have a conflicting read lock
UNLOCK TABLES;
DROP TABLE t1;
+CALL mtr.add_suppression("CREATE TABLE isolation failure");
diff --git a/mysql-test/suite/galera/r/MDEV-27276.result b/mysql-test/suite/galera/r/MDEV-27276.result
new file mode 100644
index 00000000000..7e5b29fad7e
--- /dev/null
+++ b/mysql-test/suite/galera/r/MDEV-27276.result
@@ -0,0 +1,36 @@
+connection node_2;
+connection node_1;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1;
+CREATE TABLE p (id INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+connection node_1;
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+INSERT INTO p VALUES(1,0);
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+CREATE TABLE c(id INT NOT NULL PRIMARY KEY, p_id INT, FOREIGN KEY (p_id) REFERENCES p(id) ON DELETE CASCADE) ENGINE=InnoDB;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_2;
+SELECT * FROM p;
+id f2
+SELECT * FROM c;
+id p_id
+DROP TABLE c;
+DROP TABLE p;
diff --git a/mysql-test/suite/galera/r/galera_split_brain.result b/mysql-test/suite/galera/r/galera_split_brain.result
index 08f9060d2a9..374fb31afd1 100644
--- a/mysql-test/suite/galera/r/galera_split_brain.result
+++ b/mysql-test/suite/galera/r/galera_split_brain.result
@@ -4,6 +4,7 @@ connection node_1;
connection node_2;
call mtr.add_suppression("WSREP: TO isolation failed for: ");
connection node_1;
+call mtr.add_suppression("CREATE TABLE isolation failure");
connection node_2;
Killing server ...
connection node_1;
diff --git a/mysql-test/suite/galera/t/MDEV-22051.test b/mysql-test/suite/galera/t/MDEV-22051.test
index b7332c47d69..a5f05f5cf3b 100644
--- a/mysql-test/suite/galera/t/MDEV-22051.test
+++ b/mysql-test/suite/galera/t/MDEV-22051.test
@@ -31,3 +31,4 @@ INSERT INTO t1 VALUES (1);
UNLOCK TABLES;
DROP TABLE t1;
+CALL mtr.add_suppression("CREATE TABLE isolation failure");
diff --git a/mysql-test/suite/galera/t/MDEV-27276.test b/mysql-test/suite/galera/t/MDEV-27276.test
new file mode 100644
index 00000000000..1c589c9e85b
--- /dev/null
+++ b/mysql-test/suite/galera/t/MDEV-27276.test
@@ -0,0 +1,44 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+--source include/galera_have_debug_sync.inc
+
+#
+# Testing CREATE TABLE statement having foreign key constraint,
+# while having concurrent DML for the referenced parent table.
+#
+# The replication of CREATE TABLE should have all referenced table names
+# appended in the key set, and DML on the parent table should be considered as
+# conflicting.
+#
+# There are related test scenarios in test mysql-wsrep#332, where a regular table
+# is altered by adding new foreign key reference.
+#
+# We use concurrency facility of test MW-369 to setup the conflict between DDL and DML
+#
+
+# Open connection node_1a here, MW-369.inc will use it later
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+# create FK parent table
+--connection node_1
+CREATE TABLE p (id INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+
+# setup conflicting queries
+--let $mw_369_parent_query = INSERT INTO p VALUES(1,0)
+--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
+
+# execute above queries through separate nodes
+--source MW-369.inc
+
+# Expect certification failure
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_2
+SELECT * FROM p;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p;
diff --git a/mysql-test/suite/galera/t/galera_split_brain.test b/mysql-test/suite/galera/t/galera_split_brain.test
index ccdfd3fd506..b1ea9c9b4ab 100644
--- a/mysql-test/suite/galera/t/galera_split_brain.test
+++ b/mysql-test/suite/galera/t/galera_split_brain.test
@@ -17,6 +17,7 @@ call mtr.add_suppression("WSREP: TO isolation failed for: ");
--connection node_1
--let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
+call mtr.add_suppression("CREATE TABLE isolation failure");
--connection node_2
--source include/kill_galera.inc
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#332.test b/mysql-test/suite/galera/t/mysql-wsrep#332.test
index 674a5c3de52..e216dfe79d4 100644
--- a/mysql-test/suite/galera/t/mysql-wsrep#332.test
+++ b/mysql-test/suite/galera/t/mysql-wsrep#332.test
@@ -111,3 +111,4 @@ SELECT * FROM c;
DROP TABLE c;
DROP TABLE p1;
DROP TABLE p2;
+
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 4409360cd8f..9a51ce49248 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -11624,7 +11624,14 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
(!thd->is_current_stmt_binlog_format_row() ||
!create_info.tmp_table()))
{
- WSREP_TO_ISOLATION_BEGIN(create_table->db.str, create_table->table_name.str, NULL);
+#ifdef WITH_WSREP
+ WSREP_TO_ISOLATION_BEGIN_ALTER(create_table->db.str, create_table->table_name.str,
+ first_table, &alter_info, NULL)
+ {
+ WSREP_WARN("CREATE TABLE isolation failure");
+ DBUG_RETURN(true);
+ }
+#endif /* WITH_WSREP */
}
/* Regular CREATE TABLE */
res= mysql_create_table(thd, create_table, &create_info, &alter_info);
@@ -11646,9 +11653,4 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
end_with_restore_list:
DBUG_RETURN(res);
-
-#ifdef WITH_WSREP
-wsrep_error_label:
- DBUG_RETURN(true);
-#endif
}
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index a2856b5034d..1e4eff831c2 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -1405,7 +1405,7 @@ static bool wsrep_prepare_keys_for_isolation(THD* thd,
goto err;
}
- if (alter_info && (alter_info->flags & (ALTER_ADD_FOREIGN_KEY)))
+ if (alter_info)
{
if (!wsrep_prepare_keys_for_alter_add_fk(table_list->db.str, alter_info, ka))
goto err;
@@ -1538,7 +1538,7 @@ wsrep::key_array wsrep_prepare_keys_for_toi(const char* db,
ret.push_back(wsrep_prepare_key_for_toi(table->db.str, table->table_name.str,
wsrep::key::exclusive));
}
- if (alter_info && (alter_info->flags & ALTER_ADD_FOREIGN_KEY))
+ if (alter_info)
{
wsrep::key_array fk(wsrep_prepare_keys_for_alter_add_fk(table_list->db.str, alter_info));
if (!fk.empty())
@@ -1803,7 +1803,6 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
switch (lex->sql_command)
{
case SQLCOM_CREATE_TABLE:
- DBUG_ASSERT(!table_list);
if (thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
{
return false;