mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Bug#37016: TRUNCATE TABLE removes some rows but not all
The special TRUNCATE TABLE (DDL) transaction wasn't being properly rolled back if a error occurred during row by row deletion. The error can be caused by a foreign key restriction imposed by InnoDB SE and would cause the server to erroneously issue a implicit commit. The solution is to rollback the transaction if a truncation via row by row deletion fails, otherwise commit. All effects of a TRUNCATE ABLE operation are rolled back if a row by row deletion fails. mysql-test/include/commit.inc: Truncate always starts a transaction and commits at the end. The commit at the end increases the count by two, one is the storage engine commit and the other is the binary log. mysql-test/r/commit_1innodb.result: Update test case results. mysql-test/r/innodb_mysql.result: Update test case results. mysql-test/t/innodb_mysql.test: Add test case for Bug#37016 sql/sql_delete.cc: Move truncation using row by row deletion to its own function. If row by row deletion fails, rollback the transaction. Remove the meddling with disabling and enabling of autocommit as TRUNCATE transaction is now explicitly ended (committed or rolled back).
This commit is contained in:
@ -950,6 +950,26 @@ bool multi_delete::send_eof()
|
||||
TRUNCATE TABLE
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
Row-by-row truncation if the engine does not support table recreation.
|
||||
Probably a InnoDB table.
|
||||
*/
|
||||
|
||||
static bool mysql_truncate_by_delete(THD *thd, TABLE_LIST *table_list)
|
||||
{
|
||||
bool error, save_binlog_row_based= thd->current_stmt_binlog_row_based;
|
||||
DBUG_ENTER("mysql_truncate_by_delete");
|
||||
table_list->lock_type= TL_WRITE;
|
||||
mysql_init_select(thd->lex);
|
||||
thd->clear_current_stmt_binlog_row_based();
|
||||
error= mysql_delete(thd, table_list, NULL, NULL, HA_POS_ERROR, LL(0), TRUE);
|
||||
ha_autocommit_or_rollback(thd, error);
|
||||
end_trans(thd, error ? ROLLBACK : COMMIT);
|
||||
thd->current_stmt_binlog_row_based= save_binlog_row_based;
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Optimize delete of all rows by doing a full generate of the table
|
||||
This will work even if the .ISM and .ISD tables are destroyed
|
||||
@ -1055,24 +1075,6 @@ end:
|
||||
DBUG_RETURN(error);
|
||||
|
||||
trunc_by_del:
|
||||
/* Probably InnoDB table */
|
||||
ulonglong save_options= thd->options;
|
||||
table_list->lock_type= TL_WRITE;
|
||||
thd->options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
|
||||
ha_enable_transaction(thd, FALSE);
|
||||
mysql_init_select(thd->lex);
|
||||
bool save_binlog_row_based= thd->current_stmt_binlog_row_based;
|
||||
thd->clear_current_stmt_binlog_row_based();
|
||||
error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
|
||||
HA_POS_ERROR, LL(0), TRUE);
|
||||
ha_enable_transaction(thd, TRUE);
|
||||
/*
|
||||
Safety, in case the engine ignored ha_enable_transaction(FALSE)
|
||||
above. Also clears thd->transaction.*.
|
||||
*/
|
||||
error= ha_autocommit_or_rollback(thd, error);
|
||||
ha_commit(thd);
|
||||
thd->options= save_options;
|
||||
thd->current_stmt_binlog_row_based= save_binlog_row_based;
|
||||
error= mysql_truncate_by_delete(thd, table_list);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
Reference in New Issue
Block a user