From 2c6d5c92c7e0e8b38dcb9fad94c7bf11ef4ba4b6 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 24 May 2021 15:41:08 +0530 Subject: [PATCH] MDEV-25642 InnoDB rename table copy DDL fails while dropping the table When doing a ALTER TABLE ... RENAME, MariaDB doesn't rename original table to #sql-backup, which it does in other cases, but insteads drops the original table directly. However this optimization doesn't work in case of InnoDB table with a foreign key constraint. During copy algorithm, InnoDB fails to rename the foreign key constraint(MDEV-25855). With this optimisation, InnoDB also fails to drop the original table because the table has FOREIGN Key constraint exist in INNODB_SYS_FOREIGN table. This leads to orphan .ibd file in InnoDB dictionary. so disabling this optimization when FK is involved. Reviewer: monty@mariadb.org --- mysql-test/suite/innodb/r/innodb-fk.result | 15 +++++++++++++++ mysql-test/suite/innodb/t/innodb-fk.test | 16 ++++++++++++++++ sql/sql_table.cc | 9 +++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-fk.result b/mysql-test/suite/innodb/r/innodb-fk.result index d3c1aa77eaf..ce873be93da 100644 --- a/mysql-test/suite/innodb/r/innodb-fk.result +++ b/mysql-test/suite/innodb/r/innodb-fk.result @@ -206,3 +206,18 @@ c0123456789012345678 int, FOREIGN KEY (a012345678901234567,c0123456789012345678,b) REFERENCES tx (x1,x2,x3) ) ENGINE=InnoDB; ERROR HY000: Can't create table `test`.`t1` (errno: 150 "Foreign key constraint is incorrectly formed") +# +# MDEV-25642 InnoDB rename table copy DDL fails +# while dropping the table +# +call mtr.add_suppression("InnoDB: In ALTER TABLE `test`.`t1` has or is referenced in foreign key constraints which are not compatible with the new table definition."); +CREATE TABLE t1 (a VARCHAR(10) NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t1_fk (a VARCHAR(40), KEY a (a), FULLTEXT KEY(a), CONSTRAINT fk FOREIGN KEY(a) REFERENCES t1 (a) ON UPDATE CASCADE) ENGINE=InnoDB; +ALTER TABLE t1 RENAME TO tm1, ALGORITHM=COPY; +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN; +ID FOR_NAME REF_NAME N_COLS TYPE +test/fk test/t1_fk test/t1 1 4 +SET FOREIGN_KEY_CHECKS=0; +CREATE TABLE t1 (c1 BIGINT NOT NULL, c2 BIGINT NOT NULL, PRIMARY KEY(c1), UNIQUE KEY(c2)) ENGINE=MEMORY; +ALTER TABLE t1 ENGINE=InnoDB, ALGORITHM=COPY; +DROP TABLE t1, tm1, t1_fk; diff --git a/mysql-test/suite/innodb/t/innodb-fk.test b/mysql-test/suite/innodb/t/innodb-fk.test index fcab4b22eb1..6d5307a1f84 100644 --- a/mysql-test/suite/innodb/t/innodb-fk.test +++ b/mysql-test/suite/innodb/t/innodb-fk.test @@ -244,3 +244,19 @@ CREATE TABLE t1 ( c0123456789012345678 int, FOREIGN KEY (a012345678901234567,c0123456789012345678,b) REFERENCES tx (x1,x2,x3) ) ENGINE=InnoDB; + +--echo # +--echo # MDEV-25642 InnoDB rename table copy DDL fails +--echo # while dropping the table +--echo # +call mtr.add_suppression("InnoDB: In ALTER TABLE `test`.`t1` has or is referenced in foreign key constraints which are not compatible with the new table definition."); + +CREATE TABLE t1 (a VARCHAR(10) NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t1_fk (a VARCHAR(40), KEY a (a), FULLTEXT KEY(a), CONSTRAINT fk FOREIGN KEY(a) REFERENCES t1 (a) ON UPDATE CASCADE) ENGINE=InnoDB; +ALTER TABLE t1 RENAME TO tm1, ALGORITHM=COPY; +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN; +# Enable SET FOREIGN_KEY_CHECKS after fixing MDEV-25885 +SET FOREIGN_KEY_CHECKS=0; +CREATE TABLE t1 (c1 BIGINT NOT NULL, c2 BIGINT NOT NULL, PRIMARY KEY(c1), UNIQUE KEY(c2)) ENGINE=MEMORY; +ALTER TABLE t1 ENGINE=InnoDB, ALGORITHM=COPY; +DROP TABLE t1, tm1, t1_fk; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8fd9265cf19..f58ce8f997d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -11009,7 +11009,12 @@ do_continue:; DBUG_PRINT("info", ("is_table_renamed: %d engine_changed: %d", alter_ctx.is_table_renamed(), engine_changed)); - if (!alter_ctx.is_table_renamed()) + /* + InnoDB cannot use the rename optimization when foreign key + constraint is involved because InnoDB fails to drop the + parent table due to foreign key constraint + */ + if (!alter_ctx.is_table_renamed() || alter_ctx.fk_error_if_delete_row) { backup_name.length= my_snprintf(backup_name_buff, sizeof(backup_name_buff), "%s-backup-%lx-%llx", tmp_file_prefix, @@ -11044,7 +11049,7 @@ do_continue:; (void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db, &alter_ctx.tmp_name, FN_IS_TMP); - if (!alter_ctx.is_table_renamed()) + if (!alter_ctx.is_table_renamed() || alter_ctx.fk_error_if_delete_row) { // Restore the backup of the original table to the old name. (void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,