List:Internals« Previous MessageNext Message »
From:guilhem Date:September 19 2005 1:49pm
Subject:bk commit into 5.0 tree (guilhem:1.1980) BUG#12844
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of guilhem. When guilhem does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.1980 05/09/19 15:49:31 guilhem@stripped +5 -0
  Fix for BUG#12844 "Multi-update or mul-DELETE that calls func with side-effect goes not to binlog"
  fix is by extending what had been done in ChangeSet 1.1616.494.1 2004/06/09 16:07:01 guilhem@stripped:
  write a multi-UPDATE or multi-DELETE to binlog even if it updated no rows (and had no error).
  Also fixing some suspicious "error" testing in UPDATE/DELETE and their multi variants.

  mysql-test/t/rpl_multi_updel_func.test
    1.1 05/09/19 15:49:27 guilhem@stripped +63 -0
    New BitKeeper file ``mysql-test/t/rpl_multi_updel_func.test''

  mysql-test/r/rpl_multi_updel_func.result
    1.1 05/09/19 15:49:27 guilhem@stripped +72 -0
    New BitKeeper file ``mysql-test/r/rpl_multi_updel_func.result''

  sql/sql_update.cc
    1.171 05/09/19 15:49:27 guilhem@stripped +13 -6
    If we updated no row in a multi-UPDATE, and got no error, do write to binlog
    (like we do for normal UPDATE). I also found some strange things which I correct:
    - Looks like the code checks for error<=0 where it should be <0, or ==0
    - And in multi-DELETE, it checks "error" at some places and "local_error" at other places of the same
    function, trying to make it better (so that no error is forgotten).

  sql/sql_delete.cc
    1.162 05/09/19 15:49:27 guilhem@stripped +8 -20
    If we deleted no row in a multi-DELETE, and got no error, do write to binlog
    (like we do for normal DELETE). I also found some strange things which I correct:
    - Looks like the code checks for error<=0 where it should be <0, or ==0
    - And in multi-DELETE, it checks "error" at some places and "local_error" at other places of the same
    function, trying to make it better (so that no error is forgotten).

  mysql-test/t/rpl_multi_updel_func.test
    1.0 05/09/19 15:49:27 guilhem@stripped +0 -0
    BitKeeper file /home/mysql_src/mysql-5.0/mysql-test/t/rpl_multi_updel_func.test

  mysql-test/t/disabled.def
    1.7 05/09/19 15:49:27 guilhem@stripped +1 -0
    new test has to be disabled until BUG#13305 is fixed

  mysql-test/r/rpl_multi_updel_func.result
    1.0 05/09/19 15:49:27 guilhem@stripped +0 -0
    BitKeeper file /home/mysql_src/mysql-5.0/mysql-test/r/rpl_multi_updel_func.result

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	guilhem
# Host:	gbichot3.local
# Root:	/home/mysql_src/mysql-5.0

