summaryrefslogtreecommitdiff
path: root/sql/sql_class.cc
diff options
context:
space:
mode:
authorunknown <hezx@mail.hezx.com>2008-03-14 11:35:41 +0800
committerunknown <hezx@mail.hezx.com>2008-03-14 11:35:41 +0800
commitf21ee5d00dd67e95a86e2c1776cd187a16760528 (patch)
tree8e93396e4d62cd6f4ab2aded6aa2244ca753e04d /sql/sql_class.cc
parent7b85da497eb3251224576c079723fe6fe0b2da5c (diff)
downloadmariadb-git-f21ee5d00dd67e95a86e2c1776cd187a16760528.tar.gz
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: add $binlog_start parameter to show binlog events from a given position sql/slave.cc: Add function to check for bug#33029 sql/slave.h: Add function to check for bug#33029 sql/sql_class.cc: 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: Add member to save and restore auto_inc_intervals_forced sql/structs.h: 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 mysql-test/std_data/bug33029-slave-relay-bin.000001: relay logs from a buggy 5.0 master for test case of BUG#33029 mysql-test/suite/binlog/r/binlog_auto_increment_bug33029.result: 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: 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: Test if the slave can process relay logs from a buggy master of BUG#33029
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r--sql/sql_class.cc50
1 files changed, 41 insertions, 9 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 044ea70e994..10c65f18a35 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -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_rollback(MYSQL_THD thd, bool all)
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_statement_state *backup,
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,17 +3594,24 @@ bool Discrete_intervals_list::append(ulonglong start, ulonglong val,
{
/* 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);
+}
+
#endif /* !defined(MYSQL_CLIENT) */