MDEV-15562: Simplify FOREIGN KEY error handling on DDL

The error handling for ALTER TABLE…ALGORITHM=COPY as well as
CREATE TABLE used to commit the CREATE TABLE transaction and then
issue DROP TABLE in a separate transaction. This is unnecessarily
breaking atomicity during DDL operations. Let us revise it so
that the DROP TABLE will be executed within the same transaction,
which will finally be rolled back.

FIXME: Introduce an undo log record so that the data file would be
deleted on rollback and no DROP TABLE would be needed at all.

FIXME: Avoid unnecessary access to per-table tablespace during DROP TABLE.
If the .ibd file is going to be deleted anyway, we should not bother
to mark the pages free.

dict_create_add_foreigns_to_dictionary(): Do not commit the transaction.
We want simple rollback in case dict_load_foreigns() would fail.

create_table_info_t::create_table(), row_create_index_for_mysql(),
row_table_add_foreign_constraints(): Before invoking rollback, drop
the table. Rollback would invoke trx_t::evict_table(), and after that
dropping the table would be a no-op.

ha_innobase::create(): Before rollback, drop the table. If the SQL
layer invoked ha_innobase::delete_table() later, it would be a no-op
because the rollback would have invoked trx_t::evict_table().
This commit is contained in:
Marko Mäkelä 2018-10-10 12:06:19 +03:00
parent cd08173490
commit f58a0b3afc
3 changed files with 16 additions and 33 deletions

View file

@ -2116,6 +2116,8 @@ dict_create_add_foreigns_to_dictionary(
return(DB_ERROR);
}
error = DB_SUCCESS;
for (dict_foreign_set::const_iterator it = local_fk_set.begin();
it != local_fk_set.end();
++it) {
@ -2127,21 +2129,11 @@ dict_create_add_foreigns_to_dictionary(
table->name.m_name, foreign, trx);
if (error != DB_SUCCESS) {
return(error);
break;
}
}
trx->op_info = "committing foreign key definitions";
if (trx_is_started(trx)) {
trx_commit(trx);
}
trx->op_info = "";
return(DB_SUCCESS);
return error;
}
/****************************************************************//**

View file

@ -12356,12 +12356,9 @@ int create_table_info_t::create_table(bool create_fk)
error = convert_error_code_to_mysql(err, 0, NULL);
if (error) {
trx_rollback_to_savepoint(m_trx, NULL);
m_trx->error_state = DB_SUCCESS;
row_drop_table_for_mysql(m_table_name, m_trx,
SQLCOM_DROP_DB);
trx_rollback_to_savepoint(m_trx, NULL);
m_trx->error_state = DB_SUCCESS;
DBUG_RETURN(error);
}
@ -12586,6 +12583,8 @@ ha_innobase::create(
}
if ((error = info.create_table(own_trx))) {
row_drop_table_for_mysql(norm_name, trx, SQLCOM_DROP_TABLE,
true);
trx_rollback_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx);
if (own_trx) {

View file

@ -2604,16 +2604,10 @@ error_handling:
trx->error_state = DB_SUCCESS;
if (trx_is_started(trx)) {
row_drop_table_for_mysql(table->name.m_name, trx,
SQLCOM_DROP_TABLE, true);
trx_rollback_to_savepoint(trx, NULL);
}
row_drop_table_for_mysql(table->name.m_name, trx,
SQLCOM_DROP_TABLE, true);
if (trx_is_started(trx)) {
trx_commit_for_mysql(trx);
ut_ad(!trx_is_started(trx));
}
trx->error_state = DB_SUCCESS;
@ -2691,15 +2685,13 @@ row_table_add_foreign_constraints(
trx->error_state = DB_SUCCESS;
if (trx_is_started(trx)) {
/* FIXME: Introduce an undo log record for
creating tablespaces and data files, so that
they would be deleted on rollback. */
row_drop_table_for_mysql(name, trx, SQLCOM_DROP_TABLE,
true);
trx_rollback_to_savepoint(trx, NULL);
}
row_drop_table_for_mysql(name, trx, SQLCOM_DROP_TABLE, true);
if (trx_is_started(trx)) {
trx_commit_for_mysql(trx);
ut_ad(!trx_is_started(trx));
}
trx->error_state = DB_SUCCESS;