mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
MDEV-5406 add index to an innodb table with a uniqueness violation crashes mysqld
After table->file->add_index() in mysql_alter_table() the table in the engine has the intermediate temporary structure, it's neither the original nor the final table structure (it'll be final after successful table->file->drop_index() call). So, when add_index() fails with a unique key violation, we cannot simply get the failed key number and easily map it to the key name and key structure via table->key_info[key_no]. For now we'll create this "intermediate temporary structure", emulating InnoDB internal rules. This bug and the fix will go away in 10.0 that uses completely different online alter table code. mysql-test/t/alter_table_trans.test: mdev:5406
This commit is contained in:
parent
0cdf1573b6
commit
2ff76f6750
3 changed files with 61 additions and 8 deletions
|
@ -4,3 +4,15 @@ ALTER TABLE t1 RENAME TO t2, DISABLE KEYS;
|
||||||
Warnings:
|
Warnings:
|
||||||
Note 1031 Table storage engine for 't1' doesn't have this option
|
Note 1031 Table storage engine for 't1' doesn't have this option
|
||||||
DROP TABLE t2;
|
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;
|
||||||
|
|
|
@ -13,3 +13,23 @@ drop table if exists t1,t2;
|
||||||
CREATE TABLE t1 (a INT, INDEX(a)) engine=innodb;
|
CREATE TABLE t1 (a INT, INDEX(a)) engine=innodb;
|
||||||
ALTER TABLE t1 RENAME TO t2, DISABLE KEYS;
|
ALTER TABLE t1 RENAME TO t2, DISABLE KEYS;
|
||||||
DROP TABLE t2;
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
/* Only report error if handler has not already reported an error */
|
||||||
if (!thd->is_error())
|
if (!thd->is_error())
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Exchange the key_info for the error message. If we exchange
|
HACK HACK HACK
|
||||||
key number by key name in the message later, we need correct info.
|
Prepare the list of keys for an error message.
|
||||||
*/
|
It must match what the engine does internally in ::add_index().
|
||||||
KEY *save_key_info= table->key_info;
|
Here we emulate what innobase_create_key_def() does.
|
||||||
table->key_info= key_info;
|
Luckily, in 10.0 this will go away.
|
||||||
table->file->print_error(error, MYF(0));
|
*/
|
||||||
table->key_info= save_key_info;
|
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;
|
goto err_new_table_cleanup;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue