List:Commits« Previous MessageNext Message »
From:hezx Date:March 14 2008 3:35am
Subject:bk commit into 5.1 tree (hezx:1.2534) BUG#33029
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of hezx.  When hezx 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@stripped, 2008-03-14 11:35:41+08:00, hezx@stripped +10 -0
  BUG#33029 5.0 to 5.1 replication fails on dup key when inserting
  using a trig in SP
  
  For all 5.0 and up to 5.1.12 exclusive, when a stored routine or
  trigger caused an INSERT into an AUTO_INCREMENT column, the
  generated AUTO_INCREMENT value should not be written into the
  binary log, which means if a statement does not generate
  AUTO_INCREMENT value itself, there will be no Intvar event (SET
  INSERT_ID) associated with it even if one of the stored routine
  or trigger caused generation of such a value. And meanwhile, when
  executing a stored routine or trigger, it would ignore the
  INSERT_ID value even if there is a INSERT_ID value available set
  by a SET INSERT_ID statement.
  
  Starting from MySQL 5.1.12, the generated AUTO_INCREMENT value is
  written into the binary log, and the value will be used if
  available when executing the stored routine or trigger.
  
  Prior fix of this bug in MySQL 5.0 and prior MySQL 5.1.12
  (referenced as the buggy versions in the text below), when a
  statement that generates AUTO_INCREMENT value by the top
  statement was executed in the body of a SP, all statements in the
  SP after this statement would be treated as if they had generated
  AUTO_INCREMENT by the top statement.  When a statement that did
  not generate AUTO_INCREMENT value by the top statement but by a
  function/trigger called by it, an erroneous Intvar event would be
  associated with the statement, this erroneous INSERT_ID value
  wouldn't cause problem when replicating between masters and
  slaves of 5.0.x or prior 5.1.12, because the erroneous INSERT_ID
  value was not used when executing functions/triggers. But when
  replicating from buggy versions to 5.1.12 or newer, which will
  use the INSERT_ID value in functions/triggers, the erroneous
  value will be used, which would cause duplicate entry error and
  cause the slave to stop.
  
  The patch for 5.1 fixed it to ignore the SET INSERT_ID value when
  executing functions/triggers if it is replicating from a master
  of buggy versions, another patch for 5.0 fixed it not to generate
  the erroneous Intvar event.

  mysql-test/include/show_binlog_events.inc@stripped, 2008-03-14 11:35:35+08:00, hezx@stripped +6 -1
    add $binlog_start parameter to show binlog events from a given position

  mysql-test/std_data/bug33029-slave-relay-bin.000001@stripped, 2008-03-14 11:35:36+08:00, hezx@stripped +89 -0
    relay logs from a buggy 5.0 master for test case of BUG#33029

  mysql-test/std_data/bug33029-slave-relay-bin.000001@stripped, 2008-03-14 11:35:36+08:00, hezx@stripped +0 -0

  mysql-test/suite/binlog/r/binlog_auto_increment_bug33029.result@stripped, 2008-03-14 11:35:36+08:00, hezx@stripped +33 -0
    Test if the slave can process relay logs from a buggy master of BUG#33029

  mysql-test/suite/binlog/r/binlog_auto_increment_bug33029.result@stripped, 2008-03-14 11:35:36+08:00, hezx@stripped +0 -0

  mysql-test/suite/binlog/t/binlog_auto_increment_bug33029-master.opt@stripped, 2008-03-14 11:35:36+08:00, hezx@stripped +1 -0
    Test if the slave can process relay logs from a buggy master of BUG#33029

  mysql-test/suite/binlog/t/binlog_auto_increment_bug33029-master.opt@stripped, 2008-03-14 11:35:36+08:00, hezx@stripped +0 -0

  mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test@stripped, 2008-03-14 11:35:36+08:00, hezx@stripped +36 -0
    Test if the slave can process relay logs from a buggy master of BUG#33029

  mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test@stripped, 2008-03-14 11:35:36+08:00, hezx@stripped +0 -0

  sql/slave.cc@stripped, 2008-03-14 11:35:35+08:00, hezx@stripped +28 -2
    Add function to check for bug#33029

  sql/slave.h@stripped, 2008-03-14 11:35:35+08:00, hezx@stripped +2 -1
    Add function to check for bug#33029

  sql/sql_class.cc@stripped, 2008-03-14 11:35:35+08:00, hezx@stripped +41 -9
    if master has bug#33029, reset auto_inc_intervals_forced for sub statements
    
    add a new function Discrete_intervals_list::append that takes a Discrete_interval as argument

  sql/sql_class.h@stripped, 2008-03-14 11:35:36+08:00, hezx@stripped +1 -0
    Add member to save and restore auto_inc_intervals_forced

  sql/structs.h@stripped, 2008-03-14 11:35:36+08:00, hezx@stripped +21 -0
    add copy constructor and assignment operator for Discrete_intervals_list
    
    add a new function Discrete_intervals_list::append that takes a Discrete_interval as argument

diff -Nrup a/mysql-test/include/show_binlog_events.inc b/mysql-test/include/show_binlog_events.inc
--- a/mysql-test/include/show_binlog_events.inc	2008-01-29 21:43:03 +08:00
+++ b/mysql-test/include/show_binlog_events.inc	2008-03-14 11:35:35 +08:00
@@ -1,4 +1,9 @@
---let $binlog_start=106
+# $binlog_start can be set by caller or take a default value
+
+if (!$binlog_start)
+{
+  let $binlog_start=106;
+}
 --replace_result $binlog_start <binlog_start>
 --replace_column 2 # 4 # 5 #
 --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /file_id=[0-9]+/file_id=#/
Binary files a/mysql-test/std_data/bug33029-slave-relay-bin.000001 and b/mysql-test/std_data/bug33029-slave-relay-bin.000001 differ
diff -Nrup a/mysql-test/suite/binlog/r/binlog_auto_increment_bug33029.result b/mysql-test/suite/binlog/r/binlog_auto_increment_bug33029.result
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/suite/binlog/r/binlog_auto_increment_bug33029.result	2008-03-14 11:35:36 +08:00
@@ -0,0 +1,33 @@
+change master to
+MASTER_HOST='dummy.localdomain',
+RELAY_LOG_FILE='slave-relay-bin.000001',
+RELAY_LOG_POS=4;
+start slave sql_thread;
+select MASTER_POS_WAIT('master-bin.000001', 3776);
+# Result on slave
+SELECT * FROM t1;
+id
+5
+6
+7
+8
+9
+10
+11
+SELECT * FROM t2;
+id
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
diff -Nrup a/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029-master.opt b/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029-master.opt
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029-master.opt	2008-03-14 11:35:36 +08:00
@@ -0,0 +1 @@
+--replicate-same-server-id --relay-log=slave-relay-bin --skip-slave-start
diff -Nrup a/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test b/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test	2008-03-14 11:35:36 +08:00
@@ -0,0 +1,36 @@
+# BUG#33029 5.0 to 5.1 replication fails on dup key when inserting
+# using a trig in SP
+
+# For all 5.0 up to 5.0.58 exclusive, and 5.1 up to 5.1.12 exclusive,
+# if one statement in a SP generated AUTO_INCREMENT value by the top
+# statement, all statements after it would be considered generated
+# AUTO_INCREMENT value by the top statement, and a erroneous INSERT_ID
+# value might be associated with these statement, which could cause
+# duplicate entry error and stop the slave.
+
+# Test if the slave can replicate from such a buggy master
+
+# The bug33029-slave-relay-bin.000001 file is the
+# slave-replay-bin.000003 file generated by run the
+# rpl_auto_increment_bug33029.test with clean up statements at the end
+# of the test case removed on a buggy 5.0 server
+
+copy_file $MYSQL_TEST_DIR/std_data/bug33029-slave-relay-bin.000001 $MYSQLTEST_VARDIR/master-data/slave-relay-bin.000001;
+
+write_file $MYSQLTEST_VARDIR/master-data/slave-relay-bin.index;
+slave-relay-bin.000001
+EOF
+
+change master to
+  MASTER_HOST='dummy.localdomain',
+  RELAY_LOG_FILE='slave-relay-bin.000001',
+  RELAY_LOG_POS=4;
+
+start slave sql_thread;
+disable_result_log;
+select MASTER_POS_WAIT('master-bin.000001', 3776);
+enable_result_log;
+
+echo # Result on slave;
+SELECT * FROM t1;
+SELECT * FROM t2;
diff -Nrup a/sql/slave.cc b/sql/slave.cc
--- a/sql/slave.cc	2008-02-21 05:24:58 +08:00
+++ b/sql/slave.cc	2008-03-14 11:35:35 +08:00
@@ -4026,9 +4026,10 @@ end:
    has a certain bug.
    @param rli Relay_log_info which tells the master's version
    @param bug_id Number of the bug as found in bugs.mysql.com
