commit 74ef5b614b28d7ddfe101ba604f9bb4f7baed9dd Author: Laurynas Biveinis Date: Thu Jun 1 16:54:01 2017 +0300 Fix bugs 76142 / 82480 / 1548597 (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_node_open_file() 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 70c6b63481c..988d5f1fa64 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 23667304766..bfcecc4aa49 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..1bf82e497eb --- /dev/null +++ b/mysql-test/suite/innodb/t/bug76142.test @@ -0,0 +1,40 @@ +--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; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 68dc0e76418..916bb2068dd 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -807,14 +807,20 @@ retry: space->flags |= flags & FSP_FLAGS_MASK_SDI; /* ut_ad(space->flags == flags); */ - if (space->flags != flags) { + /* Validate the flags but 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() << "Table flags are " - << ib::hex(space->flags) << " in the data" - " dictionary but the flags in file " - << node->name << " are " << ib::hex(flags) - << "!"; + << ib::hex(relevant_space_flags) << " in the " + "data dictionary but the flags in file " + << node->name << " are " + << ib::hex(relevant_flags) << "!"; } { diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index f90df482224..45685e054a7 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -692,8 +692,8 @@ xdes_get_descriptor_with_space_hdr( || (srv_startup_is_before_trx_rollback_phase && fspace->id <= srv_undo_tablespaces)))); 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 ad2ef2f0fbd..27262e140aa 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1312,12 +1312,15 @@ 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) {