commit fff909357124ddf6d9115696c7dacfa94113bcb2 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 5a29e6f7e26..cbd18df013d 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 7d2563d69ef..79898e36d15 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2582,7 +2582,13 @@ Fil_shard::get_file_size( 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() << "Table flags are " diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index e7c6c826e0e..9cac0f35bba 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -629,8 +629,8 @@ xdes_get_descriptor_with_space_hdr( || (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 58340856f86..813e25c57a4 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1332,12 +1332,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) { @@ -4021,7 +4024,8 @@ row_import_for_mysql( 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)) {