commit 8a3e177ea092ed59f500872d8ecba6d37b8dd037 Author: Laurynas Biveinis Date: Thu Jun 1 16:54:01 2017 +0300 Fix bugs 76142 / 82480 / PS-1697 (InnoDB tablespace import fails when importing table w/ different data directory) Importing a transportable tablespace will fail if its table definition has data directory specified while the donor table did not have one, and vice versa. Fix by relaxing the checks in Fil_shard::get_file_size() and row_import::match_schema() to allow this particular mismatch while still requiring that the rest of the flags match. Do not actually patch the tablespace header with the new flag value as InnoDB is already making assumptions elsewhere that the data directory flag bits may mismatch. Also fix tablespace import diagnostics that in the case of flags mismatch printed number of columns, not flags (bug 82480). Add a testcase. diff --git a/mysql-test/suite/innodb/r/bug76142.result b/mysql-test/suite/innodb/r/bug76142.result new file mode 100644 index 00000000000..26e2930c249 --- /dev/null +++ b/mysql-test/suite/innodb/r/bug76142.result @@ -0,0 +1,26 @@ +# +# Bug 76142: InnoDB tablespace import fails when importing table w/ different data directory +# +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB DATA DIRECTORY='MYSQL_TMP_DIR'; +INSERT INTO t2 VALUES (3); +FLUSH TABLE t2 FOR EXPORT; +UNLOCK TABLES; +ALTER TABLE t2 DISCARD TABLESPACE; +FLUSH TABLE t1 FOR EXPORT; +UNLOCK TABLES; +ALTER TABLE t2 IMPORT TABLESPACE; +INSERT INTO t2 VALUES (2); +ALTER TABLE t1 DISCARD TABLESPACE; +ALTER TABLE t1 IMPORT TABLESPACE; +INSERT INTO t1 VALUES (4); +SELECT * FROM t1; +a +3 +4 +SELECT * FROM t2; +a +1 +2 +DROP TABLE t1, t2; diff --git a/mysql-test/suite/innodb/r/default_row_format_compatibility.result b/mysql-test/suite/innodb/r/default_row_format_compatibility.result index 534c5a14cb5..55b71ed754d 100644 --- a/mysql-test/suite/innodb/r/default_row_format_compatibility.result +++ b/mysql-test/suite/innodb/r/default_row_format_compatibility.result @@ -40,7 +40,7 @@ SET GLOBAL innodb_default_row_format=Dynamic; CREATE TABLE tab(a INT); ALTER TABLE tab DISCARD TABLESPACE; ALTER TABLE tab IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x4 and the meta-data file has 0x1) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x21 and the meta-data file has 0x1) DROP TABLE tab; SET GLOBAL innodb_default_row_format=Compact; SELECT @@innodb_default_row_format; diff --git a/mysql-test/suite/innodb/r/innodb-wl5522.result b/mysql-test/suite/innodb/r/innodb-wl5522.result index a21a2630966..2d44022aca3 100644 --- a/mysql-test/suite/innodb/r/innodb-wl5522.result +++ b/mysql-test/suite/innodb/r/innodb-wl5522.result @@ -102,7 +102,7 @@ ALTER TABLE t2 ROW_FORMAT=DYNAMIC; ALTER TABLE t2 DISCARD TABLESPACE; # List after t2 DISCARD ALTER TABLE t2 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x4 and the meta-data file has 0x1) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x21 and the meta-data file has 0x1) ALTER TABLE t2 IMPORT TABLESPACE; ERROR HY000: Schema mismatch (Table has ROW_TYPE_DYNAMIC row format, .ibd file has ROW_TYPE_COMPACT row format.) DROP TABLE t2; @@ -574,7 +574,7 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x5 and the meta-data file has 0x0) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x1 and the meta-data file has 0x0) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -586,7 +586,7 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x5 and the meta-data file has 0x0) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x21 and the meta-data file has 0x0) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -760,7 +760,7 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x5 and the meta-data file has 0x1) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x0 and the meta-data file has 0x1) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -772,7 +772,7 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x5 and the meta-data file has 0x1) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x21 and the meta-data file has 0x1) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -949,7 +949,7 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x5 and the meta-data file has 0x21) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x1 and the meta-data file has 0x21) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; @@ -961,7 +961,7 @@ SELECT * FROM t1; ERROR HY000: Tablespace has been discarded for table 't1' restore: t1 .ibd and .cfg files ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x5 and the meta-data file has 0x21) +ERROR HY000: Schema mismatch (Table flags don't match, server table has 0x0 and the meta-data file has 0x21) unlink: t1.ibd unlink: t1.cfg DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/bug76142.test b/mysql-test/suite/innodb/t/bug76142.test new file mode 100644 index 00000000000..cfc53008502 --- /dev/null +++ b/mysql-test/suite/innodb/t/bug76142.test @@ -0,0 +1,42 @@ +--echo # +--echo # Bug 76142: InnoDB tablespace import fails when importing table w/ different data directory +--echo # + +--let $MYSQLD_DATADIR = `SELECT @@datadir` +--let $DB = `SELECT DATABASE()` + +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); + +--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR +eval CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB DATA DIRECTORY='$MYSQL_TMP_DIR'; +INSERT INTO t2 VALUES (3); + +FLUSH TABLE t2 FOR EXPORT; +--copy_file $MYSQL_TMP_DIR/$DB/t2.cfg $MYSQLD_DATADIR/$DB/temp.cfg +--copy_file $MYSQL_TMP_DIR/$DB/t2.ibd $MYSQLD_DATADIR/$DB/temp.ibd +UNLOCK TABLES; + +ALTER TABLE t2 DISCARD TABLESPACE; + +FLUSH TABLE t1 FOR EXPORT; +--copy_file $MYSQLD_DATADIR/$DB/t1.cfg $MYSQL_TMP_DIR/$DB/t2.cfg +--copy_file $MYSQLD_DATADIR/$DB/t1.ibd $MYSQL_TMP_DIR/$DB/t2.ibd +UNLOCK TABLES; + +ALTER TABLE t2 IMPORT TABLESPACE; +INSERT INTO t2 VALUES (2); + +ALTER TABLE t1 DISCARD TABLESPACE; +--move_file $MYSQLD_DATADIR/$DB/temp.cfg $MYSQLD_DATADIR/$DB/t1.cfg +--move_file $MYSQLD_DATADIR/$DB/temp.ibd $MYSQLD_DATADIR/$DB/t1.ibd + +ALTER TABLE t1 IMPORT TABLESPACE; +INSERT INTO t1 VALUES (4); + +SELECT * FROM t1; +SELECT * FROM t2; + +DROP TABLE t1, t2; + +--rmdir $MYSQL_TMP_DIR/$DB diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index eda44437b7a..f81dd469d4b 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2286,7 +2286,11 @@ dberr_t Fil_shard::get_file_size(fil_node_t *file, bool read_only_mode) { space->flags |= flags & FSP_FLAGS_MASK_SDI; /* ut_ad(space->flags == flags); */ - if (space->flags != flags) { + /* Do not compare the data directory flag, in case this tablespace was + relocated. */ + const auto relevant_space_flags = space->flags & ~FSP_FLAGS_MASK_DATA_DIR; + const auto relevant_flags = flags & ~FSP_FLAGS_MASK_DATA_DIR; + if (UNIV_UNLIKELY(relevant_space_flags != relevant_flags)) { ib::fatal(ER_IB_MSG_272, space->flags, file->name, flags); } diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 8968a8beb45..d6d39b81630 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -518,7 +518,8 @@ UNIV_INLINE MY_ATTRIBUTE((warn_unused_result)) xdes_t (srv_startup_is_before_trx_rollback_phase && fsp_is_undo_tablespace(fspace->id))))); ut_ad(size == fspace->size_in_header); - ut_ad(flags == fspace->flags); + ut_ad((flags & ~FSP_FLAGS_MASK_DATA_DIR) == + (fspace->flags & ~FSP_FLAGS_MASK_DATA_DIR)); if ((offset >= size) || (offset >= limit)) { return (NULL); diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 73feb56bdcc..e174c3ffbed 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1160,12 +1160,14 @@ matches the in memory table definition. @return DB_SUCCESS or error code. */ dberr_t row_import::match_schema(THD *thd) UNIV_NOTHROW { /* Do some simple checks. */ + const auto relevant_flags = m_flags & ~DICT_TF_MASK_DATA_DIR; + const auto relevant_table_flags = m_table->flags & ~DICT_TF_MASK_DATA_DIR; - if (m_flags != m_table->flags) { + if (relevant_flags != relevant_table_flags) { ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH, - "Table flags don't match, server table has 0x%lx" - " and the meta-data file has 0x%lx", - (ulong)m_table->n_cols, (ulong)m_flags); + "Table flags don't match, server table has 0x%x " + "and the meta-data file has 0x%lx", + relevant_table_flags, relevant_flags); return (DB_ERROR); } else if (m_table->n_cols != m_n_cols) { @@ -3495,7 +3497,8 @@ dberr_t row_import_for_mysql(dict_table_t *table, dd::Table *table_def, return (row_import_error(prebuilt, trx, DB_TABLESPACE_NOT_FOUND)); } } else { - ut_ad(space->flags == space_flags_from_disk); + ut_ad((space->flags & ~FSP_FLAGS_MASK_DATA_DIR) == + (space_flags_from_disk & ~FSP_FLAGS_MASK_DATA_DIR)); } if (dict_table_is_encrypted(table)) {