summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Kosov <claprix@yandex.ru>2020-10-20 20:10:40 +0300
committerEugene Kosov <claprix@yandex.ru>2020-10-26 17:39:52 +0300
commit31cde275c26ba5009d16dfc62654884b94b22322 (patch)
tree22accfbb43d0a36b48831f48224b1162dd29dac9
parent045671d473609fe1947b1ce7775c4aa2e1a6269b (diff)
downloadmariadb-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.result36
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_index_rename.test20
-rw-r--r--storage/innobase/handler/handler0alter.cc73
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));
}