Commit 4e75bfcb authored by Marko Mäkelä's avatar Marko Mäkelä

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.
parent a0d3ead8
...@@ -489,7 +489,9 @@ DROP TABLE t1; ...@@ -489,7 +489,9 @@ DROP TABLE t1;
SET DEBUG_SYNC= 'alter_table_copy_after_lock_upgrade SIGNAL upgraded'; SET DEBUG_SYNC= 'alter_table_copy_after_lock_upgrade SIGNAL upgraded';
#Setup a table with FULLTEXT index. #Setup a table with FULLTEXT index.
connection default; 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"); INSERT INTO t1 VALUES("String1");
#OPTIMIZE TABLE operation. #OPTIMIZE TABLE operation.
OPTIMIZE TABLE t1; OPTIMIZE TABLE t1;
......
...@@ -650,7 +650,7 @@ SET DEBUG_SYNC= 'alter_table_copy_after_lock_upgrade SIGNAL upgraded'; ...@@ -650,7 +650,7 @@ SET DEBUG_SYNC= 'alter_table_copy_after_lock_upgrade SIGNAL upgraded';
--echo #Setup a table with FULLTEXT index. --echo #Setup a table with FULLTEXT index.
--connection default --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"); INSERT INTO t1 VALUES("String1");
--echo #OPTIMIZE TABLE operation. --echo #OPTIMIZE TABLE operation.
......
...@@ -439,15 +439,15 @@ tt CREATE TABLE `tt` ( ...@@ -439,15 +439,15 @@ tt CREATE TABLE `tt` (
FULLTEXT KEY `ct` (`ct`) FULLTEXT KEY `ct` (`ct`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ) ENGINE=InnoDB DEFAULT CHARSET=latin1
ALTER TABLE tt ADD COLUMN c CHAR(1) NOT NULL FIRST, LOCK=NONE; 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; 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 ( CREATE TABLE tu (
pk INT PRIMARY KEY, FTS_DOC_ID BIGINT UNSIGNED NOT NULL, t TEXT, pk INT PRIMARY KEY, FTS_DOC_ID BIGINT UNSIGNED NOT NULL, t TEXT,
FULLTEXT INDEX(t) FULLTEXT INDEX(t)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
ALTER TABLE tu ADD COLUMN c CHAR(1) NOT NULL FIRST, LOCK=NONE; 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; ALTER TABLE tu ADD COLUMN c CHAR(1) NOT NULL, LOCK=NONE;
DROP TABLE tu; DROP TABLE tu;
CREATE TABLE tv ( CREATE TABLE tv (
...@@ -456,7 +456,7 @@ UNIQUE INDEX FTS_DOC_ID_INDEX(FTS_DOC_ID), ...@@ -456,7 +456,7 @@ UNIQUE INDEX FTS_DOC_ID_INDEX(FTS_DOC_ID),
FULLTEXT INDEX(t) FULLTEXT INDEX(t)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
ALTER TABLE tv ADD COLUMN c CHAR(1) NOT NULL FIRST, LOCK=NONE; 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; ALTER TABLE tv ADD COLUMN c CHAR(1) NOT NULL, LOCK=NONE;
DROP TABLE tv; DROP TABLE tv;
ALTER TABLE t1o CHANGE c1 dB_row_Id INT, ALGORITHM=COPY; 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; ...@@ -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 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 ADD COLUMN FTS_DOC_ID BIGINT UNSIGNED NOT NULL,
ALGORITHM=INPLACE; 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; 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 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; ALTER TABLE t1o DROP COLUMN FTS_DOC_ID;
......
...@@ -272,13 +272,8 @@ ALTER TABLE t1o ADD FULLTEXT INDEX(cu), ...@@ -272,13 +272,8 @@ ALTER TABLE t1o ADD FULLTEXT INDEX(cu),
ADD COLUMN FTS_DOC_ID BIGINT UNSIGNED NOT NULL, ALGORITHM=INPLACE; ADD COLUMN FTS_DOC_ID BIGINT UNSIGNED NOT NULL, ALGORITHM=INPLACE;
# Replace the hidden FTS_DOC_ID column with a user-visible one. # 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, ALTER TABLE t1o ADD COLUMN FTS_DOC_ID BIGINT UNSIGNED NOT NULL,
ALGORITHM=INPLACE; 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. # Replace the user-visible FTS_DOC_ID column with a hidden one.
# We do not support this in-place. # We do not support this in-place.
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON --error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
......
...@@ -79,7 +79,7 @@ CREATE FULLTEXT INDEX idx on fts_test (title, body) LOCK=NONE; ...@@ -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 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 ADD FULLTEXT `idx` (title, body), ALGORITHM=NOCOPY;
ALTER TABLE fts_test ROW_FORMAT=REDUNDANT, LOCK=NONE; 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; ALTER TABLE fts_test ROW_FORMAT=REDUNDANT;
SELECT * FROM fts_test WHERE MATCH (title, body) SELECT * FROM fts_test WHERE MATCH (title, body)
AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE);
...@@ -228,3 +228,12 @@ DROP TABLE articles; ...@@ -228,3 +228,12 @@ DROP TABLE articles;
CREATE TABLE t1 (a VARCHAR(3)) ENGINE=InnoDB; CREATE TABLE t1 (a VARCHAR(3)) ENGINE=InnoDB;
ALTER TABLE t1 ADD FULLTEXT KEY(a), ADD COLUMN b VARCHAR(3), ADD FULLTEXT KEY(b); ALTER TABLE t1 ADD FULLTEXT KEY(a), ADD COLUMN b VARCHAR(3), ADD FULLTEXT KEY(b);
DROP TABLE t1; 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;
...@@ -276,3 +276,13 @@ ALTER TABLE t1 ADD FULLTEXT KEY(a), ADD COLUMN b VARCHAR(3), ADD FULLTEXT KEY(b) ...@@ -276,3 +276,13 @@ ALTER TABLE t1 ADD FULLTEXT KEY(a), ADD COLUMN b VARCHAR(3), ADD FULLTEXT KEY(b)
# Cleanup # Cleanup
DROP TABLE t1; 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;
...@@ -453,20 +453,18 @@ my_error_innodb( ...@@ -453,20 +453,18 @@ my_error_innodb(
/** Determine if fulltext indexes exist in a given table. /** Determine if fulltext indexes exist in a given table.
@param table MySQL table @param table MySQL table
@return whether fulltext indexes exist on the table */ @return number of fulltext indexes */
static static uint innobase_fulltext_exist(const TABLE* table)
bool
innobase_fulltext_exist(
/*====================*/
const TABLE* table)
{ {
uint count = 0;
for (uint i = 0; i < table->s->keys; i++) { for (uint i = 0; i < table->s->keys; i++) {
if (table->key_info[i].flags & HA_FULLTEXT) { if (table->key_info[i].flags & HA_FULLTEXT) {
return(true); count++;
} }
} }
return(false); return count;
} }
/** Determine whether indexed virtual columns exist in a table. /** Determine whether indexed virtual columns exist in a table.
...@@ -925,11 +923,14 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -925,11 +923,14 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
} }
const char* reason_rebuild = NULL;
switch (ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) { switch (ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) {
case ALTER_OPTIONS: case ALTER_OPTIONS:
if (alter_options_need_rebuild(ha_alter_info, table)) { 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); ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD);
ha_alter_info->unsupported_reason = reason_rebuild;
break; break;
} }
/* fall through */ /* fall through */
...@@ -1056,8 +1057,9 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -1056,8 +1057,9 @@ ha_innobase::check_if_supported_inplace_alter(
} }
/* We should be able to do the operation in-place. /* We should be able to do the operation in-place.
See if we can do it online (LOCK=NONE). */ See if we can do it online (LOCK=NONE) or without rebuild. */
bool online = true; bool online = true, need_rebuild = false;
const uint fulltext_indexes = innobase_fulltext_exist(altered_table);
List_iterator_fast<Create_field> cf_it( List_iterator_fast<Create_field> cf_it(
ha_alter_info->alter_info->create_list); ha_alter_info->alter_info->create_list);
...@@ -1118,8 +1120,7 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -1118,8 +1120,7 @@ ha_innobase::check_if_supported_inplace_alter(
/* We cannot replace a hidden FTS_DOC_ID /* We cannot replace a hidden FTS_DOC_ID
with a user-visible FTS_DOC_ID. */ with a user-visible FTS_DOC_ID. */
if (m_prebuilt->table->fts if (fulltext_indexes && m_prebuilt->table->fts
&& innobase_fulltext_exist(altered_table)
&& !my_strcasecmp( && !my_strcasecmp(
system_charset_info, system_charset_info,
key_part->field->field_name.str, key_part->field->field_name.str,
...@@ -1135,8 +1136,8 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -1135,8 +1136,8 @@ ha_innobase::check_if_supported_inplace_alter(
& AUTO_INCREMENT_FLAG)); & AUTO_INCREMENT_FLAG));
if (key_part->field->flags & AUTO_INCREMENT_FLAG) { if (key_part->field->flags & AUTO_INCREMENT_FLAG) {
/* We cannot assign an AUTO_INCREMENT /* We cannot assign AUTO_INCREMENT values
column values during online ALTER. */ during online or instant ALTER. */
DBUG_ASSERT(key_part->field == altered_table DBUG_ASSERT(key_part->field == altered_table
-> found_next_number_field); -> found_next_number_field);
...@@ -1146,6 +1147,7 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -1146,6 +1147,7 @@ ha_innobase::check_if_supported_inplace_alter(
} }
online = false; online = false;
need_rebuild = true;
} }
if (innobase_is_v_fld(key_part->field)) { if (innobase_is_v_fld(key_part->field)) {
...@@ -1178,7 +1180,7 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -1178,7 +1180,7 @@ ha_innobase::check_if_supported_inplace_alter(
|| (m_prebuilt->table->fts->doc_col || (m_prebuilt->table->fts->doc_col
< dict_table_get_n_user_cols(m_prebuilt->table))); < 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. */ /* FULLTEXT indexes are supposed to remain. */
/* Disallow DROP INDEX FTS_DOC_ID_INDEX */ /* Disallow DROP INDEX FTS_DOC_ID_INDEX */
...@@ -1308,44 +1310,39 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -1308,44 +1310,39 @@ ha_innobase::check_if_supported_inplace_alter(
} }
bool fts_need_rebuild = false; 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 if (need_rebuild
operation is possible. */ && (fulltext_indexes
} else if ((need_rebuild || (ha_alter_info->handler_flags || innobase_spatial_exist(altered_table)
& ALTER_ADD_PK_INDEX)) || innobase_indexed_virtual_exist(altered_table))) {
&& (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 the table already contains fulltext indexes, /* If the table already contains fulltext indexes,
refuse to rebuild the table natively altogether. */ refuse to rebuild the table natively altogether. */
if (m_prebuilt->table->fts) { if (fulltext_indexes > 1) {
cannot_create_many_fulltext_index: cannot_create_many_fulltext_index:
ha_alter_info->unsupported_reason = ha_alter_info->unsupported_reason =
my_get_err_msg(ER_INNODB_FT_LIMIT); my_get_err_msg(ER_INNODB_FT_LIMIT);
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
} }
if (ha_alter_info->online if (!online || !ha_alter_info->online
&& !ha_alter_info->unsupported_reason) { || ha_alter_info->unsupported_reason != reason_rebuild) {
/* Either LOCK=NONE was not requested, or we already
if (innobase_spatial_exist(altered_table)) { gave specific reason to refuse it. */
ha_alter_info->unsupported_reason = my_get_err_msg( } else if (fulltext_indexes) {
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS); ha_alter_info->unsupported_reason = my_get_err_msg(
} else if (!innobase_fulltext_exist(altered_table)) { ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS);
/* MDEV-14341 FIXME: Remove this limitation. */ } else if (innobase_spatial_exist(altered_table)) {
ha_alter_info->unsupported_reason = ha_alter_info->unsupported_reason = my_get_err_msg(
"online rebuild with indexed virtual columns"; ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS);
} else { } else {
ha_alter_info->unsupported_reason = my_get_err_msg( /* MDEV-14341 FIXME: Remove this limitation. */
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS); ha_alter_info->unsupported_reason =
} "online rebuild with indexed virtual columns";
} }
online = false;
} }
if (ha_alter_info->handler_flags if (ha_alter_info->handler_flags
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment