Commit 905659a2 authored by hezx@mail.hezx.com's avatar hezx@mail.hezx.com

Merge mail.hezx.com:/media/sda3/work/mysql/bkroot/mysql-5.1-new-rpl

into  mail.hezx.com:/media/sda3/work/mysql/bkwork/b33029_5.0_to_5.1_fails_on_dup_key/5.1
parents 69a755d6 a3d02647
--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=#/
......
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
--replicate-same-server-id --relay-log=slave-relay-bin --skip-slave-start
# 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;
......@@ -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 *rli, uint bug_id)
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 *rli, uint bug_id)
(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"
......@@ -4085,6 +4091,26 @@ bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id)
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;
}
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List_iterator<i_string>;
template class I_List_iterator<i_string_pair>;
......
......@@ -165,7 +165,8 @@ int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
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);
......
......@@ -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>
......@@ -2843,6 +2844,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;
......@@ -2880,6 +2893,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
......@@ -3585,17 +3610,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) */
......@@ -912,6 +912,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;
......
......@@ -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; }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment