From 69221746db4814d9395fc9905e1aae4f497c92e1 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 17 Jan 2019 23:17:37 +0100 Subject: [PATCH 1/4] MDEV-18289 - Fix a race between thd_destructor_proxy() startup and server shutdown. Prior to adding current thd to the global thd list, initialize thd->mysys_var->current_cond / thd->mysys_var->current_mutex. Otherwise thd_destructor_proxy can miss the abort condition, which is set by the shutdown thread. --- storage/innobase/handler/ha_innodb.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 195712a5e54..e439db8d828 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -317,11 +317,12 @@ thd_destructor_proxy(void *) mysql_cond_init(PSI_NOT_INSTRUMENTED, &thd_destructor_cond, 0); st_my_thread_var *myvar= _my_thread_var(); + myvar->current_mutex = &thd_destructor_mutex; + myvar->current_cond = &thd_destructor_cond; + THD *thd= create_thd(); thd_proc_info(thd, "InnoDB shutdown handler"); - myvar->current_mutex = &thd_destructor_mutex; - myvar->current_cond = &thd_destructor_cond; mysql_mutex_lock(&thd_destructor_mutex); my_atomic_storeptr_explicit(reinterpret_cast(&srv_running), From 1d72db45a880d07fec5eda648601235f96a693c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 18 Jan 2019 06:46:39 +0200 Subject: [PATCH 2/4] MDEV-18237 InnoDB: Unable to drop FTS index aux table and further errors (possibly bogus) row_drop_table_for_mysql(): Fix a regression introduced in MDEV-16515. Similar to the follow-up fixes MDEV-16647 and MDEV-17470, we must make the internal tables of FULLTEXT INDEX immune to kills, to avoid noise and resource leakage on DROP TABLE or ALTER TABLE. (Orphan internal tables would be dropped at the next InnoDB startup only.) --- storage/innobase/row/row0mysql.cc | 6 ++++-- storage/xtradb/row/row0mysql.cc | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 6ccedfd5343..afab1822bf5 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2018, MariaDB Corporation. +Copyright (c) 2015, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -4225,7 +4225,9 @@ row_drop_table_for_mysql( hold the InnoDB dictionary lock, we will drop any adaptive hash index entries upfront. */ const bool is_temp = dict_table_is_temporary(table) - || strstr(tablename_minus_db, tmp_file_prefix); + || strncmp(tablename_minus_db, tmp_file_prefix, + tmp_file_prefix_length) + || strncmp(tablename_minus_db, "FTS_", 4); while (buf_LRU_drop_page_hash_for_tablespace(table)) { if ((!is_temp && trx_is_interrupted(trx)) || srv_shutdown_state != SRV_SHUTDOWN_NONE) { diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc index 57d06e58943..6c11dd78d7a 100644 --- a/storage/xtradb/row/row0mysql.cc +++ b/storage/xtradb/row/row0mysql.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2018, MariaDB Corporation. +Copyright (c) 2015, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -4235,7 +4235,9 @@ row_drop_table_for_mysql( hold the InnoDB dictionary lock, we will drop any adaptive hash index entries upfront. */ const bool is_temp = dict_table_is_temporary(table) - || strstr(tablename_minus_db, tmp_file_prefix); + || strncmp(tablename_minus_db, tmp_file_prefix, + tmp_file_prefix_length) + || strncmp(tablename_minus_db, "FTS_", 4); while (buf_LRU_drop_page_hash_for_tablespace(table)) { if ((!is_temp && trx_is_interrupted(trx)) || srv_shutdown_state != SRV_SHUTDOWN_NONE) { From 5f60c7c3c23c5f20fd9a8074aa72df00e13a1c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 18 Jan 2019 10:39:52 +0200 Subject: [PATCH 3/4] MDEV-17823 Assertion failed when accessing indexed instantly added column This assertion would fail when a secondary index record for an instantly added column was accessed. It is unclear to me why this code path is executed so rarely. I was unable to cover it even when using FORCE INDEX. row_sel_sec_rec_is_for_clust_rec(): Remove the assertion, and use the proper function rec_get_nth_cfield(). row_sel_store_mysql_field_func(): Simply use rec_get_nth_cfield() instead of duplicating its logic. --- storage/innobase/row/row0sel.cc | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 58b063a3b05..8ca33d33d80 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -254,9 +254,9 @@ row_sel_sec_rec_is_for_clust_rec( clust_field = static_cast(vfield->data); } else { clust_pos = dict_col_get_clust_pos(col, clust_index); - ut_ad(!rec_offs_nth_default(clust_offs, clust_pos)); - clust_field = rec_get_nth_field( - clust_rec, clust_offs, clust_pos, &clust_len); + clust_field = rec_get_nth_cfield( + clust_rec, clust_index, clust_offs, + clust_pos, &clust_len); } sec_field = rec_get_nth_field(sec_rec, sec_offs, i, &sec_len); @@ -3010,17 +3010,7 @@ row_sel_store_mysql_field_func( } else { /* The field is stored in the index record, or in the metadata for instant ADD COLUMN. */ - - if (rec_offs_nth_default(offsets, field_no)) { - ut_ad(dict_index_is_clust(index)); - ut_ad(index->is_instant()); - const dict_index_t* clust_index - = dict_table_get_first_index(prebuilt->table); - ut_ad(index == clust_index); - data = clust_index->instant_field_value(field_no,&len); - } else { - data = rec_get_nth_field(rec, offsets, field_no, &len); - } + data = rec_get_nth_cfield(rec, index, offsets, field_no, &len); if (len == UNIV_SQL_NULL) { /* MySQL assumes that the field for an SQL From 4e75bfcb21469c9efbbc55d2ff3978e11475d40d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 18 Jan 2019 12:39:19 +0200 Subject: [PATCH 4/4] MDEV-18152 Assertion 'num_fts_index <= 1' failed InnoDB does not allow creating multiple FULLTEXT INDEX in ALGORITHM=INPLACE. This constraint was not being properly enforced after MariaDB started to support ALGORITHM=INSTANT and instant ADD COLUMN. As a side effect of this bug, we again allow ALGORITHM=INPLACE to rebuild a table when one FULLTEXT INDEX survives. Also, we are returning a more accurate reason for refusing LOCK=NONE. innobase_fulltext_exist(): Return the number of fulltext indexes. ha_innobase::check_if_supported_inplace_alter(): If the table needs to be rebuilt, refuse the operation if multiple fulltext indexes would remain. --- mysql-test/main/innodb_mysql_sync.result | 4 +- mysql-test/main/innodb_mysql_sync.test | 2 +- mysql-test/suite/innodb/r/innodb-alter.result | 10 +-- mysql-test/suite/innodb/t/innodb-alter.test | 5 -- .../suite/innodb_fts/r/innodb-fts-ddl.result | 11 ++- .../suite/innodb_fts/t/innodb-fts-ddl.test | 10 +++ storage/innobase/handler/handler0alter.cc | 83 +++++++++---------- 7 files changed, 68 insertions(+), 57 deletions(-) diff --git a/mysql-test/main/innodb_mysql_sync.result b/mysql-test/main/innodb_mysql_sync.result index a8a264d6580..3f284edde86 100644 --- a/mysql-test/main/innodb_mysql_sync.result +++ b/mysql-test/main/innodb_mysql_sync.result @@ -489,7 +489,9 @@ DROP TABLE t1; SET DEBUG_SYNC= 'alter_table_copy_after_lock_upgrade SIGNAL upgraded'; #Setup a table with FULLTEXT index. connection default; -CREATE TABLE t1(fld1 CHAR(10), FULLTEXT(fld1)) ENGINE= INNODB; +CREATE TABLE t1(fld1 CHAR(10), FULLTEXT(fld1), FULLTEXT(fld1)) ENGINE= INNODB; +Warnings: +Note 1831 Duplicate index `fld1_2`. This is deprecated and will be disallowed in a future release INSERT INTO t1 VALUES("String1"); #OPTIMIZE TABLE operation. OPTIMIZE TABLE t1; diff --git a/mysql-test/main/innodb_mysql_sync.test b/mysql-test/main/innodb_mysql_sync.test index 66935f811d7..4026080c4b4 100644 --- a/mysql-test/main/innodb_mysql_sync.test +++ b/mysql-test/main/innodb_mysql_sync.test @@ -650,7 +650,7 @@ SET DEBUG_SYNC= 'alter_table_copy_after_lock_upgrade SIGNAL upgraded'; --echo #Setup a table with FULLTEXT index. --connection default -CREATE TABLE t1(fld1 CHAR(10), FULLTEXT(fld1)) ENGINE= INNODB; +CREATE TABLE t1(fld1 CHAR(10), FULLTEXT(fld1), FULLTEXT(fld1)) ENGINE= INNODB; INSERT INTO t1 VALUES("String1"); --echo #OPTIMIZE TABLE operation. diff --git a/mysql-test/suite/innodb/r/innodb-alter.result b/mysql-test/suite/innodb/r/innodb-alter.result index 528cd07770b..c596dbb497d 100644 --- a/mysql-test/suite/innodb/r/innodb-alter.result +++ b/mysql-test/suite/innodb/r/innodb-alter.result @@ -439,15 +439,15 @@ tt CREATE TABLE `tt` ( FULLTEXT KEY `ct` (`ct`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ALTER TABLE tt ADD COLUMN c CHAR(1) NOT NULL FIRST, LOCK=NONE; -ERROR 0A000: LOCK=NONE is not supported. Reason: InnoDB presently supports one FULLTEXT index creation at a time. Try LOCK=SHARED +ERROR 0A000: LOCK=NONE is not supported. Reason: Fulltext index creation requires a lock. Try LOCK=SHARED ALTER TABLE tt ADD COLUMN c CHAR(1) NOT NULL, LOCK=NONE; -ERROR 0A000: LOCK=NONE is not supported. Reason: InnoDB presently supports one FULLTEXT index creation at a time. Try LOCK=SHARED +ERROR 0A000: LOCK=NONE is not supported. Reason: Fulltext index creation requires a lock. Try LOCK=SHARED CREATE TABLE tu ( pk INT PRIMARY KEY, FTS_DOC_ID BIGINT UNSIGNED NOT NULL, t TEXT, FULLTEXT INDEX(t) ) ENGINE=InnoDB; ALTER TABLE tu ADD COLUMN c CHAR(1) NOT NULL FIRST, LOCK=NONE; -ERROR 0A000: LOCK=NONE is not supported. Reason: InnoDB presently supports one FULLTEXT index creation at a time. Try LOCK=SHARED +ERROR 0A000: LOCK=NONE is not supported. Reason: Fulltext index creation requires a lock. Try LOCK=SHARED ALTER TABLE tu ADD COLUMN c CHAR(1) NOT NULL, LOCK=NONE; DROP TABLE tu; CREATE TABLE tv ( @@ -456,7 +456,7 @@ UNIQUE INDEX FTS_DOC_ID_INDEX(FTS_DOC_ID), FULLTEXT INDEX(t) ) ENGINE=InnoDB; ALTER TABLE tv ADD COLUMN c CHAR(1) NOT NULL FIRST, LOCK=NONE; -ERROR 0A000: LOCK=NONE is not supported. Reason: InnoDB presently supports one FULLTEXT index creation at a time. Try LOCK=SHARED +ERROR 0A000: LOCK=NONE is not supported. Reason: Fulltext index creation requires a lock. Try LOCK=SHARED ALTER TABLE tv ADD COLUMN c CHAR(1) NOT NULL, LOCK=NONE; DROP TABLE tv; ALTER TABLE t1o CHANGE c1 dB_row_Id INT, ALGORITHM=COPY; @@ -498,8 +498,6 @@ ADD COLUMN FTS_DOC_ID BIGINT UNSIGNED NOT NULL, ALGORITHM=INPLACE; ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: InnoDB presently supports one FULLTEXT index creation at a time. Try ALGORITHM=COPY ALTER TABLE t1o ADD COLUMN FTS_DOC_ID BIGINT UNSIGNED NOT NULL, ALGORITHM=INPLACE; -ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: InnoDB presently supports one FULLTEXT index creation at a time. Try ALGORITHM=COPY -ALTER TABLE t1o ADD COLUMN FTS_DOC_ID BIGINT UNSIGNED NOT NULL; ALTER TABLE t1o DROP COLUMN FTS_DOC_ID, ALGORITHM=INPLACE; ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot drop or rename FTS_DOC_ID. Try ALGORITHM=COPY ALTER TABLE t1o DROP COLUMN FTS_DOC_ID; diff --git a/mysql-test/suite/innodb/t/innodb-alter.test b/mysql-test/suite/innodb/t/innodb-alter.test index 28ff110fc01..14f90dec43c 100644 --- a/mysql-test/suite/innodb/t/innodb-alter.test +++ b/mysql-test/suite/innodb/t/innodb-alter.test @@ -272,13 +272,8 @@ ALTER TABLE t1o ADD FULLTEXT INDEX(cu), ADD COLUMN FTS_DOC_ID BIGINT UNSIGNED NOT NULL, ALGORITHM=INPLACE; # Replace the hidden FTS_DOC_ID column with a user-visible one. -# This used to work if there is at most one fulltext index. -# Currently, we disallow native ALTER TABLE if the table -# contains any FULLTEXT indexes. ---error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON ALTER TABLE t1o ADD COLUMN FTS_DOC_ID BIGINT UNSIGNED NOT NULL, ALGORITHM=INPLACE; -ALTER TABLE t1o ADD COLUMN FTS_DOC_ID BIGINT UNSIGNED NOT NULL; # Replace the user-visible FTS_DOC_ID column with a hidden one. # We do not support this in-place. --error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON diff --git a/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result b/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result index 6ee5f9f4322..1382457debf 100644 --- a/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result +++ b/mysql-test/suite/innodb_fts/r/innodb-fts-ddl.result @@ -79,7 +79,7 @@ CREATE FULLTEXT INDEX idx on fts_test (title, body) LOCK=NONE; ERROR 0A000: LOCK=NONE is not supported. Reason: Fulltext index creation requires a lock. Try LOCK=SHARED ALTER TABLE fts_test ADD FULLTEXT `idx` (title, body), ALGORITHM=NOCOPY; ALTER TABLE fts_test ROW_FORMAT=REDUNDANT, LOCK=NONE; -ERROR 0A000: LOCK=NONE is not supported. Reason: InnoDB presently supports one FULLTEXT index creation at a time. Try LOCK=SHARED +ERROR 0A000: LOCK=NONE is not supported. Reason: Fulltext index creation requires a lock. Try LOCK=SHARED ALTER TABLE fts_test ROW_FORMAT=REDUNDANT; SELECT * FROM fts_test WHERE MATCH (title, body) AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); @@ -228,3 +228,12 @@ DROP TABLE articles; CREATE TABLE t1 (a VARCHAR(3)) ENGINE=InnoDB; ALTER TABLE t1 ADD FULLTEXT KEY(a), ADD COLUMN b VARCHAR(3), ADD FULLTEXT KEY(b); DROP TABLE t1; +# +# MDEV-18152 Assertion 'num_fts_index <= 1' failed +# in prepare_inplace_alter_table_dict +# +CREATE TABLE t1 +(a VARCHAR(128), b VARCHAR(128), FULLTEXT INDEX(a), FULLTEXT INDEX(b)) +ENGINE=InnoDB; +ALTER TABLE t1 ADD c SERIAL; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test index ddd92556772..c81ec18a4e6 100644 --- a/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test +++ b/mysql-test/suite/innodb_fts/t/innodb-fts-ddl.test @@ -276,3 +276,13 @@ ALTER TABLE t1 ADD FULLTEXT KEY(a), ADD COLUMN b VARCHAR(3), ADD FULLTEXT KEY(b) # Cleanup DROP TABLE t1; + +--echo # +--echo # MDEV-18152 Assertion 'num_fts_index <= 1' failed +--echo # in prepare_inplace_alter_table_dict +--echo # +CREATE TABLE t1 +(a VARCHAR(128), b VARCHAR(128), FULLTEXT INDEX(a), FULLTEXT INDEX(b)) +ENGINE=InnoDB; +ALTER TABLE t1 ADD c SERIAL; +DROP TABLE t1; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index a1ec47d17dc..7bea19bc4ad 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -453,20 +453,18 @@ my_error_innodb( /** Determine if fulltext indexes exist in a given table. @param table MySQL table -@return whether fulltext indexes exist on the table */ -static -bool -innobase_fulltext_exist( -/*====================*/ - const TABLE* table) +@return number of fulltext indexes */ +static uint innobase_fulltext_exist(const TABLE* table) { + uint count = 0; + for (uint i = 0; i < table->s->keys; i++) { if (table->key_info[i].flags & HA_FULLTEXT) { - return(true); + count++; } } - return(false); + return count; } /** Determine whether indexed virtual columns exist in a table. @@ -925,11 +923,14 @@ ha_innobase::check_if_supported_inplace_alter( DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } + const char* reason_rebuild = NULL; + switch (ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) { case ALTER_OPTIONS: if (alter_options_need_rebuild(ha_alter_info, table)) { - ha_alter_info->unsupported_reason = my_get_err_msg( + reason_rebuild = my_get_err_msg( ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD); + ha_alter_info->unsupported_reason = reason_rebuild; break; } /* fall through */ @@ -1056,8 +1057,9 @@ ha_innobase::check_if_supported_inplace_alter( } /* We should be able to do the operation in-place. - See if we can do it online (LOCK=NONE). */ - bool online = true; + See if we can do it online (LOCK=NONE) or without rebuild. */ + bool online = true, need_rebuild = false; + const uint fulltext_indexes = innobase_fulltext_exist(altered_table); List_iterator_fast cf_it( ha_alter_info->alter_info->create_list); @@ -1118,8 +1120,7 @@ ha_innobase::check_if_supported_inplace_alter( /* We cannot replace a hidden FTS_DOC_ID with a user-visible FTS_DOC_ID. */ - if (m_prebuilt->table->fts - && innobase_fulltext_exist(altered_table) + if (fulltext_indexes && m_prebuilt->table->fts && !my_strcasecmp( system_charset_info, key_part->field->field_name.str, @@ -1135,8 +1136,8 @@ ha_innobase::check_if_supported_inplace_alter( & AUTO_INCREMENT_FLAG)); if (key_part->field->flags & AUTO_INCREMENT_FLAG) { - /* We cannot assign an AUTO_INCREMENT - column values during online ALTER. */ + /* We cannot assign AUTO_INCREMENT values + during online or instant ALTER. */ DBUG_ASSERT(key_part->field == altered_table -> found_next_number_field); @@ -1146,6 +1147,7 @@ ha_innobase::check_if_supported_inplace_alter( } online = false; + need_rebuild = true; } if (innobase_is_v_fld(key_part->field)) { @@ -1178,7 +1180,7 @@ ha_innobase::check_if_supported_inplace_alter( || (m_prebuilt->table->fts->doc_col < dict_table_get_n_user_cols(m_prebuilt->table))); - if (m_prebuilt->table->fts && innobase_fulltext_exist(altered_table)) { + if (fulltext_indexes && m_prebuilt->table->fts) { /* FULLTEXT indexes are supposed to remain. */ /* Disallow DROP INDEX FTS_DOC_ID_INDEX */ @@ -1308,44 +1310,39 @@ next_column: } bool fts_need_rebuild = false; - const bool need_rebuild = innobase_need_rebuild(ha_alter_info, table); + need_rebuild = need_rebuild + || innobase_need_rebuild(ha_alter_info, table); - if (!online) { - /* We already determined that only a non-locking - operation is possible. */ - } else if ((need_rebuild || (ha_alter_info->handler_flags - & ALTER_ADD_PK_INDEX)) - && (innobase_fulltext_exist(altered_table) - || innobase_spatial_exist(altered_table) - || innobase_indexed_virtual_exist(altered_table))) { - /* Refuse to rebuild the table online, if - FULLTEXT OR SPATIAL indexes are to survive the rebuild. */ - online = false; + if (need_rebuild + && (fulltext_indexes + || innobase_spatial_exist(altered_table) + || innobase_indexed_virtual_exist(altered_table))) { /* If the table already contains fulltext indexes, refuse to rebuild the table natively altogether. */ - if (m_prebuilt->table->fts) { + if (fulltext_indexes > 1) { cannot_create_many_fulltext_index: ha_alter_info->unsupported_reason = my_get_err_msg(ER_INNODB_FT_LIMIT); DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } - if (ha_alter_info->online - && !ha_alter_info->unsupported_reason) { - - if (innobase_spatial_exist(altered_table)) { - ha_alter_info->unsupported_reason = my_get_err_msg( - ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS); - } else if (!innobase_fulltext_exist(altered_table)) { - /* MDEV-14341 FIXME: Remove this limitation. */ - ha_alter_info->unsupported_reason = - "online rebuild with indexed virtual columns"; - } else { - ha_alter_info->unsupported_reason = my_get_err_msg( - ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS); - } + if (!online || !ha_alter_info->online + || ha_alter_info->unsupported_reason != reason_rebuild) { + /* Either LOCK=NONE was not requested, or we already + gave specific reason to refuse it. */ + } else if (fulltext_indexes) { + ha_alter_info->unsupported_reason = my_get_err_msg( + ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS); + } else if (innobase_spatial_exist(altered_table)) { + ha_alter_info->unsupported_reason = my_get_err_msg( + ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS); + } else { + /* MDEV-14341 FIXME: Remove this limitation. */ + ha_alter_info->unsupported_reason = + "online rebuild with indexed virtual columns"; } + online = false; } if (ha_alter_info->handler_flags