diff options
author | Eugene Kosov <claprix@yandex.ru> | 2020-10-20 20:10:40 +0300 |
---|---|---|
committer | Eugene Kosov <claprix@yandex.ru> | 2020-10-26 17:39:52 +0300 |
commit | 31cde275c26ba5009d16dfc62654884b94b22322 (patch) | |
tree | 22accfbb43d0a36b48831f48224b1162dd29dac9 | |
parent | 045671d473609fe1947b1ce7775c4aa2e1a6269b (diff) | |
download | mariadb-git-31cde275c26ba5009d16dfc62654884b94b22322.tar.gz |
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ä
-rw-r--r-- | mysql-test/suite/innodb/r/instant_alter_index_rename.result | 36 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/instant_alter_index_rename.test | 20 | ||||
-rw-r--r-- | storage/innobase/handler/handler0alter.cc | 73 |
3 files changed, 114 insertions, 15 deletions
diff --git a/mysql-test/suite/innodb/r/instant_alter_index_rename.result b/mysql-test/suite/innodb/r/instant_alter_index_rename.result index 69f7cc8df4c..41dec275d90 100644 --- a/mysql-test/suite/innodb/r/instant_alter_index_rename.result +++ b/mysql-test/suite/innodb/r/instant_alter_index_rename.result @@ -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; diff --git a/mysql-test/suite/innodb/t/instant_alter_index_rename.test b/mysql-test/suite/innodb/t/instant_alter_index_rename.test index dd6cee7c860..af66c1027cc 100644 --- a/mysql-test/suite/innodb/t/instant_alter_index_rename.test +++ b/mysql-test/suite/innodb/t/instant_alter_index_rename.test @@ -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; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index fef2d9650c0..5700bdcacb6 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -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,22 +7452,28 @@ 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 @@ -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)); } |