diff options
author | Monty <monty@mariadb.org> | 2018-05-15 12:30:32 +0300 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2018-05-15 13:12:35 +0300 |
commit | b050df4fd3ee5f2377a814fd24ac3774d1458f99 (patch) | |
tree | cd4b05e9e20c6dfe6f9f9d42a402cf934ec7c583 /sql | |
parent | 197bf0fe35efb148c4e751e1b695786d61238e8e (diff) | |
download | mariadb-git-b050df4fd3ee5f2377a814fd24ac3774d1458f99.tar.gz |
MDEV-14943 Alter table ORDER BY bug
Problem was that if copy_data_between_tables() didn't do proper
clean up in case of failures:
- copy object was not properly freed
- end_bulk_insert() was not called
- mysql_trans_prepare_alter_copy_data() set THD->transaction.on to
false which was not properly restored
The last part caused a crash in Aria as Aria depends on that THD
is correct.
Other things:
- Reset info->switched_transactional after usage (safety)
- Reset bulk_insert_single_undo (safety)
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sql_table.cc | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8f3468a44db..27d579a6b19 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9356,9 +9356,7 @@ bool mysql_trans_prepare_alter_copy_data(THD *thd) This needs to be done before external_lock. */ - if (ha_enable_transaction(thd, FALSE)) - DBUG_RETURN(TRUE); - DBUG_RETURN(FALSE); + DBUG_RETURN(ha_enable_transaction(thd, FALSE) != 0); } @@ -9409,6 +9407,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, ha_rows examined_rows; ha_rows found_rows; bool auto_increment_field_copied= 0; + bool cleanup_done= 0; ulonglong save_sql_mode= thd->variables.sql_mode; ulonglong prev_insert_id, time_to_report_progress; Field **dfield_ptr= to->default_field; @@ -9417,15 +9416,23 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, /* Two or 3 stages; Sorting, copying data and update indexes */ thd_progress_init(thd, 2 + MY_TEST(order)); - if (mysql_trans_prepare_alter_copy_data(thd)) - DBUG_RETURN(-1); - if (!(copy= new Copy_field[to->s->fields])) DBUG_RETURN(-1); /* purecov: inspected */ + if (mysql_trans_prepare_alter_copy_data(thd)) + { + delete [] copy; + DBUG_RETURN(-1); + } + /* We need external lock before we can disable/enable keys */ if (to->file->ha_external_lock(thd, F_WRLCK)) + { + /* Undo call to mysql_trans_prepare_alter_copy_data() */ + ha_enable_transaction(thd, TRUE); + delete [] copy; DBUG_RETURN(-1); + } alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff); @@ -9435,7 +9442,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, from->file->info(HA_STATUS_VARIABLE); to->file->ha_start_bulk_insert(from->file->stats.records, ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT); - List_iterator<Create_field> it(create); Create_field *def; copy_end=copy; @@ -9637,7 +9643,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, } end_read_record(&info); free_io_cache(from); - delete [] copy; THD_STAGE_INFO(thd, stage_enabling_keys); thd_progress_next_stage(thd); @@ -9652,6 +9657,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, to->file->print_error(my_errno,MYF(0)); error= 1; } + cleanup_done= 1; to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); if (mysql_trans_commit_alter_copy_data(thd)) @@ -9663,6 +9669,16 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, *copied= found_count; *deleted=delete_count; to->file->ha_release_auto_increment(); + delete [] copy; + + if (!cleanup_done) + { + /* This happens if we get an error during initialzation of data */ + DBUG_ASSERT(error); + to->file->ha_end_bulk_insert(); + ha_enable_transaction(thd, TRUE); + } + if (to->file->ha_external_lock(thd,F_UNLCK)) error=1; if (error < 0 && to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME)) |