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;
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;
......
......@@ -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.
......
......@@ -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;
......
......@@ -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
......
......@@ -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;
......@@ -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;
......@@ -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<Create_field> 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 @@ ha_innobase::check_if_supported_inplace_alter(
}
bool fts_need_rebuild = false;
const bool 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;
need_rebuild = need_rebuild
|| innobase_need_rebuild(ha_alter_info, table);
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
......
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