diff --git a/mysql-test/suite/innodb/r/truncate_foreign.result b/mysql-test/suite/innodb/r/truncate_foreign.result index fc09b74d62f..12a41860708 100644 --- a/mysql-test/suite/innodb/r/truncate_foreign.result +++ b/mysql-test/suite/innodb/r/truncate_foreign.result @@ -57,3 +57,14 @@ disconnect dml; connection default; SET DEBUG_SYNC = RESET; DROP TABLE child, parent; +# +# MDEV-24532 Table corruption ER_NO_SUCH_TABLE_IN_ENGINE or +# ER_CRASHED_ON_USAGE after ALTER on table with foreign key +# +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)) ENGINE=InnoDB; +ALTER TABLE t1 ADD FOREIGN KEY (b) REFERENCES t1 (a) ON UPDATE CASCADE; +LOCK TABLE t1 WRITE; +TRUNCATE TABLE t1; +ALTER TABLE t1 ADD c INT; +UNLOCK TABLES; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/truncate_foreign.test b/mysql-test/suite/innodb/t/truncate_foreign.test index d9d647e69f0..1c150e5db40 100644 --- a/mysql-test/suite/innodb/t/truncate_foreign.test +++ b/mysql-test/suite/innodb/t/truncate_foreign.test @@ -67,3 +67,16 @@ connection default; SET DEBUG_SYNC = RESET; DROP TABLE child, parent; + +--echo # +--echo # MDEV-24532 Table corruption ER_NO_SUCH_TABLE_IN_ENGINE or +--echo # ER_CRASHED_ON_USAGE after ALTER on table with foreign key +--echo # + +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)) ENGINE=InnoDB; +ALTER TABLE t1 ADD FOREIGN KEY (b) REFERENCES t1 (a) ON UPDATE CASCADE; +LOCK TABLE t1 WRITE; +TRUNCATE TABLE t1; +ALTER TABLE t1 ADD c INT; +UNLOCK TABLES; +DROP TABLE t1; diff --git a/sql/handler.h b/sql/handler.h index 6113b748696..e0e0604176d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1419,6 +1419,12 @@ handlerton *ha_default_tmp_handlerton(THD *thd); // MySQL compatibility. Unused. #define HTON_SUPPORTS_FOREIGN_KEYS (1 << 0) //Foreign key constraint supported. +/* + Table requires and close and reopen after truncate + If the handler has HTON_CAN_RECREATE, this flag is not used +*/ +#define HTON_REQUIRES_CLOSE_AFTER_TRUNCATE (1 << 18) + class Ha_trx_info; struct THD_TRANS diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index ea4d7399ea3..7d1f630b88c 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -439,6 +439,15 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) */ error= handler_truncate(thd, table_ref, FALSE); + if (error == TRUNCATE_OK && thd->locked_tables_mode && + (table_ref->table->file->ht->flags & + HTON_REQUIRES_CLOSE_AFTER_TRUNCATE)) + { + thd->locked_tables_list.mark_table_for_reopen(thd, table_ref->table); + if (unlikely(thd->locked_tables_list.reopen_tables(thd, true))) + thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); + } + /* All effects of a TRUNCATE TABLE operation are committed even if truncation fails in the case of non transactional tables. Thus, the diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2c51f0a9fdf..c67bf6bd607 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3702,7 +3702,8 @@ innobase_init( innobase_hton->flush_logs = innobase_flush_logs; innobase_hton->show_status = innobase_show_status; innobase_hton->flags = - HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS; + HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS | + HTON_REQUIRES_CLOSE_AFTER_TRUNCATE; #ifdef WITH_WSREP innobase_hton->abort_transaction=wsrep_abort_transaction;