Fix bug 76142 (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. Add a testcase. diff --git a/mysql-test/suite/innodb/r/bug-76142.result b/mysql-test/suite/innodb/r/bug-76142.result new file mode 100644 index 0000000..26e2930 --- /dev/null +++ b/mysql-test/suite/innodb/r/bug-76142.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/innodb-wl5522.result b/mysql-test/suite/innodb/r/innodb-wl5522.result index d85873e..f09f153 100644 --- a/mysql-test/suite/innodb/r/innodb-wl5522.result +++ b/mysql-test/suite/innodb/r/innodb-wl5522.result @@ -580,7 +580,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; @@ -592,7 +592,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; @@ -766,7 +766,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; @@ -778,7 +778,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; @@ -955,7 +955,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; @@ -967,7 +967,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/bug-76142.test b/mysql-test/suite/innodb/t/bug-76142.test new file mode 100644 index 0000000..1fb92fe --- /dev/null +++ b/mysql-test/suite/innodb/t/bug-76142.test @@ -0,0 +1,42 @@ +--source include/have_innodb.inc + +--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 5e1a9d6..4922e2d 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -819,12 +819,19 @@ fil_node_open_file( ut_error; } - if (UNIV_UNLIKELY(space->flags != flags)) { + /* Validate the flags but do not compare the data directory + flag, in case this tablespace was relocated. */ + const unsigned relevant_space_flags + = space->flags & ~FSP_FLAGS_MASK_DATA_DIR; + const unsigned relevant_flags + = flags & ~FSP_FLAGS_MASK_DATA_DIR; + if (UNIV_UNLIKELY(relevant_space_flags != relevant_flags)) { fprintf(stderr, - "InnoDB: Error: table flags are 0x%lx" + "InnoDB: Error: table flags are 0x%x" " in the data dictionary\n" - "InnoDB: but the flags in file %s are 0x%lx!\n", - space->flags, node->name, flags); + "InnoDB: but the flags in file %s are 0x%x!\n", + relevant_space_flags, node->name, + relevant_flags); ut_error; } diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 4b49976..31a14f1 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -177,7 +177,7 @@ allows InnoDB to update_create_info() accordingly. */ #define DICT_TF_HAS_ATOMIC_BLOBS(flags) \ ((flags & DICT_TF_MASK_ATOMIC_BLOBS) \ >> DICT_TF_POS_ATOMIC_BLOBS) -/** Return the value of the ATOMIC_BLOBS field */ +/** Return the value of the DATA_DIR field */ #define DICT_TF_HAS_DATA_DIR(flags) \ ((flags & DICT_TF_MASK_DATA_DIR) \ >> DICT_TF_POS_DATA_DIR) diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index eda8995..11c4333 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1335,12 +1335,15 @@ row_import::match_schema( THD* thd) UNIV_NOTHROW { /* Do some simple checks. */ + const unsigned relevant_flags = m_flags & ~DICT_TF_MASK_DATA_DIR; + const unsigned 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%x", + relevant_table_flags, relevant_flags); return(DB_ERROR); } else if (m_table->n_cols != m_n_cols) {