diff --git a/mysql-test/suite/innodb/r/instant_alter_charset.result b/mysql-test/suite/innodb/r/instant_alter_charset.result index 1f5f61f9451..82d6ce899c0 100644 --- a/mysql-test/suite/innodb/r/instant_alter_charset.result +++ b/mysql-test/suite/innodb/r/instant_alter_charset.result @@ -1820,3 +1820,10 @@ HEX(a) 61 62 DROP TABLE t1; +# +# MDEV-19524 Server crashes in Bitmap<64u>::is_clear_all / Field_longstr::csinfo_change_allows_instant_alter +# +CREATE TABLE t1 (a VARCHAR(1), UNIQUE(a)) ENGINE=InnoDB; +ALTER TABLE t1 MODIFY a INT, ADD b INT, ADD UNIQUE (b), ALGORITHM=INSTANT; +ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Cannot change column type. Try ALGORITHM=COPY +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/instant_alter_charset.test b/mysql-test/suite/innodb/t/instant_alter_charset.test index 37801b9414d..8c2d6112c8c 100644 --- a/mysql-test/suite/innodb/t/instant_alter_charset.test +++ b/mysql-test/suite/innodb/t/instant_alter_charset.test @@ -1,5 +1,4 @@ --source include/innodb_row_format.inc -#--source include/innodb_page_size.inc --let $row_format= `SELECT @@GLOBAL.innodb_default_row_format` set names utf8; @@ -593,3 +592,15 @@ ALTER TABLE t1 ALGORITHM=INSTANT, MODIFY a VARCHAR(10) CHARACTER SET latin1 COLL ALTER IGNORE TABLE t1 MODIFY a VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_general_ci; SELECT HEX(a) FROM t1; DROP TABLE t1; + + + +--echo # +--echo # MDEV-19524 Server crashes in Bitmap<64u>::is_clear_all / Field_longstr::csinfo_change_allows_instant_alter +--echo # + +CREATE TABLE t1 (a VARCHAR(1), UNIQUE(a)) ENGINE=InnoDB; +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +ALTER TABLE t1 MODIFY a INT, ADD b INT, ADD UNIQUE (b), ALGORITHM=INSTANT; +DROP TABLE t1; + diff --git a/sql/sql_table.cc b/sql/sql_table.cc index df5dea0bfad..7c1672ace93 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6540,8 +6540,16 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key, *new_part= new_key->key_part; key_part < end; key_part++, new_part++) { + /* + For prefix keys KEY_PART_INFO::field points to cloned Field + object with adjusted length. So below we have to check field + indexes instead of simply comparing pointers to Field objects. + */ Create_field *new_field= alter_info->create_list.elem(new_part->fieldnr); - const Field *old_field= table->field[key_part->fieldnr - 1]; + if (!new_field->field || + new_field->field->field_index != key_part->fieldnr - 1) + return Compare_keys::NotEqual; + /* If there is a change in index length due to column expansion like varchar(X) changed to varchar(X + N) and has a compatible @@ -6551,6 +6559,7 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key, Key definition has changed if we are using a different field or if the user key part length is different. */ + const Field *old_field= table->field[key_part->fieldnr - 1]; auto old_field_len= old_field->pack_length(); if (old_field->type() == MYSQL_TYPE_VARCHAR) @@ -6568,15 +6577,6 @@ Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key, } else if (key_part->length != new_part->length) return Compare_keys::NotEqual; - - /* - For prefix keys KEY_PART_INFO::field points to cloned Field - object with adjusted length. So below we have to check field - indexes instead of simply comparing pointers to Field objects. - */ - if (!new_field->field || - new_field->field->field_index != key_part->fieldnr - 1) - return Compare_keys::NotEqual; } /*