summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorJon Olav Hauglid <jon.hauglid@oracle.com>2012-07-10 16:13:02 +0200
committerJon Olav Hauglid <jon.hauglid@oracle.com>2012-07-10 16:13:02 +0200
commit96bb813a456a6095ba98de6bb5b23b3223698413 (patch)
tree2f0f5bf0730e49db52ff4147ebaa46333c876ba4 /sql
parentacc896135e083c5615403f4d60365349f6ede8e4 (diff)
downloadmariadb-git-96bb813a456a6095ba98de6bb5b23b3223698413.tar.gz
Bug#12623923 Server can crash after failure to create
primary key with innodb tables The bug was triggered if a single ALTER TABLE statement both added and dropped indexes and ALTER TABLE failed during drop (e.g. because the index was needed in a foreign key constraint). In such cases, the server index information would get out of sync with InnoDB - the added index would be present inside InnoDB, but not in the server. This could then lead to InnoDB error messages and/or server crashes. The root cause is that new indexes are added before old indexes are dropped. This means that if ALTER TABLE fails while dropping indexes, index changes will be reverted in the server but not inside InnoDB. This patch fixes the problem by dropping any added indexes if drop fails (for ALTER TABLE statements that both adds and drops indexes). However, this won't work if we added a primary key as this key might not be possible to drop inside InnoDB. Therefore, we resort to the copy algorithm if a primary key is added by an ALTER TABLE statement that also drops an index. In 5.6 this bug is more properly fixed by the handler interface changes done in the scope of WL#5534 "Online ALTER".
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_table.cc49
1 files changed, 41 insertions, 8 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 60ae2ed800b..7d70fa8afd2 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -6313,11 +6313,23 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
the primary key is not added and dropped in the same statement.
Otherwise we have to recreate the table.
need_copy_table is no-zero at this place.
+
+ Also, in-place is not possible if we add a primary key
+ and drop another key in the same statement. If the drop fails,
+ we will not be able to revert adding of primary key.
*/
if ( pk_changed < 2 )
{
- if ((alter_flags & needed_inplace_with_read_flags) ==
- needed_inplace_with_read_flags)
+ if ((needed_inplace_with_read_flags & HA_INPLACE_ADD_PK_INDEX_NO_WRITE) &&
+ index_drop_count > 0)
+ {
+ /*
+ Do copy, not in-place ALTER.
+ Avoid setting ALTER_TABLE_METADATA_ONLY.
+ */
+ }
+ else if ((alter_flags & needed_inplace_with_read_flags) ==
+ needed_inplace_with_read_flags)
{
/* All required in-place flags to allow concurrent reads are present. */
need_copy_table= ALTER_TABLE_METADATA_ONLY;
@@ -6579,17 +6591,38 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Tell the handler to prepare for drop indexes.
This re-numbers the indexes to get rid of gaps.
*/
- if ((error= table->file->prepare_drop_index(table, key_numbers,
- index_drop_count)))
+ error= table->file->prepare_drop_index(table, key_numbers,
+ index_drop_count);
+ if (!error)
{
- table->file->print_error(error, MYF(0));
- goto err_new_table_cleanup;
+ /* Tell the handler to finally drop the indexes. */
+ error= table->file->final_drop_index(table);
}
- /* Tell the handler to finally drop the indexes. */
- if ((error= table->file->final_drop_index(table)))
+ if (error)
{
table->file->print_error(error, MYF(0));
+ if (index_add_count) // Drop any new indexes added.
+ {
+ /*
+ Temporarily set table-key_info to include information about the
+ indexes added above that we now need to drop.
+ */
+ KEY *save_key_info= table->key_info;
+ table->key_info= key_info_buffer;
+ if ((error= table->file->prepare_drop_index(table, index_add_buffer,
+ index_add_count)))
+ table->file->print_error(error, MYF(0));
+ else if ((error= table->file->final_drop_index(table)))
+ table->file->print_error(error, MYF(0));
+ table->key_info= save_key_info;
+ }
+
+ /*
+ Mark this TABLE instance as stale to avoid
+ out-of-sync index information.
+ */
+ table->m_needs_reopen= true;
goto err_new_table_cleanup;
}
}