summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Kosov <claprix@yandex.ru>2022-01-17 18:18:30 +0300
committerEugene Kosov <claprix@yandex.ru>2022-01-19 00:04:57 +0300
commite128d852e84b950c8820ba885789888f5580efdc (patch)
treedc7e53c035971ba84be0273d0eaa4dd89f0e08d3
parentf43ef9ba3ad846737b98c60b0d54840ee907c3a3 (diff)
downloadmariadb-git-bb-10.4-MDEV-27272-import-instant-add.tar.gz
MDEV-27272 Crash on EXPORT/IMPORT tablespace with column added in the middlebb-10.4-MDEV-27272-import-instant-add
dict_index_t::reconstruct_fields(): add input validation by replacing some assertions handle_instant_metadata(): fix nullptr dereference
-rw-r--r--mysql-test/suite/innodb/r/instant_alter_import.result9
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_import.test23
-rw-r--r--storage/innobase/dict/dict0mem.cc20
-rw-r--r--storage/innobase/include/dict0mem.h5
-rw-r--r--storage/innobase/row/row0import.cc5
5 files changed, 52 insertions, 10 deletions
diff --git a/mysql-test/suite/innodb/r/instant_alter_import.result b/mysql-test/suite/innodb/r/instant_alter_import.result
index c31e9c8e656..fad2fd99685 100644
--- a/mysql-test/suite/innodb/r/instant_alter_import.result
+++ b/mysql-test/suite/innodb/r/instant_alter_import.result
@@ -118,3 +118,12 @@ FLUSH TABLE t1 FOR EXPORT;
UNLOCK TABLES;
ALTER TABLE t2 IMPORT TABLESPACE;
DROP TABLE t2, t1;
+CREATE TABLE t1 ( id INT NOT NULL, i1 INT, i2 INT, PRIMARY KEY (id)) engine=innodb;
+CREATE TABLE t2 ( id INT NOT NULL, i1 INT, i2 INT, PRIMARY KEY (id)) engine=innodb;
+ALTER TABLE test.t1 add COLUMN i3 INT AFTER i1;
+ALTER TABLE t2 DISCARD TABLESPACE;
+FLUSH TABLES t1 FOR EXPORT;
+UNLOCK TABLES;
+ALTER TABLE t2 IMPORT TABLESPACE;
+ERROR HY000: Index for table 't2' is corrupt; try to repair it
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/innodb/t/instant_alter_import.test b/mysql-test/suite/innodb/t/instant_alter_import.test
index 4bec3f8b7f5..fdf9f8e6cd9 100644
--- a/mysql-test/suite/innodb/t/instant_alter_import.test
+++ b/mysql-test/suite/innodb/t/instant_alter_import.test
@@ -2,6 +2,11 @@
--source include/have_sequence.inc
--source include/innodb_checksum_algorithm.inc
+--disable_query_log
+call mtr.add_suppression("Table `test`.`t2` contains unrecognizable instant ALTER metadata");
+call mtr.add_suppression("Index for table 't2' is corrupt; try to repair it");
+--enable_query_log
+
set default_storage_engine=innodb;
--echo #
@@ -180,3 +185,21 @@ UNLOCK TABLES;
ALTER TABLE t2 IMPORT TABLESPACE;
DROP TABLE t2, t1;
+
+
+CREATE TABLE t1 ( id INT NOT NULL, i1 INT, i2 INT, PRIMARY KEY (id)) engine=innodb;
+CREATE TABLE t2 ( id INT NOT NULL, i1 INT, i2 INT, PRIMARY KEY (id)) engine=innodb;
+
+ALTER TABLE test.t1 add COLUMN i3 INT AFTER i1;
+
+ALTER TABLE t2 DISCARD TABLESPACE;
+FLUSH TABLES t1 FOR EXPORT;
+
+--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd
+--copy_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_DATADIR/test/t2.cfg
+
+UNLOCK TABLES;
+--error ER_NOT_KEYFILE
+ALTER TABLE t2 IMPORT TABLESPACE;
+
+DROP TABLE t1, t2;
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index 2741e29740a..6b1f837634b 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -1211,8 +1211,9 @@ bool dict_foreign_t::affects_fulltext() const
return false;
}
-/** Reconstruct the clustered index fields. */
-inline void dict_index_t::reconstruct_fields()
+/** Reconstruct the clustered index fields.
+@return whether metadata is incorrect */
+inline bool dict_index_t::reconstruct_fields()
{
DBUG_ASSERT(is_primary());
@@ -1243,10 +1244,14 @@ inline void dict_index_t::reconstruct_fields()
fields + n_first, fields + n_fields,
[c](const dict_field_t& o)
{ return o.col->ind == c.ind(); });
+
+ if (old >= fields + n_fields
+ || old->prefix_len
+ || old->col != &table->cols[c.ind()]) {
+ return true;
+ }
+
ut_ad(old >= &fields[n_first]);
- ut_ad(old < &fields[n_fields]);
- DBUG_ASSERT(!old->prefix_len);
- DBUG_ASSERT(old->col == &table->cols[c.ind()]);
f = *old;
}
@@ -1259,6 +1264,8 @@ inline void dict_index_t::reconstruct_fields()
fields = tfields;
n_core_null_bytes = UT_BITS_IN_BYTES(n_core_null);
+
+ return false;
}
/** Reconstruct dropped or reordered columns.
@@ -1323,8 +1330,7 @@ bool dict_table_t::deserialise_columns(const byte* metadata, ulint len)
}
DBUG_ASSERT(col == &dropped_cols[n_dropped_cols]);
- UT_LIST_GET_FIRST(indexes)->reconstruct_fields();
- return false;
+ return UT_LIST_GET_FIRST(indexes)->reconstruct_fields();
}
/** Check if record in clustered index is historical row.
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index fe029fc9fcf..8f0b08e7864 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -1321,8 +1321,9 @@ public:
ulint get_new_n_vcol() const
{ return new_vcol_info ? new_vcol_info->n_v_col : 0; }
- /** Reconstruct the clustered index fields. */
- inline void reconstruct_fields();
+ /** Reconstruct the clustered index fields.
+ @return whether metadata is incorrect */
+ inline bool reconstruct_fields();
/** Check if the index contains a column or a prefix of that column.
@param[in] n column number
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index fa79f223637..e29684f6081 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -3288,7 +3288,10 @@ static dberr_t handle_instant_metadata(dict_table_t *table,
}
mem_heap_t *heap= NULL;
- SCOPE_EXIT([&heap]() { mem_heap_free(heap); });
+ SCOPE_EXIT([&heap]() {
+ if (heap)
+ mem_heap_free(heap);
+ });
while (btr_page_get_level(page.get()) != 0)
{