Commit 49791cbc authored by sjaakola's avatar sjaakola Committed by Jan Lindström

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: default avatarJan Lindström <jan.lindstrom@mariadb.com>
parent 4b25790e
......@@ -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_)
......
......@@ -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");
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;
......@@ -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;
......
......@@ -31,3 +31,4 @@ INSERT INTO t1 VALUES (1);
UNLOCK TABLES;
DROP TABLE t1;
CALL mtr.add_suppression("CREATE TABLE isolation failure");
--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;
......@@ -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
......
......@@ -111,3 +111,4 @@ SELECT * FROM c;
DROP TABLE c;
DROP TABLE p1;
DROP TABLE p2;
......@@ -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
}
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment