From 0292cd0a27418fabe4660fa6f2a92a0952b06826 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Mon, 15 Jan 2018 21:08:00 +0300 Subject: [PATCH 1/8] Better explanation why rpl_row_triggers is disabled. --- storage/rocksdb/mysql-test/rocksdb/t/disabled.def | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/storage/rocksdb/mysql-test/rocksdb/t/disabled.def b/storage/rocksdb/mysql-test/rocksdb/t/disabled.def index c2ca6efe46c..60f658ec7e1 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/disabled.def +++ b/storage/rocksdb/mysql-test/rocksdb/t/disabled.def @@ -59,7 +59,7 @@ bytes_written: Needs I_S.TABLE_STATISTICS.IO_WRITE_BYTES trx_info_rpl : MariaRocks: @@rpl_skip_tx_api doesn't work, yet. rpl_read_free: MDEV-10976 lock_wait_timeout_stats: MDEV-13404 - +rpl_row_triggers : Requires read-free slave. ## ## Test failures (in buildbot or else where) @@ -74,5 +74,4 @@ information_schema: MDEV-14372: unstable testcase ## mysqlbinlog_gtid_skip_empty_trans_rocksdb : MariaRocks: requires GTIDs -rpl_row_triggers : MariaRocks: requires GTIDs From f5e158183cb72de5bfc1cc7a9b6864a85c6517fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 16 Jan 2018 07:46:51 +0200 Subject: [PATCH 2/8] Follow-up fix to MDEV-14441: Correct a misplaced condition btr_cur_update_in_place(): The call rw_lock_x_lock(ahi_latch) must of course be inside the if (ahi_latch) condition. This is a mistake that I made when backporting the fix-under-development from 10.3. --- storage/innobase/btr/btr0cur.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 2830a38fa4a..8146667f7c2 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -3711,9 +3711,9 @@ btr_cur_update_in_place( to this record */ btr_search_update_hash_on_delete(cursor); } - } - rw_lock_x_lock(ahi_latch); + rw_lock_x_lock(ahi_latch); + } assert_block_ahi_valid(block); #endif /* BTR_CUR_HASH_ADAPT */ From 33ecf8345d357cbf71bde2b03b641a612db7781f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 16 Jan 2018 13:55:45 +0200 Subject: [PATCH 3/8] Follow-up fix to MDEV-14441: Fix a potential race condition btr_cur_update_in_place(): Read block->index only once, so that it cannot change to NULL after the first read. When block->index != NULL, it must be equal to index. --- storage/innobase/btr/btr0cur.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 8146667f7c2..139e06ab996 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -3694,7 +3694,7 @@ btr_cur_update_in_place( #ifdef BTR_CUR_HASH_ADAPT { rw_lock_t* ahi_latch = block->index - ? btr_get_search_latch(block->index) : NULL; + ? btr_get_search_latch(index) : NULL; if (ahi_latch) { /* TO DO: Can we skip this if none of the fields index->search_info->curr_n_fields From be85c2dc889b668382106071e712213cd3b1cbcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 16 Jan 2018 13:57:30 +0200 Subject: [PATCH 4/8] Mariabackup --prepare: Do not access transactions or data dictionary innobase_start_or_create_for_mysql(): Only start the data dictionary and transaction subsystems in normal server startup and during mariabackup --export. --- storage/innobase/srv/srv0start.cc | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 7bfd1715e9b..f45e4c98e81 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -2246,17 +2246,32 @@ files_checked: recv_sys->dblwr.pages.clear(); - if (err == DB_SUCCESS) { - /* Initialize the change buffer. */ - err = dict_boot(); - } - if (err != DB_SUCCESS) { return(srv_init_abort(err)); } - /* This must precede recv_apply_hashed_log_recs(true). */ - trx_sys_init_at_db_start(); + switch (srv_operation) { + case SRV_OPERATION_NORMAL: + case SRV_OPERATION_RESTORE_EXPORT: + /* Initialize the change buffer. */ + err = dict_boot(); + if (err != DB_SUCCESS) { + return(srv_init_abort(err)); + } + /* This must precede + recv_apply_hashed_log_recs(true). */ + trx_sys_init_at_db_start(); + break; + case SRV_OPERATION_RESTORE_DELTA: + case SRV_OPERATION_BACKUP: + ut_ad(!"wrong mariabackup mode"); + /* fall through */ + case SRV_OPERATION_RESTORE: + /* mariabackup --prepare only deals with + the redo log and the data files, not with + transactions or the data dictionary. */ + break; + } if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) { /* Apply the hashed log records to the From 81378b394763e56d57c4a4fc3c20244cc0ee9cc5 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 16 Jan 2018 16:09:51 +0400 Subject: [PATCH 5/8] Moving a change_list related methods from THD to Item_change_list 1. Moving the following methods from THD to Item_change_list: nocheck_register_item_tree_change() check_and_register_item_tree_change() rollback_item_tree_changes() as they work only with the "change_list" member and don't require anything else from THD. 2. Deriving THD from Item_change_list This change will help to fix "MDEV-14603 signal 11 with short stacktrace" easier. --- sql/sp_head.cc | 8 ++++---- sql/sql_class.cc | 14 +++++++++----- sql/sql_class.h | 37 +++++++++++++++++++++++-------------- sql/sql_parse.cc | 2 +- sql/sql_prepare.cc | 8 ++++---- 5 files changed, 41 insertions(+), 28 deletions(-) diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 7816af398c2..8b05d14f2de 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1249,7 +1249,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) We should also save Item tree change list to avoid rollback something too early in the calling query. */ - thd->change_list.move_elements_to(&old_change_list); + thd->Item_change_list::move_elements_to(&old_change_list); /* Cursors will use thd->packet, so they may corrupt data which was prepared for sending by upper level. OTOH cursors in the same routine can share this @@ -1389,8 +1389,8 @@ sp_head::execute(THD *thd, bool merge_da_on_success) /* Restore all saved */ thd->server_status= (thd->server_status & ~status_backup_mask) | old_server_status; old_packet.swap(thd->packet); - DBUG_ASSERT(thd->change_list.is_empty()); - old_change_list.move_elements_to(&thd->change_list); + DBUG_ASSERT(thd->Item_change_list::is_empty()); + old_change_list.move_elements_to(thd); thd->lex= old_lex; thd->set_query_id(old_query_id); DBUG_ASSERT(!thd->derived_tables); @@ -2976,7 +2976,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, bool parent_modified_non_trans_table= thd->transaction.stmt.modified_non_trans_table; thd->transaction.stmt.modified_non_trans_table= FALSE; DBUG_ASSERT(!thd->derived_tables); - DBUG_ASSERT(thd->change_list.is_empty()); + DBUG_ASSERT(thd->Item_change_list::is_empty()); /* Use our own lex. We should not save old value since it is saved/restored in diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c8eb8ed3128..d0b45441d83 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2605,8 +2605,10 @@ struct Item_change_record: public ilink thd->mem_root (due to possible set_n_backup_active_arena called for thd). */ -void THD::nocheck_register_item_tree_change(Item **place, Item *old_value, - MEM_ROOT *runtime_memroot) +void +Item_change_list::nocheck_register_item_tree_change(Item **place, + Item *old_value, + MEM_ROOT *runtime_memroot) { Item_change_record *change; DBUG_ENTER("THD::nocheck_register_item_tree_change"); @@ -2647,8 +2649,10 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value, changes to substitute the same reference at both locations L1 and L2. */ -void THD::check_and_register_item_tree_change(Item **place, Item **new_value, - MEM_ROOT *runtime_memroot) +void +Item_change_list::check_and_register_item_tree_change(Item **place, + Item **new_value, + MEM_ROOT *runtime_memroot) { Item_change_record *change; I_List_iterator it(change_list); @@ -2663,7 +2667,7 @@ void THD::check_and_register_item_tree_change(Item **place, Item **new_value, } -void THD::rollback_item_tree_changes() +void Item_change_list::rollback_item_tree_changes() { I_List_iterator it(change_list); Item_change_record *change; diff --git a/sql/sql_class.h b/sql/sql_class.h index e5aaba9b407..bcd43cd62cd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1279,7 +1279,21 @@ public: */ struct Item_change_record; -typedef I_List Item_change_list; +class Item_change_list +{ + I_List change_list; +public: + void nocheck_register_item_tree_change(Item **place, Item *old_value, + MEM_ROOT *runtime_memroot); + void check_and_register_item_tree_change(Item **place, Item **new_value, + MEM_ROOT *runtime_memroot); + void rollback_item_tree_changes(); + void move_elements_to(Item_change_list *to) + { + change_list.move_elements_to(&to->change_list); + } + bool is_empty() { return change_list.is_empty(); } +}; /** @@ -2040,6 +2054,14 @@ void dbug_serve_apcs(THD *thd, int n_calls); */ class THD :public Statement, + /* + This is to track items changed during execution of a prepared + statement/stored procedure. It's created by + nocheck_register_item_tree_change() in memory root of THD, + and freed in rollback_item_tree_changes(). + For conventional execution it's always empty. + */ + public Item_change_list, public MDL_context_owner, public Open_tables_state { @@ -2510,14 +2532,6 @@ public: #ifdef SIGNAL_WITH_VIO_CLOSE Vio* active_vio; #endif - /* - This is to track items changed during execution of a prepared - statement/stored procedure. It's created by - nocheck_register_item_tree_change() in memory root of THD, and freed in - rollback_item_tree_changes(). For conventional execution it's always - empty. - */ - Item_change_list change_list; /* A permanent memory area of the statement. For conventional @@ -3599,11 +3613,6 @@ public: */ memcpy((char*) place, new_value, sizeof(*new_value)); } - void nocheck_register_item_tree_change(Item **place, Item *old_value, - MEM_ROOT *runtime_memroot); - void check_and_register_item_tree_change(Item **place, Item **new_value, - MEM_ROOT *runtime_memroot); - void rollback_item_tree_changes(); /* Cleanup statement parse state (parse tree, lex) and execution diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6d068eb99ac..21abc1a248c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7910,7 +7910,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size); thd->end_statement(); thd->cleanup_after_query(); - DBUG_ASSERT(thd->change_list.is_empty()); + DBUG_ASSERT(thd->Item_change_list::is_empty()); } else { diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 390b70877f5..4e847fb9ff3 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3930,7 +3930,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) If called from a stored procedure, ensure that we won't rollback external changes when cleaning up after validation. */ - DBUG_ASSERT(thd->change_list.is_empty()); + DBUG_ASSERT(thd->Item_change_list::is_empty()); /* Marker used to release metadata locks acquired while the prepared @@ -4407,7 +4407,7 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable) bool error; Query_arena *save_stmt_arena= thd->stmt_arena; Item_change_list save_change_list; - thd->change_list.move_elements_to(&save_change_list); + thd->Item_change_list::move_elements_to(&save_change_list); state= STMT_CONVENTIONAL_EXECUTION; @@ -4426,7 +4426,7 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable) thd->restore_backup_statement(this, &stmt_backup); thd->stmt_arena= save_stmt_arena; - save_change_list.move_elements_to(&thd->change_list); + save_change_list.move_elements_to(thd); /* Items and memory will freed in destructor */ @@ -4654,7 +4654,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) If the free_list is not empty, we'll wrongly free some externally allocated items when cleaning up after execution of this statement. */ - DBUG_ASSERT(thd->change_list.is_empty()); + DBUG_ASSERT(thd->Item_change_list::is_empty()); /* The only case where we should have items in the thd->free_list is From f44017384afa7a10df9866423291fc764046043f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 16 Jan 2018 20:02:38 +0200 Subject: [PATCH 6/8] MDEV-14968 On upgrade, InnoDB reports "started; log sequence number 0" srv_prepare_to_delete_redo_log_files(): Initialize srv_start_lsn. --- storage/innobase/srv/srv0start.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index f45e4c98e81..d3b7fb6bf94 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1446,6 +1446,7 @@ srv_prepare_to_delete_redo_log_files( << " bytes; LSN=" << flushed_lsn; } + srv_start_lsn = flushed_lsn; /* Flush the old log files. */ log_mutex_exit(); From 04eef79bf93fc825cf2651633bcbcc21b20e3a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 17 Jan 2018 11:28:02 +0200 Subject: [PATCH 7/8] Do not define unused function mark_blocks_free() Follow-up to commit 9ec19b9b41804d8d4491f0f58ac06ae417e02ffa --- mysys/my_alloc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index 3df73127998..b2a1264bd2b 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -325,7 +325,8 @@ void *multi_alloc_root(MEM_ROOT *root, ...) #define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left) -/* Mark all data in blocks free for reusage */ +#if !(defined(HAVE_valgrind) && defined(EXTRA_DEBUG)) +/** Mark all data in blocks free for reusage */ static inline void mark_blocks_free(MEM_ROOT* root) { @@ -355,6 +356,7 @@ static inline void mark_blocks_free(MEM_ROOT* root) root->first_block_usage= 0; root->block_num= 4; } +#endif /* From 656f66def27b7a2cf42a28f873f1eeef0416aa71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 17 Jan 2018 15:53:30 +0200 Subject: [PATCH 8/8] Follow-up fix to MDEV-14585 Automatically remove #sql- tables in InnoDB dictionary during recovery If InnoDB is killed while ALTER TABLE...ALGORITHM=COPY is in progress, after recovery there could be undo log records some records that were inserted into an intermediate copy of the table. Due to these undo log records, InnoDB would resurrect locks at recovery, and the intermediate table would be locked while we are trying to drop it. This would cause a call to row_rename_table_for_mysql(), either from row_mysql_drop_garbage_tables() or from the rollback of a RENAME operation that was part of the ALTER TABLE. row_rename_table_for_mysql(): Do not attempt to parse FOREIGN KEY constraints when renaming from #sql-something to #sql-something-else, because it does not make any sense. row_drop_table_for_mysql(): When deferring DROP TABLE due to locks, do not rename the table if its name already starts with the #sql- prefix, which is what row_mysql_drop_garbage_tables() uses. Previously, the too strict prefix #sql-ib was used, and some tables were renamed unnecessarily. --- .../suite/innodb/r/rename_table_debug.result | 31 +++++++++++++-- .../suite/innodb/t/rename_table_debug.test | 39 ++++++++++++++++++- storage/innobase/row/row0mysql.cc | 4 +- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/innodb/r/rename_table_debug.result b/mysql-test/suite/innodb/r/rename_table_debug.result index 912ed9de48b..7c9b961dee5 100644 --- a/mysql-test/suite/innodb/r/rename_table_debug.result +++ b/mysql-test/suite/innodb/r/rename_table_debug.result @@ -1,5 +1,5 @@ -CREATE TABLE t1 (a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; -INSERT INTO t1 VALUES(42); +CREATE TABLE t1 (a SERIAL, b INT, c INT, d INT) ENGINE=InnoDB; +INSERT INTO t1 () VALUES (); connect con1,localhost,root,,test; SET DEBUG_SYNC='before_rename_table_commit SIGNAL renamed WAIT_FOR ever'; RENAME TABLE t1 TO t2; @@ -7,6 +7,29 @@ connection default; SET DEBUG_SYNC='now WAIT_FOR renamed'; disconnect con1; SELECT * FROM t1; -a -42 +a b c d +1 NULL NULL NULL +BEGIN; +COMMIT; +UPDATE t1 SET b=a%7, c=a%11, d=a%13; +SET DEBUG_DBUG='+d,crash_commit_before'; +ALTER TABLE t1 +ADD INDEX(b,c,d,a),ADD INDEX(b,c,a,d),ADD INDEX(b,a,c,d),ADD INDEX(b,a,d,c), +ADD INDEX(b,d,a,c),ADD INDEX(b,d,c,a),ADD INDEX(a,b,c,d),ADD INDEX(a,b,d,c), +ADD INDEX(a,c,b,d),ADD INDEX(a,c,d,b),ADD INDEX(a,d,b,c),ADD INDEX(a,d,c,b), +ADD INDEX(c,a,b,d),ADD INDEX(c,a,d,b),ADD INDEX(c,b,a,d),ADD INDEX(c,b,d,a), +ADD INDEX(c,d,a,b),ADD INDEX(c,d,b,a),ADD INDEX(d,a,b,c),ADD INDEX(d,a,c,b), +ADD INDEX(d,b,a,c),ADD INDEX(d,b,c,a),ADD INDEX(d,c,a,b),ADD INDEX(d,c,b,a), +ADD INDEX(a,b,c), ADD INDEX(a,c,b), ADD INDEX(a,c,d), ADD INDEX(a,d,c), +ADD INDEX(a,b,d), ADD INDEX(a,d,b), ADD INDEX(b,c,d), ADD INDEX(b,d,c), +ALGORITHM=COPY; +ERROR HY000: Lost connection to MySQL server during query +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +SELECT COUNT(*) FROM t1; +COUNT(*) +1000 DROP TABLE t1; +SET GLOBAL innodb_background_drop_list_empty= +@@GLOBAL.innodb_background_drop_list_empty; diff --git a/mysql-test/suite/innodb/t/rename_table_debug.test b/mysql-test/suite/innodb/t/rename_table_debug.test index 4620f7bef22..20af12dc15c 100644 --- a/mysql-test/suite/innodb/t/rename_table_debug.test +++ b/mysql-test/suite/innodb/t/rename_table_debug.test @@ -3,8 +3,10 @@ --source include/have_debug_sync.inc --source include/not_embedded.inc -CREATE TABLE t1 (a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; -INSERT INTO t1 VALUES(42); +LET $datadir= `SELECT @@datadir`; + +CREATE TABLE t1 (a SERIAL, b INT, c INT, d INT) ENGINE=InnoDB; +INSERT INTO t1 () VALUES (); --connect (con1,localhost,root,,test) SET DEBUG_SYNC='before_rename_table_commit SIGNAL renamed WAIT_FOR ever'; @@ -16,4 +18,37 @@ SET DEBUG_SYNC='now WAIT_FOR renamed'; --source include/restart_mysqld.inc --disconnect con1 SELECT * FROM t1; + +let $c = 999; +BEGIN; +--disable_query_log +while ($c) { +INSERT INTO t1() VALUES(); +dec $c; +} +--enable_query_log +COMMIT; +UPDATE t1 SET b=a%7, c=a%11, d=a%13; + +--source include/expect_crash.inc +SET DEBUG_DBUG='+d,crash_commit_before'; +--error 2013 +ALTER TABLE t1 +ADD INDEX(b,c,d,a),ADD INDEX(b,c,a,d),ADD INDEX(b,a,c,d),ADD INDEX(b,a,d,c), +ADD INDEX(b,d,a,c),ADD INDEX(b,d,c,a),ADD INDEX(a,b,c,d),ADD INDEX(a,b,d,c), +ADD INDEX(a,c,b,d),ADD INDEX(a,c,d,b),ADD INDEX(a,d,b,c),ADD INDEX(a,d,c,b), +ADD INDEX(c,a,b,d),ADD INDEX(c,a,d,b),ADD INDEX(c,b,a,d),ADD INDEX(c,b,d,a), +ADD INDEX(c,d,a,b),ADD INDEX(c,d,b,a),ADD INDEX(d,a,b,c),ADD INDEX(d,a,c,b), +ADD INDEX(d,b,a,c),ADD INDEX(d,b,c,a),ADD INDEX(d,c,a,b),ADD INDEX(d,c,b,a), +ADD INDEX(a,b,c), ADD INDEX(a,c,b), ADD INDEX(a,c,d), ADD INDEX(a,d,c), +ADD INDEX(a,b,d), ADD INDEX(a,d,b), ADD INDEX(b,c,d), ADD INDEX(b,d,c), +ALGORITHM=COPY; +--source include/start_mysqld.inc +CHECK TABLE t1; +SELECT COUNT(*) FROM t1; DROP TABLE t1; +# MDEV-11415 TODO: remove the following +SET GLOBAL innodb_background_drop_list_empty= +@@GLOBAL.innodb_background_drop_list_empty; +# Work around missing crash recovery at the SQL layer. +--remove_files_wildcard $datadir/test #sql-*.frm diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 8f9b5296015..c3c6e66b3e4 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3712,7 +3712,7 @@ row_drop_table_for_mysql( if (table->n_foreign_key_checks_running > 0) { defer: - if (!strstr(table->name.m_name, "/" TEMP_FILE_PREFIX_INNODB)) { + if (!strstr(table->name.m_name, "/" TEMP_FILE_PREFIX)) { heap = mem_heap_create(FN_REFLEN); const char* tmp_name = dict_mem_create_temporary_tablename( @@ -4477,7 +4477,7 @@ row_rename_table_for_mysql( goto funct_exit; - } else if (new_is_tmp) { + } else if (!old_is_tmp && new_is_tmp) { /* MySQL is doing an ALTER TABLE command and it renames the original table to a temporary table name. We want to preserve the original foreign key constraint definitions despite the