From 941ca92a2ca3990020b23bcc92e7ca98dcc8f814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 4 Oct 2018 16:12:04 +0300 Subject: [PATCH] MDEV-11369: Perform validation at IMPORT TABLESPACE btr_cur_instant_root_init(): Check the "infimum" and "supremum" record strings already here, and not later in btr_cur_instant_root_init(). In this way, we can properly reject files from later versions where instant ALTER TABLE could support further operations that change the format of InnoDB clustered indexes. --- storage/innobase/btr/btr0cur.cc | 47 ++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index aa56911d337d9..27975abe0ab10 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -392,24 +392,28 @@ when loading a table definition. @return error code @retval DB_SUCCESS if no error occurred @retval DB_CORRUPTION if any corruption was noticed */ -static -dberr_t -btr_cur_instant_init_low(dict_index_t* index, mtr_t* mtr) +static dberr_t btr_cur_instant_init_low(dict_index_t* index, mtr_t* mtr) { ut_ad(index->is_primary()); ut_ad(index->n_core_null_bytes == dict_index_t::NO_CORE_NULL_BYTES); ut_ad(index->table->supports_instant()); ut_ad(index->table->is_readable()); - page_t* root = btr_root_get(index, mtr); - - if (!root || btr_cur_instant_root_init(index, root)) { + const fil_space_t* space = index->table->space; + if (!space) { +unreadable: ib::error() << "Table " << index->table->name << " has an unreadable root page"; index->table->corrupted = true; return DB_CORRUPTION; } + page_t* root = btr_root_get(index, mtr); + + if (!root || btr_cur_instant_root_init(index, root)) { + goto unreadable; + } + ut_ad(index->n_core_null_bytes != dict_index_t::NO_CORE_NULL_BYTES); if (fil_page_get_type(root) == FIL_PAGE_INDEX) { @@ -417,17 +421,6 @@ btr_cur_instant_init_low(dict_index_t* index, mtr_t* mtr) return DB_SUCCESS; } - /* In a later format, these fields in a FIL_PAGE_TYPE_INSTANT - root page could be repurposed for something else. */ - if (memcmp(page_get_infimum_rec(root), "infimum", 8) - || memcmp(page_get_supremum_rec(root), "supremum", 8)) { -incompatible: - ib::error() << "Table " << index->table->name - << " contains unrecognizable instant ALTER metadata"; - index->table->corrupted = true; - return DB_CORRUPTION; - } - btr_cur_t cur; dberr_t err = btr_cur_open_at_index_side(true, index, BTR_SEARCH_LEAF, &cur, 0, mtr); @@ -466,7 +459,11 @@ btr_cur_instant_init_low(dict_index_t* index, mtr_t* mtr) if (info_bits != REC_INFO_MIN_REC_FLAG || (comp && rec_get_status(rec) != REC_STATUS_COLUMNS_ADDED)) { - goto incompatible; +incompatible: + ib::error() << "Table " << index->table->name + << " contains unrecognizable instant ALTER metadata"; + index->table->corrupted = true; + return DB_CORRUPTION; } /* Read the metadata. We can get here on server restart @@ -558,8 +555,7 @@ index root page. @param[in] index clustered index that is on its first access @param[in] page clustered index root page @return whether the page is corrupted */ -bool -btr_cur_instant_root_init(dict_index_t* index, const page_t* page) +bool btr_cur_instant_root_init(dict_index_t* index, const page_t* page) { ut_ad(page_is_root(page)); ut_ad(!page_is_comp(page) == !dict_table_is_comp(index->table)); @@ -590,7 +586,8 @@ btr_cur_instant_root_init(dict_index_t* index, const page_t* page) break; } - uint16_t n = page_get_instant(page); + const uint16_t n = page_get_instant(page); + if (n < index->n_uniq + DATA_ROLL_PTR || n > index->n_fields) { /* The PRIMARY KEY (or hidden DB_ROW_ID) and DB_TRX_ID,DB_ROLL_PTR columns must always be present @@ -599,6 +596,14 @@ btr_cur_instant_root_init(dict_index_t* index, const page_t* page) dictionary. */ return true; } + + if (memcmp(page_get_infimum_rec(page), "infimum", 8) + || memcmp(page_get_supremum_rec(page), "supremum", 8)) { + /* In a later format, these fields in a FIL_PAGE_TYPE_INSTANT + root page could be repurposed for something else. */ + return true; + } + index->n_core_fields = n; ut_ad(!index->is_dummy); ut_d(index->is_dummy = true);