Commit 03045ee7 authored by unknown's avatar unknown
Browse files

Fix fur BUG#13348: "multi-table updates and deletes are not logged if no rows were affected".

Not fixed in 4.1 as not critical. Also I'm correcting error checking of multi-UPDATE/DELETE
when it comes to binlogging, to make it consistent with when we rollback the statement.


mysql-test/r/rpl_multi_delete.result:
  result update
mysql-test/r/rpl_multi_update.result:
  result update
mysql-test/t/rpl_multi_delete.test:
  test for BUG#13348
mysql-test/t/rpl_multi_update.test:
  test of BUG#13348
sql/sql_delete.cc:
  We now binlog multi-DELETE even if no row was updated (like we do for DELETE).
  I'm also correcting some error checking (< instead of <=), basing myself on when we rollback.
sql/sql_update.cc:
  we now binlog multi-UPDATE even if no row was updated (like we do for UPDATE).
  Adding to existing tests to test new behaviour.
  I'm also correcting some error checking (< instead of <=), basing myself on when we rollback.
parent 2b24a2b5
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -19,4 +19,13 @@ a
select * from t2;
a
1
delete from t1;
delete from t2;
insert into t1 values(1);
insert into t2 values(1);
DELETE t1.*, t2.* from t1, t2;
select * from t1;
a
select * from t2;
a
drop table t1,t2;
+13 −0
Original line number Diff line number Diff line
@@ -24,3 +24,16 @@ a b
1	0
2	1
UPDATE t1, t2 SET t1.b = t2.b WHERE t1.a = t2.a;
delete from t1;
delete from t2;
insert into t1 values(1,1);
insert into t2 values(1,1);
update t1 set a=2;
UPDATE t1, t2 SET t1.a = t2.a;
select * from t1;
a	b
1	1
select * from t2;
a	b
1	1
drop table t1, t2;
+20 −4
Original line number Diff line number Diff line
@@ -16,10 +16,26 @@ sync_with_master;
select * from t1;
select * from t2;

# End of 4.1 tests

# Check if deleting 0 rows is binlogged (BUG#13348)

connection master;
drop table t1,t2;
save_master_pos;
delete from t1;
delete from t2;

connection slave;
sync_with_master;
# force a difference to see if master's multi-DELETE will correct it
insert into t1 values(1);
insert into t2 values(1);

# End of 4.1 tests
connection master;
DELETE t1.*, t2.* from t1, t2;

sync_slave_with_master;
select * from t1;
select * from t2;

connection master;
drop table t1,t2;
sync_slave_with_master;
+23 −0
Original line number Diff line number Diff line
@@ -24,3 +24,26 @@ connection slave;
sync_with_master;

# End of 4.1 tests

# Check if updating 0 rows is binlogged (BUG#13348)

connection master;
delete from t1;
delete from t2;
insert into t1 values(1,1);
insert into t2 values(1,1);

connection slave;
# force a difference to see if master's multi-UPDATE will correct it
update t1 set a=2;

connection master;
UPDATE t1, t2 SET t1.a = t2.a;

sync_slave_with_master;
select * from t1;
select * from t2;

connection master;
drop table t1, t2;
sync_slave_with_master;
+8 −20
Original line number Diff line number Diff line
@@ -258,19 +258,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,

  delete select;
  transactional_table= table->file->has_transactions();
  /*
    We write to the binary log even if we deleted no row, because maybe the
    user is using this command to ensure that a table is clean on master *and
    on slave*. Think of the case of a user having played separately with the
    master's table and slave's table and wanting to take a fresh identical
    start now.
    error < 0 means "really no error". error <= 0 means "maybe some error".
  */
  if ((deleted || (error < 0)) && (error <= 0 || !transactional_table))
  /* See similar binlogging code in sql_update.cc, for comments */
  if ((error < 0) || (deleted && !transactional_table))
  {
    if (mysql_bin_log.is_open())
    {
      if (error <= 0)
      if (error < 0)
        thd->clear_error();
      Query_log_event qinfo(thd, thd->query, thd->query_length,
			    transactional_table, FALSE);
@@ -718,6 +711,9 @@ bool multi_delete::send_eof()
  /* Does deletes for the last n - 1 tables, returns 0 if ok */
  int local_error= do_deletes();		// returns 0 if success

  /* compute a total error to know if something failed */
  local_error= local_error || error;

  /* reset used flags */
  thd->proc_info="end";

@@ -730,19 +726,11 @@ bool multi_delete::send_eof()
    query_cache_invalidate3(thd, delete_tables, 1);
  }

  /*
    Write the SQL statement to the binlog if we deleted
    rows and we succeeded, or also in an error case when there
    was a non-transaction-safe table involved, since
    modifications in it cannot be rolled back.
    Note that if we deleted nothing we don't write to the binlog (TODO:
    fix this).
  */
  if (deleted && ((error <= 0 && !local_error) || normal_tables))
  if ((local_error == 0) || (deleted && normal_tables))
  {
    if (mysql_bin_log.is_open())
    {
      if (error <= 0 && !local_error)
      if (local_error == 0)
        thd->clear_error();
      Query_log_event qinfo(thd, thd->query, thd->query_length,
			    transactional_tables, FALSE);
Loading