summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/handler/handler0alter.cc59
-rw-r--r--storage/innobase/include/dict0mem.h9
2 files changed, 68 insertions, 0 deletions
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 8b8ccd2fc11..522f6288762 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -5217,6 +5217,51 @@ dict_index_t::instant_metadata(const dtuple_t& row, mem_heap_t* heap) const
return entry;
}
+/** Assign a new id to invalidate old undo log records, so
+that purge will be unable to refer to fields that used to be
+instantly added to the end of the index. This is only to be
+used during ALTER TABLE when the table is empty, before
+invoking dict_index_t::clear_instant_alter().
+@param[in,out] trx dictionary transaction
+@return error code */
+inline dberr_t dict_table_t::reassign_id(trx_t* trx)
+{
+ DBUG_ASSERT(instant);
+ ut_ad(magic_n == DICT_TABLE_MAGIC_N);
+
+ table_id_t new_id;
+ dict_hdr_get_new_id(&new_id, NULL, NULL, NULL, false);
+ pars_info_t* pinfo = pars_info_create();
+
+ pars_info_add_ull_literal(pinfo, "old", id);
+ pars_info_add_ull_literal(pinfo, "new", new_id);
+
+ ut_ad(mutex_own(&dict_sys->mutex));
+ ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
+ ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
+
+ dberr_t err = que_eval_sql(
+ pinfo,
+ "PROCEDURE RENUMBER_TABLE_ID_PROC () IS\n"
+ "BEGIN\n"
+ "UPDATE SYS_TABLES SET ID=:new WHERE ID=:old;\n"
+ "UPDATE SYS_COLUMNS SET TABLE_ID=:new WHERE TABLE_ID=:old;\n"
+ "UPDATE SYS_INDEXES SET TABLE_ID=:new WHERE TABLE_ID=:old;\n"
+ "END;\n"
+ , FALSE, trx);
+ if (err == DB_SUCCESS) {
+ auto fold = ut_fold_ull(id);
+ HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
+ fold, this);
+ id = new_id;
+ fold = ut_fold_ull(id);
+ HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
+ fold, this);
+ }
+
+ return err;
+}
+
/** Insert or update SYS_COLUMNS and the hidden metadata record
for instant ALTER TABLE.
@param[in] ha_alter_info ALTER TABLE context
@@ -5495,6 +5540,20 @@ add_all_virtual:
empty_table:
/* The table is empty. */
ut_ad(page_is_root(block->frame));
+ if (index->table->instant) {
+ /* Assign a new dict_table_t::id
+ to invalidate old undo log records in purge,
+ so that they cannot refer to fields that were
+ instantly added to the end of the index,
+ instead of using the canonical positions
+ that will be replaced below
+ by index->clear_instant_alter(). */
+ err = index->table->reassign_id(trx);
+ if (err != DB_SUCCESS) {
+ goto func_exit;
+ }
+ }
+ /* MDEV-17383: free metadata BLOBs! */
btr_page_empty(block, NULL, index, 0, &mtr);
index->clear_instant_alter();
err = DB_SUCCESS;
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 7e6fe455b72..6a408aaaa9e 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -1677,6 +1677,15 @@ struct dict_table_t {
const char* old_v_col_names,
const ulint* col_map);
+ /** Assign a new id to invalidate old undo log records, so
+ that purge will be unable to refer to fields that used to be
+ instantly added to the end of the index. This is only to be
+ used during ALTER TABLE when the table is empty, before
+ invoking dict_index_t::clear_instant_alter().
+ @param[in,out] trx dictionary transaction
+ @return error code */
+ inline dberr_t reassign_id(trx_t* trx);
+
/** Add the table definition to the data dictionary cache */
void add_to_cache();