--- 1.161/sql/sql_delete.cc	2005-09-01 21:42:21 +02:00
+++ 1.162/sql/sql_delete.cc	2005-09-19 15:49:27 +02:00
@@ -258,19 +258,12 @@
 
   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 ((deleted || (error < 0)) && ((error < 0) || !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 @@
   /* 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 @@
     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 ((deleted || (local_error == 0)) && ((local_error == 0) || 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);

--- 1.170/sql/sql_update.cc	2005-09-15 01:57:52 +02:00
+++ 1.171/sql/sql_update.cc	2005-09-19 15:49:27 +02:00
@@ -475,11 +475,20 @@
     query_cache_invalidate3(thd, table_list, 1);
   }
 
-  if ((updated || (error < 0)) && (error <= 0 || !transactional_table))
+  /*
+    error < 0 means really no error at all: we processed all rows until the
+    last one without error. error > 0 means an error (e.g. unique key
+    violation and no IGNORE or REPLACE). error == 0 is also an error (if
+    preparing the record or invoking before triggers fails). See
+    ha_autocommit_or_rollback(error>=0) and DBUG_RETURN(error>=0) below.
+    Sometimes we want to binlog even if we updated no rows, in case user used
+    it to be sure master and slave are in same state.
+  */
+  if ((updated || (error < 0)) && ((error < 0) || !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);
@@ -1440,15 +1449,13 @@
     Write the SQL statement to the binlog if we updated
     rows and we succeeded or if we updated some non
     transacational tables.
-    Note that if we updated nothing we don't write to the binlog (TODO:
-    fix this).
   */
 
-  if (updated && (local_error <= 0 || !trans_safe))
+  if ((updated || (local_error == 0)) && ((local_error == 0) || !trans_safe))
   {
     if (mysql_bin_log.is_open())
     {
-      if (local_error <= 0)
+      if (local_error == 0)
         thd->clear_error();
       Query_log_event qinfo(thd, thd->query, thd->query_length,
 			    transactional_tables, FALSE);
--- New file ---
+++ mysql-test/r/rpl_multi_updel_func.result	05/09/19 15:49:27
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
drop function if exists f1;
create table t1(a int);
insert into t1 values (1),(2);
create table t2(a int);
insert into t2 values (1),(2);
create table t3 (a int);
create function f1(a int) returns int deterministic modifies sql data
begin
insert into t3 values(a);
return 0;
end//
update t1,t2 set t1.a=3, t2.a=3 where f1(t1.a) = 0;
update t1,t2 set t1.a=3, t2.a=3 where f1(t1.a);
select 'master' A;
A
master
select * from t3;
a
1
2
3
3
select 'slave' A;
A
slave
select * from t3;
a
1
2
3
3
delete t1,t2 from t1,t2 where f1(t1.a);
insert into t1 values (1),(2);
insert into t2 values (1),(2);
delete t1,t2 from t1,t2 where f1(t1.a) = 0;
select 'master' A;
A
master
select * from t3;
a
1
2
3
3
3
3
3
3
1
2
drop function f1;
select 'slave' A;
A
slave
select * from t3;
a
1
2
3
3
3
3
3
3
1
2

--- New file ---
+++ mysql-test/t/rpl_multi_updel_func.test	05/09/19 15:49:27
# Test for two bugs involving multi-UPDATE and functions in
# replication:
# BUG#12844: master does not binlog the statement if no rows were
# updated directly by the multi-UPDATE/DELETE (though some other table
# was updated by the function call present in the multi-UPDATE/DELETE)
# BUG#13305: slave crashes when executing multi-UPDATE containing a
# function

source include/master-slave.inc;

--disable_warnings
drop function if exists f1;
--enable_warnings
create table t1(a int);
insert into t1 values (1),(2);
create table t2(a int);
insert into t2 values (1),(2);

create table t3 (a int);
delimiter //;

create function f1(a int) returns int deterministic modifies sql data
begin
  insert into t3 values(a);
  return 0;
end//

delimiter ;//

# test for crash (BUG#13305)

update t1,t2 set t1.a=3, t2.a=3 where f1(t1.a) = 0;

# test for good data on slave (BUG#12844)

update t1,t2 set t1.a=3, t2.a=3 where f1(t1.a);

select 'master' A;
select * from t3;
sync_slave_with_master;
select 'slave' A;
select * from t3;

connection master;

# same test with multi-DELETE

delete t1,t2 from t1,t2 where f1(t1.a);

# repopulate to test again
insert into t1 values (1),(2);
insert into t2 values (1),(2);

# does it crash too?

delete t1,t2 from t1,t2 where f1(t1.a) = 0;

select 'master' A;
select * from t3;
drop function f1;
sync_slave_with_master;
select 'slave' A;
select * from t3;


--- 1.6/mysql-test/t/disabled.def	2005-08-25 02:25:38 +02:00
+++ 1.7/mysql-test/t/disabled.def	2005-09-19 15:49:27 +02:00
@@ -15,3 +15,4 @@
 rpl_until       : Unstable test case, bug#12429
 rpl_deadlock    : Unstable test case, bug#12429
 kill            : Unstable test case, bug#9712
+rpl_multi_updel_func: causes crash (bug#13305), fixer of 13305: please re-enable thx
Thread
bk commit into 5.0 tree (guilhem:1.1980) BUG#12844guilhem19 Sep