diff --git a/mysql-test/suite/galera/r/mwb-1789-alter.result b/mysql-test/suite/galera/r/mwb-1789-alter.result new file mode 100644 index 0000000000000..1b88cf2130354 --- /dev/null +++ b/mysql-test/suite/galera/r/mwb-1789-alter.result @@ -0,0 +1,41 @@ +connection node_2; +connection node_1; +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; +UPDATE t1 SET f2 = 1 WHERE id=2; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET GLOBAL DEBUG_DBUG="RESET"; +SET GLOBAL wsrep_slave_threads=DEFAULT; +DROP TABLE t3, t2, t1; diff --git a/mysql-test/suite/galera/r/mwb-1789-create.result b/mysql-test/suite/galera/r/mwb-1789-create.result new file mode 100644 index 0000000000000..e879456e99562 --- /dev/null +++ b/mysql-test/suite/galera/r/mwb-1789-create.result @@ -0,0 +1,40 @@ +connection node_2; +connection node_1; +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; +UPDATE t1 SET f2 = 1 WHERE id=2; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET GLOBAL DEBUG_DBUG="RESET"; +SET GLOBAL wsrep_slave_threads=DEFAULT; +DROP TABLE t3, t2, t1; diff --git a/mysql-test/suite/galera/r/mwb-1789-drop-fk2.result b/mysql-test/suite/galera/r/mwb-1789-drop-fk2.result new file mode 100644 index 0000000000000..bb2ccbe7ccdcf --- /dev/null +++ b/mysql-test/suite/galera/r/mwb-1789-drop-fk2.result @@ -0,0 +1,43 @@ +connection node_2; +connection node_1; +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), +CONSTRAINT key_t2_id 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,1234); +INSERT INTO t2 VALUES (2,2,1234); +INSERT INTO t3 VALUES (1,1,1234); +INSERT INTO t3 VALUES (2,2,1234); +connection node_2; +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; +connection node_1; +DROP TABLE t3; +connection node_2; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; +SET SESSION wsrep_sync_wait = 0; +connection node_1; +UPDATE t1 SET f2 = 1 WHERE id=2; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET GLOBAL DEBUG_DBUG="RESET"; +SET GLOBAL wsrep_slave_threads=DEFAULT; +DROP TABLE t2, t1; diff --git a/mysql-test/suite/galera/r/mwb-1789-drop.result b/mysql-test/suite/galera/r/mwb-1789-drop.result new file mode 100644 index 0000000000000..b09faf14703df --- /dev/null +++ b/mysql-test/suite/galera/r/mwb-1789-drop.result @@ -0,0 +1,32 @@ +connection node_2; +connection node_1; +connection node_2; +SET GLOBAL wsrep_slave_threads=2; +CREATE TABLE t1 ( +id INTEGER PRIMARY KEY, +f2 INTEGER); +CREATE TABLE t2 ( +f1 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; +DROP TABLE t2; +connection node_2; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; +SET SESSION wsrep_sync_wait = 0; +connection node_1; +UPDATE t1 SET f2 = 1 WHERE id=2; +connection node_2; +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; +SET GLOBAL DEBUG_DBUG="RESET"; +SET GLOBAL wsrep_slave_threads=DEFAULT; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/mwb-1789-alter.test b/mysql-test/suite/galera/t/mwb-1789-alter.test new file mode 100644 index 0000000000000..8ad4a6a9c146a --- /dev/null +++ b/mysql-test/suite/galera/t/mwb-1789-alter.test @@ -0,0 +1,94 @@ +# +# 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. +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +# +# 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 +# +--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; +--let $expected_apply_waits = `SELECT VARIABLE_VALUE+1 FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_apply_waits'` + +# +# 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). +# +--connection node_1 +UPDATE t1 SET f2 = 1 WHERE id=2; + + +# +# Expect the UPDATE to depend on the ALTER TABLE, +# therefore it should wait for the CREAT TABLE to +# finish before it can be applied. +# 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 ALTER TABLE will +# also try to MDL lock t1, causing a BF-BF conflict +# on that MDL lock. +# +--connection node_2 +--let $wait_condition = SELECT VARIABLE_VALUE = $expected_apply_waits FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_apply_waits'; +--source include/wait_condition.inc +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; + + +# +# Cleanup +# +SET GLOBAL DEBUG_DBUG="RESET"; +SET GLOBAL wsrep_slave_threads=DEFAULT; + +DROP TABLE t3, t2, t1; diff --git a/mysql-test/suite/galera/t/mwb-1789-create.test b/mysql-test/suite/galera/t/mwb-1789-create.test new file mode 100644 index 0000000000000..2c95c5a9178a1 --- /dev/null +++ b/mysql-test/suite/galera/t/mwb-1789-create.test @@ -0,0 +1,93 @@ +# +# 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. +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +# +# 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); + +# +# CREATE TABLE t3 and wait for it to reach node_2 +# +--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; +--let $expected_apply_waits = `SELECT VARIABLE_VALUE+1 FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_apply_waits'` + +# +# 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). +# +--connection node_1 +UPDATE t1 SET f2 = 1 WHERE id=2; + + +# +# Expect the UPDATE to depend on the CREATE TABLE, +# therefore it should wait for the CREAT TABLE to +# finish before it can be applied. +# 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 CREATE TABLE will +# also try to MDL lock t1, causing a BF-BF conflict +# on that MDL lock. +# +--connection node_2 +--let $wait_condition = SELECT VARIABLE_VALUE = $expected_apply_waits FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_apply_waits'; +--source include/wait_condition.inc +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; + + +# +# Cleanup +# +SET GLOBAL DEBUG_DBUG="RESET"; +SET GLOBAL wsrep_slave_threads=DEFAULT; + +DROP TABLE t3, t2, t1; diff --git a/mysql-test/suite/galera/t/mwb-1789-drop-fk2.test b/mysql-test/suite/galera/t/mwb-1789-drop-fk2.test new file mode 100644 index 0000000000000..3b5433ce55e8f --- /dev/null +++ b/mysql-test/suite/galera/t/mwb-1789-drop-fk2.test @@ -0,0 +1,99 @@ +# +# BF-BF conflict on MDL locks between: DROP TABLE t2 and UPDATE on t1 +# with t2 referencing t1 +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +# +# 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), + CONSTRAINT key_t2_id 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,1234); +INSERT INTO t2 VALUES (2,2,1234); + +INSERT INTO t3 VALUES (1,1,1234); +INSERT INTO t3 VALUES (2,2,1234); + +# +# DROP TABLE t2 and wait for it to reach node_2 +# +--connection node_2 +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; + +--connection node_1 +DROP TABLE t3; + +--connection node_2 +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; + +SET SESSION wsrep_sync_wait = 0; +--let $expected_apply_waits = `SELECT VARIABLE_VALUE+1 FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_apply_waits'` + +# +# 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). +# +--connection node_1 +UPDATE t1 SET f2 = 1 WHERE id=2; + + +# +# Expect the UPDATE to depend on the DROP, +# therefore it should wait for the DROP to +# finish before it can be applied. +# 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. +# +--connection node_2 +--let $wait_condition = SELECT VARIABLE_VALUE = $expected_apply_waits FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_apply_waits'; +--source include/wait_condition.inc +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; + + +# +# Cleanup +# +SET GLOBAL DEBUG_DBUG="RESET"; +# SET DEBUG_SYNC = 'RESET'; + +SET GLOBAL wsrep_slave_threads=DEFAULT; + +DROP TABLE t2, t1; diff --git a/mysql-test/suite/galera/t/mwb-1789-drop.test b/mysql-test/suite/galera/t/mwb-1789-drop.test new file mode 100644 index 0000000000000..eb43d029748f5 --- /dev/null +++ b/mysql-test/suite/galera/t/mwb-1789-drop.test @@ -0,0 +1,85 @@ +# +# BF-BF conflict on MDL locks between: DROP TABLE t2 and UPDATE on t1 +# with t2 referencing t1 +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +# +# Setup +# +--connection node_2 +SET GLOBAL wsrep_slave_threads=2; + +CREATE TABLE t1 ( + id INTEGER PRIMARY KEY, + f2 INTEGER); + +CREATE TABLE t2 ( + f1 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); + +# +# DROP TABLE t2 and wait for it to reach node_2 +# +--connection node_2 +SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi'; + +--connection node_1 +DROP TABLE t2; + +--connection node_2 +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached"; + +SET SESSION wsrep_sync_wait = 0; +--let $expected_apply_waits = `SELECT VARIABLE_VALUE+1 FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_apply_waits'` + +# +# 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). +# +--connection node_1 +UPDATE t1 SET f2 = 1 WHERE id=2; + + +# +# Expect the UPDATE to depend on the DROP, +# therefore it should wait for the DROP to +# finish before it can be applied. +# 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. +# +--connection node_2 +--let $wait_condition = SELECT VARIABLE_VALUE = $expected_apply_waits FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_apply_waits'; +--source include/wait_condition.inc +SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi'; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi"; + + +# +# Cleanup +# +SET GLOBAL DEBUG_DBUG="RESET"; +# SET DEBUG_SYNC = 'RESET'; + +SET GLOBAL wsrep_slave_threads=DEFAULT; + +DROP TABLE t1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index bc5bf04591d7f..d2ff98bbefa79 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5049,10 +5049,10 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) for (TABLE_LIST *table= all_tables; table; table= table->next_global) { if (!lex->tmp_table() && - (!thd->is_current_stmt_binlog_format_row() || - !is_temporary_table(table))) + (!thd->is_current_stmt_binlog_format_row() || + !is_temporary_table(table))) { - WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables); + WSREP_TO_ISOLATION_BEGIN_DROP(NULL, NULL, all_tables); break; } } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4580f7ae9829f..43a719ffa49ae 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -12313,12 +12313,16 @@ bool Sql_cmd_create_table_like::execute(THD *thd) wsrep_check_sequence(thd, lex->create_info.seq_create_info, used_engine)) DBUG_RETURN(true); - WSREP_TO_ISOLATION_BEGIN_ALTER(create_table->db.str, create_table->table_name.str, - first_table, &alter_info, NULL, &create_info) + wsrep::key_array keys; + if (!wsrep_append_fk_parent_table(thd, create_table, &keys)) { - WSREP_WARN("CREATE TABLE isolation failure"); - res= true; - goto end_with_restore_list; + WSREP_TO_ISOLATION_BEGIN_ALTER(create_table->db.str, create_table->table_name.str, + first_table, &alter_info, &keys, &create_info) + { + WSREP_WARN("CREATE TABLE isolation failure"); + res= true; + goto end_with_restore_list; + } } } // check_engine will set db_type to NULL if e.g. TEMPORARY is diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 6997e5b777018..a97d8645bf706 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1721,6 +1721,83 @@ static void wsrep_keys_free(wsrep_key_arr_t* key_arr) key_arr->keys_len= 0; } +/*! + * @param thd thread + * @param tables list of tables + * @param keys prepared keys + + * @return 0 if parent table append was successful, non-zero otherwise. +*/ +bool +wsrep_append_fk_parent_single_table(THD* thd, TABLE_LIST* tables, + wsrep::key_array* keys) +{ + DBUG_ENTER("wsrep_append_fk_parent_single_table"); + bool fail= false; + TABLE_LIST *table; + + for (table= tables; table; table= table->next_local) + { + if (is_temporary_table(table)) + { + WSREP_DEBUG("Temporary table %s.%s already opened query=%s", table->db.str, + table->table_name.str, wsrep_thd_query(thd)); + DBUG_RETURN(false); + } + } + + uint counter; + if (open_tables(thd, &tables, &counter, MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)) + { + WSREP_DEBUG("Unable to open table for FK checks for %s", wsrep_thd_query(thd)); + fail= true; + goto exit; + } + + for (table= tables; table; table= table->next_local) + { + if (!is_temporary_table(table) && table->table) + { + FOREIGN_KEY_INFO *f_key_info; + List f_key_list; + + table->table->file->get_foreign_key_list(thd, &f_key_list); + List_iterator_fast it(f_key_list); + while ((f_key_info=it++)) + { + keys->push_back(wsrep_prepare_key_for_toi(f_key_info->referenced_db->str, + f_key_info->referenced_table->str, + wsrep::key::shared)); + + TABLE_LIST *tl_tmp= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); + tl_tmp->init_one_table(f_key_info->referenced_db, + f_key_info->referenced_table, 0, TL_READ); + table->next_local = tl_tmp; + if (wsrep_append_fk_parent_single_table(thd, table->next_local, keys)) + { + fail= true; + goto exit; + } + } + } else { + DBUG_RETURN(false); + } + } + +exit: + if (!fail) + { + mysql_mutex_lock(&thd->LOCK_thd_kill); + if (thd->killed) + { + fail= true; + } + mysql_mutex_unlock(&thd->LOCK_thd_kill); + } + + DBUG_RETURN(fail); +} + /*! * @param thd thread * @param tables list of tables @@ -2083,14 +2160,41 @@ wsrep::key wsrep_prepare_key_for_toi(const char* db, const char* table, return ret; } -wsrep::key_array -wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db, - const Alter_info* alter_info) +void +wsrep_prepare_keys_for_drop_table_fk(THD* thd, const char* db_name, + const char* table_name, + wsrep::key_array &ret) + +{ + ret.push_back(wsrep_prepare_key_for_toi(db_name, table_name, + wsrep::key::exclusive)); + thd->release_transactional_locks(); + MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); + TABLE_LIST *table; + TABLE_LIST *tl_tmp= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); + LEX_CSTRING db_name_lex = {db_name, strlen(db_name)}; + LEX_CSTRING table_name_lex = {table_name, strlen(table_name)}; + tl_tmp->init_one_table(&db_name_lex, &table_name_lex, 0, TL_READ); + wsrep_append_fk_parent_single_table(thd, tl_tmp, &ret); + + close_thread_tables(thd); + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + + for (table= tl_tmp; table; table= table->next_local) + { + table->table= NULL; + table->next_global= NULL; + table->mdl_request.ticket= NULL; + } +} + +void +wsrep_prepare_keys_for_alter_add_fk(THD* thd, const char* child_table_db, + List_iterator &key_iterator, + wsrep::key_array &ret) { - wsrep::key_array ret; Key *key; - List_iterator key_iterator(const_cast(alter_info)->key_list); while ((key= key_iterator++)) { if (key->type == Key::FOREIGN_KEY) @@ -2104,39 +2208,77 @@ wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db, } ret.push_back(wsrep_prepare_key_for_toi(db_name, table_name, wsrep::key::exclusive)); + thd->release_transactional_locks(); + MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); + TABLE_LIST *table; + TABLE_LIST *tl_tmp= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); + LEX_CSTRING db_name_lex = {db_name, strlen(db_name)}; + tl_tmp->init_one_table(&db_name_lex, &fk_key->ref_table, 0, TL_READ); + wsrep_append_fk_parent_single_table(thd, tl_tmp, &ret); + + close_thread_tables(thd); + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + + for (table= tl_tmp; table; table= table->next_local) + { + table->table= NULL; + table->next_global= NULL; + table->mdl_request.ticket= NULL; + } } } - return ret; } -wsrep::key_array wsrep_prepare_keys_for_toi(const char *db, +wsrep::key_array wsrep_prepare_keys_for_toi(THD* thd, const char *db, const char *table, const TABLE_LIST *table_list, const Alter_info *alter_info, - const wsrep::key_array *fk_tables) + const wsrep::key_array *fk_tables, + bool is_drop_table_enable= false) { wsrep::key_array ret; + if (db || table) { ret.push_back(wsrep_prepare_key_for_toi(db, table, wsrep::key::exclusive)); } + for (const TABLE_LIST* table= table_list; table; table= table->next_global) { - ret.push_back(wsrep_prepare_key_for_toi(table->db.str, table->table_name.str, + ret.push_back(wsrep_prepare_key_for_toi(table->db.str, + table->table_name.str, wsrep::key::exclusive)); } + if (alter_info) { - wsrep::key_array fk(wsrep_prepare_keys_for_alter_add_fk(table_list->db.str, alter_info)); + wsrep::key_array fk; + List_iterator key_iterator( + const_cast(alter_info)->key_list); + wsrep_prepare_keys_for_alter_add_fk(thd, table_list->db.str, key_iterator, + fk); + if (!fk.empty()) + { + ret.insert(ret.end(), fk.begin(), fk.end()); + } + } + + if (is_drop_table_enable) + { + wsrep::key_array fk; + wsrep_prepare_keys_for_drop_table_fk(thd, table_list->db.str, + table_list->table_name.str, fk); if (!fk.empty()) { ret.insert(ret.end(), fk.begin(), fk.end()); } } + if (fk_tables && !fk_tables->empty()) { ret.insert(ret.end(), fk_tables->begin(), fk_tables->end()); } + return ret; } @@ -2702,7 +2844,8 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, const TABLE_LIST *table_list, const Alter_info *alter_info, const wsrep::key_array *fk_tables, - const HA_CREATE_INFO *create_info) + const HA_CREATE_INFO *create_info, + bool is_drop_table_enable= false) { DBUG_ASSERT(wsrep_OSU_method_get(thd) == WSREP_OSU_TOI); @@ -2733,7 +2876,8 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, struct wsrep_buf buff= { buf, buf_len }; wsrep::key_array key_array= - wsrep_prepare_keys_for_toi(db, table, table_list, alter_info, fk_tables); + wsrep_prepare_keys_for_toi(thd, db, table, table_list, alter_info, + fk_tables, is_drop_table_enable); if (thd->has_read_only_protection()) { @@ -2940,7 +3084,8 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, const TABLE_LIST* table_list, const Alter_info *alter_info, const wsrep::key_array *fk_tables, - const HA_CREATE_INFO *create_info) + const HA_CREATE_INFO *create_info, + bool is_drop_table_enable) { mysql_mutex_lock(&thd->LOCK_thd_kill); const killed_state killed = thd->killed; @@ -3030,7 +3175,7 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, switch (wsrep_OSU_method_get(thd)) { case WSREP_OSU_TOI: ret= wsrep_TOI_begin(thd, db_, table_, table_list, alter_info, fk_tables, - create_info); + create_info, is_drop_table_enable); break; case WSREP_OSU_RSU: ret= wsrep_RSU_begin(thd, db_, table_); diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index a2d0b71fba6b1..9b58133fb8a0f 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -241,6 +241,12 @@ void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...); if (WSREP_ON && WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) \ goto wsrep_error_label; +#define WSREP_TO_ISOLATION_BEGIN_DROP(db_, table_, table_list_) \ + if (WSREP_ON && WSREP(thd) && \ + wsrep_to_isolation_begin(thd, db_, table_, \ + table_list_, nullptr, nullptr, nullptr, true))\ + goto wsrep_error_label; + #define WSREP_TO_ISOLATION_BEGIN_CREATE(db_, table_, table_list_, create_info_) \ if (WSREP_ON && WSREP(thd) && \ wsrep_to_isolation_begin(thd, db_, table_, \ @@ -353,7 +359,8 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, const TABLE_LIST* table_list, const Alter_info* alter_info= nullptr, const wsrep::key_array *fk_tables= nullptr, - const HA_CREATE_INFO* create_info= nullptr); + const HA_CREATE_INFO* create_info= nullptr, + bool is_drop_table_enable= false); bool wsrep_should_replicate_ddl(THD* thd, const handlerton *db_type); bool wsrep_should_replicate_ddl_iterate(THD* thd, const TABLE_LIST* table_list);