diff options
author | Sergei Golubchik <sergii@pisem.net> | 2014-01-23 11:04:59 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2014-01-23 11:04:59 +0100 |
commit | 2ff76f67506ec056910835d577e6eb88de106b09 (patch) | |
tree | 6fa191da40a2112c9f774f70b718dbc5df52d366 /sql/sql_table.cc | |
parent | 0cdf1573b698bad3a2de5b726eaab8a6a015e12a (diff) | |
download | mariadb-git-2ff76f67506ec056910835d577e6eb88de106b09.tar.gz |
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
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r-- | sql/sql_table.cc | 37 |
1 files changed, 29 insertions, 8 deletions
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; } |