From c8b6d1050933f0b9b18367c421702c9f16907de5 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 13 Oct 2007 15:49:42 +0300 Subject: Bug #29136 erred multi-delete on trans table does not rollback the statement similar to bug_27716, but it was stressed on in the synopsis on that there is another side of the artifact affecting behaviour in transaction. Fixed with deploying multi_delete::send_error() - otherwise never called - and refining its logic to perform binlogging job if needed. The changeset includes the following side effects: - added tests to check bug_23333's scenarios on the mixture of tables for multi_update; - fixes bug@30763 with two-liner patch and a test coinciding to one added for bug_23333. mysql-test/r/innodb.result: results changed mysql-test/r/mix_innodb_myisam_binlog.result: results changed mysql-test/r/multi_update.result: results changed mysql-test/t/innodb.test: trans table specific test added mysql-test/t/mix_innodb_myisam_binlog.test: multi-update and multi-delete of mixure of ta and not-ta tables tests added (relates to bug_23333). mysql-test/t/multi_update.test: testing another branch of mult-delete: send_eof() (binloggin there), send_error (early return) sql/sql_class.h: a new flag to designate the fact the statement's error has been handled. The flag is checked by ::send_error() methods (multi_update and _delete classes) sql/sql_delete.cc: expanding multi_delete::send_error to 1. early return if error_handled == t 2. binlogging locally if there was a non-trans table modified side effect sql/sql_parse.cc: adding multi_update::send_error which can perform binlogging and rollback job in needed sql/sql_update.cc: issues relating to 1. bug_27716 with zeroing of `updated' to serve as the flag of early return from send_error(). The flag is changed to be a new member error_handled; also moved outside binlogging branch. The reason for this change is that bug_23333 fixes were pushed after the bug_27716's and they left this flaw (also no test coverage). 2. bug_30763 with assertion on trans_safe. I decide to make 2 liner fix for that bug here instead of to remove those two assertions. This new bug test case is the same as for multi-update on the mixure of tables. The rational for this fix: presumption for mutli_update::trans_safe to be set to zero at multi_update::multi_update or multi_update::initialize_tables() is incorrect. trans_safe := false should happen only when a non-transactional table gets modified. Therefore, at initialization the member must be be set to true. --- sql/sql_delete.cc | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'sql/sql_delete.cc') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7555219f5d8..add37c8c552 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -504,7 +504,7 @@ bool mysql_multi_delete_prepare(THD *thd) multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg) : delete_tables(dt), deleted(0), found(0), num_of_tables(num_of_tables_arg), error(0), - do_delete(0), transactional_tables(0), normal_tables(0) + do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0) { tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables); } @@ -685,12 +685,14 @@ void multi_delete::send_error(uint errcode,const char *err) /* First send error what ever it is ... */ my_message(errcode, err, MYF(0)); - /* If nothing deleted return */ - if (!deleted) + /* the error was handled or nothing deleted and no side effects return */ + if (error_handled || + !thd->transaction.stmt.modified_non_trans_table && !deleted) DBUG_VOID_RETURN; /* Something already deleted so we have to invalidate cache */ - query_cache_invalidate3(thd, delete_tables, 1); + if (deleted) + query_cache_invalidate3(thd, delete_tables, 1); /* If rows from the first table only has been deleted and it is @@ -710,12 +712,29 @@ void multi_delete::send_error(uint errcode,const char *err) */ error= 1; send_eof(); + DBUG_ASSERT(error_handled); + DBUG_VOID_RETURN; + } + + if (thd->transaction.stmt.modified_non_trans_table) + { + /* + there is only side effects; to binlog with the error + */ + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, + transactional_tables, FALSE); + mysql_bin_log.write(&qinfo); + } + thd->transaction.all.modified_non_trans_table= true; } DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); DBUG_VOID_RETURN; } + /* Do delete from other tables. Returns values: @@ -832,6 +851,8 @@ bool multi_delete::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } + if (local_error != 0) + error_handled= TRUE; // to force early leave from ::send_error() /* Commit or rollback the current SQL statement */ if (transactional_tables) -- cgit v1.2.1