From a0849011471dd15c2789436ed57350691e030101 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Aug 2007 15:16:55 +0300 Subject: Bug #23333 stored function + non-transac table + transac table = breaks stmt-based binlog Binlogging of the statement with a side effect like a modified non-trans table did not happen. The artifact involved all binloggable dml queries. Fixed with changing the binlogging conditions all over the code to exploit thd->transaction.stmt.modified_non_trans_table introduced by the patch for bug@27417. Multi-delete case has own specific addressed by another bug@29136. Multi-update case has been addressed by bug#27716 and patch and will need merging. mysql-test/r/mix_innodb_myisam_binlog.result: results changed mysql-test/r/sp_trans_log.result: results changed mysql-test/t/mix_innodb_myisam_binlog.test: specific to the bug tests added mysql-test/t/sp_trans_log.test: refining of the proof of that there is an event in binlog sql/sql_delete.cc: deploying the binlogging check with thd->transaction.stmt.modified_non_trans_table sql/sql_insert.cc: binlogging when thd->transaction.stmt.modified_non_trans_table is TRUE. Merge with Bug#29571. sql/sql_load.cc: binlogging when thd->transaction.stmt.modified_non_trans_table is true sql/sql_update.cc: binlogging when thd->transaction.stmt.modified_non_trans_table is true --- sql/sql_delete.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql/sql_delete.cc') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 56edfa6c5b2..7555219f5d8 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -319,7 +319,7 @@ cleanup: thd->transaction.stmt.modified_non_trans_table= TRUE; /* See similar binlogging code in sql_update.cc, for comments */ - if ((error < 0) || (deleted && !transactional_table)) + if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { @@ -817,7 +817,8 @@ bool multi_delete::send_eof() { query_cache_invalidate3(thd, delete_tables, 1); } - if ((local_error == 0) || (deleted && normal_tables)) + DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); + if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { @@ -831,7 +832,6 @@ bool multi_delete::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } - DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); /* Commit or rollback the current SQL statement */ if (transactional_tables) -- cgit v1.2.1 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 From bf9eb0f0d71f741d1ab9ff5375892d93b53c01d4 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 13 Oct 2007 23:12:50 +0300 Subject: manual merge for bug_29136, bug#29309. mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test: manual merge from 5.0 mysql-test/r/innodb.result: results changed mysql-test/r/multi_update.result: results changed mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: manual merge: results re-recorded mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: results changed mysql-test/suite/manual/r/rpl_replication_delay.result: results recorded for 5.1 mysql-test/t/innodb.test: removing bug27716 regression test as one exists in binlog suite already. mysql-test/t/multi_update.test: manual merge plus refining for execution in both binlog_format. sql/log_event.cc: bloody manual merge; the fact that an event is artificial is encode with setting timestamp argument to zero. rli's last_master_timestamp won't be updated in stmt_done in such case. sql/rpl_rli.cc: simulation and the real fixing code. Don't update last_master_timestamp with zero. sql/sql_delete.cc: manual merge --- sql/sql_delete.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql/sql_delete.cc') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index aad0514b10b..b4b877b9a37 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -758,9 +758,9 @@ void multi_delete::send_error(uint errcode,const char *err) */ 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->binlog_query(THD::ROW_QUERY_TYPE, + thd->query, thd->query_length, + transactional_tables, FALSE); } thd->transaction.all.modified_non_trans_table= true; } -- cgit v1.2.1 From 95f3db7be1b3425b47f34090f33c7eeb52f97703 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 29 Oct 2007 15:20:59 +0200 Subject: Bug #27571 asynchronousity in setting mysql_`query`::error and Query_log_event::error_code A query can perform completely having the local var error of mysql_$query zero, where $query in insert, update, delete, load, and be binlogged with error_code e.g KILLED_QUERY while there is no reason do to so. That can happen because Query_log_event consults thd->killed flag to evaluate error_code. Fixed with implementing a scheme suggested and partly implemented at time of bug@22725 work-on. error_status is cached immediatly after the control leaves the main rows-loop and that instance always corresponds to `error' the local of mysql_$query functions. The cached value is passed to Query_log_event constructor, not the default thd->killed which can be changed in between of the caching and the constructing. mysql-test/r/binlog_killed.result: results changed mysql-test/t/binlog_killed.test: Demonstrating that effective killing during rows-loop execution leads to the speficied actions: binlogging with the error for a query modified a not-transactional table or rolling back effects for transactional table; fixing possible non-determinism with ID when query_log_enabled; leave commented out tests for multi-update,delete due to another bug; removing an obsolete tests template; changing system rm to --remove_file. sql/log_event.cc: adding killed status arg sql/log_event.h: added killed status arg sql/sql_delete.cc: deploying the update part patch for delete, multi-delete sql/sql_insert.cc: deploying the update-part patch for insert..select sql/sql_load.cc: deploying the update-part patch for load data. simulation added. sql/sql_update.cc: Impementing the fix as described in the comments left by bug@22725. Also simulation of killing after the loop that would affect binlogging in the old code. mysql-test/t/binlog_killed_bug27571-master.opt: post rows-loop killing simulation's options mysql-test/t/binlog_killed_bug27571.test: Checking that if killing happens inbetween of the end of rows loop and recording into binlog that will not lead to recording any error incl the killed error. mysql-test/t/binlog_killed_simulate-master.opt: simulation options mysql-test/t/binlog_killed_simulate.test: tests for a query (update is choosen) being killed after the row-loop; load data killed within the loop - effective killed error in the event is gained. --- sql/sql_delete.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'sql/sql_delete.cc') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index add37c8c552..a28a39a769d 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -38,6 +38,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ha_rows deleted; uint usable_index= MAX_KEY; SELECT_LEX *select_lex= &thd->lex->select_lex; + THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_delete"); if (open_and_lock_tables(thd, table_list)) @@ -280,8 +281,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, else table->file->unlock_row(); // Row failed selection, release lock on it } - if (thd->killed && !error) - error= 1; // Aborted + killed_status= thd->killed; + error= (killed_status == THD::NOT_KILLED)? error : 1; thd->proc_info="end"; end_read_record(&info); free_io_cache(table); // Will not do any harm @@ -326,7 +327,7 @@ cleanup: if (error < 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, killed_status); if (mysql_bin_log.write(&qinfo) && transactional_table) error=1; } @@ -729,7 +730,8 @@ void multi_delete::send_error(uint errcode,const char *err) } thd->transaction.all.modified_non_trans_table= true; } - DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); + DBUG_ASSERT(!normal_tables || !deleted || + thd->transaction.stmt.modified_non_trans_table); DBUG_VOID_RETURN; } @@ -817,6 +819,7 @@ int multi_delete::do_deletes() bool multi_delete::send_eof() { + THD::killed_state killed_status= THD::NOT_KILLED; thd->proc_info="deleting from reference tables"; /* Does deletes for the last n - 1 tables, returns 0 if ok */ @@ -824,7 +827,7 @@ bool multi_delete::send_eof() /* compute a total error to know if something failed */ local_error= local_error || error; - + killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed; /* reset used flags */ thd->proc_info="end"; @@ -836,7 +839,8 @@ bool multi_delete::send_eof() { query_cache_invalidate3(thd, delete_tables, 1); } - DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); + DBUG_ASSERT(!normal_tables || !deleted || + thd->transaction.stmt.modified_non_trans_table); if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) @@ -844,7 +848,7 @@ bool multi_delete::send_eof() if (local_error == 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); + transactional_tables, FALSE, killed_status); if (mysql_bin_log.write(&qinfo) && !normal_tables) local_error=1; // Log write failed: roll back the SQL statement } -- cgit v1.2.1 From 356bdcb7c47e9fc848281687f725b1783194594a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Oct 2007 13:49:42 +0200 Subject: Manual merge 5.0-rpl -> 5.1-rpl. involved bug#12691, bug#27571 mysql-test/suite/rpl/r/rpl_sp_effects.result: results changed sql/slave.cc: pended manual merge done (mats) sql/sql_delete.cc: manual merge sql/sql_insert.cc: manual merge sql/sql_load.cc: manual merge sql/sql_update.cc: manual merge. --- sql/sql_delete.cc | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) (limited to 'sql/sql_delete.cc') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 33d19852371..81bfaadd4ce 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -352,12 +352,6 @@ cleanup: { if (error < 0) thd->clear_error(); -<<<<<<< gca sql/sql_delete.cc 1.144.1.57 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); - if (mysql_bin_log.write(&qinfo) && transactional_table) -<<<<<<< local sql/sql_delete.cc 1.230 - /* [binlog]: If 'handler::delete_all_rows()' was called and the storage engine does not inject the rows itself, we replicate @@ -366,15 +360,10 @@ cleanup: */ int log_result= thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, killed_status); if (log_result && transactional_table) { -<<<<<<< remote sql/sql_delete.cc 1.144.1.58 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE, killed_status); - if (mysql_bin_log.write(&qinfo) && transactional_table) ->>>>>>> error=1; } } @@ -902,21 +891,11 @@ bool multi_delete::send_eof() { if (local_error == 0) thd->clear_error(); -<<<<<<< gca sql/sql_delete.cc 1.144.1.57 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - if (mysql_bin_log.write(&qinfo) && !normal_tables) -<<<<<<< local sql/sql_delete.cc 1.230 if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - transactional_tables, FALSE) && + transactional_tables, FALSE, killed_status) && !normal_tables) { -<<<<<<< remote sql/sql_delete.cc 1.144.1.58 - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE, killed_status); - if (mysql_bin_log.write(&qinfo) && !normal_tables) ->>>>>>> local_error=1; // Log write failed: roll back the SQL statement } } -- cgit v1.2.1