summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorguilhem@gbichot3.local <>2007-02-15 16:05:22 +0100
committerguilhem@gbichot3.local <>2007-02-15 16:05:22 +0100
commit03dfe4ab3ff5fbac85823587440599826d1c5a47 (patch)
tree740183d99797b55429ba0e91cff17c165bc6557e
parentfaf05bf314ce07697ca832a0a9b2ef092df74840 (diff)
parent2f75c9cd69412de5d3736e775dd302ebdbc1e36d (diff)
downloadmariadb-git-03dfe4ab3ff5fbac85823587440599826d1c5a47.tar.gz
Merge gbichot3.local:/home/mysql_src/mysql-5.0-rpl-25507
into gbichot3.local:/home/mysql_src/mysql-5.1-rpl-25507
-rw-r--r--mysql-test/r/innodb-replace.result4
-rw-r--r--mysql-test/r/rpl_insert_delayed.result31
-rw-r--r--mysql-test/r/rpl_insert_id.result58
-rw-r--r--mysql-test/r/rpl_known_bugs_detection.result133
-rw-r--r--mysql-test/t/innodb-replace.test4
-rw-r--r--mysql-test/t/rpl_insert_delayed.test67
-rw-r--r--mysql-test/t/rpl_known_bugs_detection-master.opt1
-rw-r--r--mysql-test/t/rpl_known_bugs_detection.test90
-rw-r--r--sql/log.cc2
-rw-r--r--sql/log_event.cc37
-rw-r--r--sql/log_event.h2
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/slave.cc64
-rw-r--r--sql/slave.h1
14 files changed, 490 insertions, 6 deletions
diff --git a/mysql-test/r/innodb-replace.result b/mysql-test/r/innodb-replace.result
index b7edcc49e56..77e0aeb38fd 100644
--- a/mysql-test/r/innodb-replace.result
+++ b/mysql-test/r/innodb-replace.result
@@ -2,11 +2,11 @@ drop table if exists t1;
create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) engine=innodb;
select * from t1;
c1 c2 stamp
-replace delayed into t1 (c1, c2) values ( "text1","11"),( "text2","12");
+replace delayed into t1 (c1, c2) values ( "text1","11");
ERROR HY000: Table storage engine for 't1' doesn't have this option
select * from t1;
c1 c2 stamp
-replace delayed into t1 (c1, c2) values ( "text1","12"),( "text2","13"),( "text3","14", "a" ),( "text4","15", "b" );
+replace delayed into t1 (c1, c2) values ( "text1","12");
ERROR HY000: Table storage engine for 't1' doesn't have this option
select * from t1;
c1 c2 stamp
diff --git a/mysql-test/r/rpl_insert_delayed.result b/mysql-test/r/rpl_insert_delayed.result
new file mode 100644
index 00000000000..38e2cddd650
--- /dev/null
+++ b/mysql-test/r/rpl_insert_delayed.result
@@ -0,0 +1,31 @@
+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;
+CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
+truncate table t1;
+insert delayed into t1 values(10, "my name");
+insert delayed into t1 values(10, "is Bond"), (20, "James Bond");
+ERROR 23000: Duplicate entry '10' for key 1
+flush table t1;
+select * from t1;
+id name
+10 my name
+select * from t1;
+id name
+10 my name
+delete from t1 where id!=10;
+insert delayed into t1 values(20, "is Bond"), (10, "James Bond");
+ERROR 23000: Duplicate entry '10' for key 1
+flush table t1;
+select * from t1;
+id name
+10 my name
+20 is Bond
+select * from t1;
+id name
+10 my name
+20 is Bond
+drop table t1;
diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result
index 63be35b8720..a88864b59c4 100644
--- a/mysql-test/r/rpl_insert_id.result
+++ b/mysql-test/r/rpl_insert_id.result
@@ -263,6 +263,64 @@ n b
2 100
3 350
drop table t1;
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT,
+UNIQUE(b));
+INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10;
+SELECT * FROM t1;
+a b
+1 10
+2 2
+SELECT * FROM t1;
+a b
+1 10
+2 2
+drop table t1;
+CREATE TABLE t1 (
+id bigint(20) unsigned NOT NULL auto_increment,
+field_1 int(10) unsigned NOT NULL,
+field_2 varchar(255) NOT NULL,
+field_3 varchar(255) NOT NULL,
+PRIMARY KEY (id),
+UNIQUE KEY field_1 (field_1, field_2)
+);
+CREATE TABLE t2 (
+field_a int(10) unsigned NOT NULL,
+field_b varchar(255) NOT NULL,
+field_c varchar(255) NOT NULL
+);
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e');
+INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c;
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f');
+INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c;
+SELECT * FROM t1;
+id field_1 field_2 field_3
+1 1 a 1a
+2 2 b 2b
+3 3 c 3c
+4 4 d 4d
+5 5 e 5e
+6 6 f 6f
+SELECT * FROM t1;
+id field_1 field_2 field_3
+1 1 a 1a
+2 2 b 2b
+3 3 c 3c
+4 4 d 4d
+5 5 e 5e
+6 6 f 6f
+drop table t1, t2;
DROP PROCEDURE IF EXISTS p1;
DROP TABLE IF EXISTS t1, t2;
SELECT LAST_INSERT_ID(0);
diff --git a/mysql-test/r/rpl_known_bugs_detection.result b/mysql-test/r/rpl_known_bugs_detection.result
new file mode 100644
index 00000000000..c23586c6f61
--- /dev/null
+++ b/mysql-test/r/rpl_known_bugs_detection.result
@@ -0,0 +1,133 @@
+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;
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT,
+UNIQUE(b));
+INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10;
+SELECT * FROM t1;
+a b
+1 10
+2 2
+show slave status;;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port #
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1105
+Last_Error Error 'master may suffer from http://bugs.mysql.com/bug.php?id=24432 so slave stops; check error log on slave for more info' on query. Default database: 'test'. Query: 'INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10'
+Skip_Counter 0
+Exec_Master_Log_Pos 238
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SELECT * FROM t1;
+a b
+stop slave;
+reset slave;
+reset master;
+drop table t1;
+start slave;
+CREATE TABLE t1 (
+id bigint(20) unsigned NOT NULL auto_increment,
+field_1 int(10) unsigned NOT NULL,
+field_2 varchar(255) NOT NULL,
+field_3 varchar(255) NOT NULL,
+PRIMARY KEY (id),
+UNIQUE KEY field_1 (field_1, field_2)
+);
+CREATE TABLE t2 (
+field_a int(10) unsigned NOT NULL,
+field_b varchar(255) NOT NULL,
+field_c varchar(255) NOT NULL
+);
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e');
+INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c;
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f');
+INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c;
+SELECT * FROM t1;
+id field_1 field_2 field_3
+1 1 a 1a
+2 2 b 2b
+3 3 c 3c
+4 4 d 4d
+5 5 e 5e
+6 6 f 6f
+show slave status;;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port #
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos #
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running No
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 1105
+Last_Error Error 'master may suffer from http://bugs.mysql.com/bug.php?id=24432 so slave stops; check error log on slave for more info' on query. Default database: 'test'. Query: 'INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c'
+Skip_Counter 0
+Exec_Master_Log_Pos 1270
+Relay_Log_Space #
+Until_Condition None
+Until_Log_File
+Until_Log_Pos 0
+Master_SSL_Allowed No
+Master_SSL_CA_File
+Master_SSL_CA_Path
+Master_SSL_Cert
+Master_SSL_Cipher
+Master_SSL_Key
+Seconds_Behind_Master #
+SELECT * FROM t1;
+id field_1 field_2 field_3
+drop table t1, t2;
+drop table t1, t2;
diff --git a/mysql-test/t/innodb-replace.test b/mysql-test/t/innodb-replace.test
index 51b70f34b65..d44ede65ce8 100644
--- a/mysql-test/t/innodb-replace.test
+++ b/mysql-test/t/innodb-replace.test
@@ -12,10 +12,10 @@ drop table if exists t1;
create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) engine=innodb;
select * from t1;
--error 1031
-replace delayed into t1 (c1, c2) values ( "text1","11"),( "text2","12");
+replace delayed into t1 (c1, c2) values ( "text1","11");
select * from t1;
--error 1031
-replace delayed into t1 (c1, c2) values ( "text1","12"),( "text2","13"),( "text3","14", "a" ),( "text4","15", "b" );
+replace delayed into t1 (c1, c2) values ( "text1","12");
select * from t1;
drop table t1;
diff --git a/mysql-test/t/rpl_insert_delayed.test b/mysql-test/t/rpl_insert_delayed.test
new file mode 100644
index 00000000000..3f72f3a3625
--- /dev/null
+++ b/mysql-test/t/rpl_insert_delayed.test
@@ -0,0 +1,67 @@
+--source include/master-slave.inc
+--source include/not_embedded.inc
+--source include/not_windows.inc
+
+connection master;
+
+let $binlog_format_statement=1;
+
+CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
+
+sync_slave_with_master;
+
+#
+# BUG#26116 "If multi-row INSERT DELAYED has errors,
+# statement-based binlogging breaks";
+# happened only in statement-based binlogging.
+#
+
+connection master;
+truncate table t1;
+# first scenario: duplicate on first row
+insert delayed into t1 values(10, "my name");
+if ($binlog_format_statement)
+{
+ # statement below will be converted to non-delayed INSERT and so
+ # will stop at first error, guaranteeing replication.
+ --error ER_DUP_ENTRY
+ insert delayed into t1 values(10, "is Bond"), (20, "James Bond");
+}
+if (!$binlog_format_statement)
+{
+ insert delayed into t1 values(10, "is Bond"), (20, "James Bond");
+}
+flush table t1; # to wait for INSERT DELAYED to be done
+select * from t1;
+sync_slave_with_master;
+# when bug existed in statement-based binlogging, t1 on slave had
+# different content from on master
+select * from t1;
+
+# second scenario: duplicate on second row
+connection master;
+delete from t1 where id!=10;
+if ($binlog_format_statement)
+{
+ # statement below will be converted to non-delayed INSERT and so
+ # will be binlogged with its ER_DUP_ENTRY error code, guaranteeing
+ # replication (slave will hit the same error code and so be fine).
+ --error ER_DUP_ENTRY
+ insert delayed into t1 values(20, "is Bond"), (10, "James Bond");
+}
+if (!$binlog_format_statement)
+{
+ insert delayed into t1 values(20, "is Bond"), (10, "James Bond");
+}
+flush table t1; # to wait for INSERT DELAYED to be done
+select * from t1;
+sync_slave_with_master;
+# when bug existed in statement-based binlogging, query was binlogged
+# with error_code=0 so slave stopped
+select * from t1;
+
+# clean up
+connection master;
+drop table t1;
+sync_slave_with_master;
+connection master;
diff --git a/mysql-test/t/rpl_known_bugs_detection-master.opt b/mysql-test/t/rpl_known_bugs_detection-master.opt
new file mode 100644
index 00000000000..d4ba386a1a0
--- /dev/null
+++ b/mysql-test/t/rpl_known_bugs_detection-master.opt
@@ -0,0 +1 @@
+--loose-debug=d,pretend_version_50034_in_binlog
diff --git a/mysql-test/t/rpl_known_bugs_detection.test b/mysql-test/t/rpl_known_bugs_detection.test
new file mode 100644
index 00000000000..4719716d4a1
--- /dev/null
+++ b/mysql-test/t/rpl_known_bugs_detection.test
@@ -0,0 +1,90 @@
+# Test to see if slave can detect certain known bugs present
+# on the master, and appropriately decides to stop
+# (assuming the bug is fixed in the slave, slave cannot of course
+# imitate the bug, so it has to stop).
+
+source include/have_debug.inc;
+source include/master-slave.inc;
+
+#
+# This is to test that slave properly detects if
+# master may suffer from:
+# BUG#24432 "INSERT... ON DUPLICATE KEY UPDATE skips auto_increment values"
+# (i.e. on master, INSERT ON DUPLICATE KEY UPDATE is used and manipulates
+# an auto_increment column, and is binlogged statement-based).
+#
+
+# testcase with INSERT VALUES
+CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT,
+UNIQUE(b));
+sync_slave_with_master;
+connection master;
+INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10;
+SELECT * FROM t1;
+connection slave;
+wait_for_slave_to_stop;
+# show the error message
+--replace_column 1 # 4 # 7 # 8 # 9 # 23 # 33 #
+--query_vertical show slave status;
+# show that it was not replicated
+SELECT * FROM t1;
+
+# restart replication for the next testcase
+stop slave;
+reset slave;
+connection master;
+reset master;
+drop table t1;
+connection slave;
+start slave;
+
+# testcase with INSERT SELECT
+connection master;
+CREATE TABLE t1 (
+ id bigint(20) unsigned NOT NULL auto_increment,
+ field_1 int(10) unsigned NOT NULL,
+ field_2 varchar(255) NOT NULL,
+ field_3 varchar(255) NOT NULL,
+ PRIMARY KEY (id),
+ UNIQUE KEY field_1 (field_1, field_2)
+);
+CREATE TABLE t2 (
+ field_a int(10) unsigned NOT NULL,
+ field_b varchar(255) NOT NULL,
+ field_c varchar(255) NOT NULL
+);
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d');
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e');
+sync_slave_with_master;
+connection master;
+# Updating table t1 based on values from table t2
+INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c;
+# Inserting new record into t2
+INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f');
+# Updating t1 again
+INSERT INTO t1 (field_1, field_2, field_3)
+SELECT t2.field_a, t2.field_b, t2.field_c
+FROM t2
+ON DUPLICATE KEY UPDATE
+t1.field_3 = t2.field_c;
+SELECT * FROM t1;
+connection slave;
+wait_for_slave_to_stop;
+# show the error message
+--replace_column 1 # 4 # 7 # 8 # 9 # 23 # 33 #
+--query_vertical show slave status;
+# show that it was not replicated
+SELECT * FROM t1;
+connection master;
+drop table t1, t2;
+connection slave;
+drop table t1, t2;
+
+# End of 5.0 tests
diff --git a/sql/log.cc b/sql/log.cc
index 1b432ca15c0..87f3920b951 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -4537,7 +4537,7 @@ int TC_LOG_MMAP::open(const char *opt_name)
goto err;
if (using_heuristic_recover())
return 1;
- if ((fd= my_create(logname, O_RDWR, 0, MYF(MY_WME))) < 0)
+ if ((fd= my_create(logname, CREATE_MODE, O_RDWR, MYF(MY_WME))) < 0)
goto err;
inited=1;
file_length= opt_tc_log_size;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 767c69959ee..e9be1f61a38 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2254,6 +2254,8 @@ Start_log_event_v3::Start_log_event_v3(const char* buf,
binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET);
memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
ST_SERVER_VER_LEN);
+ // prevent overrun if log is corrupted on disk
+ server_version[ST_SERVER_VER_LEN-1]= 0;
created= uint4korr(buf+ST_CREATED_OFFSET);
/* We use log_pos to mark if this was an artificial event or not */
artificial_event= (log_pos == 0);
@@ -2377,6 +2379,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
switch (binlog_ver) {
case 4: /* MySQL 5.0 */
memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
+ DBUG_EXECUTE_IF("pretend_version_50034_in_binlog",
+ strmov(server_version, "5.0.34"););
common_header_len= LOG_EVENT_HEADER_LEN;
number_of_event_types= LOG_EVENT_TYPES;
/* we'll catch my_malloc() error in is_valid() */
@@ -2467,6 +2471,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len= 0; /* will make is_valid() fail */
break;
}
+ calc_server_version_split();
}
@@ -2506,6 +2511,7 @@ Format_description_log_event(const char* buf,
post_header_len= (uint8*) my_memdup((byte*)buf+ST_COMMON_HEADER_LEN_OFFSET+1,
number_of_event_types*
sizeof(*post_header_len), MYF(0));
+ calc_server_version_split();
DBUG_VOID_RETURN;
}
@@ -2606,6 +2612,37 @@ int Format_description_log_event::exec_event(struct st_relay_log_info* rli)
}
#endif
+
+/**
+ Splits the event's 'server_version' string into three numeric pieces stored
+ into 'server_version_split':
+ X.Y.Zabc (X,Y,Z numbers, a not a digit) -> {X,Y,Z}
+ X.Yabc -> {X,Y,0}
+ Xabc -> {X,0,0}
+ 'server_version_split' is then used for lookups to find if the server which
+ created this event has some known bug.
+*/
+void Format_description_log_event::calc_server_version_split()
+{
+ char *p= server_version, *r;
+ ulong number;
+ for (uint i= 0; i<=2; i++)
+ {
+ number= strtoul(p, &r, 10);
+ server_version_split[i]= (uchar)number;
+ DBUG_ASSERT(number < 256); // fit in uchar
+ p= r;
+ DBUG_ASSERT(!((i == 0) && (*r != '.'))); // should be true in practice
+ if (*r == '.')
+ p++; // skip the dot
+ }
+ DBUG_PRINT("info",("Format_description_log_event::server_version_split:"
+ " '%s' %d %d %d", server_version,
+ server_version_split[0],
+ server_version_split[1], server_version_split[2]));
+}
+
+
/**************************************************************************
Load_log_event methods
General note about Load_log_event: the binlogging of LOAD DATA INFILE is
diff --git a/sql/log_event.h b/sql/log_event.h
index 5994beb0df3..c888275151c 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1153,6 +1153,7 @@ public:
uint8 number_of_event_types;
/* The list of post-headers' lengthes */
uint8 *post_header_len;
+ uchar server_version_split[3];
Format_description_log_event(uint8 binlog_ver, const char* server_ver=0);
@@ -1184,6 +1185,7 @@ public:
*/
return FORMAT_DESCRIPTION_HEADER_LEN;
}
+ void calc_server_version_split();
};
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d080ef70dad..26c91740c41 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3308,7 +3308,7 @@ server.");
(TC_LOG *) &tc_log_mmap) :
(TC_LOG *) &tc_log_dummy);
- if (tc_log->open(opt_bin_logname))
+ if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
{
sql_print_error("Can't init tc log");
unireg_abort(1);
diff --git a/sql/slave.cc b/sql/slave.cc
index c21aec49e88..022647afcee 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3651,6 +3651,70 @@ end:
}
+/**
+ Detects, based on master's version (as found in the relay log), if master
+ 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
+ @return TRUE if master has the bug, FALSE if it does not.
+*/
+bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id)
+{
+ struct st_version_range_for_one_bug {
+ uint bug_id;
+ const uchar introduced_in[3]; // first version with bug
+ const uchar fixed_in[3]; // first version with fix
+ };
+ static struct st_version_range_for_one_bug versions_for_all_bugs[]=
+ {
+ {24432, { 5, 0, 24 }, { 5, 0, 36 } },
+ {24432, { 5, 1, 12 }, { 5, 1, 16 } }
+ };
+ const uchar *master_ver=
+ rli->relay_log.description_event_for_exec->server_version_split;
+
+ DBUG_ASSERT(sizeof(rli->relay_log.description_event_for_exec->server_version_split) == 3);
+
+ for (uint i= 0;
+ i < sizeof(versions_for_all_bugs)/sizeof(*versions_for_all_bugs);i++)
+ {
+ const uchar *introduced_in= versions_for_all_bugs[i].introduced_in,
+ *fixed_in= versions_for_all_bugs[i].fixed_in;
+ if ((versions_for_all_bugs[i].bug_id == bug_id) &&
+ (memcmp(introduced_in, master_ver, 3) <= 0) &&
+ (memcmp(fixed_in, master_ver, 3) > 0))
+ {
+ // a verbose message for the error log
+ slave_print_error(rli, ER_UNKNOWN_ERROR,
+ "According to the master's version ('%s'),"
+ " it is probable that master suffers from this bug:"
+ " http://bugs.mysql.com/bug.php?id=%u"
+ " and thus replicating the current binary log event"
+ " may make the slave's data become different from the"
+ " master's data."
+ " To take no risk, slave refuses to replicate"
+ " this event and stops."
+ " We recommend that all updates be stopped on the"
+ " master and slave, that the data of both be"
+ " manually synchronized,"
+ " that master's binary logs be deleted,"
+ " that master be upgraded to a version at least"
+ " equal to '%d.%d.%d'. Then replication can be"
+ " restarted.",
+ rli->relay_log.description_event_for_exec->server_version,
+ bug_id,
+ fixed_in[0], fixed_in[1], fixed_in[2]);
+ // 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"
+ " so slave stops; check error log on slave"
+ " for more info", MYF(0), bug_id);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List_iterator<i_string>;
template class I_List_iterator<i_string_pair>;
diff --git a/sql/slave.h b/sql/slave.h
index 43eb71be601..a0febe3fd73 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -161,6 +161,7 @@ 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);
const char *print_slave_db_safe(const char *db);
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);