diff --git a/mysql-test/r/alter_table_trans.result b/mysql-test/r/alter_table_trans.result index 3dd5c00d3d8..67ae4075d57 100644 --- a/mysql-test/r/alter_table_trans.result +++ b/mysql-test/r/alter_table_trans.result @@ -4,3 +4,15 @@ ALTER TABLE t1 RENAME TO t2, DISABLE KEYS; Warnings: Note 1031 Table storage engine for 't1' doesn't have this option DROP TABLE t2; +CREATE TABLE t1 ( +col4 text NOT NULL, +col2 int(11) NOT NULL DEFAULT '0', +col3 int(11) DEFAULT NULL, +extra int(11) DEFAULT NULL, +KEY idx (col4(10)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +insert t1 values (repeat('1', 8193),3,1,1); +insert t1 values (repeat('3', 8193),3,1,1); +ALTER TABLE t1 ADD PRIMARY KEY (col4(10)) , ADD UNIQUE KEY uidx (col3); +ERROR 23000: Duplicate entry '1' for key 'uidx' +DROP TABLE t1; diff --git a/mysql-test/t/alter_table_trans.test b/mysql-test/t/alter_table_trans.test index 9096a392af4..29b9b4c212f 100644 --- a/mysql-test/t/alter_table_trans.test +++ b/mysql-test/t/alter_table_trans.test @@ -13,3 +13,23 @@ drop table if exists t1,t2; CREATE TABLE t1 (a INT, INDEX(a)) engine=innodb; ALTER TABLE t1 RENAME TO t2, DISABLE KEYS; DROP TABLE t2; + +# +# MDEV-5406 add index to an innodb table with a uniqueness violation crashes mysqld +# + +CREATE TABLE t1 ( + col4 text NOT NULL, + col2 int(11) NOT NULL DEFAULT '0', + col3 int(11) DEFAULT NULL, + extra int(11) DEFAULT NULL, + KEY idx (col4(10)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +insert t1 values (repeat('1', 8193),3,1,1); +insert t1 values (repeat('3', 8193),3,1,1); +--error ER_DUP_ENTRY +ALTER TABLE t1 ADD PRIMARY KEY (col4(10)) , ADD UNIQUE KEY uidx (col3); +DROP TABLE t1; + + diff --git a/sql/sql_table.cc b/sql/sql_table.cc index eda178fcc64..c9f754a204f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6893,14 +6893,35 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, /* Only report error if handler has not already reported an error */ if (!thd->is_error()) { - /* - Exchange the key_info for the error message. If we exchange - key number by key name in the message later, we need correct info. - */ - KEY *save_key_info= table->key_info; - table->key_info= key_info; - table->file->print_error(error, MYF(0)); - table->key_info= save_key_info; + /* + HACK HACK HACK + Prepare the list of keys for an error message. + It must match what the engine does internally in ::add_index(). + Here we emulate what innobase_create_key_def() does. + Luckily, in 10.0 this will go away. + */ + KEY *save_key_info= table->key_info; + uint add_cnt= index_add_count, old_cnt= table->s->keys; + KEY *merged= (KEY*)thd->alloc((old_cnt + add_cnt) * sizeof(KEY)); +#define is_PK(K) (!my_strcasecmp(system_charset_info, (K)->name, "PRIMARY")) + + if (is_PK(key_info)) + { + merged[0]= key_info[0]; + if (is_PK(table->key_info)) + { + old_cnt--; + table->key_info++; + } + memcpy(merged + 1, table->key_info, old_cnt * sizeof(KEY)); + memcpy(merged + old_cnt + 1, key_info + 1, (add_cnt - 1) * sizeof(KEY)); + } + else + merged= key_info; + + table->key_info= merged; + table->file->print_error(error, MYF(0)); + table->key_info= save_key_info; } goto err_new_table_cleanup; }