summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqlbinlog.cc10
-rw-r--r--include/my_global.h11
-rw-r--r--mysql-test/extra/binlog_tests/ctype_cp932.test11
-rw-r--r--mysql-test/extra/rpl_tests/rpl_insert_delayed.test86
-rw-r--r--mysql-test/extra/rpl_tests/rpl_insert_id.test55
-rw-r--r--mysql-test/r/binlog_row_ctype_cp932.result12
-rwxr-xr-xmysql-test/r/binlog_stm_ctype_cp932.result12
-rw-r--r--mysql-test/r/innodb-replace.result4
-rw-r--r--mysql-test/r/mysqlbinlog_base64.result20
-rw-r--r--mysql-test/r/rpl_insert_id.result60
-rw-r--r--mysql-test/r/rpl_known_bugs_detection.result133
-rw-r--r--mysql-test/r/rpl_row_insert_delayed.result48
-rw-r--r--mysql-test/r/rpl_stm_insert_delayed.result88
-rw-r--r--mysql-test/r/rpl_switch_stm_row_mixed.result36
-rw-r--r--mysql-test/r/show_check.result8
-rw-r--r--mysql-test/r/xml.result75
-rw-r--r--mysql-test/t/innodb-replace.test4
-rw-r--r--mysql-test/t/mysqlbinlog_base64.test28
-rw-r--r--mysql-test/t/rpl_known_bugs_detection-master.opt1
-rw-r--r--mysql-test/t/rpl_known_bugs_detection.test93
-rw-r--r--mysql-test/t/rpl_row_insert_delayed.test14
-rw-r--r--mysql-test/t/rpl_stm_insert_delayed.test20
-rw-r--r--mysql-test/t/rpl_switch_stm_row_mixed.test38
-rw-r--r--mysql-test/t/show_check.test12
-rw-r--r--mysql-test/t/xml.test38
-rw-r--r--mysys/mf_iocache2.c17
-rw-r--r--sql/field.cc2
-rw-r--r--sql/item_xmlfunc.cc92
-rw-r--r--sql/log.cc20
-rw-r--r--sql/log_event.cc124
-rw-r--r--sql/log_event.h48
-rw-r--r--sql/mysql_priv.h17
-rw-r--r--sql/mysqld.cc70
-rw-r--r--sql/rpl_utility.h105
-rw-r--r--sql/slave.cc64
-rw-r--r--sql/slave.h1
-rw-r--r--sql/sql_insert.cc56
-rw-r--r--sql/sql_show.cc8
-rw-r--r--storage/ndb/include/ndb_global.h.in2
39 files changed, 1359 insertions, 184 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 027cf2ea435..66f440ff048 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -486,18 +486,15 @@ write_event_header_and_base64(Log_event *ev, FILE *result_file,
DBUG_ENTER("write_event_header_and_base64");
/* Write header and base64 output to cache */
IO_CACHE result_cache;
- if (init_io_cache(&result_cache, -1, 0, WRITE_CACHE, 0L, FALSE,
- MYF(MY_WME | MY_NABP)))
- {
+ if (open_cached_file(&result_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP)))
return 1;
- }
ev->print_header(&result_cache, print_event_info, FALSE);
ev->print_base64(&result_cache, print_event_info, FALSE);
/* Read data from cache and write to result file */
my_b_copy_to_file(&result_cache, result_file);
- end_io_cache(&result_cache);
+ close_cached_file(&result_cache);
DBUG_RETURN(0);
}
@@ -1016,6 +1013,9 @@ static int dump_log_entries(const char* logname)
{
int rc;
PRINT_EVENT_INFO print_event_info;
+
+ if (!print_event_info.init_ok())
+ return 1;
/*
Set safe delimiter, to dump things
like CREATE PROCEDURE safely
diff --git a/include/my_global.h b/include/my_global.h
index 98733711d24..d92e5f07948 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -1478,4 +1478,15 @@ do { doubleget_union _tmp; \
#define dlerror() ""
#endif
+/*
+ Define placement versions of operator new and operator delete since
+ we cannot be sure that the <new> include exists.
+ */
+#ifdef __cplusplus
+inline void *operator new(size_t, void *ptr) { return ptr; }
+inline void *operator new[](size_t, void *ptr) { return ptr; }
+inline void operator delete(void*, void*) { /* Do nothing */ }
+inline void operator delete[](void*, void*) { /* Do nothing */ }
+#endif
+
#endif /* my_global_h */
diff --git a/mysql-test/extra/binlog_tests/ctype_cp932.test b/mysql-test/extra/binlog_tests/ctype_cp932.test
index 688d06c4dde..c6196b928b0 100644
--- a/mysql-test/extra/binlog_tests/ctype_cp932.test
+++ b/mysql-test/extra/binlog_tests/ctype_cp932.test
@@ -413,3 +413,14 @@ select * from t1;
insert into t1 values ('abc');
select * from t1;
drop table t1;
+
+#
+# Bug#25815 Data truncated for column TEXT
+#
+set names utf8;
+create table t1 (a text) default character set cp932;
+insert into t1 values (_utf8 0xE38182);
+show warnings;
+select * from t1;
+select hex(a) from t1;
+drop table t1;
diff --git a/mysql-test/extra/rpl_tests/rpl_insert_delayed.test b/mysql-test/extra/rpl_tests/rpl_insert_delayed.test
new file mode 100644
index 00000000000..11856953959
--- /dev/null
+++ b/mysql-test/extra/rpl_tests/rpl_insert_delayed.test
@@ -0,0 +1,86 @@
+# The two bugs below (BUG#25507 and BUG#26116) existed only in
+# statement-based binlogging; we test that now they are fixed;
+# we also test that mixed and row-based binlogging work too,
+# for completeness.
+
+connection master;
+--disable_warnings
+CREATE SCHEMA IF NOT EXISTS mysqlslap;
+USE mysqlslap;
+--enable_warnings
+
+select @@global.binlog_format;
+
+#
+# BUG#25507 "multi-row insert delayed + auto increment causes
+# duplicate key entries on slave";
+# happened only in statement-based binlogging.
+#
+
+CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
+let $query = "INSERT DELAYED INTO t1 VALUES (null, 'Dr. No'), (null, 'From Russia With Love'), (null, 'Goldfinger'), (null, 'Thunderball'), (null, 'You Only Live Twice')";
+--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=200 --query=$query --delimiter=";"
+
+FLUSH TABLE t1; # another way to be sure INSERT DELAYED has inserted
+SELECT COUNT(*) FROM t1;
+# when bug existed slave failed below ("duplicate key" error at random INSERT)
+sync_slave_with_master;
+use mysqlslap;
+SELECT COUNT(*) FROM t1;
+
+#
+# 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;
+USE test;
+DROP SCHEMA mysqlslap;
+sync_slave_with_master;
+connection master;
diff --git a/mysql-test/extra/rpl_tests/rpl_insert_id.test b/mysql-test/extra/rpl_tests/rpl_insert_id.test
index 0b07216cf11..bd2abbac6de 100644
--- a/mysql-test/extra/rpl_tests/rpl_insert_id.test
+++ b/mysql-test/extra/rpl_tests/rpl_insert_id.test
@@ -209,7 +209,7 @@ connection master;
drop function bug15728;
drop function bug15728_insert;
-drop table t1;
+drop table t1,t2;
drop procedure foo;
# test of BUG#20188 REPLACE or ON DUPLICATE KEY UPDATE in
@@ -276,6 +276,59 @@ connection master;
drop table t1;
sync_slave_with_master;
+#
+# BUG#24432 "INSERT... ON DUPLICATE KEY UPDATE skips auto_increment values"
+#
+
+connection master;
+# testcase with INSERT VALUES
+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;
+sync_slave_with_master;
+SELECT * FROM t1;
+connection master;
+drop table t1;
+
+# tescase with INSERT SELECT
+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');
+# 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;
+sync_slave_with_master;
+SELECT * FROM t1;
+connection master;
+drop table t1, t2;
#
# BUG#20339: stored procedure using LAST_INSERT_ID() does not
diff --git a/mysql-test/r/binlog_row_ctype_cp932.result b/mysql-test/r/binlog_row_ctype_cp932.result
index ed57b87c1ba..10451686e2c 100644
--- a/mysql-test/r/binlog_row_ctype_cp932.result
+++ b/mysql-test/r/binlog_row_ctype_cp932.result
@@ -11353,3 +11353,15 @@ a
a
a
drop table t1;
+set names utf8;
+create table t1 (a text) default character set cp932;
+insert into t1 values (_utf8 0xE38182);
+show warnings;
+Level Code Message
+select * from t1;
+a
+あ
+select hex(a) from t1;
+hex(a)
+82A0
+drop table t1;
diff --git a/mysql-test/r/binlog_stm_ctype_cp932.result b/mysql-test/r/binlog_stm_ctype_cp932.result
index ed57b87c1ba..10451686e2c 100755
--- a/mysql-test/r/binlog_stm_ctype_cp932.result
+++ b/mysql-test/r/binlog_stm_ctype_cp932.result
@@ -11353,3 +11353,15 @@ a
a
a
drop table t1;
+set names utf8;
+create table t1 (a text) default character set cp932;
+insert into t1 values (_utf8 0xE38182);
+show warnings;
+Level Code Message
+select * from t1;
+a
+あ
+select hex(a) from t1;
+hex(a)
+82A0
+drop table t1;
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/mysqlbinlog_base64.result b/mysql-test/r/mysqlbinlog_base64.result
index 33047a8774d..b62023e0ccf 100644
--- a/mysql-test/r/mysqlbinlog_base64.result
+++ b/mysql-test/r/mysqlbinlog_base64.result
@@ -86,5 +86,25 @@ Aberdeen
Abernathy
aberrant
aberration
+flush logs;
+drop table t2;
+create table t2 (word varchar(20));
+load data infile '../std_data_ln/words.dat' into table t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+select count(*) from t2;
+count(*)
+35840
+flush logs;
+select count(*) from t2;
+count(*)
+35840
drop table t1;
drop table t2;
diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result
index 63be35b8720..b0c1b6cfd73 100644
--- a/mysql-test/r/rpl_insert_id.result
+++ b/mysql-test/r/rpl_insert_id.result
@@ -196,7 +196,7 @@ id last_id
3 5
drop function bug15728;
drop function bug15728_insert;
-drop table t1;
+drop table t1,t2;
drop procedure foo;
create table t1 (n int primary key auto_increment not null,
b int, unique(b));
@@ -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..eabc6185780
--- /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 242
+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 1274
+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/r/rpl_row_insert_delayed.result b/mysql-test/r/rpl_row_insert_delayed.result
new file mode 100644
index 00000000000..2044672f49d
--- /dev/null
+++ b/mysql-test/r/rpl_row_insert_delayed.result
@@ -0,0 +1,48 @@
+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;
+set @old_global_binlog_format = @@global.binlog_format;
+set @@global.binlog_format = row;
+CREATE SCHEMA IF NOT EXISTS mysqlslap;
+USE mysqlslap;
+select @@global.binlog_format;
+@@global.binlog_format
+ROW
+CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
+FLUSH TABLE t1;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5000
+use mysqlslap;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5000
+truncate table t1;
+insert delayed into t1 values(10, "my name");
+insert delayed into t1 values(10, "is Bond"), (20, "James Bond");
+flush table t1;
+select * from t1;
+id name
+10 my name
+20 James Bond
+select * from t1;
+id name
+10 my name
+20 James Bond
+delete from t1 where id!=10;
+insert delayed into t1 values(20, "is Bond"), (10, "James Bond");
+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
+USE test;
+DROP SCHEMA mysqlslap;
+set @@global.binlog_format = @old_global_binlog_format;
diff --git a/mysql-test/r/rpl_stm_insert_delayed.result b/mysql-test/r/rpl_stm_insert_delayed.result
new file mode 100644
index 00000000000..1c003856eb9
--- /dev/null
+++ b/mysql-test/r/rpl_stm_insert_delayed.result
@@ -0,0 +1,88 @@
+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;
+set @old_global_binlog_format = @@global.binlog_format;
+set @@global.binlog_format = statement;
+CREATE SCHEMA IF NOT EXISTS mysqlslap;
+USE mysqlslap;
+select @@global.binlog_format;
+@@global.binlog_format
+STATEMENT
+CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
+FLUSH TABLE t1;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5000
+use mysqlslap;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5000
+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 'PRIMARY'
+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 'PRIMARY'
+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
+USE test;
+DROP SCHEMA mysqlslap;
+set @@global.binlog_format = mixed;
+CREATE SCHEMA IF NOT EXISTS mysqlslap;
+USE mysqlslap;
+select @@global.binlog_format;
+@@global.binlog_format
+MIXED
+CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
+FLUSH TABLE t1;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5000
+use mysqlslap;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5000
+truncate table t1;
+insert delayed into t1 values(10, "my name");
+insert delayed into t1 values(10, "is Bond"), (20, "James Bond");
+flush table t1;
+select * from t1;
+id name
+10 my name
+20 James Bond
+select * from t1;
+id name
+10 my name
+20 James Bond
+delete from t1 where id!=10;
+insert delayed into t1 values(20, "is Bond"), (10, "James Bond");
+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
+USE test;
+DROP SCHEMA mysqlslap;
+set @@global.binlog_format = @old_global_binlog_format;
diff --git a/mysql-test/r/rpl_switch_stm_row_mixed.result b/mysql-test/r/rpl_switch_stm_row_mixed.result
index 258adc83b04..48b228550a7 100644
--- a/mysql-test/r/rpl_switch_stm_row_mixed.result
+++ b/mysql-test/r/rpl_switch_stm_row_mixed.result
@@ -7,8 +7,31 @@ start slave;
drop database if exists mysqltest1;
create database mysqltest1;
use mysqltest1;
+set session binlog_format=mixed;
+show session variables like "binlog_format%";
+Variable_name Value
+binlog_format MIXED
+set session binlog_format=statement;
+show session variables like "binlog_format%";
+Variable_name Value
+binlog_format STATEMENT
set session binlog_format=row;
-set global binlog_format=row;
+show session variables like "binlog_format%";
+Variable_name Value
+binlog_format ROW
+set global binlog_format=DEFAULT;
+show global variables like "binlog_format%";
+Variable_name Value
+binlog_format MIXED
+set global binlog_format=MIXED;
+show global variables like "binlog_format%";
+Variable_name Value
+binlog_format MIXED
+set global binlog_format=STATEMENT;
+show global variables like "binlog_format%";
+Variable_name Value
+binlog_format STATEMENT
+set global binlog_format=ROW;
show global variables like "binlog_format%";
Variable_name Value
binlog_format ROW
@@ -67,12 +90,11 @@ execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values("for_10_");
insert into t1 select "yesterday_11_";
-set binlog_format=default;
+set binlog_format=statement;
select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format @@session.binlog_format
STATEMENT STATEMENT
-set global binlog_format=default;
-ERROR 42000: Variable 'binlog_format' doesn't have a default value
+set global binlog_format=statement;
select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format @@session.binlog_format
STATEMENT STATEMENT
@@ -87,11 +109,11 @@ execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values("for_15_");
insert into t1 select "yesterday_16_";
-set binlog_format=mixed;
+set global binlog_format=mixed;
select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format @@session.binlog_format
-STATEMENT MIXED
-set global binlog_format=mixed;
+MIXED STATEMENT
+set binlog_format=default;
select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format @@session.binlog_format
MIXED MIXED
diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index 516355839b5..823511e3196 100644
--- a/mysql-test/r/show_check.result
+++ b/mysql-test/r/show_check.result
@@ -730,4 +730,12 @@ show keys from `mysqlttest\1`.`a\b`;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
drop table `mysqlttest\1`.`a\b`;
drop database `mysqlttest\1`;
+set names utf8;
+drop table if exists `été`;
+create table `été` (field1 int);
+show full tables;
+Tables_in_test Table_type
+été BASE TABLE
+drop table `été`;
+set names latin1;
End of 5.1 tests
diff --git a/mysql-test/r/xml.result b/mysql-test/r/xml.result
index 08f8293ff52..236c50774bd 100644
--- a/mysql-test/r/xml.result
+++ b/mysql-test/r/xml.result
@@ -809,3 +809,78 @@ ExtractValue(@xml, "/entry[(50<pt)]/id")
select ExtractValue(@xml, "/entry[(50<=pt)]/id");
ExtractValue(@xml, "/entry[(50<=pt)]/id")
pt50
+select ExtractValue('<a><b><Text>test</Text></b></a>','/a/b/Text');
+ExtractValue('<a><b><Text>test</Text></b></a>','/a/b/Text')
+test
+select ExtractValue('<a><b><comment>test</comment></b></a>','/a/b/comment');
+ExtractValue('<a><b><comment>test</comment></b></a>','/a/b/comment')
+test
+select ExtractValue('<a><b><node>test</node></b></a>','/a/b/node');
+ExtractValue('<a><b><node>test</node></b></a>','/a/b/node')
+test
+select ExtractValue('<a><b><processing-instruction>test</processing-instruction></b></a>','/a/b/processing-instruction');
+ExtractValue('<a><b><processing-instruction>test</processing-instruction></b></a>','/a/b/processing-instruction')
+test
+select ExtractValue('<a><and>test</and></a>', '/a/and');
+ExtractValue('<a><and>test</and></a>', '/a/and')
+test
+select ExtractValue('<a><or>test</or></a>', '/a/or');
+ExtractValue('<a><or>test</or></a>', '/a/or')
+test
+select ExtractValue('<a><mod>test</mod></a>', '/a/mod');
+ExtractValue('<a><mod>test</mod></a>', '/a/mod')
+test
+select ExtractValue('<a><div>test</div></a>', '/a/div');
+ExtractValue('<a><div>test</div></a>', '/a/div')
+test
+select ExtractValue('<a><and:and>test</and:and></a>', '/a/and:and');
+ExtractValue('<a><and:and>test</and:and></a>', '/a/and:and')
+test
+select ExtractValue('<a><or:or>test</or:or></a>', '/a/or:or');
+ExtractValue('<a><or:or>test</or:or></a>', '/a/or:or')
+test
+select ExtractValue('<a><mod:mod>test</mod:mod></a>', '/a/mod:mod');
+ExtractValue('<a><mod:mod>test</mod:mod></a>', '/a/mod:mod')
+test
+select ExtractValue('<a><div:div>test</div:div></a>', '/a/div:div');
+ExtractValue('<a><div:div>test</div:div></a>', '/a/div:div')
+test
+select ExtractValue('<a><ancestor>test</ancestor></a>', '/a/ancestor');
+ExtractValue('<a><ancestor>test</ancestor></a>', '/a/ancestor')
+test
+select ExtractValue('<a><ancestor-or-self>test</ancestor-or-self></a>', '/a/ancestor-or-self');
+ExtractValue('<a><ancestor-or-self>test</ancestor-or-self></a>', '/a/ancestor-or-self')
+test
+select ExtractValue('<a><attribute>test</attribute></a>', '/a/attribute');
+ExtractValue('<a><attribute>test</attribute></a>', '/a/attribute')
+test
+select ExtractValue('<a><child>test</child></a>', '/a/child');
+ExtractValue('<a><child>test</child></a>', '/a/child')
+test
+select ExtractValue('<a><descendant>test</descendant></a>', '/a/descendant');
+ExtractValue('<a><descendant>test</descendant></a>', '/a/descendant')
+test
+select ExtractValue('<a><descendant-or-self>test</descendant-or-self></a>', '/a/descendant-or-self');
+ExtractValue('<a><descendant-or-self>test</descendant-or-self></a>', '/a/descendant-or-self')
+test
+select ExtractValue('<a><following>test</following></a>', '/a/following');
+ExtractValue('<a><following>test</following></a>', '/a/following')
+test
+select ExtractValue('<a><following-sibling>test</following-sibling></a>', '/a/following-sibling');
+ExtractValue('<a><following-sibling>test</following-sibling></a>', '/a/following-sibling')
+test
+select ExtractValue('<a><namespace>test</namespace></a>', '/a/namespace');
+ExtractValue('<a><namespace>test</namespace></a>', '/a/namespace')
+test
+select ExtractValue('<a><parent>test</parent></a>', '/a/parent');
+ExtractValue('<a><parent>test</parent></a>', '/a/parent')
+test
+select ExtractValue('<a><preceding>test</preceding></a>', '/a/preceding');
+ExtractValue('<a><preceding>test</preceding></a>', '/a/preceding')
+test
+select ExtractValue('<a><preceding-sibling>test</preceding-sibling></a>', '/a/preceding-sibling');
+ExtractValue('<a><preceding-sibling>test</preceding-sibling></a>', '/a/preceding-sibling')
+test
+select ExtractValue('<a><self>test</self></a>', '/a/self');
+ExtractValue('<a><self>test</self></a>', '/a/self')
+test
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/mysqlbinlog_base64.test b/mysql-test/t/mysqlbinlog_base64.test
index 1ca018218b2..1b5dc67c150 100644
--- a/mysql-test/t/mysqlbinlog_base64.test
+++ b/mysql-test/t/mysqlbinlog_base64.test
@@ -32,6 +32,34 @@ select * from t1;
select * from t2;
#
+# Verify that events larger than the default IO_CACHE buffer
+# are handled correctly (BUG#25628).
+#
+flush logs;
+drop table t2;
+create table t2 (word varchar(20));
+load data infile '../std_data_ln/words.dat' into table t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+select count(*) from t2;
+
+flush logs;
+--exec $MYSQL_BINLOG --hexdump $MYSQLTEST_VARDIR/log/master-bin.000003 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_base64.sql
+--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/mysqlbinlog_base64.sql
+
+#
+# Verify that all binlog events have been executed
+#
+select count(*) from t2;
+
+#
# Test cleanup
#
--exec rm $MYSQLTEST_VARDIR/tmp/mysqlbinlog_base64.sql
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..ce3debf3c5b
--- /dev/null
+++ b/mysql-test/t/rpl_known_bugs_detection.test
@@ -0,0 +1,93 @@
+# 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;
+
+# Currently only statement-based-specific bugs are here
+-- source include/have_binlog_format_mixed_or_statement.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/mysql-test/t/rpl_row_insert_delayed.test b/mysql-test/t/rpl_row_insert_delayed.test
new file mode 100644
index 00000000000..9aeb57c4fa2
--- /dev/null
+++ b/mysql-test/t/rpl_row_insert_delayed.test
@@ -0,0 +1,14 @@
+--source include/have_binlog_format_row.inc
+--source include/master-slave.inc
+--source include/not_embedded.inc
+--source include/not_windows.inc
+
+connection master;
+set @old_global_binlog_format = @@global.binlog_format;
+
+let $binlog_format_statement=0;
+set @@global.binlog_format = row;
+--source extra/rpl_tests/rpl_insert_delayed.test
+
+connection master;
+set @@global.binlog_format = @old_global_binlog_format;
diff --git a/mysql-test/t/rpl_stm_insert_delayed.test b/mysql-test/t/rpl_stm_insert_delayed.test
new file mode 100644
index 00000000000..d55e3a4da2c
--- /dev/null
+++ b/mysql-test/t/rpl_stm_insert_delayed.test
@@ -0,0 +1,20 @@
+# we run first in statement-based then in mixed binlogging
+
+--source include/have_binlog_format_mixed_or_statement.inc
+--source include/master-slave.inc
+--source include/not_embedded.inc
+--source include/not_windows.inc
+
+connection master;
+set @old_global_binlog_format = @@global.binlog_format;
+
+let $binlog_format_statement=1;
+set @@global.binlog_format = statement;
+--source extra/rpl_tests/rpl_insert_delayed.test
+
+let $binlog_format_statement=0;
+set @@global.binlog_format = mixed;
+--source extra/rpl_tests/rpl_insert_delayed.test
+
+connection master;
+set @@global.binlog_format = @old_global_binlog_format;
diff --git a/mysql-test/t/rpl_switch_stm_row_mixed.test b/mysql-test/t/rpl_switch_stm_row_mixed.test
index ccd505941c8..bffa5905f1f 100644
--- a/mysql-test/t/rpl_switch_stm_row_mixed.test
+++ b/mysql-test/t/rpl_switch_stm_row_mixed.test
@@ -1,3 +1,14 @@
+#
+# rpl_switch_stm_row_mixed tests covers
+#
+# - switching explicitly between STATEMENT, ROW, and MIXED binlog format
+# showing when it is possible and when not.
+# - switching from MIXED to RBR implicitly listing all use cases,
+# e.g a query invokes UUID(), thereafter to serve as the definition
+# of MIXED binlog format
+# - correctness of execution
+
+
-- source include/not_ndb_default.inc
-- source include/master-slave.inc
@@ -8,9 +19,22 @@ create database mysqltest1;
--enable_warnings
use mysqltest1;
+
+# play with switching
+set session binlog_format=mixed;
+show session variables like "binlog_format%";
+set session binlog_format=statement;
+show session variables like "binlog_format%";
set session binlog_format=row;
-set global binlog_format=row;
+show session variables like "binlog_format%";
+set global binlog_format=DEFAULT;
+show global variables like "binlog_format%";
+set global binlog_format=MIXED;
+show global variables like "binlog_format%";
+set global binlog_format=STATEMENT;
+show global variables like "binlog_format%";
+set global binlog_format=ROW;
show global variables like "binlog_format%";
show session variables like "binlog_format%";
select @@global.binlog_format, @@session.binlog_format;
@@ -63,12 +87,10 @@ deallocate prepare stmt1;
insert into t1 values("for_10_");
insert into t1 select "yesterday_11_";
-# test SET DEFAULT (=statement at this point of test)
-set binlog_format=default;
+# test statement (is not default after wl#3368)
+set binlog_format=statement;
select @@global.binlog_format, @@session.binlog_format;
-# due to cluster it's hard to set back to default
---error ER_NO_DEFAULT
-set global binlog_format=default;
+set global binlog_format=statement;
select @@global.binlog_format, @@session.binlog_format;
prepare stmt1 from 'insert into t1 select ?';
@@ -87,10 +109,10 @@ insert into t1 select "yesterday_16_";
# and now the mixed mode
-set binlog_format=mixed;
-select @@global.binlog_format, @@session.binlog_format;
set global binlog_format=mixed;
select @@global.binlog_format, @@session.binlog_format;
+set binlog_format=default;
+select @@global.binlog_format, @@session.binlog_format;
prepare stmt1 from 'insert into t1 select concat(UUID(),?)';
set @string="emergency_17_";
diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test
index 938baec51d1..dae6f1f075e 100644
--- a/mysql-test/t/show_check.test
+++ b/mysql-test/t/show_check.test
@@ -563,4 +563,16 @@ show keys from `mysqlttest\1`.`a\b`;
drop table `mysqlttest\1`.`a\b`;
drop database `mysqlttest\1`;
+#
+# Bug#25081 SHOW FULL TABLES on table with latin chars in name fails
+#
+set names utf8;
+--disable_warnings
+drop table if exists `été`;
+--enable_warnings
+create table `été` (field1 int);
+show full tables;
+drop table `été`;
+set names latin1;
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/xml.test b/mysql-test/t/xml.test
index ef94c7508c4..8517dce111f 100644
--- a/mysql-test/t/xml.test
+++ b/mysql-test/t/xml.test
@@ -406,3 +406,41 @@ select ExtractValue(@xml, "/entry[(50>pt)]/id");
select ExtractValue(@xml, "/entry[(50>=pt)]/id");
select ExtractValue(@xml, "/entry[(50<pt)]/id");
select ExtractValue(@xml, "/entry[(50<=pt)]/id");
+
+#
+# Bug#24747 XPath error with the node name "Text"
+#
+#
+# Test nodetypes in node name context
+#
+select ExtractValue('<a><b><Text>test</Text></b></a>','/a/b/Text');
+select ExtractValue('<a><b><comment>test</comment></b></a>','/a/b/comment');
+select ExtractValue('<a><b><node>test</node></b></a>','/a/b/node');
+select ExtractValue('<a><b><processing-instruction>test</processing-instruction></b></a>','/a/b/processing-instruction');
+#
+# Test keywords in node name contexts
+#
+select ExtractValue('<a><and>test</and></a>', '/a/and');
+select ExtractValue('<a><or>test</or></a>', '/a/or');
+select ExtractValue('<a><mod>test</mod></a>', '/a/mod');
+select ExtractValue('<a><div>test</div></a>', '/a/div');
+select ExtractValue('<a><and:and>test</and:and></a>', '/a/and:and');
+select ExtractValue('<a><or:or>test</or:or></a>', '/a/or:or');
+select ExtractValue('<a><mod:mod>test</mod:mod></a>', '/a/mod:mod');
+select ExtractValue('<a><div:div>test</div:div></a>', '/a/div:div');
+#
+# Test axis names in node name context
+#
+select ExtractValue('<a><ancestor>test</ancestor></a>', '/a/ancestor');
+select ExtractValue('<a><ancestor-or-self>test</ancestor-or-self></a>', '/a/ancestor-or-self');
+select ExtractValue('<a><attribute>test</attribute></a>', '/a/attribute');
+select ExtractValue('<a><child>test</child></a>', '/a/child');
+select ExtractValue('<a><descendant>test</descendant></a>', '/a/descendant');
+select ExtractValue('<a><descendant-or-self>test</descendant-or-self></a>', '/a/descendant-or-self');
+select ExtractValue('<a><following>test</following></a>', '/a/following');
+select ExtractValue('<a><following-sibling>test</following-sibling></a>', '/a/following-sibling');
+select ExtractValue('<a><namespace>test</namespace></a>', '/a/namespace');
+select ExtractValue('<a><parent>test</parent></a>', '/a/parent');
+select ExtractValue('<a><preceding>test</preceding></a>', '/a/preceding');
+select ExtractValue('<a><preceding-sibling>test</preceding-sibling></a>', '/a/preceding-sibling');
+select ExtractValue('<a><self>test</self></a>', '/a/self');
diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c
index b3ae18e9932..bdb5d057a16 100644
--- a/mysys/mf_iocache2.c
+++ b/mysys/mf_iocache2.c
@@ -50,7 +50,6 @@
int
my_b_copy_to_file(IO_CACHE *cache, FILE *file)
{
- byte buf[IO_SIZE];
uint bytes_in_cache;
DBUG_ENTER("my_b_copy_to_file");
@@ -58,19 +57,17 @@ my_b_copy_to_file(IO_CACHE *cache, FILE *file)
if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE))
DBUG_RETURN(1);
bytes_in_cache= my_b_bytes_in_cache(cache);
- while (bytes_in_cache > 0) {
- uint const read_bytes= min(bytes_in_cache, sizeof(buf));
- DBUG_PRINT("debug", ("Remaining %u bytes - Reading %u bytes",
- bytes_in_cache, read_bytes));
- if (my_b_read(cache, buf, read_bytes))
- DBUG_RETURN(1);
- if (my_fwrite(file, buf, read_bytes, MYF(MY_WME | MY_NABP)) == (uint) -1)
+ do
+ {
+ if (my_fwrite(file, cache->read_pos, bytes_in_cache,
+ MYF(MY_WME | MY_NABP)) == (uint) -1)
DBUG_RETURN(1);
- bytes_in_cache -= read_bytes;
- }
+ cache->read_pos= cache->read_end;
+ } while ((bytes_in_cache= my_b_fill(cache)));
DBUG_RETURN(0);
}
+
my_off_t my_b_append_tell(IO_CACHE* info)
{
/*
diff --git a/sql/field.cc b/sql/field.cc
index 867edc6f9dd..9e75bb96452 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -7203,7 +7203,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
cannot_convert_error_pos, from + length))
return 2;
- if (copy_length < length)
+ if (from_end_pos < from + length)
{
report_data_too_long(this);
return 2;
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 9321992e566..26474990644 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -1044,12 +1044,12 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
{MY_XPATH_LEX_OR , "or" , 2, 0 },
{MY_XPATH_LEX_DIV , "div" , 3, 0 },
{MY_XPATH_LEX_MOD , "mod" , 3, 0 },
-
- {MY_XPATH_LEX_NODETYPE, "comment" , 7, 0 },
- {MY_XPATH_LEX_NODETYPE, "text" , 4, 0 },
- {MY_XPATH_LEX_NODETYPE, "processing-instruction" , 22,0 },
- {MY_XPATH_LEX_NODETYPE, "node" , 4, 0 },
-
+ {0,NULL,0,0}
+};
+
+
+static struct my_xpath_keyword_names_st my_axis_names[]=
+{
{MY_XPATH_LEX_AXIS,"ancestor" , 8,MY_XPATH_AXIS_ANCESTOR },
{MY_XPATH_LEX_AXIS,"ancestor-or-self" ,16,MY_XPATH_AXIS_ANCESTOR_OR_SELF },
{MY_XPATH_LEX_AXIS,"attribute" , 9,MY_XPATH_AXIS_ATTRIBUTE },
@@ -1063,7 +1063,16 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
{MY_XPATH_LEX_AXIS,"preceding" , 9,MY_XPATH_AXIS_PRECEDING },
{MY_XPATH_LEX_AXIS,"preceding-sibling" ,17,MY_XPATH_AXIS_PRECEDING_SIBLING },
{MY_XPATH_LEX_AXIS,"self" , 4,MY_XPATH_AXIS_SELF },
+ {0,NULL,0,0}
+};
+
+static struct my_xpath_keyword_names_st my_nodetype_names[]=
+{
+ {MY_XPATH_LEX_NODETYPE, "comment" , 7, 0 },
+ {MY_XPATH_LEX_NODETYPE, "text" , 4, 0 },
+ {MY_XPATH_LEX_NODETYPE, "processing-instruction" , 22,0 },
+ {MY_XPATH_LEX_NODETYPE, "node" , 4, 0 },
{0,NULL,0,0}
};
@@ -1078,11 +1087,14 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
- Token type, on lookup success.
- MY_XPATH_LEX_IDENT, on lookup failure.
*/
-static int my_xpath_keyword(MY_XPATH *x, const char *beg, const char *end)
+static int
+my_xpath_keyword(MY_XPATH *x,
+ struct my_xpath_keyword_names_st *keyword_names,
+ const char *beg, const char *end)
{
struct my_xpath_keyword_names_st *k;
size_t length= end-beg;
- for (k= my_keyword_names; k->name; k++)
+ for (k= keyword_names; k->name; k++)
{
if (length == k->length && !strncasecmp(beg, k->name, length))
{
@@ -1368,15 +1380,32 @@ my_xpath_lex_scan(MY_XPATH *xpath,
beg+= length) /* no op */;
lex->end= beg;
- // check if a function call
- if (*beg == '(' && (xpath->func= my_xpath_function(lex->beg, beg)))
+ if (beg < end)
{
- lex->term= MY_XPATH_LEX_FUNC;
- return;
+ if (*beg == '(')
+ {
+ /*
+ check if a function call, e.g.: count(/a/b)
+ or a nodetype test, e.g.: /a/b/text()
+ */
+ if ((xpath->func= my_xpath_function(lex->beg, beg)))
+ lex->term= MY_XPATH_LEX_FUNC;
+ else
+ lex->term= my_xpath_keyword(xpath, my_nodetype_names,
+ lex->beg, beg);
+ return;
+ }
+ // check if an axis specifier, e.g.: /a/b/child::*
+ else if (*beg == ':' && beg + 1 < end && beg[1] == ':')
+ {
+ lex->term= my_xpath_keyword(xpath, my_axis_names,
+ lex->beg, beg);
+ return;
+ }
}
-
// check if a keyword
- lex->term= my_xpath_keyword(xpath, lex->beg, beg);
+ lex->term= my_xpath_keyword(xpath, my_keyword_names,
+ lex->beg, beg);
return;
}
@@ -2329,6 +2358,36 @@ static int my_xpath_parse_Number(MY_XPATH *xpath)
/*
+ Scan NCName.
+
+ SYNOPSYS
+
+ The keywords AND, OR, MOD, DIV are valid identitiers
+ when they are in identifier context:
+
+ SELECT
+ ExtractValue('<and><or><mod><div>VALUE</div></mod></or></and>',
+ '/and/or/mod/div')
+ -> VALUE
+
+ RETURN
+ 1 - success
+ 0 - failure
+*/
+
+static int
+my_xpath_parse_NCName(MY_XPATH *xpath)
+{
+ return
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_AND) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_OR) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_MOD) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_DIV) ? 1 : 0;
+}
+
+
+/*
QName grammar can be found in a separate document
http://www.w3.org/TR/REC-xml-names/#NT-QName
@@ -2336,16 +2395,17 @@ static int my_xpath_parse_Number(MY_XPATH *xpath)
[7] Prefix ::= NCName
[8] LocalPart ::= NCName
*/
+
static int
my_xpath_parse_QName(MY_XPATH *xpath)
{
const char *beg;
- if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))
+ if (!my_xpath_parse_NCName(xpath))
return 0;
beg= xpath->prevtok.beg;
if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_COLON))
return 1; /* Non qualified name */
- if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))
+ if (!my_xpath_parse_NCName(xpath))
return 0;
xpath->prevtok.beg= beg;
return 1;
diff --git a/sql/log.cc b/sql/log.cc
index 5e9ebfcb902..c797e72a076 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -31,15 +31,6 @@
#include <mysql/plugin.h>
-/*
- Define placement versions of operator new and operator delete since
- we cannot be sure that the <new> include exists.
- */
-inline void *operator new(size_t, void *ptr) { return ptr; }
-inline void *operator new[](size_t, void *ptr) { return ptr; }
-inline void operator delete(void*, void*) { /* Do nothing */ }
-inline void operator delete[](void*, void*) { /* Do nothing */ }
-
/* max size of the log message */
#define MAX_LOG_BUFFER_SIZE 1024
#define MAX_USER_HOST_SIZE 512
@@ -147,7 +138,8 @@ public:
*/
void truncate(my_off_t pos)
{
- DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
+ DBUG_PRINT("info", ("truncating to position %ld", pos));
+ DBUG_PRINT("info", ("before_stmt_pos=%lu", (void*) pos));
delete pending();
set_pending(0);
reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0);
@@ -3473,10 +3465,10 @@ int THD::binlog_flush_transaction_cache()
{
DBUG_ENTER("binlog_flush_transaction_cache");
binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot];
- DBUG_PRINT("enter", ("trx_data: 0x%lx", (ulong) trx_data));
+ DBUG_PRINT("enter", ("trx_data=0x%lu", (void*) trx_data));
if (trx_data)
- DBUG_PRINT("enter", ("trx_data->before_stmt_pos: %lu",
- (ulong) trx_data->before_stmt_pos));
+ DBUG_PRINT("enter", ("trx_data->before_stmt_pos=%d",
+ trx_data->before_stmt_pos));
/*
Write the transaction cache to the binary log. We don't flush and
@@ -4525,7 +4517,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 54d75449cd5..2657700435d 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1130,13 +1130,18 @@ void Log_event::print_header(IO_CACHE* file,
char emit_buf[256];
int const bytes_written=
my_snprintf(emit_buf, sizeof(emit_buf),
- "# %8.8lx %-48.48s |%s|\n# ",
+ "# %8.8lx %-48.48s |%s|\n",
(unsigned long) (hexdump_from + (i & 0xfffffff0)),
hex_string, char_string);
DBUG_ASSERT(bytes_written >= 0);
DBUG_ASSERT(static_cast<my_size_t>(bytes_written) < sizeof(emit_buf));
my_b_write(file, (byte*) emit_buf, bytes_written);
}
+ /*
+ need a # to prefix the rest of printouts for example those of
+ Rows_log_event::print_helper().
+ */
+ my_b_write(file, "# ", 2);
}
DBUG_VOID_RETURN;
}
@@ -2240,6 +2245,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);
@@ -2363,6 +2370,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() */
@@ -2453,6 +2462,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();
}
@@ -2492,6 +2502,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;
}
@@ -2592,6 +2603,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
@@ -5762,15 +5804,45 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
DBUG_RETURN(error);
}
}
+
+ /*
+ When the open and locking succeeded, we check all tables to
+ ensure that they still have the correct type.
+
+ We can use a down cast here since we know that every table added
+ to the tables_to_lock is a RPL_TABLE_LIST.
+ */
+
+ {
+ RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(rli->tables_to_lock);
+ for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global))
+ {
+ if (ptr->m_tabledef.compatible_with(rli, ptr->table))
+ {
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock= 0;
+ thd->query_error= 1;
+ rli->clear_tables_to_lock();
+ DBUG_RETURN(ERR_BAD_TABLE_DEF);
+ }
+ }
+ }
+
/*
- When the open and locking succeeded, we add all the tables to
- the table map and remove them from tables to lock.
+ ... and then we add all the tables to the table map and remove
+ them from tables to lock.
We also invalidate the query cache for all the tables, since
they will now be changed.
+
+ TODO [/Matz]: Maybe the query cache should not be invalidated
+ here? It might be that a table is not changed, even though it
+ was locked for the statement. We do know that each
+ Rows_log_event contain at least one row, so after processing one
+ Rows_log_event, we can invalidate the query cache for the
+ associated table.
*/
- TABLE_LIST *ptr;
- for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
+ for (TABLE_LIST *ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
{
rli->m_table_map.set_table(ptr->table_id, ptr->table);
}
@@ -6041,7 +6113,7 @@ void Rows_log_event::print_helper(FILE *file,
{
bool const last_stmt_event= get_flags(STMT_END_F);
print_header(head, print_event_info, !last_stmt_event);
- my_b_printf(head, "\t%s: table id %lu", name, m_table_id);
+ my_b_printf(head, "\t%s: table id %lu\n", name, m_table_id);
print_base64(body, print_event_info, !last_stmt_event);
}
@@ -6223,11 +6295,11 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
thd->query_id= next_query_id();
pthread_mutex_unlock(&LOCK_thread_count);
- TABLE_LIST *table_list;
+ RPL_TABLE_LIST *table_list;
char *db_mem, *tname_mem;
void *const memory=
my_multi_malloc(MYF(MY_WME),
- &table_list, sizeof(TABLE_LIST),
+ &table_list, sizeof(RPL_TABLE_LIST),
&db_mem, NAME_LEN + 1,
&tname_mem, NAME_LEN + 1,
NULL);
@@ -6273,11 +6345,27 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
}
/*
- Open the table if it is not already open and add the table to table map.
- Note that for any table that should not be replicated, a filter is needed.
+ Open the table if it is not already open and add the table to
+ table map. Note that for any table that should not be
+ replicated, a filter is needed.
+
+ The creation of a new TABLE_LIST is used to up-cast the
+ table_list consisting of RPL_TABLE_LIST items. This will work
+ since the only case where the argument to open_tables() is
+ changed, is when thd->lex->query_tables == table_list, i.e.,
+ when the statement requires prelocking. Since this is not
+ executed when a statement is executed, this case will not occur.
+ As a precaution, an assertion is added to ensure that the bad
+ case is not a fact.
+
+ Either way, the memory in the list is *never* released
+ internally in the open_tables() function, hence we take a copy
+ of the pointer to make sure that it's not lost.
*/
uint count;
- if ((error= open_tables(thd, &table_list, &count, 0)))
+ DBUG_ASSERT(thd->lex->query_tables != table_list);
+ TABLE_LIST *tmp_table_list= table_list;
+ if ((error= open_tables(thd, &tmp_table_list, &count, 0)))
{
if (thd->query_error || thd->is_fatal_error)
{
@@ -6304,14 +6392,12 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
*/
DBUG_ASSERT(m_table->in_use);
- table_def const def(m_coltype, m_colcnt);
- if (def.compatible_with(rli, m_table))
- {
- thd->query_error= 1;
- error= ERR_BAD_TABLE_DEF;
- goto err;
- /* purecov: end */
- }
+ /*
+ Use placement new to construct the table_def instance in the
+ memory allocated for it inside table_list.
+ */
+ const table_def *const def=
+ new (&table_list->m_tabledef) table_def(m_coltype, m_colcnt);
/*
We record in the slave's information that the table should be
diff --git a/sql/log_event.h b/sql/log_event.h
index 5994beb0df3..ac7bc0cb082 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -546,16 +546,19 @@ typedef struct st_print_event_info
bzero(db, sizeof(db));
bzero(charset, sizeof(charset));
bzero(time_zone_str, sizeof(time_zone_str));
- strcpy(delimiter, ";");
- uint const flags = MYF(MY_WME | MY_NABP);
- init_io_cache(&head_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
- init_io_cache(&body_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
+ delimiter[0]= ';';
+ delimiter[1]= 0;
+ myf const flags = MYF(MY_WME | MY_NABP);
+ open_cached_file(&head_cache, NULL, NULL, 0, flags);
+ open_cached_file(&body_cache, NULL, NULL, 0, flags);
}
~st_print_event_info() {
- end_io_cache(&head_cache);
- end_io_cache(&body_cache);
+ close_cached_file(&head_cache);
+ close_cached_file(&body_cache);
}
+ bool init_ok() /* tells if construction was successful */
+ { return my_b_inited(&head_cache) && my_b_inited(&body_cache); }
/* Settings on how to print the events */
@@ -1153,6 +1156,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 +1188,7 @@ public:
*/
return FORMAT_DESCRIPTION_HEADER_LEN;
}
+ void calc_server_version_split();
};
@@ -1727,14 +1732,17 @@ public:
TYPE_CODE = TABLE_MAP_EVENT
};
+ /**
+ Enumeration of the errors that can be returned.
+ */
enum enum_error
{
- ERR_OPEN_FAILURE = -1, /* Failure to open table */
- ERR_OK = 0, /* No error */
- ERR_TABLE_LIMIT_EXCEEDED = 1, /* No more room for tables */
- ERR_OUT_OF_MEM = 2, /* Out of memory */
- ERR_BAD_TABLE_DEF = 3, /* Table definition does not match */
- ERR_RBR_TO_SBR = 4 /* daisy-chanining RBR to SBR not allowed */
+ ERR_OPEN_FAILURE = -1, /**< Failure to open table */
+ ERR_OK = 0, /**< No error */
+ ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */
+ ERR_OUT_OF_MEM = 2, /**< Out of memory */
+ ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */
+ ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */
};
enum enum_flag
@@ -1814,7 +1822,7 @@ private:
Row level log event class.
- Common base class for all row-level log events.
+ Common base class for all row-containing log events.
RESPONSIBILITIES
@@ -1828,6 +1836,19 @@ private:
class Rows_log_event : public Log_event
{
public:
+ /**
+ Enumeration of the errors that can be returned.
+ */
+ enum enum_error
+ {
+ ERR_OPEN_FAILURE = -1, /**< Failure to open table */
+ ERR_OK = 0, /**< No error */
+ ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */
+ ERR_OUT_OF_MEM = 2, /**< Out of memory */
+ ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */
+ ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */
+ };
+
/*
These definitions allow you to combine the flags into an
appropriate flag set using the normal bitwise operators. The
@@ -1835,7 +1856,6 @@ public:
accepted by the compiler, which is then used to set the real set
of flags.
*/
-
enum enum_flag
{
/* Last event of a statement */
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 68465c08746..3bbee20567c 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -95,15 +95,18 @@ void net_set_read_timeout(NET *net, uint timeout);
#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
#define all_bits_set(A,B) ((A) & (B) != (B))
-#define WARN_DEPRECATED(Thd,Ver,Old,New) \
- do { \
- DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) >= 0); \
- push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \
- ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), \
- (Old), (Ver), (New)); \
+#define WARN_DEPRECATED(Thd,Ver,Old,New) \
+ do { \
+ DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) > 0); \
+ if (Thd != NULL) \
+ push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \
+ ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), \
+ (Old), (Ver), (New)); \
+ else \
+ sql_print_warning("The syntax %s is deprecated and will be removed " \
+ "in MySQL %s. Please use %s instead.", (Old), (Ver), (New)); \
} while(0)
-
extern CHARSET_INFO *system_charset_info, *files_charset_info ;
extern CHARSET_INFO *national_charset_info, *table_alias_charset;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 172891b7c8e..3f65d2d4065 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -361,6 +361,7 @@ my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0;
my_bool opt_innodb;
+bool slave_warning_issued = false;
/*
Legacy global handlerton. These will be removed (please do not add more).
@@ -448,9 +449,10 @@ my_bool sp_automatic_privileges= 1;
ulong opt_binlog_rows_event_max_size;
const char *binlog_format_names[]= {"STATEMENT", "ROW", "MIXED", NullS};
TYPELIB binlog_format_typelib=
- { array_elements(binlog_format_names)-1,"",
+ { array_elements(binlog_format_names) - 1, "",
binlog_format_names, NULL };
-
+ulong opt_binlog_format_id= (ulong) BINLOG_FORMAT_UNSPEC;
+const char *opt_binlog_format= binlog_format_names[opt_binlog_format_id];
#ifdef HAVE_INITGROUPS
static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */
#endif
@@ -3193,17 +3195,24 @@ with --log-bin instead.");
"--log-slave-updates work.");
unireg_abort(1);
}
-
- if (!opt_bin_log && (global_system_variables.binlog_format != BINLOG_FORMAT_UNSPEC))
- {
- sql_print_error("You need to use --log-bin to make "
- "--binlog-format work.");
- unireg_abort(1);
- }
- if (global_system_variables.binlog_format == BINLOG_FORMAT_UNSPEC)
- {
+ if (!opt_bin_log)
+ if (opt_binlog_format_id != BINLOG_FORMAT_UNSPEC)
+ {
+ sql_print_error("You need to use --log-bin to make "
+ "--binlog-format work.");
+ unireg_abort(1);
+ }
+ else
+ {
+ global_system_variables.binlog_format= BINLOG_FORMAT_UNSPEC;
+ }
+ else
+ if (opt_binlog_format_id == BINLOG_FORMAT_UNSPEC)
global_system_variables.binlog_format= BINLOG_FORMAT_MIXED;
- }
+ else
+ {
+ DBUG_ASSERT(global_system_variables.binlog_format != BINLOG_FORMAT_UNSPEC);
+ }
/* Check that we have not let the format to unspecified at this point */
DBUG_ASSERT((uint)global_system_variables.binlog_format <=
@@ -3339,7 +3348,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);
@@ -4946,6 +4955,7 @@ struct my_option my_long_options[] =
(gptr*) &my_bind_addr_str, (gptr*) &my_bind_addr_str, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"binlog_format", OPT_BINLOG_FORMAT,
+ "Does not have any effect without '--log-bin'. "
"Tell the master the form of binary logging to use: either 'row' for "
"row-based binary logging, or 'statement' for statement-based binary "
"logging, or 'mixed'. 'mixed' is statement-based binary logging except "
@@ -4953,11 +4963,12 @@ struct my_option my_long_options[] =
"involve user-defined functions (i.e. UDFs) or the UUID() function; for "
"those, row-based binary logging is automatically used. "
#ifdef HAVE_NDB_BINLOG
- "If ndbcluster is enabled, the default is 'row'."
+ "If ndbcluster is enabled and binlog_format is `mixed', the format switches"
+ " to 'row' and back implicitly per each query accessing a NDB table."
#endif
- , 0, 0, 0, GET_STR, REQUIRED_ARG,
- BINLOG_FORMAT_MIXED
- , 0, 0, 0, 0, 0 },
+ ,(gptr*) &opt_binlog_format, (gptr*) &opt_binlog_format,
+ 0, GET_STR, REQUIRED_ARG, BINLOG_FORMAT_MIXED, BINLOG_FORMAT_STMT,
+ BINLOG_FORMAT_MIXED, 0, 0, 0},
{"binlog-do-db", OPT_BINLOG_DO_DB,
"Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -7334,7 +7345,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
binlog_format_names[BINLOG_FORMAT_MIXED]);
exit(1);
}
- global_system_variables.binlog_format= id-1;
+ global_system_variables.binlog_format= opt_binlog_format_id= id - 1;
break;
}
case (int)OPT_BINLOG_DO_DB:
@@ -7518,6 +7529,29 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int) OPT_STANDALONE: /* Dummy option for NT */
break;
#endif
+ /*
+ The following change issues a deprecation warning if the slave
+ configuration is specified either in the my.cnf file or on
+ the command-line. See BUG#21490.
+ */
+ case OPT_MASTER_HOST:
+ case OPT_MASTER_USER:
+ case OPT_MASTER_PASSWORD:
+ case OPT_MASTER_PORT:
+ case OPT_MASTER_CONNECT_RETRY:
+ case OPT_MASTER_SSL:
+ case OPT_MASTER_SSL_KEY:
+ case OPT_MASTER_SSL_CERT:
+ case OPT_MASTER_SSL_CAPATH:
+ case OPT_MASTER_SSL_CIPHER:
+ case OPT_MASTER_SSL_CA:
+ if (!slave_warning_issued) //only show the warning once
+ {
+ slave_warning_issued = true;
+ WARN_DEPRECATED(0, "5.2", "for replication startup options",
+ "'CHANGE MASTER'");
+ }
+ break;
case OPT_CONSOLE:
if (opt_console)
opt_error_log= 0; // Force logs to stdout
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index 34cebf93ddb..8694b5724f9 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -23,97 +23,96 @@
#include "mysql_priv.h"
uint32
-field_length_from_packed(enum_field_types const field_type,
- byte const *const data);
+field_length_from_packed(enum_field_types field_type, byte const *data);
-/*
+/**
A table definition from the master.
- RESPONSIBILITIES
-
+ The responsibilities of this class is:
- Extract and decode table definition data from the table map event
- Check if table definition in table map is compatible with table
definition on slave
- DESCRIPTION
-
- Currently, the only field type data available is an array of the
- type operators that are present in the table map event.
-
- TODO
+ Currently, the only field type data available is an array of the
+ type operators that are present in the table map event.
- Add type operands to this structure to allow detection of
- difference between, e.g., BIT(5) and BIT(10).
+ @todo Add type operands to this structure to allow detection of
+ difference between, e.g., BIT(5) and BIT(10).
*/
class table_def
{
public:
- /*
+ /**
Convenience declaration of the type of the field type data in a
table map event.
*/
typedef unsigned char field_type;
- /*
+ /**
Constructor.
- SYNOPSIS
- table_def()
- types Array of types
- size Number of elements in array 'types'
+ @param types Array of types
+ @param size Number of elements in array 'types'
*/
table_def(field_type *types, my_size_t size)
- : m_type(types), m_size(size)
+ : m_type(new unsigned char [size]), m_size(size)
{
+ if (m_type)
+ memcpy(m_type, types, size);
+ else
+ m_size= 0;
}
- /*
- Return the number of fields there is type data for.
+ ~table_def() {
+ if (m_type)
+ delete [] m_type;
+#ifndef DBUG_OFF
+ m_type= 0;
+ m_size= 0;
+#endif
+ }
- SYNOPSIS
- size()
+ /**
+ Return the number of fields there is type data for.
- RETURN VALUE
- The number of fields that there is type data for.
+ @return The number of fields that there is type data for.
*/
my_size_t size() const { return m_size; }
+
/*
Return a representation of the type data for one field.
- SYNOPSIS
- type()
- i Field index to return data for
-
- RETURN VALUE
+ @param index Field index to return data for
- Will return a representation of the type data for field
- 'i'. Currently, only the type identifier is returned.
+ @return Will return a representation of the type data for field
+ <code>index</code>. Currently, only the type identifier is
+ returned.
*/
- field_type type(my_ptrdiff_t i) const { return m_type[i]; }
+ field_type type(my_ptrdiff_t index) const
+ {
+ DBUG_ASSERT(0 <= index);
+ DBUG_ASSERT(static_cast<my_size_t>(index) < m_size);
+ return m_type[index];
+ }
- /*
+ /**
Decide if the table definition is compatible with a table.
- SYNOPSIS
- compatible_with()
- rli Pointer to relay log info
- table Pointer to table to compare with.
-
- DESCRIPTION
-
- Compare the definition with a table to see if it is compatible
- with it. A table definition is compatible with a table if:
+ Compare the definition with a table to see if it is compatible
+ with it.
+ A table definition is compatible with a table if:
- the columns types of the table definition is a (not
necessarily proper) prefix of the column type of the table, or
-
- the other way around
- RETURN VALUE
- 1 if the table definition is not compatible with 'table'
- 0 if the table definition is compatible with 'table'
+ @param rli Pointer to relay log info
+ @param table Pointer to table to compare with.
+
+ @retval 1 if the table definition is not compatible with @c table
+ @retval 0 if the table definition is compatible with @c table
*/
int compatible_with(RELAY_LOG_INFO *rli, TABLE *table) const;
@@ -122,4 +121,14 @@ private:
field_type *m_type; // Array of type descriptors
};
+/**
+ Extend the normal table list with a few new fields needed by the
+ slave thread, but nowhere else.
+ */
+struct RPL_TABLE_LIST
+ : public st_table_list
+{
+ table_def m_tabledef;
+};
+
#endif /* RPL_UTILITY_H */
diff --git a/sql/slave.cc b/sql/slave.cc
index f2bd24bd05e..f67657eef89 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3660,6 +3660,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, 38 } },
+ {24432, { 5, 1, 12 }, { 5, 1, 17 } }
+ };
+ 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 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);
+ // a verbose message for the error log
+ slave_print_msg(ERROR_LEVEL, 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]);
+ 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 bc039f6eb75..f21266bbee4 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -159,6 +159,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);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 9b66d5c5148..f4a999f918a 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -59,6 +59,7 @@
#include "sql_trigger.h"
#include "sql_select.h"
#include "sql_show.h"
+#include "slave.h"
#ifndef EMBEDDED_LIBRARY
static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list);
@@ -391,6 +392,36 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
(duplic == DUP_UPDATE))
lock_type=TL_WRITE;
#endif
+ if ((lock_type == TL_WRITE_DELAYED) &&
+ (global_system_variables.binlog_format == BINLOG_FORMAT_STMT) &&
+ log_on && mysql_bin_log.is_open() &&
+ (values_list.elements > 1))
+ {
+ /*
+ Statement-based binary logging does not work in this case, because:
+ a) two concurrent statements may have their rows intermixed in the
+ queue, leading to autoincrement replication problems on slave (because
+ the values generated used for one statement don't depend only on the
+ value generated for the first row of this statement, so are not
+ replicable)
+ b) if first row of the statement has an error the full statement is
+ not binlogged, while next rows of the statement may be inserted.
+ c) if first row succeeds, statement is binlogged immediately with a
+ zero error code (i.e. "no error"), if then second row fails, query
+ will fail on slave too and slave will stop (wrongly believing that the
+ master got no error).
+ So we fallback to non-delayed INSERT.
+ Note that to be fully correct, we should test the "binlog format which
+ the delayed thread is going to use for this row". But in the common case
+ where the global binlog format is not changed and the session binlog
+ format may be changed, that is equal to the global binlog format.
+ We test it without mutex for speed reasons (condition rarely true), and
+ in the common case (global not changed) it is as good as without mutex;
+ if global value is changed, anyway there is uncertainty as the delayed
+ thread may be old and use the before-the-change value.
+ */
+ lock_type= TL_WRITE;
+ }
table_list->lock_type= lock_type;
#ifndef EMBEDDED_LIBRARY
@@ -504,6 +535,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->cuted_fields = 0L;
table->next_number_field=table->found_next_number_field;
+#ifdef HAVE_REPLICATION
+ if (thd->slave_thread &&
+ (info.handle_duplicates == DUP_UPDATE) &&
+ (table->next_number_field != NULL) &&
+ rpl_master_has_bug(&active_mi->rli, 24432))
+ goto abort;
+#endif
+
error=0;
thd->proc_info="update";
if (duplic != DUP_ERROR || ignore)
@@ -1196,14 +1235,13 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (res == VIEW_CHECK_ERROR)
goto before_trg_err;
+ table->file->restore_auto_increment(prev_insert_id);
if ((error=table->file->ha_update_row(table->record[1],
table->record[0])))
{
if (info->ignore &&
!table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
{
- table->file->restore_auto_increment(prev_insert_id);
-
goto ok_or_after_trg_err;
}
goto err;
@@ -2545,6 +2583,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
}
restore_record(table,s->default_values); // Get empty record
table->next_number_field=table->found_next_number_field;
+
+#ifdef HAVE_REPLICATION
+ if (thd->slave_thread &&
+ (info.handle_duplicates == DUP_UPDATE) &&
+ (table->next_number_field != NULL) &&
+ rpl_master_has_bug(&active_mi->rli, 24432))
+ DBUG_RETURN(1);
+#endif
+
thd->cuted_fields=0;
if (info.ignore || info.handle_duplicates != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
@@ -3148,9 +3195,8 @@ void select_create::send_error(uint errcode,const char *err)
("Current statement %s row-based",
thd->current_stmt_binlog_row_based ? "is" : "is NOT"));
DBUG_PRINT("info",
- ("Current table (at 0x%lx) %s a temporary (or non-existing) "
- "table",
- (ulong) table,
+ ("Current table (at 0x%lu) %s a temporary (or non-existant) table",
+ (void*) table,
table && !table->s->tmp_table ? "is NOT" : "is"));
DBUG_PRINT("info",
("Table %s prior to executing this statement",
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 99fb0fd4236..ed79e089b65 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2536,7 +2536,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
SELECT_LEX sel;
INDEX_FIELD_VALUES idx_field_vals;
- char path[FN_REFLEN], *end, *base_name, *orig_base_name, *file_name;
+ char path[FN_REFLEN], *base_name, *orig_base_name, *file_name;
uint len;
bool with_i_schema;
enum enum_schema_tables schema_table_idx;
@@ -2554,7 +2554,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
#endif
DBUG_ENTER("get_all_tables");
- LINT_INIT(end);
LINT_INIT(len);
lex->view_prepare_mode= TRUE;
@@ -2646,7 +2645,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
else
{
len= build_table_filename(path, sizeof(path), base_name, "", "", 0);
- end= path + len;
len= FN_LEN - len;
find_files_result res= find_files(thd, &files, base_name,
path, idx_field_vals.table_value, 0);
@@ -2696,7 +2694,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
}
else
{
- my_snprintf(end, len, "/%s%s", file_name, reg_ext);
+ build_table_filename(path, sizeof(path),
+ base_name, file_name, reg_ext, 0);
+
switch (mysql_frm_type(thd, path, &not_used)) {
case FRMTYPE_ERROR:
table->field[3]->store(STRING_WITH_LEN("ERROR"),
diff --git a/storage/ndb/include/ndb_global.h.in b/storage/ndb/include/ndb_global.h.in
index 60d32f62ee3..dd4303f949c 100644
--- a/storage/ndb/include/ndb_global.h.in
+++ b/storage/ndb/include/ndb_global.h.in
@@ -115,8 +115,6 @@ static const char table_name_separator = '/';
#endif
#ifdef __cplusplus
-inline void* operator new(size_t, void* __p) { return __p; }
-inline void* operator new[](size_t, void* __p) { return __p; }
extern "C" {
#endif