+   @param report bool report error message, default TRUE
    @return TRUE if master has the bug, FALSE if it does not.
 */
-bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id)
+bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id, bool report)
 {
   struct st_version_range_for_one_bug {
     uint        bug_id;
@@ -4038,7 +4039,9 @@ bool rpl_master_has_bug(Relay_log_info *
   static struct st_version_range_for_one_bug versions_for_all_bugs[]=
   {
     {24432, { 5, 0, 24 }, { 5, 0, 38 } },
-    {24432, { 5, 1, 12 }, { 5, 1, 17 } }
+    {24432, { 5, 1, 12 }, { 5, 1, 17 } },
+    {33029, { 5, 0,  0 }, { 5, 0, 58 } },
+    {33029, { 5, 1,  0 }, { 5, 1, 12 } },
   };
   const uchar *master_ver=
     rli->relay_log.description_event_for_exec->server_version_split;
@@ -4054,6 +4057,9 @@ bool rpl_master_has_bug(Relay_log_info *
         (memcmp(introduced_in, master_ver, 3) <= 0) &&
         (memcmp(fixed_in,      master_ver, 3) >  0))
     {
+      if (!report)
+	return TRUE;
+      
       // a short message for SHOW SLAVE STATUS (message length constraints)
       my_printf_error(ER_UNKNOWN_ERROR, "master may suffer from"
                       " http://bugs.mysql.com/bug.php?id=%u"
@@ -4081,6 +4087,26 @@ bool rpl_master_has_bug(Relay_log_info *
                       fixed_in[0], fixed_in[1], fixed_in[2]);
       return TRUE;
     }
+  }
+  return FALSE;
+}
+
+/**
+   BUG#33029, For all 5.0 up to 5.0.58 exclusive, and 5.1 up to 5.1.12
+   exclusive, if one statement in a SP generated AUTO_INCREMENT value
+   by the top statement, all statements after it would be considered
+   generated AUTO_INCREMENT value by the top statement, and a
+   erroneous INSERT_ID value might be associated with these statement,
+   which could cause duplicate entry error and stop the slave.
+
+   Detect buggy master to work around.
+ */
+bool rpl_master_erroneous_autoinc(THD *thd)
+{
+  if (active_mi && active_mi->rli.sql_thd == thd)
+  {
+    Relay_log_info *rli= &active_mi->rli;
+    return rpl_master_has_bug(rli, 33029, FALSE);
   }
   return FALSE;
 }
diff -Nrup a/sql/slave.h b/sql/slave.h
--- a/sql/slave.h	2008-02-07 04:07:43 +08:00
+++ b/sql/slave.h	2008-03-14 11:35:35 +08:00
@@ -165,7 +165,8 @@ int fetch_master_table(THD* thd, const c
 
 bool show_master_info(THD* thd, Master_info* mi);
 bool show_binlog_info(THD* thd);
-bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id);
+bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id, bool report=TRUE);
+bool rpl_master_erroneous_autoinc(THD* thd);
 
 const char *print_slave_db_safe(const char *db);
 int check_expected_error(THD* thd, Relay_log_info const *rli, int error_code);
diff -Nrup a/sql/sql_class.cc b/sql/sql_class.cc
--- a/sql/sql_class.cc	2008-02-13 01:21:07 +08:00
+++ b/sql/sql_class.cc	2008-03-14 11:35:35 +08:00
@@ -28,6 +28,7 @@
 #include "mysql_priv.h"
 #include "rpl_rli.h"
 #include "rpl_record.h"
+#include "slave.h"
 #include <my_bitmap.h>
 #include "log_event.h"
 #include <m_ctype.h>
@@ -2827,6 +2828,18 @@ extern "C" void thd_mark_transaction_to_
 void THD::reset_sub_statement_state(Sub_statement_state *backup,
                                     uint new_state)
 {
+#ifndef EMBEDDED_LIBRARY
+  /* BUG#33029, if we are replicating from a buggy master, reset
+     auto_inc_intervals_forced to prevent substatement
+     (triggers/functions) from using erroneous INSERT_ID value
+   */
+  if (rpl_master_erroneous_autoinc(this))
+  {
+    backup->auto_inc_intervals_forced= auto_inc_intervals_forced;
+    auto_inc_intervals_forced.empty();
+  }
+#endif
+  
   backup->options=         options;
   backup->in_sub_stmt=     in_sub_stmt;
   backup->enable_slow_log= enable_slow_log;
@@ -2864,6 +2877,18 @@ void THD::reset_sub_statement_state(Sub_
 
 void THD::restore_sub_statement_state(Sub_statement_state *backup)
 {
+#ifndef EMBEDDED_LIBRARY
+  /* BUG#33029, if we are replicating from a buggy master, restore
+     auto_inc_intervals_forced so that the top statement can use the
+     INSERT_ID value set before this statement.
+   */
+  if (rpl_master_erroneous_autoinc(this))
+  {
+    auto_inc_intervals_forced= backup->auto_inc_intervals_forced;
+    backup->auto_inc_intervals_forced.empty();
+  }
+#endif
+
   /*
     To save resources we want to release savepoints which were created
     during execution of function or trigger before leaving their savepoint
@@ -3569,16 +3594,23 @@ bool Discrete_intervals_list::append(ulo
   {
     /* it cannot, so need to add a new interval */
     Discrete_interval *new_interval= new Discrete_interval(start, val, incr);
-    if (unlikely(new_interval == NULL)) // out of memory
-      DBUG_RETURN(1);
-    DBUG_PRINT("info",("adding new auto_increment interval"));
-    if (head == NULL)
-      head= current= new_interval;
-    else
-      tail->next= new_interval;
-    tail= new_interval;
-    elements++;
+    DBUG_RETURN(append(new_interval));
   }
+  DBUG_RETURN(0);
+}
+
+bool Discrete_intervals_list::append(Discrete_interval *new_interval)
+{
+  DBUG_ENTER("Discrete_intervals_list::append");
+  if (unlikely(new_interval == NULL))
+    DBUG_RETURN(1);
+  DBUG_PRINT("info",("adding new auto_increment interval"));
+  if (head == NULL)
+    head= current= new_interval;
+  else
+    tail->next= new_interval;
+  tail= new_interval;
+  elements++;
   DBUG_RETURN(0);
 }
 
diff -Nrup a/sql/sql_class.h b/sql/sql_class.h
--- a/sql/sql_class.h	2008-02-20 22:22:13 +08:00
+++ b/sql/sql_class.h	2008-03-14 11:35:36 +08:00
@@ -911,6 +911,7 @@ public:
   ulonglong first_successful_insert_id_in_prev_stmt;
   ulonglong first_successful_insert_id_in_cur_stmt, insert_id_for_cur_row;
   Discrete_interval auto_inc_interval_for_cur_row;
+  Discrete_intervals_list auto_inc_intervals_forced;
   ulonglong limit_found_rows;
   ha_rows    cuted_fields, sent_row_count, examined_row_count;
   ulong client_capabilities;
diff -Nrup a/sql/structs.h b/sql/structs.h
--- a/sql/structs.h	2007-12-15 01:01:47 +08:00
+++ b/sql/structs.h	2008-03-14 11:35:36 +08:00
@@ -314,8 +314,27 @@ private:
   */
   Discrete_interval        *current;
   uint                  elements; // number of elements
+
+  /* helper function for copy construct and assignment operator */
+  void copy_(const Discrete_intervals_list& from)
+  {
+    for (Discrete_interval *i= from.head; i; i= i->next)
+    {
+      Discrete_interval j= *i;
+      append(&j);
+    }
+  }
 public:
   Discrete_intervals_list() : head(NULL), current(NULL), elements(0) {};
+  Discrete_intervals_list(const Discrete_intervals_list& from)
+  {
+    copy_(from);
+  }
+  void operator=(const Discrete_intervals_list& from)
+  {
+    empty();
+    copy_(from);
+  }
   void empty_no_free()
   {
     head= current= NULL;
@@ -331,6 +350,7 @@ public:
     }
     empty_no_free();
   }
+
   const Discrete_interval* get_next()
   {
     Discrete_interval *tmp= current;
@@ -340,6 +360,7 @@ public:
   }
   ~Discrete_intervals_list() { empty(); };
   bool append(ulonglong start, ulonglong val, ulonglong incr);
+  bool append(Discrete_interval *interval);
   ulonglong minimum()     const { return (head ? head->minimum() : 0); };
   ulonglong maximum()     const { return (head ? tail->maximum() : 0); };
   uint      nb_elements() const { return elements; }
Thread
bk commit into 5.1 tree (hezx:1.2534) BUG#33029hezx14 Mar