1
0
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.
This commit is contained in:
Davi Arnaut
2009-01-09 08:20:32 -02:00
parent 2ce96d24ec
commit 577e390ece
5 changed files with 137 additions and 25 deletions

View File

@ -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);
}