Skip to content

Commit

Permalink
MDEV-17816 Crash in TRUNCATE TABLE when table creation fails
Browse files Browse the repository at this point in the history
The error handling in the MDEV-13564 TRUNCATE TABLE was broken
when an error occurred during table creation.

row_create_index_for_mysql(): Do not drop the table on error.

fts_create_one_common_table(), fts_create_one_index_table():
Do drop the table on error.

create_index(), create_table_info_t::create_table():
Let the caller handle the index creation errors.

ha_innobase::create(): If create_table_info_t::create_table()
fails, drop the incomplete table, roll back the transaction,
and finally return an error to the caller.
  • Loading branch information
dr-m committed Nov 26, 2018
1 parent a81fcea commit 2a31b82
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 34 deletions.
12 changes: 12 additions & 0 deletions mysql-test/suite/innodb/r/truncate.result
Expand Up @@ -6,3 +6,15 @@ connection default;
TRUNCATE TABLE t;
disconnect dml;
DROP TABLE t;
#
# MDEV-17816 Crash in TRUNCATE TABLE when table creation fails
#
CREATE TABLE t1 (c VARCHAR(1024), KEY(c)) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
INSERT INTO t1 SET c='character';
ALTER TABLE t1 ROW_FORMAT=REDUNDANT;
TRUNCATE TABLE t1;
ERROR HY000: Index column size too large. The maximum column size is 767 bytes
SELECT * FROM t1;
c
character
DROP TABLE t1;
12 changes: 12 additions & 0 deletions mysql-test/suite/innodb/t/truncate.test
Expand Up @@ -15,3 +15,15 @@ TRUNCATE TABLE t;
disconnect dml;

DROP TABLE t;

--echo #
--echo # MDEV-17816 Crash in TRUNCATE TABLE when table creation fails
--echo #
CREATE TABLE t1 (c VARCHAR(1024), KEY(c)) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
INSERT INTO t1 SET c='character';
# FIXME: MDEV-17833 ALTER TABLE is not enforcing prefix index size limit
ALTER TABLE t1 ROW_FORMAT=REDUNDANT;
--error ER_INDEX_COLUMN_TOO_LONG
TRUNCATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
12 changes: 8 additions & 4 deletions storage/innobase/fts/fts0fts.cc
Expand Up @@ -1771,7 +1771,7 @@ fts_create_one_common_table(
const char* fts_suffix,
mem_heap_t* heap)
{
dict_table_t* new_table = NULL;
dict_table_t* new_table;
dberr_t error;
bool is_config = strcmp(fts_suffix, "CONFIG") == 0;

Expand Down Expand Up @@ -1823,11 +1823,13 @@ fts_create_one_common_table(
}

if (error != DB_SUCCESS) {
trx->error_state = error;
dict_mem_table_free(new_table);
new_table = NULL;
ib::warn() << "Failed to create FTS common table "
<< fts_table_name;
trx->error_state = DB_SUCCESS;
row_drop_table_for_mysql(fts_table_name, trx, SQLCOM_DROP_DB);
trx->error_state = error;
}
return(new_table);
}
Expand Down Expand Up @@ -1969,7 +1971,7 @@ fts_create_one_index_table(
mem_heap_t* heap)
{
dict_field_t* field;
dict_table_t* new_table = NULL;
dict_table_t* new_table;
char table_name[MAX_FULL_NAME_LEN];
dberr_t error;
CHARSET_INFO* charset;
Expand Down Expand Up @@ -2032,11 +2034,13 @@ fts_create_one_index_table(
}

if (error != DB_SUCCESS) {
trx->error_state = error;
dict_mem_table_free(new_table);
new_table = NULL;
ib::warn() << "Failed to create FTS index table "
<< table_name;
trx->error_state = DB_SUCCESS;
row_drop_table_for_mysql(table_name, trx, SQLCOM_DROP_DB);
trx->error_state = error;
}

return(new_table);
Expand Down
15 changes: 12 additions & 3 deletions storage/innobase/handler/ha_innodb.cc
Expand Up @@ -12589,11 +12589,14 @@ int create_table_info_t::create_table(bool create_fk)
dict_table_close(innobase_table, TRUE, FALSE);

if (error) {
trx_rollback_to_savepoint(m_trx, NULL);
/* Drop the being-created table before rollback,
so that rollback can possibly rename back a table
that could have been renamed before
the failed creation. */
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);
Expand Down Expand Up @@ -12835,12 +12838,18 @@ ha_innobase::create(
}

if ((error = info.create_table(own_trx))) {
/* Drop the being-created table before rollback,
so that rollback can possibly rename back a table
that could have been renamed before the failed creation. */
trx->error_state = DB_SUCCESS;
row_drop_table_for_mysql(info.table_name(), trx,
SQLCOM_DROP_DB, true);
trx_rollback_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx);
if (own_trx) {
trx_free_for_mysql(trx);
DBUG_RETURN(error);
}
DBUG_RETURN(error);
}

innobase_commit_low(trx);
Expand Down
5 changes: 2 additions & 3 deletions storage/innobase/include/row0mysql.h
Expand Up @@ -359,9 +359,8 @@ row_create_table_for_mysql(
MY_ATTRIBUTE((warn_unused_result));

/*********************************************************************//**
Does an index creation operation for MySQL. TODO: currently failure
to create an index results in dropping the whole table! This is no problem
currently as all indexes must be created at the same time as the table.
Create an index when creating a table.
On failure, the caller must drop the table!
@return error number or DB_SUCCESS */
dberr_t
row_create_index_for_mysql(
Expand Down
26 changes: 2 additions & 24 deletions storage/innobase/row/row0mysql.cc
Expand Up @@ -2354,9 +2354,8 @@ row_create_table_for_mysql(
}

/*********************************************************************//**
Does an index creation operation for MySQL. TODO: currently failure
to create an index results in dropping the whole table! This is no problem
currently as all indexes must be created at the same time as the table.
Create an index when creating a table.
On failure, the caller must drop the table!
@return error number or DB_SUCCESS */
dberr_t
row_create_index_for_mysql(
Expand Down Expand Up @@ -2490,27 +2489,6 @@ row_create_index_for_mysql(
error_handling:
dict_table_close(table, TRUE, FALSE);

if (err != DB_SUCCESS) {
/* We have special error handling here */

trx->error_state = DB_SUCCESS;

if (trx_is_started(trx)) {

trx_rollback_to_savepoint(trx, NULL);
}

row_drop_table_for_mysql(table_name, trx, SQLCOM_DROP_TABLE,
true);

if (trx_is_started(trx)) {

trx_commit_for_mysql(trx);
}

trx->error_state = DB_SUCCESS;
}

trx->op_info = "";

ut_free(table_name);
Expand Down

0 comments on commit 2a31b82

Please sign in to comment.