MDEV-23356 InnoDB: Failing assertion: field->col->mtype == type, crash or ASAN failures in row_sel_convert_mysql_key_to_innobase, InnoDB indexes are inconsistent after INDEX changes
innobase_rename_indexes_cache(): fix corruption of index cache. Index ids help distinguish indexes when their names clash. innobase_rename_indexes_cache(): fix corruption of index statistics table. Use unique temporary names to avoid names clashing. Reviewed by: Marko Mäkelä
This commit is contained in:
parent
045671d473
commit
31cde275c2
@ -198,3 +198,39 @@ Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
DROP TABLE t1;
|
||||
DROP FUNCTION get_index_id;
|
||||
#
|
||||
# MDEV-23356 InnoDB: Failing assertion: field->col->mtype == type, crash or ASAN failures in row_sel_convert_mysql_key_to_innobase, InnoDB indexes are inconsistent after INDEX changes
|
||||
#
|
||||
CREATE TABLE t1 (a INT, b INT, c CHAR(8),
|
||||
KEY ind1(c), KEY ind2(b)) ENGINE=InnoDB STATS_PERSISTENT=1;
|
||||
INSERT INTO t1 SELECT 1, 1, 'a' FROM seq_1_to_100;
|
||||
SELECT table_name, index_name, stat_name FROM mysql.innodb_index_stats;
|
||||
table_name index_name stat_name
|
||||
t1 GEN_CLUST_INDEX n_diff_pfx01
|
||||
t1 GEN_CLUST_INDEX n_leaf_pages
|
||||
t1 GEN_CLUST_INDEX size
|
||||
t1 ind1 n_diff_pfx01
|
||||
t1 ind1 n_diff_pfx02
|
||||
t1 ind1 n_leaf_pages
|
||||
t1 ind1 size
|
||||
t1 ind2 n_diff_pfx01
|
||||
t1 ind2 n_diff_pfx02
|
||||
t1 ind2 n_leaf_pages
|
||||
t1 ind2 size
|
||||
ALTER TABLE t1 DROP INDEX ind2, ADD INDEX ind3(b),
|
||||
DROP INDEX ind1, ADD INDEX ind2(c);
|
||||
SELECT table_name, index_name, stat_name FROM mysql.innodb_index_stats;
|
||||
table_name index_name stat_name
|
||||
t1 GEN_CLUST_INDEX n_diff_pfx01
|
||||
t1 GEN_CLUST_INDEX n_leaf_pages
|
||||
t1 GEN_CLUST_INDEX size
|
||||
t1 ind2 n_diff_pfx01
|
||||
t1 ind2 n_diff_pfx02
|
||||
t1 ind2 n_leaf_pages
|
||||
t1 ind2 size
|
||||
t1 ind3 n_diff_pfx01
|
||||
t1 ind3 n_diff_pfx02
|
||||
t1 ind3 n_leaf_pages
|
||||
t1 ind3 size
|
||||
UPDATE t1 SET a = 1 WHERE c = 'foo';
|
||||
DROP TABLE t1;
|
||||
|
@ -1,5 +1,6 @@
|
||||
--source include/have_innodb.inc
|
||||
--source include/have_debug.inc
|
||||
--source include/have_sequence.inc
|
||||
|
||||
delimiter |;
|
||||
create function get_index_id(tbl_id int, index_name char(100))
|
||||
@ -207,3 +208,22 @@ CHECK TABLE t1 EXTENDED ;
|
||||
DROP TABLE t1;
|
||||
|
||||
DROP FUNCTION get_index_id;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-23356 InnoDB: Failing assertion: field->col->mtype == type, crash or ASAN failures in row_sel_convert_mysql_key_to_innobase, InnoDB indexes are inconsistent after INDEX changes
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT, b INT, c CHAR(8),
|
||||
KEY ind1(c), KEY ind2(b)) ENGINE=InnoDB STATS_PERSISTENT=1;
|
||||
|
||||
INSERT INTO t1 SELECT 1, 1, 'a' FROM seq_1_to_100;
|
||||
|
||||
SELECT table_name, index_name, stat_name FROM mysql.innodb_index_stats;
|
||||
|
||||
ALTER TABLE t1 DROP INDEX ind2, ADD INDEX ind3(b),
|
||||
DROP INDEX ind1, ADD INDEX ind2(c);
|
||||
|
||||
SELECT table_name, index_name, stat_name FROM mysql.innodb_index_stats;
|
||||
|
||||
UPDATE t1 SET a = 1 WHERE c = 'foo';
|
||||
DROP TABLE t1;
|
||||
|
@ -57,6 +57,8 @@ Smart ALTER TABLE
|
||||
#include "ha_innodb.h"
|
||||
#include "ut0stage.h"
|
||||
#include "span.h"
|
||||
#include <thread>
|
||||
#include <sstream>
|
||||
|
||||
using st_::span;
|
||||
/** File format constraint for ALTER TABLE */
|
||||
@ -7450,23 +7452,29 @@ innobase_rename_index_cache(dict_index_t* index, const char* new_name)
|
||||
/** Rename the index name in cache.
|
||||
@param[in] ctx alter context
|
||||
@param[in] ha_alter_info Data used during inplace alter. */
|
||||
static void innobase_rename_indexes_cache(
|
||||
const ha_innobase_inplace_ctx* ctx,
|
||||
const Alter_inplace_info* ha_alter_info)
|
||||
static void
|
||||
innobase_rename_indexes_cache(const ha_innobase_inplace_ctx *ctx,
|
||||
const Alter_inplace_info *ha_alter_info)
|
||||
{
|
||||
DBUG_ASSERT(ha_alter_info->handler_flags & ALTER_RENAME_INDEX);
|
||||
DBUG_ASSERT(ha_alter_info->handler_flags & ALTER_RENAME_INDEX);
|
||||
|
||||
for (const Alter_inplace_info::Rename_key_pair& pair :
|
||||
ha_alter_info->rename_keys) {
|
||||
dict_index_t* index = dict_table_get_index_on_name(
|
||||
ctx->old_table, pair.old_key->name.str);
|
||||
ut_ad(index);
|
||||
std::vector<std::pair<dict_index_t *, const char *>> rename_info;
|
||||
rename_info.reserve(ha_alter_info->rename_keys.size());
|
||||
|
||||
innobase_rename_index_cache(index, pair.new_key->name.str);
|
||||
}
|
||||
for (const Alter_inplace_info::Rename_key_pair &pair :
|
||||
ha_alter_info->rename_keys)
|
||||
{
|
||||
dict_index_t *index=
|
||||
dict_table_get_index_on_name(ctx->old_table, pair.old_key->name.str);
|
||||
ut_ad(index);
|
||||
|
||||
rename_info.emplace_back(index, pair.new_key->name.str);
|
||||
}
|
||||
|
||||
for (const auto &pair : rename_info)
|
||||
innobase_rename_index_cache(pair.first, pair.second);
|
||||
}
|
||||
|
||||
|
||||
/** Fill the stored column information in s_cols list.
|
||||
@param[in] altered_table mysql table object
|
||||
@param[in] table innodb table object
|
||||
@ -10600,11 +10608,18 @@ alter_stats_norebuild(
|
||||
}
|
||||
}
|
||||
|
||||
for (const Alter_inplace_info::Rename_key_pair& pair :
|
||||
ha_alter_info->rename_keys) {
|
||||
for (size_t i = 0; i < ha_alter_info->rename_keys.size(); i++) {
|
||||
const Alter_inplace_info::Rename_key_pair& pair
|
||||
= ha_alter_info->rename_keys[i];
|
||||
|
||||
std::stringstream ss;
|
||||
ss << TEMP_FILE_PREFIX_INNODB << std::this_thread::get_id()
|
||||
<< i;
|
||||
auto tmp_name = ss.str();
|
||||
|
||||
dberr_t err = dict_stats_rename_index(ctx->new_table,
|
||||
pair.old_key->name.str,
|
||||
pair.new_key->name.str);
|
||||
tmp_name.c_str());
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
push_warning_printf(
|
||||
@ -10616,6 +10631,34 @@ alter_stats_norebuild(
|
||||
" statistics storage: %s",
|
||||
ctx->new_table->name.m_name,
|
||||
pair.old_key->name.str,
|
||||
tmp_name.c_str(),
|
||||
ut_strerr(err));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ha_alter_info->rename_keys.size(); i++) {
|
||||
const Alter_inplace_info::Rename_key_pair& pair
|
||||
= ha_alter_info->rename_keys[i];
|
||||
|
||||
std::stringstream ss;
|
||||
ss << TEMP_FILE_PREFIX_INNODB << std::this_thread::get_id()
|
||||
<< i;
|
||||
auto tmp_name = ss.str();
|
||||
|
||||
dberr_t err = dict_stats_rename_index(ctx->new_table,
|
||||
tmp_name.c_str(),
|
||||
pair.new_key->name.str);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
push_warning_printf(
|
||||
thd,
|
||||
Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_ERROR_ON_RENAME,
|
||||
"Error renaming an index of table '%s'"
|
||||
" from '%s' to '%s' in InnoDB persistent"
|
||||
" statistics storage: %s",
|
||||
ctx->new_table->name.m_name,
|
||||
tmp_name.c_str(),
|
||||
pair.new_key->name.str,
|
||||
ut_strerr(err));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user