From 8c1c61309d0a9d8da0ad51326f3fb1f1f7922bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 29 Apr 2022 12:32:44 +0300 Subject: [PATCH] MDEV-27274: DROP TABLE does not delete detached InnoDB files In commit 1bd681c8b3c5213ce1f7976940a7dc38b48a0d39 (MDEV-25506 part 3) the way how DDL transactions delete files was rewritten. Only files that are actually attached to InnoDB tablespaces would be deleted, and only after the DDL transaction was durably committed. After a failed ALTER TABLE...IMPORT TABLESPACE, any data files that the user might have moved to the data directory will not be attached to the InnoDB data dictionary. Therefore, DROP TABLE would not attempt to delete those files, and a subsequent CREATE TABLE would fail. The logic was that the user who created the files outside the DBMS is still the owner of those files, and InnoDB should not delete those files because an "ownership transfer" (IMPORT TABLESPACE) was not successfully completed. However, not deleting those detached files could surprise users. ha_innobase::delete_table(): Even if no tablespace exists, try to delete any files that might match the table name. Reviewed by: Thirunarayanan Balathandayuthapani --- mysql-test/suite/innodb/r/import_bugs.result | 8 ++++++- mysql-test/suite/innodb/t/import_bugs.test | 10 +++++++-- .../suite/innodb/t/import_corrupted.test | 8 ++----- mysql-test/suite/innodb/t/innodb-wl5522.test | 14 ------------- storage/innobase/handler/ha_innodb.cc | 21 +++++++++++++++++++ 5 files changed, 38 insertions(+), 23 deletions(-) diff --git a/mysql-test/suite/innodb/r/import_bugs.result b/mysql-test/suite/innodb/r/import_bugs.result index 14e4954e79f..98f3e76763b 100644 --- a/mysql-test/suite/innodb/r/import_bugs.result +++ b/mysql-test/suite/innodb/r/import_bugs.result @@ -8,13 +8,19 @@ FLUSH TABLES t1 FOR EXPORT; UNLOCK TABLES; ALTER TABLE imp_t1 IMPORT TABLESPACE; ERROR HY000: Schema mismatch (ROW_FORMAT mismatch) +CREATE TABLE imp_t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +ERROR 42S01: Table 'imp_t1' already exists +DROP TABLE imp_t1; +CREATE TABLE imp_t1 (a INT PRIMARY KEY) ENGINE=InnoDB; DROP TABLE imp_t1, t1; SET GLOBAL innodb_checksum_algorithm=@save_innodb_checksum_algorithm; # -# MDEV-27006 Assertion `!lock_trx_has_sys_table_locks(trx)' --echo # failed in dberr_t row_discard_tablespace_for_mysql +# MDEV-27006 Assertion `!lock_trx_has_sys_table_locks(trx)' +# failed in dberr_t row_discard_tablespace_for_mysql # (dict_table_t*, trx_t*) CREATE TABLE t1 (c INT KEY) ENGINE=INNODB; CREATE TABLE t2 (c INT KEY,FOREIGN KEY(c) REFERENCES t1 (c)) ENGINE=INNODB; ALTER TABLE t1 DISCARD TABLESPACE; ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails DROP TABLE t2, t1; +# End of 10.6 tests diff --git a/mysql-test/suite/innodb/t/import_bugs.test b/mysql-test/suite/innodb/t/import_bugs.test index 9898d11fc80..7fcab9f9abc 100644 --- a/mysql-test/suite/innodb/t/import_bugs.test +++ b/mysql-test/suite/innodb/t/import_bugs.test @@ -14,16 +14,22 @@ let $datadir=`select @@datadir`; UNLOCK TABLES; --error ER_TABLE_SCHEMA_MISMATCH ALTER TABLE imp_t1 IMPORT TABLESPACE; +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE imp_t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +DROP TABLE imp_t1; +CREATE TABLE imp_t1 (a INT PRIMARY KEY) ENGINE=InnoDB; DROP TABLE imp_t1, t1; ---remove_file $datadir/test/imp_t1.ibd SET GLOBAL innodb_checksum_algorithm=@save_innodb_checksum_algorithm; --echo # ---echo # MDEV-27006 Assertion `!lock_trx_has_sys_table_locks(trx)' --echo # failed in dberr_t row_discard_tablespace_for_mysql +--echo # MDEV-27006 Assertion `!lock_trx_has_sys_table_locks(trx)' +--echo # failed in dberr_t row_discard_tablespace_for_mysql --echo # (dict_table_t*, trx_t*) CREATE TABLE t1 (c INT KEY) ENGINE=INNODB; CREATE TABLE t2 (c INT KEY,FOREIGN KEY(c) REFERENCES t1 (c)) ENGINE=INNODB; --error ER_ROW_IS_REFERENCED_2 ALTER TABLE t1 DISCARD TABLESPACE; DROP TABLE t2, t1; + +--echo # End of 10.6 tests diff --git a/mysql-test/suite/innodb/t/import_corrupted.test b/mysql-test/suite/innodb/t/import_corrupted.test index 016b71041f1..3a9b9a40493 100644 --- a/mysql-test/suite/innodb/t/import_corrupted.test +++ b/mysql-test/suite/innodb/t/import_corrupted.test @@ -56,14 +56,10 @@ CREATE TABLE t2 ( ALTER TABLE t2 DISCARD TABLESPACE; ---copy_file $MYSQLD_DATADIR/test/tmp.ibd $MYSQLD_DATADIR/test/t2.ibd ---copy_file $MYSQLD_DATADIR/test/tmp.cfg $MYSQLD_DATADIR/test/t2.cfg +--move_file $MYSQLD_DATADIR/test/tmp.ibd $MYSQLD_DATADIR/test/t2.ibd +--move_file $MYSQLD_DATADIR/test/tmp.cfg $MYSQLD_DATADIR/test/t2.cfg --error ER_NOT_KEYFILE ALTER TABLE t2 IMPORT TABLESPACE; DROP TABLE t2; - ---remove_file $MYSQLD_DATADIR/test/t2.ibd ---remove_file $MYSQLD_DATADIR/test/tmp.ibd ---remove_file $MYSQLD_DATADIR/test/tmp.cfg diff --git a/mysql-test/suite/innodb/t/innodb-wl5522.test b/mysql-test/suite/innodb/t/innodb-wl5522.test index 80d987fb87f..19652d8e8fd 100644 --- a/mysql-test/suite/innodb/t/innodb-wl5522.test +++ b/mysql-test/suite/innodb/t/innodb-wl5522.test @@ -98,10 +98,6 @@ if ($checksum_algorithm == "strict_full_crc32") { ALTER TABLE t2 IMPORT TABLESPACE; DROP TABLE t2; -if ($error_code) { ---remove_file $MYSQLD_DATADIR/test/t2.ibd -} - SET GLOBAL innodb_file_per_table = 1; SELECT @@innodb_file_per_table; @@ -1102,7 +1098,6 @@ DROP TABLE t1, t2; CREATE TABLE t1 ( id INT NOT NULL, i1 INT, i2 INT, PRIMARY KEY (id)) engine=innodb; ---remove_file $MYSQLD_DATADIR/test/t2.ibd CREATE TABLE t2 ( id INT NOT NULL, i1 INT, i2 INT, i3 INT, PRIMARY KEY (id)) engine=innodb; ALTER TABLE t2 DISCARD TABLESPACE; @@ -1114,18 +1109,9 @@ FLUSH TABLES t1 FOR EXPORT; UNLOCK TABLES; --error ER_TABLE_SCHEMA_MISMATCH ALTER TABLE t2 IMPORT TABLESPACE; - ---remove_file $MYSQLD_DATADIR/test/t2.ibd ---remove_file $MYSQLD_DATADIR/test/t2.cfg - - DROP TABLE t1, t2; call mtr.add_suppression("Got error -1 when reading table '.*'"); call mtr.add_suppression("InnoDB: Error: tablespace id and flags in file '.*'"); call mtr.add_suppression("InnoDB: The table .* doesn't have a corresponding tablespace, it was discarded"); - -# cleanup ---remove_file $MYSQLTEST_VARDIR/tmp/t1.cfg ---remove_file $MYSQLTEST_VARDIR/tmp/t1.ibd diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2ce02ca018c..46f178ffab2 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -13616,7 +13616,28 @@ int ha_innobase::delete_table(const char *name) } if (err == DB_SUCCESS) + { + if (!table->space) + { + const char *data_dir_path= DICT_TF_HAS_DATA_DIR(table->flags) + ? table->data_dir_path : nullptr; + char *path= fil_make_filepath(data_dir_path, table->name, CFG, + data_dir_path != nullptr); + os_file_delete_if_exists(innodb_data_file_key, path, nullptr); + ut_free(path); + path= fil_make_filepath(data_dir_path, table->name, IBD, + data_dir_path != nullptr); + os_file_delete_if_exists(innodb_data_file_key, path, nullptr); + ut_free(path); + if (data_dir_path) + { + path= fil_make_filepath(nullptr, table->name, ISL, false); + os_file_delete_if_exists(innodb_data_file_key, path, nullptr); + ut_free(path); + } + } err= lock_sys_tables(trx); + } dict_sys.lock(SRW_LOCK_CALL);