summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <mkindahl@dl145h.mysql.com>2007-11-14 11:07:30 +0100
committerunknown <mkindahl@dl145h.mysql.com>2007-11-14 11:07:30 +0100
commit19ef3ae88dd66f4a2fb6d9059ec388f673716063 (patch)
treed9b883b86c3d3cfcacb0ef412b5c6daedc325184
parentc4f94b70bdaa26e9b8782771f079a2dc3c1594d6 (diff)
parent296931c1c7db0f502da7ec34060e2ca5d86bddd3 (diff)
downloadmariadb-git-19ef3ae88dd66f4a2fb6d9059ec388f673716063.tar.gz
Merge dl145h.mysql.com:/data0/mkindahl/mysql-5.1
into dl145h.mysql.com:/data0/mkindahl/mysql-5.1-new-rpl mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test: Auto merged mysql-test/mysql-test-run.pl: Auto merged mysql-test/suite/rpl/include/rpl_mixed_dml.inc: Auto merged mysql-test/suite/rpl/r/rpl_bug31076.result: Auto merged mysql-test/suite/rpl/t/rpl_bug31076.test: Auto merged mysql-test/suite/rpl/t/rpl_innodb_bug28430.test: Auto merged mysql-test/suite/rpl_ndb/t/disabled.def: Auto merged sql/field.cc: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/handler.cc: Auto merged sql/log.cc: Auto merged sql/log_event.cc: Auto merged sql/log_event_old.cc: Auto merged sql/mysqld.cc: Auto merged sql/slave.cc: Auto merged sql/sp_head.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_insert.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_yacc.yy: Auto merged mysql-test/t/partition.test: Manual merge. BitKeeper/deleted/.del-rpl_row_extraColmaster_ndb.result~a2c64bae75b49d2: Manual merge. mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result: Manual merge. mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result: Manual merge. mysql-test/suite/rpl/t/disabled.def: Manual merge. sql/sql_delete.cc: Manual merge.
-rw-r--r--client/mysql.cc11
-rw-r--r--include/my_base.h8
-rw-r--r--mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test298
-rw-r--r--mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test2
-rw-r--r--mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test73
-rw-r--r--mysql-test/extra/rpl_tests/rpl_row_basic.test36
-rw-r--r--mysql-test/extra/rpl_tests/rpl_truncate_helper.test14
-rw-r--r--mysql-test/include/ctype_regex.inc42
-rw-r--r--mysql-test/include/reset_master_and_slave.inc10
-rw-r--r--mysql-test/include/wait_for_slave_sql_error.inc33
-rw-r--r--mysql-test/lib/mtr_cases.pl99
-rwxr-xr-xmysql-test/mysql-test-run.pl5
-rw-r--r--mysql-test/r/ctype_euckr.result41
-rw-r--r--mysql-test/r/ctype_uca.result45
-rw-r--r--mysql-test/r/ctype_ucs.result45
-rw-r--r--mysql-test/r/ctype_utf8.result45
-rw-r--r--mysql-test/r/func_regexp.result14
-rw-r--r--mysql-test/r/innodb.result17
-rw-r--r--mysql-test/r/multi_update.result23
-rw-r--r--mysql-test/r/mysql.result2
-rw-r--r--mysql-test/suite/binlog/r/binlog_killed.result131
-rw-r--r--mysql-test/suite/binlog/r/binlog_killed_simulate.result33
-rw-r--r--mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result233
-rw-r--r--mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result169
-rw-r--r--mysql-test/suite/binlog/t/binlog_killed.test323
-rw-r--r--mysql-test/suite/binlog/t/binlog_killed_simulate-master.opt1
-rw-r--r--mysql-test/suite/binlog/t/binlog_killed_simulate.test69
-rw-r--r--mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test2
-rw-r--r--mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test120
-rw-r--r--mysql-test/suite/manual/r/rpl_replication_delay.result136
-rw-r--r--mysql-test/suite/manual/t/rpl_replication_delay-slave.opt1
-rw-r--r--mysql-test/suite/manual/t/rpl_replication_delay.test71
-rw-r--r--mysql-test/suite/rpl/data/rpl_bug28618.dat3
-rw-r--r--mysql-test/suite/rpl/include/rpl_mixed_check_select.inc8
-rw-r--r--mysql-test/suite/rpl/include/rpl_mixed_check_view.inc4
-rw-r--r--mysql-test/suite/rpl/include/rpl_mixed_dml.inc8
-rw-r--r--mysql-test/suite/rpl/r/rpl_extraCol_innodb.result63
-rw-r--r--mysql-test/suite/rpl/r/rpl_extraCol_myisam.result63
-rw-r--r--mysql-test/suite/rpl/r/rpl_found_rows.result233
-rw-r--r--mysql-test/suite/rpl/r/rpl_idempotency.result71
-rw-r--r--mysql-test/suite/rpl/r/rpl_innodb_bug28430.result16
-rw-r--r--mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result152
-rw-r--r--mysql-test/suite/rpl/r/rpl_invoked_features.result30
-rw-r--r--mysql-test/suite/rpl/r/rpl_packet.result42
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result31
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result19
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result19
-rw-r--r--mysql-test/suite/rpl/r/rpl_skip_error.result3
-rw-r--r--mysql-test/suite/rpl/r/rpl_slave_skip.result208
-rw-r--r--mysql-test/suite/rpl/r/rpl_sp_effects.result41
-rw-r--r--mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result68
-rw-r--r--mysql-test/suite/rpl/r/rpl_temporary_errors.result81
-rw-r--r--mysql-test/suite/rpl/r/rpl_truncate_2myisam.result42
-rw-r--r--mysql-test/suite/rpl/r/rpl_truncate_3innodb.result42
-rw-r--r--mysql-test/suite/rpl/t/disabled.def2
-rw-r--r--mysql-test/suite/rpl/t/rpl_bug31076.test1
-rw-r--r--mysql-test/suite/rpl/t/rpl_dual_pos_advance.test6
-rw-r--r--mysql-test/suite/rpl/t/rpl_found_rows.test256
-rw-r--r--mysql-test/suite/rpl/t/rpl_idempotency.test79
-rw-r--r--mysql-test/suite/rpl/t/rpl_innodb_bug28430.test3
-rw-r--r--mysql-test/suite/rpl/t/rpl_invoked_features.test80
-rw-r--r--mysql-test/suite/rpl/t/rpl_packet.test17
-rw-r--r--mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test35
-rw-r--r--mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test1
-rw-r--r--mysql-test/suite/rpl/t/rpl_row_until.test4
-rw-r--r--mysql-test/suite/rpl/t/rpl_skip_error-slave.opt2
-rw-r--r--mysql-test/suite/rpl/t/rpl_skip_error.test8
-rw-r--r--mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt1
-rw-r--r--mysql-test/suite/rpl/t/rpl_slave_skip.test239
-rw-r--r--mysql-test/suite/rpl/t/rpl_sp_effects.test50
-rw-r--r--mysql-test/suite/rpl/t/rpl_stm_mystery22.test2
-rw-r--r--mysql-test/suite/rpl/t/rpl_stm_until.test4
-rw-r--r--mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test36
-rw-r--r--mysql-test/suite/rpl/t/rpl_temporary.test3
-rw-r--r--mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt3
-rw-r--r--mysql-test/suite/rpl/t/rpl_temporary_errors.test27
-rw-r--r--mysql-test/suite/rpl/t/rpl_trigger.test5
-rw-r--r--mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result62
-rw-r--r--mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result19
-rw-r--r--mysql-test/suite/rpl_ndb/t/disabled.def2
-rw-r--r--mysql-test/t/ctype_euckr.test23
-rw-r--r--mysql-test/t/ctype_uca.test4
-rw-r--r--mysql-test/t/ctype_ucs.test3
-rw-r--r--mysql-test/t/ctype_utf8.test7
-rw-r--r--mysql-test/t/func_regexp.test23
-rw-r--r--mysql-test/t/innodb.test32
-rw-r--r--mysql-test/t/multi_update.test38
-rw-r--r--mysql-test/t/mysql.test9
-rw-r--r--sql/field.cc414
-rw-r--r--sql/field.h271
-rw-r--r--sql/ha_ndbcluster.cc110
-rw-r--r--sql/item_cmpfunc.cc122
-rw-r--r--sql/item_cmpfunc.h4
-rw-r--r--sql/item_xmlfunc.cc60
-rw-r--r--sql/log.cc13
-rw-r--r--sql/log.h8
-rw-r--r--sql/log_event.cc254
-rw-r--r--sql/log_event.h1060
-rw-r--r--sql/mysqld.cc1
-rw-r--r--sql/records.cc2
-rw-r--r--sql/rpl_record.cc53
-rw-r--r--sql/rpl_rli.cc10
-rw-r--r--sql/rpl_rli.h12
-rw-r--r--sql/rpl_utility.cc36
-rw-r--r--sql/rpl_utility.h14
-rw-r--r--sql/slave.cc46
-rw-r--r--sql/sp_head.cc5
-rw-r--r--sql/sql_class.h22
-rw-r--r--sql/sql_delete.cc51
-rw-r--r--sql/sql_insert.cc109
-rw-r--r--sql/sql_load.cc29
-rw-r--r--sql/sql_parse.cc18
-rw-r--r--sql/sql_repl.cc10
-rw-r--r--sql/sql_show.cc6
-rw-r--r--sql/sql_update.cc103
-rw-r--r--sql/sql_yacc.yy2
-rw-r--r--strings/ctype-euc_kr.c28
117 files changed, 6175 insertions, 1183 deletions
diff --git a/client/mysql.cc b/client/mysql.cc
index 1dd33593b83..abb89fcf2e4 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -1087,6 +1087,17 @@ static int read_and_execute(bool interactive)
if (!interactive)
{
line=batch_readline(status.line_buff);
+ /*
+ Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF.
+ Editors like "notepad" put this marker in
+ the very beginning of a text file when
+ you save the file using "Unicode UTF-8" format.
+ */
+ if (!line_number &&
+ (uchar) line[0] == 0xEF &&
+ (uchar) line[1] == 0xBB &&
+ (uchar) line[2] == 0xBF)
+ line+= 3;
line_number++;
if (!glob_buffer.length())
status.query_start_line=line_number;
diff --git a/include/my_base.h b/include/my_base.h
index 339554979a8..e65a04bb16d 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -407,9 +407,11 @@ enum ha_base_keytype {
#define HA_ERR_RECORD_IS_THE_SAME 169 /* row not actually updated :
new values same as the old values */
-#define HA_ERR_LOGGING_IMPOSSIBLE 170 /* It is not possible to log this
- statement */
-#define HA_ERR_LAST 170 /*Copy last error nr.*/
+#define HA_ERR_LOGGING_IMPOSSIBLE 170 /* It is not possible to log this
+ statement */
+#define HA_ERR_CORRUPT_EVENT 171 /* The event was corrupt, leading to
+ illegal data being read */
+#define HA_ERR_LAST 171 /*Copy last error nr.*/
/* Add error numbers before HA_ERR_LAST and change it accordingly. */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test
new file mode 100644
index 00000000000..03514bfdb55
--- /dev/null
+++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test
@@ -0,0 +1,298 @@
+# the file to be sourced from binlog.binlog_mix_innodb_myisam
+
+#
+# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack
+# bug #28960 non-trans temp table changes with insert .. select
+# not binlogged after rollback
+#
+# testing appearence of insert into temp_table in binlog.
+# There are two branches of execution that require different setup.
+
+# checking binlog content filled with row-based events due to
+# a used stored function modifies non-transactional table
+
+## send_eof() branch
+
+# prepare
+
+create temporary table tt (a int unique);
+create table ti (a int) engine=innodb;
+reset master;
+show master status;
+
+# action
+
+begin;
+insert into ti values (1);
+insert into ti values (2) ;
+insert into tt select * from ti;
+rollback;
+
+# check
+
+select count(*) from tt /* 2 */;
+show master status;
+source include/show_binlog_events.inc;
+select count(*) from ti /* zero */;
+insert into ti select * from tt;
+select * from ti /* that is what slave would miss - bug#28960 */;
+
+
+## send_error() branch
+delete from ti;
+delete from tt where a=1;
+reset master;
+show master status;
+
+# action
+
+begin;
+insert into ti values (1);
+insert into ti values (2) /* to make the dup error in the following */;
+--error ER_DUP_ENTRY
+insert into tt select * from ti /* one affected and error */;
+rollback;
+
+# check
+
+show master status;
+source include/show_binlog_events.inc; # nothing in binlog with row bilog format
+select count(*) from ti /* zero */;
+insert into ti select * from tt;
+select * from tt /* that is what otherwise slave missed - the bug */;
+
+drop table ti;
+
+
+#
+# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack
+#
+# Testing asserts: if there is a side effect of modifying non-transactional
+# table thd->no_trans_update.stmt must be TRUE;
+# the assert is active with debug build
+#
+
+--disable_warnings
+drop function if exists bug27417;
+drop table if exists t1,t2;
+--enable_warnings
+# side effect table
+CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM;
+# target tables
+CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a));
+
+delimiter |;
+create function bug27417(n int)
+RETURNS int(11)
+begin
+ insert into t1 values (null);
+ return n;
+end|
+delimiter ;|
+
+reset master;
+
+# execute
+
+insert into t2 values (bug27417(1));
+insert into t2 select bug27417(2);
+reset master;
+
+--error ER_DUP_ENTRY
+insert into t2 values (bug27417(2));
+source include/show_binlog_events.inc; #only (!) with fixes for #23333 will show there is the query
+select count(*) from t1 /* must be 3 */;
+
+reset master;
+select count(*) from t2;
+delete from t2 where a=bug27417(3);
+select count(*) from t2 /* nothing got deleted */;
+source include/show_binlog_events.inc; # the query must be in regardless of #23333
+select count(*) from t1 /* must be 5 */;
+
+--enable_info
+delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */;
+--disable_info
+select count(*) from t1 /* must be 7 */;
+
+# function bug27417 remains for the following testing of bug#23333
+drop table t1,t2;
+
+#
+# Bug#23333 using the patch (and the test) for bug#27471
+# throughout the bug tests
+# t1 - non-trans side effects gatherer;
+# t2 - transactional table;
+#
+CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM;
+CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
+CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM;
+CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb;
+CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
+
+
+#
+# INSERT
+#
+
+# prepare
+
+ insert into t2 values (1);
+ reset master;
+
+# execute
+
+ --error ER_DUP_ENTRY
+ insert into t2 values (bug27417(1));
+
+# check
+
+ source include/show_binlog_events.inc; # must be event of the query
+ select count(*) from t1 /* must be 1 */;
+
+#
+# INSERT SELECT
+#
+
+# prepare
+ delete from t1;
+ delete from t2;
+ insert into t2 values (2);
+ reset master;
+
+# execute
+
+ --error ER_DUP_ENTRY
+ insert into t2 select bug27417(1) union select bug27417(2);
+
+# check
+
+ source include/show_binlog_events.inc; # must be events of the query
+ select count(*) from t1 /* must be 2 */;
+
+#
+# UPDATE inc multi-update
+#
+
+# prepare
+ delete from t1;
+ insert into t3 values (1,1),(2,3),(3,4);
+ reset master;
+
+# execute
+ --error ER_DUP_ENTRY
+ update t3 set b=b+bug27417(1);
+
+# check
+ source include/show_binlog_events.inc; # must be events of the query
+ select count(*) from t1 /* must be 2 */;
+
+## multi_update::send_eof() branch
+
+# prepare
+ delete from t3;
+ delete from t4;
+ insert into t3 values (1,1);
+ insert into t4 values (1,1),(2,2);
+
+ reset master;
+
+# execute
+ --error ER_DUP_ENTRY
+ UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */;
+
+# check
+ source include/show_binlog_events.inc; # the offset must denote there is the query
+ select count(*) from t1 /* must be 4 */;
+
+## send_error() branch of multi_update
+
+# prepare
+ delete from t1;
+ delete from t3;
+ delete from t4;
+ insert into t3 values (1,1),(2,2);
+ insert into t4 values (1,1),(2,2);
+
+ reset master;
+
+# execute
+ --error ER_DUP_ENTRY
+ UPDATE t3,t4 SET t3.a=t4.a + bug27417(1);
+
+# check
+ select count(*) from t1 /* must be 1 */;
+
+# cleanup
+ drop table t4;
+
+
+#
+# DELETE incl multi-delete
+#
+
+# prepare
+ delete from t1;
+ delete from t2;
+ delete from t3;
+ insert into t2 values (1);
+ insert into t3 values (1,1);
+ create trigger trg_del before delete on t2 for each row
+ insert into t3 values (bug27417(1), 2);
+ reset master;
+
+# execute
+ --error ER_DUP_ENTRY
+ delete from t2;
+# check
+ source include/show_binlog_events.inc; # the offset must denote there is the query
+ select count(*) from t1 /* must be 1 */;
+
+# cleanup
+ drop trigger trg_del;
+
+# prepare
+ delete from t1;
+ delete from t2;
+ delete from t5;
+ create trigger trg_del_t2 after delete on t2 for each row
+ insert into t1 values (1);
+ insert into t2 values (2),(3);
+ insert into t5 values (1),(2);
+ reset master;
+
+# execute
+ --error ER_DUP_ENTRY
+ delete t2.* from t2,t5 where t2.a=t5.a + 1;
+
+# check
+ source include/show_binlog_events.inc; # must be events of the query
+ select count(*) from t1 /* must be 1 */;
+
+
+#
+# LOAD DATA
+#
+
+# prepare
+ delete from t1;
+ create table t4 (a int default 0, b int primary key) engine=innodb;
+ insert into t4 values (0, 17);
+ reset master;
+
+# execute
+ --error ER_DUP_ENTRY
+ load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2);
+# check
+ select * from t4;
+ select count(*) from t1 /* must be 2 */;
+ source include/show_binlog_events.inc; # must be events of the query
+
+#
+# bug#23333 cleanup
+#
+
+
+drop trigger trg_del_t2;
+drop table t1,t2,t3,t4,t5;
+drop function bug27417;
diff --git a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test
index d3959d10306..cdd828305dc 100644
--- a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test
+++ b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test
@@ -410,7 +410,7 @@ binary data';
select * from t2 order by f1;
select * from t3 order by f1;
select * from t4 order by f1;
- select * from t31 order by f1;
+ select * from t31 order by f3;
connection master;
--echo
diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test
index a4ac55cc2e8..6fa2c9ac1b5 100644
--- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test
+++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test
@@ -10,7 +10,7 @@
########### Clean up ################
--disable_warnings
--disable_query_log
-DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17;
+DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t14a,t15,t16,t17;
--enable_query_log
--enable_warnings
@@ -662,6 +662,68 @@ sync_slave_with_master;
--replace_column 7 CURRENT_TIMESTAMP
SELECT * FROM t14 ORDER BY c1;
+####################################################
+# - Alter Master drop column at end of table #
+# Expect: column dropped #
+####################################################
+
+--echo *** Create t14a on slave ***
+STOP SLAVE;
+RESET SLAVE;
+eval CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5),
+ c6 INT DEFAULT '1',
+ c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+ )ENGINE=$engine_type;
+
+--echo *** Create t14a on Master ***
+connection master;
+eval CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5)
+ ) ENGINE=$engine_type;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14a () VALUES(1,@b1,'Kyle'),
+ (2,@b1,'JOE'),
+ (3,@b1,'QA');
+
+SELECT * FROM t14a ORDER BY c1;
+--echo *** Select on Slave ****
+sync_slave_with_master;
+--replace_column 5 CURRENT_TIMESTAMP
+SELECT * FROM t14a ORDER BY c1;
+STOP SLAVE;
+RESET SLAVE;
+
+--echo *** Master Drop c5 ***
+connection master;
+ALTER TABLE t14a DROP COLUMN c5;
+RESET MASTER;
+
+--echo *** Start Slave ***
+connection slave;
+START SLAVE;
+
+--echo *** Master Data Insert ***
+connection master;
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+
+INSERT INTO t14a () VALUES(4,@b1),
+ (5,@b1),
+ (6,@b1);
+SELECT * FROM t14a ORDER BY c1;
+
+--echo *** Select on Slave ****
+sync_slave_with_master;
+--replace_column 5 CURRENT_TIMESTAMP
+SELECT * FROM t14a ORDER BY c1;
####################################################
# - Alter Master Dropping columns from the middle. #
@@ -736,7 +798,7 @@ connection slave;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 #
--query_vertical SHOW SLAVE STATUS
-SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
START SLAVE;
--echo *** Try to insert in master ****
@@ -744,6 +806,8 @@ connection master;
INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2);
SELECT * FROM t15 ORDER BY c1;
+#SHOW BINLOG EVENTS;
+
--echo *** Try to select from slave ****
sync_slave_with_master;
--replace_column 7 CURRENT_TIMESTAMP
@@ -856,7 +920,10 @@ sync_slave_with_master;
#### Clean Up ####
--disable_warnings
--disable_query_log
-DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17;
+connection master;
+DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t14a,t15,t16,t17;
+sync_slave_with_master;
+connection master;
--enable_query_log
--enable_warnings
diff --git a/mysql-test/extra/rpl_tests/rpl_row_basic.test b/mysql-test/extra/rpl_tests/rpl_row_basic.test
index 6de254d9931..c35a53f15bc 100644
--- a/mysql-test/extra/rpl_tests/rpl_row_basic.test
+++ b/mysql-test/extra/rpl_tests/rpl_row_basic.test
@@ -215,11 +215,36 @@ sync_slave_with_master;
--echo --- on slave ---
SELECT * FROM t8 ORDER BY a;
-#
-# Test conflicting operations when changing in a table referenced by a
-# foreign key. We'll reuse the above table and just add a table that
-# references it.
-#
+# BUG#31552: Replication breaks when deleting rows from out-of-sync
+# table without PK
+
+--echo **** Test for BUG#31552 ****
+
+--echo **** On Master ****
+# Clean up t1 so that we can use it.
+connection master;
+DELETE FROM t1;
+sync_slave_with_master;
+
+# Just to get a clean binary log
+source include/reset_master_and_slave.inc;
+
+--echo **** On Master ****
+connection master;
+INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M');
+--echo **** On Master ****
+sync_slave_with_master;
+DELETE FROM t1 WHERE C1 = 'L';
+
+connection master;
+DELETE FROM t1;
+query_vertical SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
+sync_slave_with_master;
+let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
+disable_query_log;
+eval SELECT "$last_error" AS Last_SQL_Error;
+enable_query_log;
+query_vertical SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
#
# cleanup
@@ -227,3 +252,4 @@ SELECT * FROM t8 ORDER BY a;
connection master;
DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8;
+sync_slave_with_master;
diff --git a/mysql-test/extra/rpl_tests/rpl_truncate_helper.test b/mysql-test/extra/rpl_tests/rpl_truncate_helper.test
index 64a8de7c6a0..76db74acfa1 100644
--- a/mysql-test/extra/rpl_tests/rpl_truncate_helper.test
+++ b/mysql-test/extra/rpl_tests/rpl_truncate_helper.test
@@ -1,17 +1,16 @@
-
---disable_query_log
---disable_warnings
connection slave;
STOP SLAVE;
+source include/wait_for_slave_to_stop.inc;
connection master;
+--disable_warnings
DROP TABLE IF EXISTS t1;
-RESET MASTER;
+--enable_warnings
connection slave;
+--disable_warnings
DROP TABLE IF EXISTS t1;
+--enable_warnings
RESET SLAVE;
START SLAVE;
---enable_warnings
---enable_query_log
--echo **** On Master ****
connection master;
@@ -38,3 +37,6 @@ connection master;
DROP TABLE t1;
let $SERVER_VERSION=`select version()`;
source include/show_binlog_events.inc;
+
+connection master;
+RESET MASTER;
diff --git a/mysql-test/include/ctype_regex.inc b/mysql-test/include/ctype_regex.inc
new file mode 100644
index 00000000000..0e6b4c41607
--- /dev/null
+++ b/mysql-test/include/ctype_regex.inc
@@ -0,0 +1,42 @@
+#
+# To test a desired collation, set session.collation_connection to
+# this collation before including this file
+#
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+#
+# Create a table with two varchar(64) null-able column,
+# using current values of
+# @@character_set_connection and @@collation_connection.
+#
+
+create table t1 as
+select repeat(' ', 64) as s1, repeat(' ',64) as s2
+union
+select null, null;
+show create table t1;
+delete from t1;
+
+insert into t1 values('aaa','aaa');
+insert into t1 values('aaa|qqq','qqq');
+insert into t1 values('gheis','^[^a-dXYZ]+$');
+insert into t1 values('aab','^aa?b');
+insert into t1 values('Baaan','^Ba*n');
+insert into t1 values('aaa','qqq|aaa');
+insert into t1 values('qqq','qqq|aaa');
+
+insert into t1 values('bbb','qqq|aaa');
+insert into t1 values('bbb','qqq');
+insert into t1 values('aaa','aba');
+
+insert into t1 values(null,'abc');
+insert into t1 values('def',null);
+insert into t1 values(null,null);
+insert into t1 values('ghi','ghi[');
+
+select HIGH_PRIORITY s1 regexp s2 from t1;
+
+drop table t1;
diff --git a/mysql-test/include/reset_master_and_slave.inc b/mysql-test/include/reset_master_and_slave.inc
new file mode 100644
index 00000000000..c2d4120ddc9
--- /dev/null
+++ b/mysql-test/include/reset_master_and_slave.inc
@@ -0,0 +1,10 @@
+--echo **** Resetting master and slave ****
+connection slave;
+STOP SLAVE;
+source include/wait_for_slave_to_stop.inc;
+RESET SLAVE;
+connection master;
+RESET MASTER;
+connection slave;
+START SLAVE;
+source include/wait_for_slave_to_start.inc;
diff --git a/mysql-test/include/wait_for_slave_sql_error.inc b/mysql-test/include/wait_for_slave_sql_error.inc
new file mode 100644
index 00000000000..6780edbe2f0
--- /dev/null
+++ b/mysql-test/include/wait_for_slave_sql_error.inc
@@ -0,0 +1,33 @@
+###################################################
+#Author: Sven
+#Date: 2007-10-09
+#Purpose: Wait until the slave has an error in the
+# sql thread, as indicated by
+# "SHOW SLAVE STATUS", or at most 30
+# seconds.
+#Details:
+# 1) Fill in and setup variables
+# 2) loop, looking for sql error on slave
+# 3) If it loops too long, die.
+####################################################
+connection slave;
+let $row_number= 1;
+let $run= 1;
+let $counter= 300;
+
+while ($run)
+{
+ let $sql_result= query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, $row_number);
+ let $run= `SELECT '$sql_result' = '0'`;
+ if ($run) {
+ real_sleep 0.1;
+ if (!$counter){
+ --echo "Failed while waiting for slave to produce an error in its sql thread"
+ --replace_result $MASTER_MYPORT MASTER_PORT
+ --replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 #
+ query_vertical SHOW SLAVE STATUS;
+ exit;
+ }
+ dec $counter;
+ }
+}
diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl
index 3d5752b4ec8..992d645f038 100644
--- a/mysql-test/lib/mtr_cases.pl
+++ b/mysql-test/lib/mtr_cases.pl
@@ -214,17 +214,44 @@ sub collect_one_suite($$)
mtr_verbose("Collecting: $suite");
+ my $combination_file= "combinations";
+ my $combinations = [];
+
my $suitedir= "$::glob_mysql_test_dir"; # Default
+ my $combination_file= "$::glob_mysql_test_dir/$combination_file";
if ( $suite ne "main" )
{
$suitedir= mtr_path_exists("$suitedir/suite/$suite",
"$suitedir/$suite");
mtr_verbose("suitedir: $suitedir");
+ $combination_file= "$suitedir/$combination_file";
}
my $testdir= "$suitedir/t";
my $resdir= "$suitedir/r";
+ if (!@::opt_combination)
+ {
+ # Read combinations file
+ if ( open(COMB,$combination_file) )
+ {
+ while (<COMB>)
+ {
+ chomp;
+ s/\ +/ /g;
+ push (@$combinations, $_) unless ($_ eq '');
+ }
+ close COMB;
+ }
+ }
+ else
+ {
+ # take the combination from command-line
+ @$combinations = @::opt_combination;
+ }
+ # Remember last element position
+ my $begin_index = $#{@$cases} + 1;
+
# ----------------------------------------------------------------------
# Build a hash of disabled testcases for this suite
# ----------------------------------------------------------------------
@@ -335,6 +362,78 @@ sub collect_one_suite($$)
closedir TESTDIR;
}
+ # ----------------------------------------------------------------------
+ # Proccess combinations only if new tests were added
+ # ----------------------------------------------------------------------
+ if ($combinations && $begin_index <= $#{@$cases})
+ {
+ my $end_index = $#{@$cases};
+ my $is_copy;
+ # Keep original master/slave options
+ my @orig_opts;
+ for (my $idx = $begin_index; $idx <= $end_index; $idx++)
+ {
+ foreach my $param (('master_opt','slave_opt','slave_mi'))
+ {
+ @{$orig_opts[$idx]{$param}} = @{$cases->[$idx]->{$param}};
+ }
+ }
+ my $comb_index = 1;
+ # Copy original test cases
+ foreach my $comb_set (@$combinations)
+ {
+ for (my $idx = $begin_index; $idx <= $end_index; $idx++)
+ {
+ my $test = $cases->[$idx];
+ my $copied_test = {};
+ foreach my $param (keys %{$test})
+ {
+ # Scalar. Copy as is.
+ $copied_test->{$param} = $test->{$param};
+ # Array. Copy reference instead itself
+ if ($param =~ /(master_opt|slave_opt|slave_mi)/)
+ {
+ my $new_arr = [];
+ @$new_arr = @{$orig_opts[$idx]{$param}};
+ $copied_test->{$param} = $new_arr;
+ }
+ elsif ($param =~ /(comment|combinations)/)
+ {
+ $copied_test->{$param} = '';
+ }
+ }
+ if ($is_copy)
+ {
+ push(@$cases, $copied_test);
+ $test = $cases->[$#{@$cases}];
+ }
+ foreach my $comb_opt (split(/ /,$comb_set))
+ {
+ push(@{$test->{'master_opt'}},$comb_opt);
+ push(@{$test->{'slave_opt'}},$comb_opt);
+ # Enable rpl if added option is --binlog-format and test case supports that
+ if ($comb_opt =~ /^--binlog-format=.+$/)
+ {
+ my @opt_pairs = split(/=/, $comb_opt);
+ if ($test->{'binlog_format'} =~ /^$opt_pairs[1]$/ || $test->{'binlog_format'} eq '')
+ {
+ $test->{'skip'} = 0;
+ $test->{'comment'} = '';
+ }
+ else
+ {
+ $test->{'skip'} = 1;
+ $test->{'comment'} = "Requiring binlog format '$test->{'binlog_format'}'";;
+ }
+ }
+ }
+ $test->{'combination'} = $comb_set;
+ }
+ $is_copy = 1;
+ $comb_index++;
+ }
+ }
+
return $cases;
}
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index c3312dce3ac..a42f0559fd2 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -164,6 +164,8 @@ our $opt_bench= 0;
our $opt_small_bench= 0;
our $opt_big_test= 0;
+our @opt_combination;
+
our @opt_extra_mysqld_opt;
our $opt_compress;
@@ -529,6 +531,7 @@ sub command_line_setup () {
'skip-im' => \$opt_skip_im,
'skip-test=s' => \$opt_skip_test,
'big-test' => \$opt_big_test,
+ 'combination=s' => \@opt_combination,
# Specify ports
'master_port=i' => \$opt_master_myport,
@@ -5141,6 +5144,8 @@ Options to control what test suites or cases to run
skip-im Don't start IM, and skip the IM test cases
big-test Set the environment variable BIG_TEST, which can be
checked from test cases.
+ combination="ARG1 .. ARG2" Specify a set of "mysqld" arguments for one
+ combination.
Options that specify ports
diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result
index b9619370d4c..ee786202c01 100644
--- a/mysql-test/r/ctype_euckr.result
+++ b/mysql-test/r/ctype_euckr.result
@@ -178,3 +178,44 @@ hex(a)
A2E6
FEF7
DROP TABLE t1;
+create table t1 (s1 varchar(5) character set euckr);
+insert into t1 values (0xA141);
+insert into t1 values (0xA15A);
+insert into t1 values (0xA161);
+insert into t1 values (0xA17A);
+insert into t1 values (0xA181);
+insert into t1 values (0xA1FE);
+insert into t1 values (0xA140);
+Warnings:
+Warning 1366 Incorrect string value: '\xA1@' for column 's1' at row 1
+insert into t1 values (0xA15B);
+Warnings:
+Warning 1366 Incorrect string value: '\xA1[' for column 's1' at row 1
+insert into t1 values (0xA160);
+Warnings:
+Warning 1366 Incorrect string value: '\xA1`' for column 's1' at row 1
+insert into t1 values (0xA17B);
+Warnings:
+Warning 1366 Incorrect string value: '\xA1{' for column 's1' at row 1
+insert into t1 values (0xA180);
+Warnings:
+Warning 1366 Incorrect string value: '\xA1\x80' for column 's1' at row 1
+insert into t1 values (0xA1FF);
+Warnings:
+Warning 1366 Incorrect string value: '\xA1\xFF' for column 's1' at row 1
+select hex(s1), hex(convert(s1 using utf8)) from t1 order by binary s1;
+hex(s1) hex(convert(s1 using utf8))
+
+
+
+
+
+
+A141 ECA2A5
+A15A ECA381
+A161 ECA382
+A17A ECA3A5
+A181 ECA3A6
+A1FE EFBFA2
+drop table t1;
+End of 5.0 tests
diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result
index e676d5a5ca0..3fff9b9cda8 100644
--- a/mysql-test/r/ctype_uca.result
+++ b/mysql-test/r/ctype_uca.result
@@ -2767,4 +2767,49 @@ a
c
ch
drop table t1;
+set collation_connection=ucs2_unicode_ci;
+drop table if exists t1;
+create table t1 as
+select repeat(' ', 64) as s1, repeat(' ',64) as s2
+union
+select null, null;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `s1` varchar(64) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci DEFAULT NULL,
+ `s2` varchar(64) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+delete from t1;
+insert into t1 values('aaa','aaa');
+insert into t1 values('aaa|qqq','qqq');
+insert into t1 values('gheis','^[^a-dXYZ]+$');
+insert into t1 values('aab','^aa?b');
+insert into t1 values('Baaan','^Ba*n');
+insert into t1 values('aaa','qqq|aaa');
+insert into t1 values('qqq','qqq|aaa');
+insert into t1 values('bbb','qqq|aaa');
+insert into t1 values('bbb','qqq');
+insert into t1 values('aaa','aba');
+insert into t1 values(null,'abc');
+insert into t1 values('def',null);
+insert into t1 values(null,null);
+insert into t1 values('ghi','ghi[');
+select HIGH_PRIORITY s1 regexp s2 from t1;
+s1 regexp s2
+1
+1
+1
+1
+1
+1
+1
+0
+0
+0
+NULL
+NULL
+NULL
+NULL
+drop table t1;
+set names utf8;
End for 5.0 tests
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index a0a8455b496..6c7372b7116 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -922,6 +922,51 @@ ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_gen
select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0);
ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_general_ci,COERCIBLE) for operation '='
drop table t1;
+set collation_connection=ucs2_general_ci;
+drop table if exists t1;
+create table t1 as
+select repeat(' ', 64) as s1, repeat(' ',64) as s2
+union
+select null, null;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `s1` varchar(64) CHARACTER SET ucs2 DEFAULT NULL,
+ `s2` varchar(64) CHARACTER SET ucs2 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+delete from t1;
+insert into t1 values('aaa','aaa');
+insert into t1 values('aaa|qqq','qqq');
+insert into t1 values('gheis','^[^a-dXYZ]+$');
+insert into t1 values('aab','^aa?b');
+insert into t1 values('Baaan','^Ba*n');
+insert into t1 values('aaa','qqq|aaa');
+insert into t1 values('qqq','qqq|aaa');
+insert into t1 values('bbb','qqq|aaa');
+insert into t1 values('bbb','qqq');
+insert into t1 values('aaa','aba');
+insert into t1 values(null,'abc');
+insert into t1 values('def',null);
+insert into t1 values(null,null);
+insert into t1 values('ghi','ghi[');
+select HIGH_PRIORITY s1 regexp s2 from t1;
+s1 regexp s2
+1
+1
+1
+1
+1
+1
+1
+0
+0
+0
+NULL
+NULL
+NULL
+NULL
+drop table t1;
+set names latin1;
select hex(char(0x41 using ucs2));
hex(char(0x41 using ucs2))
0041
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 8243b2bc015..5c90c3b5e0b 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -267,6 +267,51 @@ b
select * from t1 where a = 'b' and a != 'b';
a
drop table t1;
+set collation_connection=utf8_general_ci;
+drop table if exists t1;
+create table t1 as
+select repeat(' ', 64) as s1, repeat(' ',64) as s2
+union
+select null, null;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `s1` varchar(64) CHARACTER SET utf8 DEFAULT NULL,
+ `s2` varchar(64) CHARACTER SET utf8 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+delete from t1;
+insert into t1 values('aaa','aaa');
+insert into t1 values('aaa|qqq','qqq');
+insert into t1 values('gheis','^[^a-dXYZ]+$');
+insert into t1 values('aab','^aa?b');
+insert into t1 values('Baaan','^Ba*n');
+insert into t1 values('aaa','qqq|aaa');
+insert into t1 values('qqq','qqq|aaa');
+insert into t1 values('bbb','qqq|aaa');
+insert into t1 values('bbb','qqq');
+insert into t1 values('aaa','aba');
+insert into t1 values(null,'abc');
+insert into t1 values('def',null);
+insert into t1 values(null,null);
+insert into t1 values('ghi','ghi[');
+select HIGH_PRIORITY s1 regexp s2 from t1;
+s1 regexp s2
+1
+1
+1
+1
+1
+1
+1
+0
+0
+0
+NULL
+NULL
+NULL
+NULL
+drop table t1;
+set names utf8;
set names utf8;
select 'вася' rlike '[[:<:]]вася[[:>:]]';
'вася' rlike '[[:<:]]вася[[:>:]]'
diff --git a/mysql-test/r/func_regexp.result b/mysql-test/r/func_regexp.result
index 05e56f05457..9d85b1d3e7f 100644
--- a/mysql-test/r/func_regexp.result
+++ b/mysql-test/r/func_regexp.result
@@ -1,5 +1,17 @@
drop table if exists t1;
-create table t1 (s1 char(64),s2 char(64));
+set names latin1;
+drop table if exists t1;
+create table t1 as
+select repeat(' ', 64) as s1, repeat(' ',64) as s2
+union
+select null, null;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `s1` varchar(64) DEFAULT NULL,
+ `s2` varchar(64) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+delete from t1;
insert into t1 values('aaa','aaa');
insert into t1 values('aaa|qqq','qqq');
insert into t1 values('gheis','^[^a-dXYZ]+$');
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index d0b67e90afb..e1cc365f5c3 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -1086,6 +1086,19 @@ n d
1 30
2 20
drop table t1,t2;
+drop table if exists t1, t2;
+CREATE TABLE t1 (a int, PRIMARY KEY (a));
+CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
+create trigger trg_del_t2 after delete on t2 for each row
+insert into t1 values (1);
+insert into t1 values (1);
+insert into t2 values (1),(2);
+delete t2 from t2;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+select count(*) from t2 /* must be 2 as restored after rollback caused by the error */;
+count(*)
+2
+drop table t1, t2;
create table t1 (a int, b int) engine=innodb;
insert into t1 values(20,null);
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
@@ -1751,10 +1764,10 @@ Variable_name Value
Innodb_page_size 16384
show status like "Innodb_rows_deleted";
Variable_name Value
-Innodb_rows_deleted 70
+Innodb_rows_deleted 71
show status like "Innodb_rows_inserted";
Variable_name Value
-Innodb_rows_inserted 1083
+Innodb_rows_inserted 1085
show status like "Innodb_rows_updated";
Variable_name Value
Innodb_rows_updated 886
diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result
index 55e47756312..0bc01e95d2d 100644
--- a/mysql-test/r/multi_update.result
+++ b/mysql-test/r/multi_update.result
@@ -614,6 +614,7 @@ CREATE TABLE `t2` (
`b` int(11) default NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
+set @sav_binlog_format= @@session.binlog_format;
set @@session.binlog_format= mixed;
insert into t1 values (1,1),(2,2);
insert into t2 values (1,1),(4,4);
@@ -626,7 +627,7 @@ a b
4 4
show master status /* there must be the UPDATE query event */;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 197
+master-bin.000001 268
delete from t1;
delete from t2;
insert into t1 values (1,2),(3,4),(4,4);
@@ -636,6 +637,24 @@ UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a;
ERROR 23000: Duplicate entry '4' for key 'PRIMARY'
show master status /* there must be the UPDATE query event */;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 212
+master-bin.000001 283
drop table t1, t2;
+set @@session.binlog_format= @sav_binlog_format;
+drop table if exists t1, t2, t3;
+CREATE TABLE t1 (a int, PRIMARY KEY (a));
+CREATE TABLE t2 (a int, PRIMARY KEY (a));
+CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM;
+create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1);
+insert into t2 values (1),(2);
+insert into t3 values (1),(2);
+reset master;
+delete t3.* from t2,t3 where t2.a=t3.a;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+select count(*) from t1 /* must be 1 */;
+count(*)
+1
+select count(*) from t3 /* must be 1 */;
+count(*)
+1
+drop table t1, t2, t3;
end of tests
diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result
index 4e39fb28454..76018962f79 100644
--- a/mysql-test/r/mysql.result
+++ b/mysql-test/r/mysql.result
@@ -178,5 +178,7 @@ ERROR at line 1: DELIMITER cannot contain a backslash character
1
1
1
+This is a file starting with UTF8 BOM 0xEFBBBF
+This is a file starting with UTF8 BOM 0xEFBBBF
End of 5.0 tests
WARNING: --server-arg option not supported in this configuration.
diff --git a/mysql-test/suite/binlog/r/binlog_killed.result b/mysql-test/suite/binlog/r/binlog_killed.result
index ba4f38fb4c1..72fda535b6f 100644
--- a/mysql-test/suite/binlog/r/binlog_killed.result
+++ b/mysql-test/suite/binlog/r/binlog_killed.result
@@ -9,4 +9,135 @@ insert into t2 values (null, null), (null, get_lock("a", 10));
select @result /* must be zero either way */;
@result
0
+select RELEASE_LOCK("a");
+RELEASE_LOCK("a")
+1
+delete from t1;
+delete from t2;
+insert into t1 values (1,1),(2,2);
+begin;
+update t1 set b=11 where a=2;
+begin;
+update t1 set b=b+10;
+kill query ID;
+rollback;
+rollback;
+select * from t1 order by a /* must be the same as before (1,1),(2,2) */;
+a b
+1 1
+2 2
+begin;
+delete from t1 where a=2;
+begin;
+delete from t1 where a=2;
+kill query ID;
+rollback;
+rollback;
+select * from t1 order by a /* must be the same as before (1,1),(2,2) */;
+a b
+1 1
+2 2
+drop table if exists t4;
+create table t4 (a int, b int) engine=innodb;
+insert into t4 values (3, 3);
+begin;
+insert into t1 values (3, 3);
+begin;
+insert into t1 select * from t4 for update;
+kill query ID;
+rollback;
+rollback;
+select * from t1 /* must be the same as before (1,1),(2,2) */;
+a b
+1 1
+2 2
+drop table t4;
+create table t4 (a int, b int) ENGINE=MyISAM /* for killing update and delete */;
+create function bug27563(n int)
+RETURNS int(11)
+DETERMINISTIC
+begin
+if @b > 0 then
+select get_lock("a", 20) into @a;
+else
+set @b= 1;
+end if;
+return n;
+end|
+delete from t4;
+insert into t4 values (1,1), (1,1);
+reset master;
+select get_lock("a", 20);
+get_lock("a", 20)
+1
+set @b= 0;
+update t4 set b=b + bug27563(b);
+select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock';
+count(*)
+1
+kill query ID;
+ERROR 70100: Query execution was interrupted
+select * from t4 order by b /* must be (1,1), (1,2) */;
+a b
+1 1
+1 2
+select @b /* must be 1 at the end of a stmt calling bug27563() */;
+@b
+1
+must have the update query event more to FD
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # User var # # @`b`=0
+master-bin.000001 # Query # # use `test`; update t4 set b=b + bug27563(b)
+select
+(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null;
+(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null
+1
+select 0 /* must return 0 to mean the killed query is in */;
+0
+0
+select RELEASE_LOCK("a");
+RELEASE_LOCK("a")
+1
+delete from t4;
+insert into t4 values (1,1), (2,2);
+reset master;
+select get_lock("a", 20);
+get_lock("a", 20)
+1
+set @b= 0;
+delete from t4 where b=bug27563(1) or b=bug27563(2);
+select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock';
+count(*)
+1
+kill query ID;
+ERROR 70100: Query execution was interrupted
+select count(*) from t4 /* must be 1 */;
+count(*)
+1
+select @b /* must be 1 at the end of a stmt calling bug27563() */;
+@b
+1
+must have the delete query event more to FD
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # User var # # @`b`=0
+master-bin.000001 # Query # # use `test`; delete from t4 where b=bug27563(1) or b=bug27563(2)
+select
+(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null;
+(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null
+1
+select 0 /* must return 0 to mean the killed query is in */;
+0
+0
+select RELEASE_LOCK("a");
+RELEASE_LOCK("a")
+1
+drop table t4;
+drop function bug27563;
drop table t1,t2,t3;
+end of the tests
diff --git a/mysql-test/suite/binlog/r/binlog_killed_simulate.result b/mysql-test/suite/binlog/r/binlog_killed_simulate.result
new file mode 100644
index 00000000000..f6a5ddade51
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_killed_simulate.result
@@ -0,0 +1,33 @@
+drop table if exists t1,t2;
+create table t1 (a int) engine=MyISAM;
+insert into t1 set a=1;
+reset master;
+update t1 set a=2 /* will be "killed" after work has been done */;
+select
+(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null;
+(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null
+1
+select 1 /* must return 1 as query completed before got killed*/;
+1
+1
+create table t2 (a int, b int) ENGINE=MyISAM;
+reset master;
+load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */;
+ERROR 70100: Query execution was interrupted
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12
+master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */ ;file_id=1
+select
+(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null;
+(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null
+1
+select 0 /* must return 0 to mean the killed query is in */;
+0
+0
+drop table t1,t2;
+end of the tests
diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
index 6ac942176c7..f69d5717a1f 100644
--- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
+++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
@@ -413,3 +413,236 @@ select
@a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%"
1 1
drop table t1, t2;
+create temporary table tt (a int unique);
+create table ti (a int) engine=innodb;
+reset master;
+show master status;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000001 106
+begin;
+insert into ti values (1);
+insert into ti values (2) ;
+insert into tt select * from ti;
+rollback;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+select count(*) from tt /* 2 */;
+count(*)
+2
+show master status;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000001 395
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Table_map # # table_id: # (test.ti)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Table_map # # table_id: # (test.ti)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from ti /* zero */;
+count(*)
+0
+insert into ti select * from tt;
+select * from ti /* that is what slave would miss - bug#28960 */;
+a
+1
+2
+delete from ti;
+delete from tt where a=1;
+reset master;
+show master status;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000001 106
+begin;
+insert into ti values (1);
+insert into ti values (2) /* to make the dup error in the following */;
+insert into tt select * from ti /* one affected and error */;
+ERROR 23000: Duplicate entry '2' for key 'a'
+rollback;
+show master status;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000001 106
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+select count(*) from ti /* zero */;
+count(*)
+0
+insert into ti select * from tt;
+select * from tt /* that is what otherwise slave missed - the bug */;
+a
+1
+2
+drop table ti;
+drop function if exists bug27417;
+drop table if exists t1,t2;
+CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM;
+CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a));
+create function bug27417(n int)
+RETURNS int(11)
+begin
+insert into t1 values (null);
+return n;
+end|
+reset master;
+insert into t2 values (bug27417(1));
+insert into t2 select bug27417(2);
+reset master;
+insert into t2 values (bug27417(2));
+ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=3
+master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(2))
+select count(*) from t1 /* must be 3 */;
+count(*)
+3
+reset master;
+select count(*) from t2;
+count(*)
+2
+delete from t2 where a=bug27417(3);
+select count(*) from t2 /* nothing got deleted */;
+count(*)
+2
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=4
+master-bin.000001 # Query # # use `test`; delete from t2 where a=bug27417(3)
+select count(*) from t1 /* must be 5 */;
+count(*)
+5
+delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */;
+affected rows: 0
+select count(*) from t1 /* must be 7 */;
+count(*)
+7
+drop table t1,t2;
+CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM;
+CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
+CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM;
+CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb;
+CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
+insert into t2 values (1);
+reset master;
+insert into t2 values (bug27417(1));
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=1
+master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1))
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from t1 /* must be 1 */;
+count(*)
+1
+delete from t1;
+delete from t2;
+insert into t2 values (2);
+reset master;
+insert into t2 select bug27417(1) union select bug27417(2);
+ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=2
+master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2)
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from t1 /* must be 2 */;
+count(*)
+2
+delete from t1;
+insert into t3 values (1,1),(2,3),(3,4);
+reset master;
+update t3 set b=b+bug27417(1);
+ERROR 23000: Duplicate entry '4' for key 'b'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=4
+master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1)
+select count(*) from t1 /* must be 2 */;
+count(*)
+2
+delete from t3;
+delete from t4;
+insert into t3 values (1,1);
+insert into t4 values (1,1),(2,2);
+reset master;
+UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */;
+ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=6
+master-bin.000001 # Query # # use `test`; UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from t1 /* must be 4 */;
+count(*)
+4
+delete from t1;
+delete from t3;
+delete from t4;
+insert into t3 values (1,1),(2,2);
+insert into t4 values (1,1),(2,2);
+reset master;
+UPDATE t3,t4 SET t3.a=t4.a + bug27417(1);
+ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
+select count(*) from t1 /* must be 1 */;
+count(*)
+1
+drop table t4;
+delete from t1;
+delete from t2;
+delete from t3;
+insert into t2 values (1);
+insert into t3 values (1,1);
+create trigger trg_del before delete on t2 for each row
+insert into t3 values (bug27417(1), 2);
+reset master;
+delete from t2;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=9
+master-bin.000001 # Query # # use `test`; delete from t2
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from t1 /* must be 1 */;
+count(*)
+1
+drop trigger trg_del;
+delete from t1;
+delete from t2;
+delete from t5;
+create trigger trg_del_t2 after delete on t2 for each row
+insert into t1 values (1);
+insert into t2 values (2),(3);
+insert into t5 values (1),(2);
+reset master;
+delete t2.* from t2,t5 where t2.a=t5.a + 1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from t1 /* must be 1 */;
+count(*)
+1
+delete from t1;
+create table t4 (a int default 0, b int primary key) engine=innodb;
+insert into t4 values (0, 17);
+reset master;
+load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2);
+ERROR 23000: Duplicate entry '17' for key 'PRIMARY'
+select * from t4;
+a b
+0 17
+select count(*) from t1 /* must be 2 */;
+count(*)
+2
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=10
+master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12
+master-bin.000001 # Intvar # # INSERT_ID=10
+master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1
+master-bin.000001 # Query # # use `test`; ROLLBACK
+drop trigger trg_del_t2;
+drop table t1,t2,t3,t4,t5;
+drop function bug27417;
diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
index 5ef36861c30..c15478bc826 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
@@ -380,7 +380,8 @@ select
@a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%"
1 1
drop table t1, t2;
-create table tt (a int unique);
+set @@session.binlog_format=statement;
+create temporary table tt (a int unique);
create table ti (a int) engine=innodb;
reset master;
show master status;
@@ -399,18 +400,18 @@ count(*)
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 515
-show binlog events from 106;
+show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query 1 # use `test`; BEGIN
-master-bin.000001 # Query 1 # use `test`; insert into ti values (1)
-master-bin.000001 # Query 1 # use `test`; insert into ti values (2)
-master-bin.000001 # Query 1 # use `test`; insert into tt select * from ti
-master-bin.000001 # Query 1 # use `test`; ROLLBACK
+master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # use `test`; insert into ti values (1)
+master-bin.000001 # Query # # use `test`; insert into ti values (2)
+master-bin.000001 # Query # # use `test`; insert into tt select * from ti
+master-bin.000001 # Query # # use `test`; ROLLBACK
select count(*) from ti /* zero */;
count(*)
0
insert into ti select * from tt;
-select * from ti /* that is what slave would miss - a bug */;
+select * from ti /* that is what slave would miss - bug#28960 */;
a
1
2
@@ -431,13 +432,13 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 589
-show binlog events from 106;
+show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query 1 # use `test`; BEGIN
-master-bin.000001 # Query 1 # use `test`; insert into ti values (1)
-master-bin.000001 # Query 1 # use `test`; insert into ti values (2) /* to make the dup error in the following */
-master-bin.000001 # Query 1 # use `test`; insert into tt select * from ti /* one affected and error */
-master-bin.000001 # Query 1 # use `test`; ROLLBACK
+master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # use `test`; insert into ti values (1)
+master-bin.000001 # Query # # use `test`; insert into ti values (2) /* to make the dup error in the following */
+master-bin.000001 # Query # # use `test`; insert into tt select * from ti /* one affected and error */
+master-bin.000001 # Query # # use `test`; ROLLBACK
select count(*) from ti /* zero */;
count(*)
0
@@ -446,7 +447,7 @@ select * from tt /* that is what otherwise slave missed - the bug */;
a
1
2
-drop table ti,tt;
+drop table ti;
drop function if exists bug27417;
drop table if exists t1,t2;
CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM;
@@ -463,6 +464,10 @@ insert into t2 select bug27417(2);
reset master;
insert into t2 values (bug27417(2));
ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=3
+master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(2))
select count(*) from t1 /* must be 3 */;
count(*)
3
@@ -474,6 +479,10 @@ delete from t2 where a=bug27417(3);
select count(*) from t2 /* nothing got deleted */;
count(*)
2
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=4
+master-bin.000001 # Query # # use `test`; delete from t2 where a=bug27417(3)
select count(*) from t1 /* must be 5 */;
count(*)
5
@@ -482,6 +491,134 @@ affected rows: 0
select count(*) from t1 /* must be 7 */;
count(*)
7
-drop function bug27417;
drop table t1,t2;
+CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM;
+CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
+CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM;
+CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb;
+CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
+insert into t2 values (1);
+reset master;
+insert into t2 values (bug27417(1));
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=1
+master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1))
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from t1 /* must be 1 */;
+count(*)
+1
+delete from t1;
+delete from t2;
+insert into t2 values (2);
+reset master;
+insert into t2 select bug27417(1) union select bug27417(2);
+ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=2
+master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2)
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from t1 /* must be 2 */;
+count(*)
+2
+delete from t1;
+insert into t3 values (1,1),(2,3),(3,4);
+reset master;
+update t3 set b=b+bug27417(1);
+ERROR 23000: Duplicate entry '4' for key 'b'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=4
+master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1)
+select count(*) from t1 /* must be 2 */;
+count(*)
+2
+delete from t3;
+delete from t4;
+insert into t3 values (1,1);
+insert into t4 values (1,1),(2,2);
+reset master;
+UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */;
+ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=6
+master-bin.000001 # Query # # use `test`; UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from t1 /* must be 4 */;
+count(*)
+4
+delete from t1;
+delete from t3;
+delete from t4;
+insert into t3 values (1,1),(2,2);
+insert into t4 values (1,1),(2,2);
+reset master;
+UPDATE t3,t4 SET t3.a=t4.a + bug27417(1);
+ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
+select count(*) from t1 /* must be 1 */;
+count(*)
+1
+drop table t4;
+delete from t1;
+delete from t2;
+delete from t3;
+insert into t2 values (1);
+insert into t3 values (1,1);
+create trigger trg_del before delete on t2 for each row
+insert into t3 values (bug27417(1), 2);
+reset master;
+delete from t2;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=9
+master-bin.000001 # Query # # use `test`; delete from t2
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from t1 /* must be 1 */;
+count(*)
+1
+drop trigger trg_del;
+delete from t1;
+delete from t2;
+delete from t5;
+create trigger trg_del_t2 after delete on t2 for each row
+insert into t1 values (1);
+insert into t2 values (2),(3);
+insert into t5 values (1),(2);
+reset master;
+delete t2.* from t2,t5 where t2.a=t5.a + 1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1
+master-bin.000001 # Query # # use `test`; ROLLBACK
+select count(*) from t1 /* must be 1 */;
+count(*)
+1
+delete from t1;
+create table t4 (a int default 0, b int primary key) engine=innodb;
+insert into t4 values (0, 17);
+reset master;
+load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2);
+ERROR 23000: Duplicate entry '17' for key 'PRIMARY'
+select * from t4;
+a b
+0 17
+select count(*) from t1 /* must be 2 */;
+count(*)
+2
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Intvar # # INSERT_ID=10
+master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12
+master-bin.000001 # Intvar # # INSERT_ID=10
+master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1
+master-bin.000001 # Query # # use `test`; ROLLBACK
+drop trigger trg_del_t2;
+drop table t1,t2,t3,t4,t5;
+drop function bug27417;
+set @@session.binlog_format=@@global.binlog_format;
end of tests
diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test
index 6c0b4b46a4e..e5f7288b17c 100644
--- a/mysql-test/suite/binlog/t/binlog_killed.test
+++ b/mysql-test/suite/binlog/t/binlog_killed.test
@@ -55,194 +55,277 @@ enable_result_log;
select @result /* must be zero either way */;
-# the functions are either *insensitive* to killing or killing can cause
-# strange problmes with the error propagation out of SF's stack
-# Bug#27563, Bug#27565, BUG#24971
-#
-# TODO: use if's block as regression test for the bugs or remove
-#
-if (0)
-{
-delimiter |;
-create function bug27563()
-RETURNS int(11)
-DETERMINISTIC
-begin
- select get_lock("a", 10) into @a;
- return 1;
-end|
-delimiter ;|
-# the function is sensitive to killing requiring innodb though with wrong client error
-# TO FIX in BUG#27565; TODO: remove --error 1105 afterwards
-delimiter |;
-create function bug27565()
-RETURNS int(11)
-DETERMINISTIC
-begin
- select a from t1 where a=1 into @a for update;
- return 1;
-end|
-delimiter ;|
+--remove_file $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog
+connection con1;
+select RELEASE_LOCK("a");
-reset master;
+#
+# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code
+#
+# checking that killing inside of select loops is safe as before
+# killing after the loop can be only simulated - another test
-### ta table case: killing causes rollback
+delete from t1;
+delete from t2;
+insert into t1 values (1,1),(2,2);
-# A. autocommit ON
+#
+# simple update
+#
connection con1;
-select get_lock("a", 20);
+begin; update t1 set b=11 where a=2;
connection con2;
let $ID= `select connection_id()`;
-send insert into t1 values (bug27563(),1);
+begin;
+send update t1 set b=b+10;
connection con1;
+--replace_result $ID ID
eval kill query $ID;
+rollback;
+
+# Bug #32148 killi query may be ineffective
+# forced to comment out the test's outcome
+# and mask out ineffective ER_QUERY_INTERRUPTED
+# todo1: revert back upon fixing bug#32148
+# todo2: the tests need refining in that
+# killing should wait till the victim requested
+# its lock (wait_condition available in 5.1 tests)
connection con2;
-# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero
---enable_info
-# todo: remove 0 return after fixing Bug#27563
--error 0,ER_QUERY_INTERRUPTED
-reap; ### pb: wrong error
---disable_info
-###--replace_column 2 # 5 #
-### show binlog events from 98 /* nothing in binlog unless Bug#27563 */;
-show master status /* must be only FD event unless Bug#27563 */;
-select count(*) from t1 /* must be zero unless Bug#27563 */;
-
-# M. multi-statement-ta
+reap;
+rollback;
+select * from t1 order by a /* must be the same as before (1,1),(2,2) */;
+
+#
+# multi update
+# commented out as Bug #31807 multi-update,delete killing does not report with ER_QUERY_INTERRUPTED
+# in the way
+#
+# connection con1;
+# begin; update t1 set b=b+10;
+
+# connection con2;
+# send update t1 as t_1,t1 as t_2 set t_1.b=11 where t_2.a=2;
+
+# connection con1;
+# --replace_result $ID ID
+# eval kill query $ID;
+# rollback;
+
+# disable_abort_on_error;
+
+# connection con2;
+# --error HY000,ER_QUERY_INTERRUPTED
+# reap;
+# select * from t1 /* must be the same as before (1,1),(2,2) */;
+
+# enable_abort_on_error;
+#
+# simple delete
+#
+connection con1;
+begin; delete from t1 where a=2;
+
connection con2;
let $ID= `select connection_id()`;
begin;
-send insert into t1 values (bug27563(),1);
+send delete from t1 where a=2;
connection con1;
+--replace_result $ID ID
eval kill query $ID;
+rollback;
+
connection con2;
-# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero
---enable_info
-# todo: remove 0 return after fixing Bug#27563
--error 0,ER_QUERY_INTERRUPTED
reap;
---disable_info
-select count(*) from t1 /* must be zero unless Bug#27563 */;
-commit;
+rollback;
+# todo1,2 above
+select * from t1 order by a /* must be the same as before (1,1),(2,2) */;
-### non-ta table case: killing must be recorded in binlog
+#
+# multi delete
+# the same as for multi-update
+#
+# connection con1;
+# begin; delete from t1 where a=2;
-reset master;
+# connection con2;
+# send delete t1 from t1 where t1.a=2;
+
+# connection con1;
+# --replace_result $ID ID
+# eval kill query $ID;
+# rollback;
+
+# connection con2;
+# --error 0,ER_QUERY_INTERRUPTED
+# reap;
+# select * from t1 /* must be the same as before (1,1),(2,2) */;
+#
+# insert select
+#
+connection con1;
+--disable_warnings
+drop table if exists t4;
+--enable_warnings
+create table t4 (a int, b int) engine=innodb;
+insert into t4 values (3, 3);
+begin; insert into t1 values (3, 3);
connection con2;
let $ID= `select connection_id()`;
-send insert into t2 values (bug27563(),1);
+begin;
+send insert into t1 select * from t4 for update;
connection con1;
+--replace_result $ID ID
eval kill query $ID;
+rollback;
connection con2;
-# todo: remove 0 return after fixing Bug#27563
--error 0,ER_QUERY_INTERRUPTED
reap;
-select count(*) from t2 /* must be one */;
-#show binlog events from 98 /* must have the insert on non-ta table */;
-show master status /* must have the insert event more to FD */;
-# the value of the error flag of KILLED_QUERY is tested further
+# todo 1,2 above
+rollback;
+select * from t1 /* must be the same as before (1,1),(2,2) */;
-connection con1;
-select RELEASE_LOCK("a");
+drop table t4; # cleanup for the sub-case
-### test with effective killing of SF()
+###
+## non-ta table case: killing must be recorded in binlog
+###
+create table t4 (a int, b int) ENGINE=MyISAM /* for killing update and delete */;
-delete from t1;
-delete from t2;
-insert into t1 values (1,1);
-insert into t2 values (1,1);
+delimiter |;
+create function bug27563(n int)
+RETURNS int(11)
+DETERMINISTIC
+begin
+ if @b > 0 then
+ select get_lock("a", 20) into @a;
+ else
+ set @b= 1;
+ end if;
+ return n;
+end|
+delimiter ;|
+
+#
+# update
+#
-#
-# Bug#27565
-# test where KILL is propagated as error to the top level
-# still another bug with the error message to the user
-# todo: fix reexecute the result file after fixing
-#
-begin; update t1 set b=0 where a=1;
+delete from t4;
+insert into t4 values (1,1), (1,1);
+reset master;
+connection con1;
+select get_lock("a", 20);
connection con2;
let $ID= `select connection_id()`;
-send update t2 set b=bug27565()-1 where a=1;
+set @b= 0;
+send update t4 set b=b + bug27563(b);
connection con1;
+let $wait_condition= select count(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock';
+source include/wait_condition.inc;
+select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock';
+
+--replace_result $ID ID
eval kill query $ID;
-commit;
connection con2;
-# todo: fix Bug #27565 killed query of SF() is not reported correctly and
-# remove 1105 (wrong)
-#--error ER_QUERY_INTERRUPTED
---error 1105,ER_QUERY_INTERRUPTED
-reap; ### pb: wrong error
-select * from t1 /* must be: (1,0) */;
-select * from t2 /* must be as before: (1,1) */;
+--error ER_QUERY_INTERRUPTED
+reap;
+select * from t4 order by b /* must be (1,1), (1,2) */;
+select @b /* must be 1 at the end of a stmt calling bug27563() */;
+--echo must have the update query event more to FD
+source include/show_binlog_events.inc;
-## bug#22725 with effective and propagating killing
-#
-# top-level ta-table
+# a proof the query is binlogged with an error
+
+--exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval select
+(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null;
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`;
+eval select $error_code /* must return 0 to mean the killed query is in */;
+
+# cleanup for the sub-case
connection con1;
-delete from t3;
+select RELEASE_LOCK("a");
+--remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
+
+#
+# delete
+#
+
+delete from t4;
+insert into t4 values (1,1), (2,2);
reset master;
-begin; update t1 set b=0 where a=1;
+connection con1;
+select get_lock("a", 20);
connection con2;
let $ID= `select connection_id()`;
-# the query won't perform completely since the function gets interrupted
-send insert into t3 values (0,0),(1,bug27565());
+set @b= 0;
+send delete from t4 where b=bug27563(1) or b=bug27563(2);
connection con1;
+let $wait_condition= select count(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock';
+source include/wait_condition.inc;
+select count(*) FROM INFORMATION_SCHEMA.PROCESSLIST where state='User lock';
+--replace_result $ID ID
eval kill query $ID;
-rollback;
connection con2;
-# todo: fix Bug #27565 killed query of SF() is not reported correctly and
-# remove 1105 (wrong)
-#--error ER_QUERY_INTERRUPTED
---error 1105,ER_QUERY_INTERRUPTED
-reap; ### pb: wrong error
-select count(*) from t3 /* must be zero */;
-show master status /* nothing in binlog */;
-
-# top-level non-ta-table
-connection con1;
-delete from t2;
-reset master;
-begin; update t1 set b=0 where a=1;
+--error ER_QUERY_INTERRUPTED
+reap;
+select count(*) from t4 /* must be 1 */;
+select @b /* must be 1 at the end of a stmt calling bug27563() */;
+--echo must have the delete query event more to FD
+source include/show_binlog_events.inc;
-connection con2;
-let $ID= `select connection_id()`;
-# the query won't perform completely since the function gets intrurrupted
-send insert into t2 values (0,0),(1,bug27565()) /* non-ta t2 */;
+# a proof the query is binlogged with an error
+
+--exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval select
+(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null;
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`;
+eval select $error_code /* must return 0 to mean the killed query is in */;
+# cleanup for the sub-case
connection con1;
-eval kill query $ID;
-rollback;
+select RELEASE_LOCK("a");
+--remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
-connection con2;
-# todo: fix Bug #27565 killed query of SF() is not reported correctly and
-# remove 1105 (wrong)
-#--error ER_QUERY_INTERRUPTED
---error 1105,ER_QUERY_INTERRUPTED
-reap; ### pb: wrong error
+drop table t4;
-select count(*) from t2 /* count must be one */;
-show master status /* insert into non-ta must be in binlog */;
+#
+# load data - see simulation tests
+#
+
+
+# bug#27571 cleanup
drop function bug27563;
-drop function bug27565;
-}
-system rm $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog ;
+
+#
+# common cleanup
+#
drop table t1,t2,t3;
+--echo end of the tests
diff --git a/mysql-test/suite/binlog/t/binlog_killed_simulate-master.opt b/mysql-test/suite/binlog/t/binlog_killed_simulate-master.opt
new file mode 100644
index 00000000000..90c70ecee29
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_killed_simulate-master.opt
@@ -0,0 +1 @@
+--loose-debug=d,simulate_kill_bug27571
diff --git a/mysql-test/suite/binlog/t/binlog_killed_simulate.test b/mysql-test/suite/binlog/t/binlog_killed_simulate.test
new file mode 100644
index 00000000000..2121a90dc8c
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_killed_simulate.test
@@ -0,0 +1,69 @@
+-- source include/have_debug.inc
+-- source include/have_binlog_format_mixed_or_statement.inc
+#
+# bug#27571 asynchronous setting mysql_$query()'s local error and
+# Query_log_event::error_code
+#
+
+--disable_warnings
+drop table if exists t1,t2;
+--enable_warnings
+
+#
+# Checking that killing upon successful row-loop does not affect binlogging
+#
+
+create table t1 (a int) engine=MyISAM;
+insert into t1 set a=1;
+reset master;
+
+update t1 set a=2 /* will be "killed" after work has been done */;
+
+# a proof the query is binlogged with no error
+#todo: introduce a suite private macro that provides numeric values
+# for some constants like the offset of the first real event
+# that is different between severs versions.
+--exec $MYSQL_BINLOG --start-position=106 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval select
+(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null;
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+let $error_code= `select @a like "%#%error_code=0%" /* must return 1 */`;
+eval select $error_code /* must return 1 as query completed before got killed*/;
+
+# cleanup for the sub-case
+system rm $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog;
+
+
+#
+# Checking that killing inside of row-loop for LOAD DATA into
+# non-transactional table affects binlogging
+#
+
+create table t2 (a int, b int) ENGINE=MyISAM;
+reset master;
+--error ER_QUERY_INTERRUPTED
+load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */;
+
+
+# a proof the query is binlogged with an error
+
+source include/show_binlog_events.inc;
+
+--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval select
+(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
+is not null;
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`;
+eval select $error_code /* must return 0 to mean the killed query is in */;
+
+# cleanup for the sub-case
+system rm $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog;
+
+
+drop table t1,t2;
+
+--echo end of the tests
diff --git a/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test
index 7b7753a487e..3148cc50fd0 100644
--- a/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test
+++ b/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test
@@ -31,3 +31,5 @@ eval select
@a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%",
@a not like "%#%error_code=%error_code=%";
drop table t1, t2;
+
+-- source extra/binlog_tests/mix_innodb_myisam_side_effects.test
diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test
index 1815f3deb34..e7149e03b87 100644
--- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test
+++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test
@@ -24,123 +24,9 @@ eval select
drop table t1, t2;
-#
-# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack
-# bug #28960 non-trans temp table changes with insert .. select
-# not binlogged after rollback
-#
-# testing appearence of insert into temp_table in binlog.
-# There are two branches of execution that require different setup.
+set @@session.binlog_format=statement;
+-- source extra/binlog_tests/mix_innodb_myisam_side_effects.test
+set @@session.binlog_format=@@global.binlog_format;
-## send_eof() branch
-
-# prepare
-
-create table tt (a int unique);
-create table ti (a int) engine=innodb;
-reset master;
-show master status;
-
-# action
-
-begin;
-insert into ti values (1);
-insert into ti values (2) ;
-insert into tt select * from ti;
-rollback;
-
-# check
-
-select count(*) from tt /* 2 */;
-show master status;
---replace_column 2 # 5 #
-show binlog events from 106;
-select count(*) from ti /* zero */;
-insert into ti select * from tt;
-select * from ti /* that is what slave would miss - a bug */;
-
-
-## send_error() branch
-delete from ti;
-delete from tt where a=1;
-reset master;
-show master status;
-
-# action
-
-begin;
-insert into ti values (1);
-insert into ti values (2) /* to make the dup error in the following */;
---error ER_DUP_ENTRY
-insert into tt select * from ti /* one affected and error */;
-rollback;
-
-# check
-
-show master status;
---replace_column 2 # 5 #
-show binlog events from 106;
-select count(*) from ti /* zero */;
-insert into ti select * from tt;
-select * from tt /* that is what otherwise slave missed - the bug */;
-
-drop table ti,tt;
-
-
-#
-# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack
-#
-# Testing asserts: if there is a side effect of modifying non-transactional
-# table thd->no_trans_update.stmt must be TRUE;
-# the assert is active with debug build
-#
-
---disable_warnings
-drop function if exists bug27417;
-drop table if exists t1,t2;
---enable_warnings
-# side effect table
-CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM;
-# target tables
-CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a));
-
-delimiter |;
-create function bug27417(n int)
-RETURNS int(11)
-begin
- insert into t1 values (null);
- return n;
-end|
-delimiter ;|
-
-reset master;
-
-# execute
-
-insert into t2 values (bug27417(1));
-insert into t2 select bug27417(2);
-reset master;
-
---error ER_DUP_ENTRY
-insert into t2 values (bug27417(2));
-#TODO: Andrei: enable this test after 23333 is pushed
-#show master status; /* only (!) with fixes for #23333 will show there is the query */;
-select count(*) from t1 /* must be 3 */;
-
-reset master;
-select count(*) from t2;
-delete from t2 where a=bug27417(3);
-select count(*) from t2 /* nothing got deleted */;
-#TODO: Andrei: enable this test after 23333 is pushed
-#show master status; /* the query must be in regardless of #23333 */;
-select count(*) from t1 /* must be 5 */;
-
---enable_info
-delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */;
---disable_info
-select count(*) from t1 /* must be 7 */;
-
-drop function bug27417;
-drop table t1,t2;
--echo end of tests
diff --git a/mysql-test/suite/manual/r/rpl_replication_delay.result b/mysql-test/suite/manual/r/rpl_replication_delay.result
new file mode 100644
index 00000000000..a8fa6ce8265
--- /dev/null
+++ b/mysql-test/suite/manual/r/rpl_replication_delay.result
@@ -0,0 +1,136 @@
+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;
+show slave status /* Second_behind reports 0 */;;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port 9306
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos 106
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running Yes
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos 106
+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 0
+Master_SSL_Verify_Server_Cert No
+Last_IO_Errno 0
+Last_IO_Error
+Last_SQL_Errno 0
+Last_SQL_Error
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+create table t1 (f1 int);
+flush logs /* contaminate rli->last_master_timestamp */;
+lock table t1 write;
+insert into t1 values (1);
+show slave status /* bug emulated: reports slave threads starting time about 3*3 not 3 secs */;;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port 9306
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos 367
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running Yes
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos 279
+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 9
+Master_SSL_Verify_Server_Cert No
+Last_IO_Errno 0
+Last_IO_Error
+Last_SQL_Errno 0
+Last_SQL_Error
+unlock tables;
+flush logs /* this time rli->last_master_timestamp is not affected */;
+lock table t1 write;
+insert into t1 values (2);
+show slave status /* reports the correct diff with master query time about 3+3 secs */;;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port 9306
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos 455
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running Yes
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos 367
+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 7
+Master_SSL_Verify_Server_Cert No
+Last_IO_Errno 0
+Last_IO_Error
+Last_SQL_Errno 0
+Last_SQL_Error
+unlock tables;
+drop table t1;
diff --git a/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt b/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt
new file mode 100644
index 00000000000..24a4c5952fe
--- /dev/null
+++ b/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt
@@ -0,0 +1 @@
+--loose-debug=d,let_first_flush_log_change_timestamp
diff --git a/mysql-test/suite/manual/t/rpl_replication_delay.test b/mysql-test/suite/manual/t/rpl_replication_delay.test
new file mode 100644
index 00000000000..8230698c8f9
--- /dev/null
+++ b/mysql-test/suite/manual/t/rpl_replication_delay.test
@@ -0,0 +1,71 @@
+#
+# Testing replication delay reporting (bug#29309)
+# there is an unavoidable non-determinism in the test
+# please compare the results with the comments
+#
+
+
+source include/master-slave.inc;
+
+connection master;
+#connection slave;
+sync_slave_with_master;
+--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT
+--replace_column 1 # 8 # 9 # 23 #
+--query_vertical show slave status /* Second_behind reports 0 */;
+sleep 3;
+
+### bug emulation
+
+connection master;
+drop table if exists t1;
+create table t1 (f1 int);
+sleep 3;
+
+#connection slave;
+sync_slave_with_master;
+flush logs /* contaminate rli->last_master_timestamp */;
+
+connection slave;
+lock table t1 write;
+
+connection master;
+insert into t1 values (1);
+
+sleep 3;
+
+connection slave;
+--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT
+--replace_column 1 # 8 # 9 # 23 #
+--query_vertical show slave status /* bug emulated: reports slave threads starting time about 3*3 not 3 secs */;
+unlock tables;
+
+connection master;
+sync_slave_with_master;
+
+### bugfix
+
+
+connection slave;
+flush logs /* this time rli->last_master_timestamp is not affected */;
+lock table t1 write;
+
+connection master;
+insert into t1 values (2);
+sleep 3;
+
+connection slave;
+--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT
+--replace_column 1 # 8 # 9 # 23 #
+--query_vertical show slave status /* reports the correct diff with master query time about 3+3 secs */;
+unlock tables;
+
+connection master;
+drop table t1;
+
+#connection slave;
+sync_slave_with_master;
+
+
+# End of tests
+
diff --git a/mysql-test/suite/rpl/data/rpl_bug28618.dat b/mysql-test/suite/rpl/data/rpl_bug28618.dat
new file mode 100644
index 00000000000..b800c4dd39d
--- /dev/null
+++ b/mysql-test/suite/rpl/data/rpl_bug28618.dat
@@ -0,0 +1,3 @@
+1|master only
+2|master only
+3|master only
diff --git a/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc b/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc
index 5d3b80e077b..b3e0cefbbd7 100644
--- a/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc
+++ b/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc
@@ -7,15 +7,15 @@
--echo ==========MASTER==========
SELECT COUNT(*) FROM t1;
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
SELECT COUNT(*) FROM t2;
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
sync_slave_with_master;
--echo ==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
SELECT COUNT(*) FROM t2;
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
connection master;
diff --git a/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc b/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc
index 43feedfe64a..a9f7ad8cd68 100644
--- a/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc
+++ b/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc
@@ -7,11 +7,11 @@
--echo ==========MASTER==========
SHOW CREATE VIEW v1;
-SELECT * FROM v1;
+SELECT * FROM v1 ORDER BY a;
sync_slave_with_master;
--echo ==========SLAVE===========
USE test_rpl;
SHOW CREATE VIEW v1;
-SELECT * FROM v1;
+SELECT * FROM v1 ORDER BY a;
connection master;
diff --git a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc
index a3ff022c43c..70db5b6cf83 100644
--- a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc
+++ b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc
@@ -54,7 +54,7 @@ DELETE FROM t2 WHERE a = 2;
--exec cp ./suite/rpl/data/rpl_mixed.dat $MYSQLTEST_VARDIR/tmp/
LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;
--remove_file $MYSQLTEST_VARDIR/tmp/rpl_mixed.dat
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
--source suite/rpl/include/rpl_mixed_check_select.inc
--source suite/rpl/include/rpl_mixed_clear_tables.inc
@@ -75,7 +75,7 @@ DELETE FROM t1 WHERE a = 2;
--echo
--echo ******************** SELECT ********************
INSERT INTO t1 VALUES(1, 't1, text 1');
-SELECT * FROM t1 WHERE b <> UUID();
+SELECT * FROM t1 WHERE b <> UUID() ORDER BY a;
--source suite/rpl/include/rpl_mixed_clear_tables.inc
# JOIN
@@ -85,8 +85,8 @@ INSERT INTO t1 VALUES(1, 'CCC');
INSERT INTO t1 VALUES(2, 'DDD');
INSERT INTO t2 VALUES(1, 'DDD');
INSERT INTO t2 VALUES(2, 'CCC');
-SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a;
-SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b;
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a ORDER BY t1.a,t2.a;
+SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b ORDER BY t1.a,t2.a;
--source suite/rpl/include/rpl_mixed_clear_tables.inc
# UNION
diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result
index fe5a5b28682..1c21a80acb1 100644
--- a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result
+++ b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result
@@ -615,6 +615,66 @@ c1 c2 c3 c4 c5 c6 c7
1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Create t14a on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='InnoDB';
+*** Create t14a on Master ***
+CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5)
+) ENGINE='InnoDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14a () VALUES(1,@b1,'Kyle'),
+(2,@b1,'JOE'),
+(3,@b1,'QA');
+SELECT * FROM t14a ORDER BY c1;
+c1 c4 c5
+1 b1b1b1b1b1b1b1b1 Kyle
+2 b1b1b1b1b1b1b1b1 JOE
+3 b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t14a ORDER BY c1;
+c1 c4 c5 c6 c7
+1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+STOP SLAVE;
+RESET SLAVE;
+*** Master Drop c5 ***
+ALTER TABLE t14a DROP COLUMN c5;
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14a () VALUES(4,@b1),
+(5,@b1),
+(6,@b1);
+SELECT * FROM t14a ORDER BY c1;
+c1 c4
+1 b1b1b1b1b1b1b1b1
+2 b1b1b1b1b1b1b1b1
+3 b1b1b1b1b1b1b1b1
+4 b1b1b1b1b1b1b1b1
+5 b1b1b1b1b1b1b1b1
+6 b1b1b1b1b1b1b1b1
+*** Select on Slave ****
+SELECT * FROM t14a ORDER BY c1;
+c1 c4 c5 c6 c7
+1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+4 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP
+5 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP
+6 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP
*** connect to master and drop columns ***
ALTER TABLE t14 DROP COLUMN c2;
ALTER TABLE t14 DROP COLUMN c4;
@@ -707,7 +767,7 @@ Last_IO_Errno #
Last_IO_Error #
Last_SQL_Errno 1060
Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5'
-SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
START SLAVE;
*** Try to insert in master ****
INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2);
@@ -723,6 +783,7 @@ c1 c2 c3 c4 c5 c6 c7
1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2 CURRENT_TIMESTAMP
*** DROP TABLE t15 ***
DROP TABLE t15;
*** Create t16 on slave ***
diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result
index e70a2efaf29..db0eb81fb0f 100644
--- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result
+++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result
@@ -615,6 +615,66 @@ c1 c2 c3 c4 c5 c6 c7
1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+*** Create t14a on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='MyISAM';
+*** Create t14a on Master ***
+CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5)
+) ENGINE='MyISAM';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14a () VALUES(1,@b1,'Kyle'),
+(2,@b1,'JOE'),
+(3,@b1,'QA');
+SELECT * FROM t14a ORDER BY c1;
+c1 c4 c5
+1 b1b1b1b1b1b1b1b1 Kyle
+2 b1b1b1b1b1b1b1b1 JOE
+3 b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t14a ORDER BY c1;
+c1 c4 c5 c6 c7
+1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+STOP SLAVE;
+RESET SLAVE;
+*** Master Drop c5 ***
+ALTER TABLE t14a DROP COLUMN c5;
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14a () VALUES(4,@b1),
+(5,@b1),
+(6,@b1);
+SELECT * FROM t14a ORDER BY c1;
+c1 c4
+1 b1b1b1b1b1b1b1b1
+2 b1b1b1b1b1b1b1b1
+3 b1b1b1b1b1b1b1b1
+4 b1b1b1b1b1b1b1b1
+5 b1b1b1b1b1b1b1b1
+6 b1b1b1b1b1b1b1b1
+*** Select on Slave ****
+SELECT * FROM t14a ORDER BY c1;
+c1 c4 c5 c6 c7
+1 b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
+2 b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
+3 b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+4 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP
+5 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP
+6 b1b1b1b1b1b1b1b1 NULL 1 CURRENT_TIMESTAMP
*** connect to master and drop columns ***
ALTER TABLE t14 DROP COLUMN c2;
ALTER TABLE t14 DROP COLUMN c4;
@@ -707,7 +767,7 @@ Last_IO_Errno #
Last_IO_Error #
Last_SQL_Errno 1060
Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5'
-SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
START SLAVE;
*** Try to insert in master ****
INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2);
@@ -723,6 +783,7 @@ c1 c2 c3 c4 c5 c6 c7
1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP
2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP
3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP
+5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2 CURRENT_TIMESTAMP
*** DROP TABLE t15 ***
DROP TABLE t15;
*** Create t16 on slave ***
diff --git a/mysql-test/suite/rpl/r/rpl_found_rows.result b/mysql-test/suite/rpl/r/rpl_found_rows.result
new file mode 100644
index 00000000000..7e757a1d141
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_found_rows.result
@@ -0,0 +1,233 @@
+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;
+==== 0. Setting it all up ====
+SET BINLOG_FORMAT=STATEMENT;
+**** On Master ****
+CREATE TABLE t1 (a INT);
+CREATE TABLE logtbl (sect INT, test INT, count INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+#### 1. Using statement mode ####
+==== 1.1. Simple test ====
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+a
+7
+SELECT FOUND_ROWS() INTO @a;
+INSERT INTO logtbl VALUES(1,1,@a);
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
+a
+1
+SELECT FOUND_ROWS() INTO @a;
+INSERT INTO logtbl VALUES(1,2,@a);
+SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
+sect test count
+1 1 183
+1 2 3
+**** On Slave ****
+SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
+sect test count
+1 1 183
+1 2 3
+==== 1.2. Stored procedure ====
+**** On Master ****
+CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN
+DECLARE cnt INT;
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
+SELECT FOUND_ROWS() INTO cnt;
+INSERT INTO logtbl VALUES(sect,test,cnt);
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+SELECT FOUND_ROWS() INTO cnt;
+INSERT INTO logtbl VALUES(sect,test+1,cnt);
+END $$
+CALL calc_and_log(2,1);
+a
+1
+a
+7
+CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN
+INSERT INTO logtbl VALUES (sect,test,found_rows);
+END $$
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+a
+7
+SELECT FOUND_ROWS() INTO @found_rows;
+CALL just_log(2,3,@found_rows);
+SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
+sect test count
+2 1 3
+2 2 183
+2 3 183
+**** On Slave ****
+SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
+sect test count
+2 1 3
+2 2 183
+2 3 183
+==== 1.3. Stored functions ====
+**** On Master ****
+CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT)
+RETURNS INT
+BEGIN
+INSERT INTO logtbl VALUES(sect,test,found_rows);
+RETURN found_rows;
+END $$
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+a
+7
+SELECT FOUND_ROWS() INTO @found_rows;
+SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows);
+log_rows(3,1,@found_rows) log_rows(3,2,@found_rows)
+183 183
+SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
+sect test count
+3 1 183
+3 2 183
+**** On Slave ****
+SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
+sect test count
+3 1 183
+3 2 183
+==== 1.9. Cleanup ====
+**** On Master ****
+DELETE FROM logtbl;
+DROP PROCEDURE just_log;
+DROP PROCEDURE calc_and_log;
+DROP FUNCTION log_rows;
+**** Resetting master and slave ****
+STOP SLAVE;
+RESET SLAVE;
+RESET MASTER;
+START SLAVE;
+#### 2. Using mixed mode ####
+==== 2.1. Checking a procedure ====
+**** On Master ****
+SET BINLOG_FORMAT=MIXED;
+CREATE PROCEDURE just_log(sect INT, test INT) BEGIN
+INSERT INTO logtbl VALUES (sect,test,FOUND_ROWS());
+END $$
+**** On Master 1 ****
+SET BINLOG_FORMAT=MIXED;
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+a
+7
+CALL just_log(1,1);
+**** On Master ****
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+a
+7
+CALL just_log(1,2);
+**** On Master 1 ****
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
+a
+1
+CALL just_log(1,3);
+**** On Master ****
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+a
+7
+CALL just_log(1,4);
+SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
+sect test count
+1 1 183
+1 2 183
+1 3 3
+1 4 183
+**** On Slave ****
+SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
+sect test count
+1 1 183
+1 2 183
+1 3 3
+1 4 183
+==== 2.1. Checking a stored function ====
+**** On Master ****
+CREATE FUNCTION log_rows(sect INT, test INT)
+RETURNS INT
+BEGIN
+DECLARE found_rows INT;
+SELECT FOUND_ROWS() INTO found_rows;
+INSERT INTO logtbl VALUES(sect,test,found_rows);
+RETURN found_rows;
+END $$
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
+a
+1
+SELECT log_rows(2,1), log_rows(2,2);
+log_rows(2,1) log_rows(2,2)
+3 3
+CREATE TABLE t2 (a INT, b INT);
+CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW
+BEGIN
+INSERT INTO logtbl VALUES (NEW.a, NEW.b, FOUND_ROWS());
+END $$
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
+a
+1
+INSERT INTO t2 VALUES (2,3), (2,4);
+DROP TRIGGER t2_tr;
+CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW
+BEGIN
+DECLARE dummy INT;
+SELECT log_rows(NEW.a, NEW.b) INTO dummy;
+END $$
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+a
+7
+INSERT INTO t2 VALUES (2,5), (2,6);
+DROP TRIGGER t2_tr;
+CREATE PROCEDURE log_me_inner(sect INT, test INT)
+BEGIN
+DECLARE dummy INT;
+SELECT log_rows(sect, test) INTO dummy;
+SELECT log_rows(sect, test+1) INTO dummy;
+END $$
+CREATE PROCEDURE log_me(sect INT, test INT)
+BEGIN
+CALL log_me_inner(sect,test);
+END $$
+CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW
+BEGIN
+CALL log_me(NEW.a, NEW.b);
+END $$
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+a
+7
+INSERT INTO t2 VALUES (2,5), (2,6);
+SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
+sect test count
+2 1 3
+2 2 3
+2 3 3
+2 4 3
+2 5 183
+2 5 183
+2 6 183
+2 6 0
+2 6 183
+2 7 0
+SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
+sect test count
+2 1 3
+2 2 3
+2 3 3
+2 4 3
+2 5 183
+2 5 183
+2 6 183
+2 6 0
+2 6 183
+2 7 0
+DROP TABLE t1, logtbl;
+DROP PROCEDURE just_log;
+DROP PROCEDURE log_me;
+DROP PROCEDURE log_me_inner;
+DROP FUNCTION log_rows;
diff --git a/mysql-test/suite/rpl/r/rpl_idempotency.result b/mysql-test/suite/rpl/r/rpl_idempotency.result
new file mode 100644
index 00000000000..f17fbd82c44
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_idempotency.result
@@ -0,0 +1,71 @@
+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 PRIMARY KEY);
+CREATE TABLE t2 (a INT);
+INSERT INTO t1 VALUES (-1),(-2),(-3);
+INSERT INTO t2 VALUES (-1),(-2),(-3);
+DELETE FROM t1 WHERE a = -2;
+DELETE FROM t2 WHERE a = -2;
+DELETE FROM t1 WHERE a = -2;
+DELETE FROM t2 WHERE a = -2;
+SELECT * FROM t1 ORDER BY a;
+a
+-3
+-1
+SELECT * FROM t2 ORDER BY a;
+a
+-3
+-1
+SELECT * FROM t1 ORDER BY a;
+a
+-3
+-1
+SELECT * FROM t2 ORDER BY a;
+a
+-3
+-1
+Last_SQL_Error
+0
+INSERT IGNORE INTO t1 VALUES (-2);
+INSERT IGNORE INTO t1 VALUES (-2);
+SELECT * FROM t1 ORDER BY a;
+a
+-3
+-2
+-1
+SELECT * FROM t1 ORDER BY a;
+a
+-3
+-2
+-1
+Last_SQL_Error
+0
+UPDATE t1 SET a = 1 WHERE a = -1;
+UPDATE t2 SET a = 1 WHERE a = -1;
+UPDATE t1 SET a = 1 WHERE a = -1;
+UPDATE t2 SET a = 1 WHERE a = -1;
+SELECT * FROM t1 ORDER BY a;
+a
+-3
+-2
+1
+SELECT * FROM t2 ORDER BY a;
+a
+-3
+1
+SELECT * FROM t1 ORDER BY a;
+a
+-3
+-2
+1
+SELECT * FROM t2 ORDER BY a;
+a
+-3
+1
+Last_SQL_Error
+0
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result
index fb2782ed9f4..c46b4016715 100644
--- a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result
+++ b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result
@@ -114,30 +114,30 @@ Create Table CREATE TABLE `byrange_tbl` (
`filler` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (id) SUBPARTITION BY HASH (id) SUBPARTITIONS 2 (PARTITION pa1 VALUES LESS THAN (10) ENGINE = InnoDB, PARTITION pa2 VALUES LESS THAN (20) ENGINE = InnoDB, PARTITION pa3 VALUES LESS THAN (30) ENGINE = InnoDB, PARTITION pa4 VALUES LESS THAN (40) ENGINE = InnoDB, PARTITION pa5 VALUES LESS THAN (50) ENGINE = InnoDB, PARTITION pa6 VALUES LESS THAN (60) ENGINE = InnoDB, PARTITION pa7 VALUES LESS THAN (70) ENGINE = InnoDB, PARTITION pa8 VALUES LESS THAN (80) ENGINE = InnoDB, PARTITION pa9 VALUES LESS THAN (90) ENGINE = InnoDB, PARTITION pa10 VALUES LESS THAN (100) ENGINE = InnoDB, PARTITION pa11 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
-show slave status;
-Slave_IO_State Waiting for master to send event
+SHOW SLAVE STATUS;
+Slave_IO_State #
Master_Host 127.0.0.1
Master_User root
Master_Port MASTER_PORT
Connect_Retry 1
Master_Log_File master-bin.000001
Read_Master_Log_Pos 945470
-Relay_Log_File slave-relay-bin.000003
-Relay_Log_Pos 945616
+Relay_Log_File #
+Relay_Log_Pos #
Relay_Master_Log_File master-bin.000001
Slave_IO_Running Yes
Slave_SQL_Running Yes
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
-Replicate_Ignore_Table
+Replicate_Ignore_Table #
Replicate_Wild_Do_Table
Replicate_Wild_Ignore_Table
Last_Errno 0
Last_Error
Skip_Counter 0
Exec_Master_Log_Pos 945470
-Relay_Log_Space 945771
+Relay_Log_Space #
Until_Condition None
Until_Log_File
Until_Log_Pos 0
@@ -149,8 +149,8 @@ Master_SSL_Cipher
Master_SSL_Key
Seconds_Behind_Master #
Master_SSL_Verify_Server_Cert No
-Last_IO_Errno 0
-Last_IO_Error
+Last_IO_Errno #
+Last_IO_Error #
Last_SQL_Errno 0
Last_SQL_Error
SELECT count(*) "Slave norm" FROM test.regular_tbl;
diff --git a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result
index 19c5299df25..0e11d132cc4 100644
--- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result
+++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result
@@ -41,26 +41,26 @@ DELETE FROM t2 WHERE b <> UUID();
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
2 t1, text 2
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
2 t1, text 2
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
DELETE FROM t1;
DELETE FROM t2;
@@ -76,13 +76,13 @@ DELETE FROM t2 WHERE a = 2;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 t1, text 1
SELECT COUNT(*) FROM t2;
COUNT(*)
1
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
1 t2, text 1
==========SLAVE===========
@@ -90,13 +90,13 @@ USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 t1, text 1
SELECT COUNT(*) FROM t2;
COUNT(*)
1
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
1 t2, text 1
DELETE FROM t1;
@@ -104,7 +104,7 @@ DELETE FROM t2;
******************** LOAD DATA INFILE ********************
LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
10 line A
20 line B
@@ -113,7 +113,7 @@ a b
SELECT COUNT(*) FROM t1;
COUNT(*)
3
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
10 line A
20 line B
@@ -121,14 +121,14 @@ a b
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
3
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
10 line A
20 line B
@@ -136,7 +136,7 @@ a b
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
DELETE FROM t1;
DELETE FROM t2;
@@ -153,35 +153,35 @@ DELETE FROM t1 WHERE a = 2;
SELECT COUNT(*) FROM t1;
COUNT(*)
2
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 t1, text 11
3 t1, text 33
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
2
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 t1, text 11
3 t1, text 33
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
DELETE FROM t1;
DELETE FROM t2;
******************** SELECT ********************
INSERT INTO t1 VALUES(1, 't1, text 1');
-SELECT * FROM t1 WHERE b <> UUID();
+SELECT * FROM t1 WHERE b <> UUID() ORDER BY a;
a b
1 t1, text 1
DELETE FROM t1;
@@ -192,11 +192,11 @@ INSERT INTO t1 VALUES(1, 'CCC');
INSERT INTO t1 VALUES(2, 'DDD');
INSERT INTO t2 VALUES(1, 'DDD');
INSERT INTO t2 VALUES(2, 'CCC');
-SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a;
+SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a ORDER BY t1.a,t2.a;
a b a b
1 CCC 1 DDD
2 DDD 2 CCC
-SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b;
+SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b ORDER BY t1.a,t2.a;
a b a b
1 CCC 2 CCC
2 DDD 1 DDD
@@ -219,50 +219,50 @@ INSERT INTO t1 VALUES(1, 't1, text 1');
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 t1, text 1
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 t1, text 1
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
TRUNCATE t1;
==========MASTER==========
SELECT COUNT(*) FROM t1;
COUNT(*)
0
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
0
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
DELETE FROM t1;
DELETE FROM t2;
@@ -275,13 +275,13 @@ UPDATE t1 SET b = 't1, text 1 updated' WHERE a = 1;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 t1, text 1 updated
SELECT COUNT(*) FROM t2;
COUNT(*)
1
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
1 t2, text 1
==========SLAVE===========
@@ -289,13 +289,13 @@ USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 t1, text 1 updated
SELECT COUNT(*) FROM t2;
COUNT(*)
1
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
1 t2, text 1
UPDATE t1, t2 SET t1.b = 'test', t2.b = 'test';
@@ -303,13 +303,13 @@ UPDATE t1, t2 SET t1.b = 'test', t2.b = 'test';
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 test
SELECT COUNT(*) FROM t2;
COUNT(*)
1
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
1 test
==========SLAVE===========
@@ -317,13 +317,13 @@ USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 test
SELECT COUNT(*) FROM t2;
COUNT(*)
1
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
1 test
DELETE FROM t1;
@@ -349,26 +349,26 @@ COMMIT;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 start
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 start
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
START TRANSACTION;
INSERT INTO t1 VALUES (2, 'rollback');
@@ -377,26 +377,26 @@ ROLLBACK;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 start
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 start
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
START TRANSACTION;
INSERT INTO t1 VALUES (3, 'before savepoint s1');
@@ -407,27 +407,27 @@ ROLLBACK TO SAVEPOINT s1;
SELECT COUNT(*) FROM t1;
COUNT(*)
2
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 start
3 before savepoint s1
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 start
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
START TRANSACTION;
INSERT INTO t1 VALUES (5, 'before savepoint s2');
@@ -441,7 +441,7 @@ DELETE FROM t1 WHERE a = 7;
SELECT COUNT(*) FROM t1;
COUNT(*)
4
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 start
3 before savepoint s1
@@ -450,14 +450,14 @@ a b
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
4
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 start
3 before savepoint s1
@@ -466,7 +466,7 @@ a b
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
DELETE FROM t1;
DELETE FROM t2;
@@ -610,28 +610,28 @@ DELETE FROM t1 WHERE a = 202;
SELECT COUNT(*) FROM t1;
COUNT(*)
2
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
100 test
201 test
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
2
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
100 test
201 test
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
ALTER PROCEDURE p1 COMMENT 'p1';
DROP PROCEDURE p1;
@@ -649,13 +649,13 @@ INSERT INTO t1 VALUES (1, 'test');
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 test
SELECT COUNT(*) FROM t2;
COUNT(*)
1
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
1 test
==========SLAVE===========
@@ -663,13 +663,13 @@ USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 test
SELECT COUNT(*) FROM t2;
COUNT(*)
1
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
1 test
DELETE FROM t1;
@@ -694,51 +694,51 @@ test_rpl e1 @ SYSTEM RECURRING NULL 1 # # NULL SLAVESIDE_DISABLED 1 latin1 latin
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 test1
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 test1
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========MASTER==========
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 test1
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 test1
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
ALTER EVENT e1 RENAME TO e2;
==========MASTER==========
@@ -754,26 +754,26 @@ test_rpl e2 @ SYSTEM RECURRING NULL 1 # # NULL SLAVESIDE_DISABLED 1 latin1 latin
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 test1
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
==========SLAVE===========
USE test_rpl;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
a b
1 test1
SELECT COUNT(*) FROM t2;
COUNT(*)
0
-SELECT * FROM t2;
+SELECT * FROM t2 ORDER BY a;
a b
DROP EVENT e2;
==========MASTER==========
@@ -795,7 +795,7 @@ CREATE VIEW v2 AS SELECT * FROM t1 WHERE b <> UUID();
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 1) latin1 latin1_swedish_ci
-SELECT * FROM v1;
+SELECT * FROM v1 ORDER BY a;
a b
1 test1
==========SLAVE===========
@@ -803,7 +803,7 @@ USE test_rpl;
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 1) latin1 latin1_swedish_ci
-SELECT * FROM v1;
+SELECT * FROM v1 ORDER BY a;
a b
1 test1
ALTER VIEW v1 AS SELECT * FROM t1 WHERE a = 2;
@@ -811,7 +811,7 @@ ALTER VIEW v1 AS SELECT * FROM t1 WHERE a = 2;
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 2) latin1 latin1_swedish_ci
-SELECT * FROM v1;
+SELECT * FROM v1 ORDER BY a;
a b
2 test2
==========SLAVE===========
@@ -819,7 +819,7 @@ USE test_rpl;
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 2) latin1 latin1_swedish_ci
-SELECT * FROM v1;
+SELECT * FROM v1 ORDER BY a;
a b
2 test2
DROP VIEW v1;
diff --git a/mysql-test/suite/rpl/r/rpl_invoked_features.result b/mysql-test/suite/rpl/r/rpl_invoked_features.result
index 3bcef762497..502bb040218 100644
--- a/mysql-test/suite/rpl/r/rpl_invoked_features.result
+++ b/mysql-test/suite/rpl/r/rpl_invoked_features.result
@@ -17,13 +17,13 @@ DROP EVENT IF EXISTS e11;
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=myisam;
INSERT INTO t1 VALUES (1,1,'1');
INSERT INTO t1 VALUES (2,2,UUID());
-CREATE TABLE t2 (a INT, b INT, c VARCHAR(64)) ENGINE=myisam;
+CREATE TABLE t2 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=myisam;
INSERT INTO t2 VALUES (1,1,'1');
INSERT INTO t2 VALUES (2,2,UUID());
CREATE TABLE t11 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=innodb;
INSERT INTO t11 VALUES (1,1,'1');
INSERT INTO t11 VALUES (2,2,UUID());
-CREATE TABLE t12 (a INT, b INT, c VARCHAR(64)) ENGINE=innodb;
+CREATE TABLE t12 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=innodb;
INSERT INTO t12 VALUES (1,1,'1');
INSERT INTO t12 VALUES (2,2,UUID());
@@ -49,21 +49,15 @@ BEGIN
UPDATE t12 SET c = '';
UPDATE t13 SET c = '';
END|
-CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND ENABLE DO
+CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND DISABLE DO
BEGIN
-DECLARE c INT;
-SELECT a INTO c FROM t1 WHERE a < 11 ORDER BY a DESC LIMIT 1;
-IF c = 7 THEN
+ALTER EVENT e1 DISABLE;
CALL p1(10, '');
-END IF;
END|
-CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND ENABLE DO
+CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND DISABLE DO
BEGIN
-DECLARE c INT;
-SELECT a INTO c FROM t11 WHERE a < 11 ORDER BY a DESC LIMIT 1;
-IF c = 7 THEN
+ALTER EVENT e11 DISABLE;
CALL p11(10, '');
-END IF;
END|
CREATE FUNCTION f1 (x INT) RETURNS VARCHAR(64)
BEGIN
@@ -78,11 +72,11 @@ RETURN f1(x);
END|
CREATE PROCEDURE p1 (IN x INT, IN y VARCHAR(64))
BEGIN
-INSERT INTO t1 VALUES (x,x,y);
+INSERT IGNORE INTO t1 VALUES (x,x,y);
END|
CREATE PROCEDURE p11 (IN x INT, IN y VARCHAR(64))
BEGIN
-INSERT INTO t11 VALUES (x,x,y);
+INSERT IGNORE INTO t11 VALUES (x,x,y);
END|
CREATE TABLE t3 SELECT * FROM v1;
@@ -110,6 +104,8 @@ INSERT INTO t11 VALUES(7,7,f2(7));
INSERT INTO t11 VALUES (103,103,'');
SET GLOBAL EVENT_SCHEDULER = on;
+ALTER EVENT e1 ENABLE;
+ALTER EVENT e11 ENABLE;
SET GLOBAL EVENT_SCHEDULER = off;
SHOW TABLES LIKE 't%';
@@ -138,8 +134,8 @@ PROCEDURE p1
PROCEDURE p11
SELECT event_name, status FROM information_schema.events WHERE event_schema='test';
event_name status
-e1 ENABLED
-e11 ENABLED
+e1 DISABLED
+e11 DISABLED
SELECT COUNT(*) FROM t1;
COUNT(*)
@@ -438,6 +434,8 @@ UPDATE t3 SET c='';
UPDATE t11 SET c='';
UPDATE t12 SET c='';
UPDATE t13 SET c='';
+ALTER TABLE t3 ORDER BY a;
+ALTER TABLE t13 ORDER BY a;
diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result
index 981c234d380..dd56eb0471c 100644
--- a/mysql-test/suite/rpl/r/rpl_packet.result
+++ b/mysql-test/suite/rpl/r/rpl_packet.result
@@ -27,6 +27,42 @@ STOP SLAVE;
START SLAVE;
CREATE TABLe `t1` (`f1` LONGTEXT) ENGINE=MyISAM;
INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048');
-SHOW STATUS LIKE 'Slave_running';
-Variable_name Value
-Slave_running OFF
+show slave status;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_MYPORT
+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 No
+Slave_SQL_Running #
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos #
+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 #
+Master_SSL_Verify_Server_Cert No
+Last_IO_Errno 0
+Last_IO_Error
+Last_SQL_Errno 0
+Last_SQL_Error
diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result
index 7dc9926522b..c3fd663fad8 100644
--- a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result
+++ b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result
@@ -242,3 +242,34 @@ a b
3 1
4 4
drop table t1,t2;
+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;
+**** On Master ****
+SET SESSION BINLOG_FORMAT=ROW;
+CREATE TABLE t1 (a INT PRIMARY KEY, b SET('master','slave'));
+INSERT INTO t1 VALUES (1,'master,slave'), (2,'master,slave');
+**** On Slave ****
+UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1;
+SELECT * FROM t1 ORDER BY a;
+a b
+2 master,slave
+5 slave
+**** On Master ****
+UPDATE t1 SET a = 5, b = 'master' WHERE a = 1;
+SELECT * FROM t1 ORDER BY a;
+a b
+2 master,slave
+5 master
+**** On Slave ****
+Last_SQL_Error
+
+SELECT * FROM t1 ORDER BY a;
+a b
+2 master,slave
+5 slave
+DROP TABLE t1;
+**** On Master ****
+DROP TABLE t1;
diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
index a6877b27b95..2efe3a3e486 100644
--- a/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
+++ b/mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result
@@ -415,4 +415,23 @@ a b c
2 4 8
3 6 9
99 99 99
+**** Test for BUG#31552 ****
+**** On Master ****
+DELETE FROM t1;
+**** Resetting master and slave ****
+STOP SLAVE;
+RESET SLAVE;
+RESET MASTER;
+START SLAVE;
+**** On Master ****
+INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M');
+**** On Master ****
+DELETE FROM t1 WHERE C1 = 'L';
+DELETE FROM t1;
+SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
+COUNT(*) 0
+Last_SQL_Error
+0
+SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
+COUNT(*) 0
DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8;
diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
index 4c6ec627db5..fc78abfbe2e 100644
--- a/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
+++ b/mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result
@@ -415,4 +415,23 @@ a b c
2 4 8
3 6 9
99 99 99
+**** Test for BUG#31552 ****
+**** On Master ****
+DELETE FROM t1;
+**** Resetting master and slave ****
+STOP SLAVE;
+RESET SLAVE;
+RESET MASTER;
+START SLAVE;
+**** On Master ****
+INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M');
+**** On Master ****
+DELETE FROM t1 WHERE C1 = 'L';
+DELETE FROM t1;
+SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
+COUNT(*) 0
+Last_SQL_Error
+0
+SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
+COUNT(*) 0
DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8;
diff --git a/mysql-test/suite/rpl/r/rpl_skip_error.result b/mysql-test/suite/rpl/r/rpl_skip_error.result
index 525909387b3..ed4c4a6b3bb 100644
--- a/mysql-test/suite/rpl/r/rpl_skip_error.result
+++ b/mysql-test/suite/rpl/r/rpl_skip_error.result
@@ -29,8 +29,7 @@ select * from t1;
a
1
2
-3
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error
-# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 786 # # master-bin.000001 Yes Yes 0 0 786 # None 0 No # No 0 0
+# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 851 # # master-bin.000001 Yes Yes 0 0 851 # None 0 No # No 0 0
drop table t1;
diff --git a/mysql-test/suite/rpl/r/rpl_slave_skip.result b/mysql-test/suite/rpl/r/rpl_slave_skip.result
index 8e492fe4732..f89fa34e319 100644
--- a/mysql-test/suite/rpl/r/rpl_slave_skip.result
+++ b/mysql-test/suite/rpl/r/rpl_slave_skip.result
@@ -142,3 +142,211 @@ Last_SQL_Errno 0
Last_SQL_Error
**** On Master ****
DROP TABLE t1, t2;
+SET SESSION BINLOG_FORMAT=ROW;
+SET AUTOCOMMIT=0;
+CREATE TABLE t1 (a INT, b VARCHAR(20)) ENGINE=myisam;
+CREATE TABLE t2 (a INT, b VARCHAR(20)) ENGINE=myisam;
+CREATE TABLE t3 (a INT, b VARCHAR(20)) ENGINE=myisam;
+INSERT INTO t1 VALUES (1,'master/slave');
+INSERT INTO t2 VALUES (1,'master/slave');
+INSERT INTO t3 VALUES (1,'master/slave');
+CREATE TRIGGER tr1 AFTER UPDATE on t1 FOR EACH ROW
+BEGIN
+INSERT INTO t2 VALUES (NEW.a,NEW.b);
+DELETE FROM t2 WHERE a < NEW.a;
+END|
+CREATE TRIGGER tr2 AFTER INSERT on t2 FOR EACH ROW
+BEGIN
+UPDATE t3 SET a =2, b = 'master only';
+END|
+**** On Slave ****
+STOP SLAVE;
+**** On Master ****
+UPDATE t1 SET a = 2, b = 'master only' WHERE a = 1;
+DROP TRIGGER tr1;
+DROP TRIGGER tr2;
+INSERT INTO t1 VALUES (3,'master/slave');
+INSERT INTO t2 VALUES (3,'master/slave');
+INSERT INTO t3 VALUES (3,'master/slave');
+SELECT * FROM t1 ORDER BY a;
+a b
+2 master only
+3 master/slave
+SELECT * FROM t2 ORDER BY a;
+a b
+2 master only
+3 master/slave
+SELECT * FROM t3 ORDER BY a;
+a b
+2 master only
+3 master/slave
+*** On Slave ***
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+SELECT * FROM t1 ORDER BY a;
+a b
+1 master/slave
+3 master/slave
+SELECT * FROM t2 ORDER BY a;
+a b
+1 master/slave
+3 master/slave
+SELECT * FROM t3 ORDER BY a;
+a b
+1 master/slave
+3 master/slave
+DROP TABLE t1, t2, t3;
+**** Case 2: Row binlog format and transactional tables ****
+*** On Master ***
+CREATE TABLE t4 (a INT, b VARCHAR(20)) ENGINE=innodb;
+CREATE TABLE t5 (a INT, b VARCHAR(20)) ENGINE=innodb;
+CREATE TABLE t6 (a INT, b VARCHAR(20)) ENGINE=innodb;
+**** On Slave ****
+STOP SLAVE;
+*** On Master ***
+BEGIN;
+INSERT INTO t4 VALUES (2, 'master only');
+INSERT INTO t5 VALUES (2, 'master only');
+INSERT INTO t6 VALUES (2, 'master only');
+COMMIT;
+BEGIN;
+INSERT INTO t4 VALUES (3, 'master/slave');
+INSERT INTO t5 VALUES (3, 'master/slave');
+INSERT INTO t6 VALUES (3, 'master/slave');
+COMMIT;
+SELECT * FROM t4 ORDER BY a;
+a b
+2 master only
+3 master/slave
+SELECT * FROM t5 ORDER BY a;
+a b
+2 master only
+3 master/slave
+SELECT * FROM t6 ORDER BY a;
+a b
+2 master only
+3 master/slave
+*** On Slave ***
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+SELECT * FROM t4 ORDER BY a;
+a b
+3 master/slave
+SELECT * FROM t5 ORDER BY a;
+a b
+3 master/slave
+SELECT * FROM t6 ORDER BY a;
+a b
+3 master/slave
+**** On Slave ****
+STOP SLAVE;
+*** On Master ***
+BEGIN;
+INSERT INTO t4 VALUES (6, 'master only');
+INSERT INTO t5 VALUES (6, 'master only');
+INSERT INTO t6 VALUES (6, 'master only');
+COMMIT;
+BEGIN;
+INSERT INTO t4 VALUES (7, 'master only');
+INSERT INTO t5 VALUES (7, 'master only');
+INSERT INTO t6 VALUES (7, 'master only');
+COMMIT;
+SELECT * FROM t4 ORDER BY a;
+a b
+2 master only
+3 master/slave
+6 master only
+7 master only
+SELECT * FROM t5 ORDER BY a;
+a b
+2 master only
+3 master/slave
+6 master only
+7 master only
+SELECT * FROM t6 ORDER BY a;
+a b
+2 master only
+3 master/slave
+6 master only
+7 master only
+*** On Slave ***
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=10;
+START SLAVE;
+SELECT * FROM t4 ORDER BY a;
+a b
+3 master/slave
+SELECT * FROM t5 ORDER BY a;
+a b
+3 master/slave
+SELECT * FROM t6 ORDER BY a;
+a b
+3 master/slave
+STOP SLAVE;
+SET AUTOCOMMIT=0;
+INSERT INTO t4 VALUES (4, 'master only');
+INSERT INTO t5 VALUES (4, 'master only');
+INSERT INTO t6 VALUES (4, 'master only');
+COMMIT;
+INSERT INTO t4 VALUES (5, 'master/slave');
+INSERT INTO t5 VALUES (5, 'master/slave');
+INSERT INTO t6 VALUES (5, 'master/slave');
+COMMIT;
+SELECT * FROM t4 ORDER BY a;
+a b
+2 master only
+3 master/slave
+4 master only
+5 master/slave
+6 master only
+7 master only
+SELECT * FROM t5 ORDER BY a;
+a b
+2 master only
+3 master/slave
+4 master only
+5 master/slave
+6 master only
+7 master only
+SELECT * FROM t6 ORDER BY a;
+a b
+2 master only
+3 master/slave
+4 master only
+5 master/slave
+6 master only
+7 master only
+*** On Slave ***
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+SELECT * FROM t4 ORDER BY a;
+a b
+3 master/slave
+5 master/slave
+SELECT * FROM t5 ORDER BY a;
+a b
+3 master/slave
+5 master/slave
+SELECT * FROM t6 ORDER BY a;
+a b
+3 master/slave
+5 master/slave
+DROP TABLE t4, t5, t6;
+**** Case 3: Statement logging format and LOAD DATA with non-transactional table ****
+*** On Master ***
+CREATE TABLE t10 (a INT, b VARCHAR(20)) ENGINE=myisam;
+*** On Slave ***
+STOP SLAVE;
+*** On Master ***
+SET SESSION BINLOG_FORMAT=STATEMENT;
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat' INTO TABLE t10 FIELDS TERMINATED BY '|';
+SELECT * FROM t10 ORDER BY a;
+a b
+1 master only
+2 master only
+3 master only
+*** On Slave ***
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+SELECT * FROM t10 ORDER BY a;
+a b
+DROP TABLE t10;
diff --git a/mysql-test/suite/rpl/r/rpl_sp_effects.result b/mysql-test/suite/rpl/r/rpl_sp_effects.result
index c2c44b06972..a39d189aa3a 100644
--- a/mysql-test/suite/rpl/r/rpl_sp_effects.result
+++ b/mysql-test/suite/rpl/r/rpl_sp_effects.result
@@ -235,4 +235,45 @@ drop table t1;
drop function f1;
drop function f2;
drop procedure p1;
+create table t2 (b BIT(7));
+create procedure sp_bug26199(bitvalue BIT(7))
+begin
+insert into t2 set b = bitvalue;
+end //
+create function sf_bug26199(b BIT(7)) returns int
+begin
+insert into t2 values(b);
+return 0;
+end//
+call sp_bug26199(b'1110');
+call sp_bug26199('\0');
+select sf_bug26199(b'1111111');
+sf_bug26199(b'1111111')
+0
+select sf_bug26199(b'101111111');
+sf_bug26199(b'101111111')
+0
+Warnings:
+Warning 1264 Out of range value for column 'b' at row 1
+select sf_bug26199('\'');
+sf_bug26199('\'')
+0
+select hex(b) from t2;
+hex(b)
+E
+0
+7F
+7F
+27
+select hex(b) from t2;
+hex(b)
+E
+0
+7F
+7F
+27
+drop table t2;
+drop procedure sp_bug26199;
+drop function sf_bug26199;
SET GLOBAL log_bin_trust_function_creators = 0;
+end of the tests
diff --git a/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result b/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result
index c3f0c07b92c..8ed9ff5dc2f 100644
--- a/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result
+++ b/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result
@@ -405,6 +405,26 @@ CREATE TABLE t12 (data LONG);
LOCK TABLES t12 WRITE;
INSERT INTO t12 VALUES(UUID());
UNLOCK TABLES;
+CREATE FUNCTION my_user()
+RETURNS CHAR(64)
+BEGIN
+DECLARE user CHAR(64);
+SELECT USER() INTO user;
+RETURN user;
+END $$
+CREATE FUNCTION my_current_user()
+RETURNS CHAR(64)
+BEGIN
+DECLARE user CHAR(64);
+SELECT CURRENT_USER() INTO user;
+RETURN user;
+END $$
+DROP TABLE IF EXISTS t13;
+CREATE TABLE t13 (data CHAR(64));
+INSERT INTO t13 VALUES (USER());
+INSERT INTO t13 VALUES (my_user());
+INSERT INTO t13 VALUES (CURRENT_USER());
+INSERT INTO t13 VALUES (my_current_user());
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # drop database if exists mysqltest1
@@ -709,6 +729,30 @@ master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t12
master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t12 (data LONG)
master-bin.000001 # Table_map # # table_id: # (mysqltest1.t12)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_user()
+RETURNS CHAR(64)
+BEGIN
+DECLARE user CHAR(64);
+SELECT USER() INTO user;
+RETURN user;
+END
+master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_current_user()
+RETURNS CHAR(64)
+BEGIN
+DECLARE user CHAR(64);
+SELECT CURRENT_USER() INTO user;
+RETURN user;
+END
+master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t13
+master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t13 (data CHAR(64))
+master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # drop database if exists mysqltest1
@@ -1013,5 +1057,29 @@ master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t12
master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t12 (data LONG)
master-bin.000001 # Table_map # # table_id: # (mysqltest1.t12)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_user()
+RETURNS CHAR(64)
+BEGIN
+DECLARE user CHAR(64);
+SELECT USER() INTO user;
+RETURN user;
+END
+master-bin.000001 # Query # # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` FUNCTION my_current_user()
+RETURNS CHAR(64)
+BEGIN
+DECLARE user CHAR(64);
+SELECT CURRENT_USER() INTO user;
+RETURN user;
+END
+master-bin.000001 # Query # # use `mysqltest1`; DROP TABLE IF EXISTS t13
+master-bin.000001 # Query # # use `mysqltest1`; CREATE TABLE t13 (data CHAR(64))
+master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Table_map # # table_id: # (mysqltest1.t13)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
drop database mysqltest1;
set global binlog_format =@my_binlog_format;
diff --git a/mysql-test/suite/rpl/r/rpl_temporary_errors.result b/mysql-test/suite/rpl/r/rpl_temporary_errors.result
new file mode 100644
index 00000000000..5c681683b08
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_temporary_errors.result
@@ -0,0 +1,81 @@
+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;
+**** On Master ****
+SET SESSION BINLOG_FORMAT=ROW;
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
+INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4);
+**** On Slave ****
+SHOW STATUS LIKE 'Slave_retried_transactions';
+Variable_name Value
+Slave_retried_transactions 0
+UPDATE t1 SET a = 5, b = 47 WHERE a = 1;
+SELECT * FROM t1;
+a b
+5 47
+2 2
+3 3
+4 4
+**** On Master ****
+UPDATE t1 SET a = 5, b = 5 WHERE a = 1;
+SELECT * FROM t1;
+a b
+5 5
+2 2
+3 3
+4 4
+**** On Slave ****
+SHOW STATUS LIKE 'Slave_retried_transactions';
+Variable_name Value
+Slave_retried_transactions 0
+SELECT * FROM t1;
+a b
+5 47
+2 2
+3 3
+4 4
+SHOW SLAVE STATUS;
+Slave_IO_State #
+Master_Host 127.0.0.1
+Master_User root
+Master_Port MASTER_PORT
+Connect_Retry 1
+Master_Log_File master-bin.000001
+Read_Master_Log_Pos 408
+Relay_Log_File #
+Relay_Log_Pos #
+Relay_Master_Log_File master-bin.000001
+Slave_IO_Running Yes
+Slave_SQL_Running Yes
+Replicate_Do_DB
+Replicate_Ignore_DB
+Replicate_Do_Table
+Replicate_Ignore_Table #
+Replicate_Wild_Do_Table
+Replicate_Wild_Ignore_Table
+Last_Errno 0
+Last_Error
+Skip_Counter 0
+Exec_Master_Log_Pos 408
+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 #
+Master_SSL_Verify_Server_Cert No
+Last_IO_Errno #
+Last_IO_Error #
+Last_SQL_Errno 0
+Last_SQL_Error
+DROP TABLE t1;
+**** On Master ****
+DROP TABLE t1;
diff --git a/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result b/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result
index c7ef28ba56b..7eee31dab7a 100644
--- a/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result
+++ b/mysql-test/suite/rpl/r/rpl_truncate_2myisam.result
@@ -4,6 +4,11 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=STATEMENT;
SET GLOBAL BINLOG_FORMAT=STATEMENT;
@@ -31,10 +36,17 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=MIXED;
SET GLOBAL BINLOG_FORMAT=MIXED;
@@ -62,10 +74,17 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=ROW;
SET GLOBAL BINLOG_FORMAT=ROW;
@@ -93,11 +112,18 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=STATEMENT;
SET GLOBAL BINLOG_FORMAT=STATEMENT;
@@ -125,10 +151,17 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
master-bin.000001 # Query # # use `test`; DELETE FROM t1
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=MIXED;
SET GLOBAL BINLOG_FORMAT=MIXED;
@@ -156,10 +189,17 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
master-bin.000001 # Query # # use `test`; DELETE FROM t1
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=ROW;
SET GLOBAL BINLOG_FORMAT=ROW;
@@ -188,9 +228,11 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=MyISAM
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
diff --git a/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result b/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result
index 7ce48c2e983..a6580a5685b 100644
--- a/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result
+++ b/mysql-test/suite/rpl/r/rpl_truncate_3innodb.result
@@ -4,6 +4,11 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=STATEMENT;
SET GLOBAL BINLOG_FORMAT=STATEMENT;
@@ -31,12 +36,19 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=MIXED;
SET GLOBAL BINLOG_FORMAT=MIXED;
@@ -64,12 +76,19 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=ROW;
SET GLOBAL BINLOG_FORMAT=ROW;
@@ -97,6 +116,7 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
@@ -104,6 +124,12 @@ master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=STATEMENT;
SET GLOBAL BINLOG_FORMAT=STATEMENT;
@@ -131,12 +157,19 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; DELETE FROM t1
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=MIXED;
SET GLOBAL BINLOG_FORMAT=MIXED;
@@ -164,12 +197,19 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; DELETE FROM t1
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
+STOP SLAVE;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1;
+RESET SLAVE;
+START SLAVE;
**** On Master ****
SET SESSION BINLOG_FORMAT=ROW;
SET GLOBAL BINLOG_FORMAT=ROW;
@@ -198,6 +238,7 @@ a b
DROP TABLE t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b LONG) ENGINE=InnoDB
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
@@ -206,3 +247,4 @@ master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; DROP TABLE t1
+RESET MASTER;
diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def
index 426bf93ae97..e9aeb31efe9 100644
--- a/mysql-test/suite/rpl/t/disabled.def
+++ b/mysql-test/suite/rpl/t/disabled.def
@@ -11,7 +11,7 @@
##############################################################################
rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master
-rpl_invoked_features : BUG#29020 2007-06-21 Lars Non-deterministic test case
rpl_auto_increment_11932 : Bug#29809 2007-07-16 ingo Slave SQL errors in warnings file
+rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported.
rpl_extraColmaster_innodb : BUG#30854 : Tables name show as binary in slave err msg on vm-win2003-64-b and Solaris
rpl_extraColmaster_myisam : BUG#30854
diff --git a/mysql-test/suite/rpl/t/rpl_bug31076.test b/mysql-test/suite/rpl/t/rpl_bug31076.test
index cc8b26ac8f4..1c7b0ca0fd1 100644
--- a/mysql-test/suite/rpl/t/rpl_bug31076.test
+++ b/mysql-test/suite/rpl/t/rpl_bug31076.test
@@ -114,4 +114,5 @@ SELECT * FROM visits_events;
# Cleanup
DROP DATABASE track;
+sync_slave_with_master;
--echo End of 5.1 tests
diff --git a/mysql-test/suite/rpl/t/rpl_dual_pos_advance.test b/mysql-test/suite/rpl/t/rpl_dual_pos_advance.test
index 27c920a3186..83c15d691be 100644
--- a/mysql-test/suite/rpl/t/rpl_dual_pos_advance.test
+++ b/mysql-test/suite/rpl/t/rpl_dual_pos_advance.test
@@ -106,9 +106,3 @@ connection slave;
sync_with_master;
# End of 4.1 tests
-
-# Cleanup
-# The A->B->A replication causes the master to start writing relay logs
-# in var/run, remove them
-remove_file $MYSQLTEST_VARDIR/run/master-relay-bin.000001;
-remove_file $MYSQLTEST_VARDIR/run/master-relay-bin.index;
diff --git a/mysql-test/suite/rpl/t/rpl_found_rows.test b/mysql-test/suite/rpl/t/rpl_found_rows.test
new file mode 100644
index 00000000000..f868061c951
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_found_rows.test
@@ -0,0 +1,256 @@
+source include/master-slave.inc;
+
+# It is not possible to replicate FOUND_ROWS() using statement-based
+# replication, but there is a workaround that stores the result of
+# FOUND_ROWS() into a user variable and then replicates this instead.
+
+# The purpose of this test case is to test that the workaround
+# function properly even when inside stored programs (i.e., stored
+# routines and triggers).
+
+--echo ==== 0. Setting it all up ====
+
+SET BINLOG_FORMAT=STATEMENT;
+
+--echo **** On Master ****
+connection master;
+CREATE TABLE t1 (a INT);
+CREATE TABLE logtbl (sect INT, test INT, count INT);
+
+INSERT INTO t1 VALUES (1),(2),(3);
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+INSERT INTO t1 SELECT 2*a+3 FROM t1;
+
+--echo #### 1. Using statement mode ####
+
+--echo ==== 1.1. Simple test ====
+
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+
+# Instead of
+# INSERT INTO logtbl VALUES(1, 1, FOUND_ROWS());
+# we write
+SELECT FOUND_ROWS() INTO @a;
+INSERT INTO logtbl VALUES(1,1,@a);
+
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
+# Instead of
+# INSERT INTO logtbl VALUES(1, 2, FOUND_ROWS());
+# we write
+SELECT FOUND_ROWS() INTO @a;
+INSERT INTO logtbl VALUES(1,2,@a);
+
+SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
+--echo **** On Slave ****
+sync_slave_with_master;
+SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
+
+--echo ==== 1.2. Stored procedure ====
+
+# Here we do both the calculation and the logging. We also do it twice
+# to make sure that there are no limitations on how many times it can
+# be used.
+
+--echo **** On Master ****
+connection master;
+--delimiter $$
+CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN
+ DECLARE cnt INT;
+ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
+ SELECT FOUND_ROWS() INTO cnt;
+ INSERT INTO logtbl VALUES(sect,test,cnt);
+ SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+ SELECT FOUND_ROWS() INTO cnt;
+ INSERT INTO logtbl VALUES(sect,test+1,cnt);
+END $$
+--delimiter ;
+
+CALL calc_and_log(2,1);
+
+--delimiter $$
+CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN
+ INSERT INTO logtbl VALUES (sect,test,found_rows);
+END $$
+--delimiter ;
+
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+SELECT FOUND_ROWS() INTO @found_rows;
+CALL just_log(2,3,@found_rows);
+
+SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
+--echo **** On Slave ****
+sync_slave_with_master;
+SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
+
+--echo ==== 1.3. Stored functions ====
+--echo **** On Master ****
+connection master;
+--delimiter $$
+CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT)
+ RETURNS INT
+BEGIN
+ INSERT INTO logtbl VALUES(sect,test,found_rows);
+ RETURN found_rows;
+END $$
+--delimiter ;
+
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+SELECT FOUND_ROWS() INTO @found_rows;
+SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows);
+
+SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
+--echo **** On Slave ****
+sync_slave_with_master;
+SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
+
+--echo ==== 1.9. Cleanup ====
+--echo **** On Master ****
+connection master;
+DELETE FROM logtbl;
+DROP PROCEDURE just_log;
+DROP PROCEDURE calc_and_log;
+DROP FUNCTION log_rows;
+sync_slave_with_master;
+
+source include/reset_master_and_slave.inc;
+
+--echo #### 2. Using mixed mode ####
+
+--echo ==== 2.1. Checking a procedure ====
+
+--echo **** On Master ****
+connection master;
+SET BINLOG_FORMAT=MIXED;
+
+# We will now check some stuff that will not work in statement-based
+# replication, but which should cause the binary log to switch to
+# row-based logging.
+
+--delimiter $$
+CREATE PROCEDURE just_log(sect INT, test INT) BEGIN
+ INSERT INTO logtbl VALUES (sect,test,FOUND_ROWS());
+END $$
+--delimiter ;
+sync_slave_with_master;
+
+--echo **** On Master 1 ****
+connection master1;
+SET BINLOG_FORMAT=MIXED;
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+CALL just_log(1,1);
+
+--echo **** On Master ****
+connection master;
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+CALL just_log(1,2);
+
+--echo **** On Master 1 ****
+
+connection master1;
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
+CALL just_log(1,3);
+sync_slave_with_master;
+
+--echo **** On Master ****
+connection master;
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+CALL just_log(1,4);
+sync_slave_with_master;
+
+connection master;
+SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
+--echo **** On Slave ****
+sync_slave_with_master;
+SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
+
+--echo ==== 2.1. Checking a stored function ====
+--echo **** On Master ****
+connection master;
+--delimiter $$
+CREATE FUNCTION log_rows(sect INT, test INT)
+ RETURNS INT
+BEGIN
+ DECLARE found_rows INT;
+ SELECT FOUND_ROWS() INTO found_rows;
+ INSERT INTO logtbl VALUES(sect,test,found_rows);
+ RETURN found_rows;
+END $$
+--delimiter ;
+
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
+SELECT log_rows(2,1), log_rows(2,2);
+
+CREATE TABLE t2 (a INT, b INT);
+
+# Trying with referencing FOUND_ROWS() directly in the trigger.
+
+--delimiter $$
+CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW
+BEGIN
+ INSERT INTO logtbl VALUES (NEW.a, NEW.b, FOUND_ROWS());
+END $$
+--delimiter ;
+
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
+INSERT INTO t2 VALUES (2,3), (2,4);
+
+# Referencing FOUND_ROWS() indirectly.
+
+DROP TRIGGER t2_tr;
+
+--delimiter $$
+CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW
+BEGIN
+ DECLARE dummy INT;
+ SELECT log_rows(NEW.a, NEW.b) INTO dummy;
+END $$
+--delimiter ;
+
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+INSERT INTO t2 VALUES (2,5), (2,6);
+
+# Putting FOUND_ROWS() even lower in the call chain.
+
+connection master;
+DROP TRIGGER t2_tr;
+
+--delimiter $$
+CREATE PROCEDURE log_me_inner(sect INT, test INT)
+BEGIN
+ DECLARE dummy INT;
+ SELECT log_rows(sect, test) INTO dummy;
+ SELECT log_rows(sect, test+1) INTO dummy;
+END $$
+
+CREATE PROCEDURE log_me(sect INT, test INT)
+BEGIN
+ CALL log_me_inner(sect,test);
+END $$
+--delimiter ;
+
+--delimiter $$
+CREATE TRIGGER t2_tr BEFORE INSERT ON t2 FOR EACH ROW
+BEGIN
+ CALL log_me(NEW.a, NEW.b);
+END $$
+--delimiter ;
+
+SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
+INSERT INTO t2 VALUES (2,5), (2,6);
+
+SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
+sync_slave_with_master;
+SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
+
+connection master;
+DROP TABLE t1, logtbl;
+DROP PROCEDURE just_log;
+DROP PROCEDURE log_me;
+DROP PROCEDURE log_me_inner;
+DROP FUNCTION log_rows;
+sync_slave_with_master;
+
diff --git a/mysql-test/suite/rpl/t/rpl_idempotency.test b/mysql-test/suite/rpl/t/rpl_idempotency.test
new file mode 100644
index 00000000000..44956b7b459
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_idempotency.test
@@ -0,0 +1,79 @@
+# Testing various forms of idempotency for replication that should
+# work the same way under statement based as under row based.
+
+source include/master-slave.inc;
+
+connection master;
+CREATE TABLE t1 (a INT PRIMARY KEY);
+CREATE TABLE t2 (a INT);
+INSERT INTO t1 VALUES (-1),(-2),(-3);
+INSERT INTO t2 VALUES (-1),(-2),(-3);
+sync_slave_with_master;
+
+# A delete for a row that does not exist, the statement is
+# deliberately written to be idempotent for statement-based
+# replication as well. We test this towards both a table with a
+# primary key and without a primary key.
+
+connection slave;
+DELETE FROM t1 WHERE a = -2;
+DELETE FROM t2 WHERE a = -2;
+connection master;
+DELETE FROM t1 WHERE a = -2;
+DELETE FROM t2 WHERE a = -2;
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+sync_slave_with_master;
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
+disable_query_log;
+eval SELECT "$last_error" AS Last_SQL_Error;
+enable_query_log;
+
+# An insert of a row that already exists. Since we are replacing the
+# row if it already exists, the most apropriate representation is
+# INSERT IGNORE. We only test this towards a table with a primary key,
+# since the other case does not make sense.
+
+INSERT IGNORE INTO t1 VALUES (-2);
+connection master;
+INSERT IGNORE INTO t1 VALUES (-2);
+SELECT * FROM t1 ORDER BY a;
+sync_slave_with_master;
+SELECT * FROM t1 ORDER BY a;
+let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
+disable_query_log;
+eval SELECT "$last_error" AS Last_SQL_Error;
+enable_query_log;
+
+# BUG#19958: RBR idempotency issue for UPDATE and DELETE
+
+# Statement-based and row-based replication have different behaviour
+# when updating a row with an explicit WHERE-clause that matches
+# exactly one row (or no row at all). For statement-based replication,
+# the statement is idempotent since the first time it is executed, it
+# will update exactly one row, and the second time it will not update
+# any row at all. This was not the case for row-based replication, so
+# we test under both row-based and statement-based replication both
+# for tables with and without primary keys.
+
+connection slave;
+UPDATE t1 SET a = 1 WHERE a = -1;
+UPDATE t2 SET a = 1 WHERE a = -1;
+connection master;
+UPDATE t1 SET a = 1 WHERE a = -1;
+UPDATE t2 SET a = 1 WHERE a = -1;
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+sync_slave_with_master;
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
+disable_query_log;
+eval SELECT "$last_error" AS Last_SQL_Error;
+enable_query_log;
+
+connection master;
+DROP TABLE t1, t2;
+sync_slave_with_master;
diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test
index 74954299920..eb828f07415 100644
--- a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test
+++ b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test
@@ -136,8 +136,7 @@ SELECT count(*) as "Master byrange" FROM test.byrange_tbl;
--sync_slave_with_master
connection slave;
show create table test.byrange_tbl;
---replace_column 4 MASTER_PORT 33 #
-show slave status;
+source include/show_slave_status.inc;
SELECT count(*) "Slave norm" FROM test.regular_tbl;
SELECT count(*) "Slave bykey" FROM test.bykey_tbl;
SELECT count(*) "Slave byrange" FROM test.byrange_tbl;
diff --git a/mysql-test/suite/rpl/t/rpl_invoked_features.test b/mysql-test/suite/rpl/t/rpl_invoked_features.test
index e797e0552ef..2e69c0fabd9 100644
--- a/mysql-test/suite/rpl/t/rpl_invoked_features.test
+++ b/mysql-test/suite/rpl/t/rpl_invoked_features.test
@@ -8,10 +8,9 @@
--source include/master-slave.inc
--source include/have_innodb.inc
-
-#
-# Define variables used by test case
-#
+# --disable_warnings/--enable_warnings added before/after query
+# if one uses UUID() function because we need to avoid warnings
+# for STATEMENT binlog format
# Non-transactional engine
--let $engine_type= myisam
@@ -45,20 +44,24 @@ DROP EVENT IF EXISTS e11;
--echo
eval CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=$engine_type;
---disable_warnings
INSERT INTO t1 VALUES (1,1,'1');
+--disable_warnings
INSERT INTO t1 VALUES (2,2,UUID());
-eval CREATE TABLE t2 (a INT, b INT, c VARCHAR(64)) ENGINE=$engine_type;
+--enable_warnings
+eval CREATE TABLE t2 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=$engine_type;
INSERT INTO t2 VALUES (1,1,'1');
+--disable_warnings
INSERT INTO t2 VALUES (2,2,UUID());
--enable_warnings
eval CREATE TABLE t11 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=$engine_type2;
---disable_warnings
INSERT INTO t11 VALUES (1,1,'1');
+--disable_warnings
INSERT INTO t11 VALUES (2,2,UUID());
-eval CREATE TABLE t12 (a INT, b INT, c VARCHAR(64)) ENGINE=$engine_type2;
+--enable_warnings
+eval CREATE TABLE t12 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=$engine_type2;
INSERT INTO t12 VALUES (1,1,'1');
+--disable_warnings
INSERT INTO t12 VALUES (2,2,UUID());
--enable_warnings
@@ -96,22 +99,16 @@ BEGIN
END|
# Create events which will run every 1 sec
-CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND ENABLE DO
+CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND DISABLE DO
BEGIN
- DECLARE c INT;
- SELECT a INTO c FROM t1 WHERE a < 11 ORDER BY a DESC LIMIT 1;
- IF c = 7 THEN
- CALL p1(10, '');
- END IF;
+ ALTER EVENT e1 DISABLE;
+ CALL p1(10, '');
END|
-CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND ENABLE DO
+CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND DISABLE DO
BEGIN
- DECLARE c INT;
- SELECT a INTO c FROM t11 WHERE a < 11 ORDER BY a DESC LIMIT 1;
- IF c = 7 THEN
- CALL p11(10, '');
- END IF;
+ ALTER EVENT e11 DISABLE;
+ CALL p11(10, '');
END|
# Create functions and procedures used for events
@@ -130,12 +127,12 @@ END|
CREATE PROCEDURE p1 (IN x INT, IN y VARCHAR(64))
BEGIN
- INSERT INTO t1 VALUES (x,x,y);
+ INSERT IGNORE INTO t1 VALUES (x,x,y);
END|
CREATE PROCEDURE p11 (IN x INT, IN y VARCHAR(64))
BEGIN
- INSERT INTO t11 VALUES (x,x,y);
+ INSERT IGNORE INTO t11 VALUES (x,x,y);
END|
DELIMITER ;|
@@ -147,17 +144,24 @@ DELIMITER ;|
# Do some actions for non-transactional tables
--echo
---disable_warnings
CREATE TABLE t3 SELECT * FROM v1;
INSERT INTO t1 VALUES (3,3,'');
UPDATE t1 SET c='2' WHERE a = 1;
+--disable_warnings
INSERT INTO t1 VALUES(4,4,f1(4));
+--enable_warnings
INSERT INTO t1 VALUES (100,100,'');
+--disable_warnings
CALL p1(5, UUID());
+--enable_warnings
INSERT INTO t1 VALUES (101,101,'');
+--disable_warnings
INSERT INTO t1 VALUES(6,6,f1(6));
+--enable_warnings
INSERT INTO t1 VALUES (102,102,'');
+--disable_warnings
INSERT INTO t1 VALUES(7,7,f2(7));
+--enable_warnings
INSERT INTO t1 VALUES (103,103,'');
# Do some actions for transactional tables
@@ -165,21 +169,34 @@ INSERT INTO t1 VALUES (103,103,'');
CREATE TABLE t13 SELECT * FROM v11;
INSERT INTO t11 VALUES (3,3,'');
UPDATE t11 SET c='2' WHERE a = 1;
+--disable_warnings
INSERT INTO t11 VALUES(4,4,f1(4));
+--enable_warnings
INSERT INTO t11 VALUES (100,100,'');
+--disable_warnings
CALL p11(5, UUID());
+--enable_warnings
INSERT INTO t11 VALUES (101,101,'');
+--disable_warnings
INSERT INTO t11 VALUES(6,6,f1(6));
+--enable_warnings
INSERT INTO t11 VALUES (102,102,'');
+--disable_warnings
INSERT INTO t11 VALUES(7,7,f2(7));
-INSERT INTO t11 VALUES (103,103,'');
--enable_warnings
+INSERT INTO t11 VALUES (103,103,'');
# Scheduler is on
--echo
+# Temporally events fire sequentally due Bug#29020.
SET GLOBAL EVENT_SCHEDULER = on;
-# Wait 2 sec while events will executed
---sleep 2
+# Wait while events will executed
+ALTER EVENT e1 ENABLE;
+let $wait_condition= SELECT COUNT(*) = 1 FROM t1 WHERE t1.a = 10;
+--source include/wait_condition.inc
+ALTER EVENT e11 ENABLE;
+let $wait_condition= SELECT COUNT(*) = 1 FROM t11 WHERE t11.a = 10;
+--source include/wait_condition.inc
SET GLOBAL EVENT_SCHEDULER = off;
# Check original objects
@@ -234,7 +251,7 @@ SELECT COUNT(*) FROM t13;
SELECT a,b FROM t13 ORDER BY a;
SELECT a,b FROM v11 ORDER BY a;
-# Remove UUID() before comparing
+# Remove UUID() before comparing and sort tables
--connection master
--echo
@@ -245,6 +262,9 @@ UPDATE t11 SET c='';
UPDATE t12 SET c='';
UPDATE t13 SET c='';
+ALTER TABLE t3 ORDER BY a;
+ALTER TABLE t13 ORDER BY a;
+
--sync_slave_with_master slave
# Compare a data from master and slave
@@ -260,13 +280,12 @@ UPDATE t13 SET c='';
# Remove dumps
--echo
---exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql
---exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql
+--remove_file $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql
+--remove_file $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql
# Remove tables,views,procedures,functions
--connection master
--echo
---disable_warnings
DROP VIEW IF EXISTS v1,v11;
DROP TABLE IF EXISTS t1,t2,t3,t11,t12,t13;
DROP PROCEDURE IF EXISTS p1;
@@ -275,7 +294,6 @@ DROP FUNCTION IF EXISTS f1;
DROP FUNCTION IF EXISTS f2;
DROP EVENT IF EXISTS e1;
DROP EVENT IF EXISTS e11;
---enable_warnings
--sync_slave_with_master slave
diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test
index 316278cb75d..0e17ae3144c 100644
--- a/mysql-test/suite/rpl/t/rpl_packet.test
+++ b/mysql-test/suite/rpl/t/rpl_packet.test
@@ -66,16 +66,11 @@ CREATE TABLe `t1` (`f1` LONGTEXT) ENGINE=MyISAM;
INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048');
# The slave I/O thread must stop after trying to read the above event
-connection slave;
-sleep 2;
---source include/wait_for_slave_io_to_stop.inc
-SHOW STATUS LIKE 'Slave_running';
-
-# cleanup
-#connection master;
-#drop table t1;
-#connection slave;
-#drop table t1;
-
+connection slave;
+--source include/wait_for_slave_io_to_stop.inc
+--replace_result $MASTER_MYPORT MASTER_MYPORT
+# import is only the 11th column Slave_IO_Running
+--replace_column 1 # 7 # 8 # 9 # 12 # 22 # 23 # 33 #
+query_vertical show slave status;
# End of tests
diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
index fb43664f121..07fe763eb3c 100644
--- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
+++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
@@ -223,3 +223,38 @@ connection master;
drop table t1,t2;
sync_slave_with_master;
+
+#
+# BUG#31702: Missing row on slave causes assertion failure under
+# row-based replication
+#
+
+disable_query_log;
+source include/master-slave-reset.inc;
+enable_query_log;
+
+--echo **** On Master ****
+connection master;
+SET SESSION BINLOG_FORMAT=ROW;
+CREATE TABLE t1 (a INT PRIMARY KEY, b SET('master','slave'));
+INSERT INTO t1 VALUES (1,'master,slave'), (2,'master,slave');
+--echo **** On Slave ****
+sync_slave_with_master;
+UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1;
+SELECT * FROM t1 ORDER BY a;
+--echo **** On Master ****
+connection master;
+UPDATE t1 SET a = 5, b = 'master' WHERE a = 1;
+SELECT * FROM t1 ORDER BY a;
+--echo **** On Slave ****
+sync_slave_with_master;
+let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
+disable_query_log;
+eval SELECT "$last_error" AS Last_SQL_Error;
+enable_query_log;
+SELECT * FROM t1 ORDER BY a;
+DROP TABLE t1;
+
+--echo **** On Master ****
+connection master;
+DROP TABLE t1;
diff --git a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test
index dd46d64f684..be76ac9f3f6 100644
--- a/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test
+++ b/mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test
@@ -344,5 +344,6 @@ FLUSH LOGS;
--exec rm $MYSQLTEST_VARDIR/tmp/local.sql
DROP TABLE IF EXISTS t1, t2, t3, t04, t05, t4, t5;
+sync_slave_with_master;
# End of 4.1 tests
diff --git a/mysql-test/suite/rpl/t/rpl_row_until.test b/mysql-test/suite/rpl/t/rpl_row_until.test
index 9464e5cfadd..610eec305df 100644
--- a/mysql-test/suite/rpl/t/rpl_row_until.test
+++ b/mysql-test/suite/rpl/t/rpl_row_until.test
@@ -13,6 +13,8 @@ save_master_pos;
connection slave;
sync_with_master;
stop slave;
+# Make sure the slave sql and io thread has stopped
+--source include/wait_for_slave_to_stop.inc
connection master;
# create some events on master
@@ -52,6 +54,8 @@ save_master_pos;
connection slave;
sync_with_master;
stop slave;
+# Make sure the slave sql and io thread has stopped
+--source include/wait_for_slave_to_stop.inc
# this should stop immediately as we are already there
start slave until master_log_file='master-bin.000001', master_log_pos=740;
diff --git a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt
index c84171976a1..a8f5deaa30b 100644
--- a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt
+++ b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt
@@ -1 +1 @@
---slave-skip-error=1062,1582
+--slave-skip-error=1062
diff --git a/mysql-test/suite/rpl/t/rpl_skip_error.test b/mysql-test/suite/rpl/t/rpl_skip_error.test
index b68b637b3b0..72d434d9c9b 100644
--- a/mysql-test/suite/rpl/t/rpl_skip_error.test
+++ b/mysql-test/suite/rpl/t/rpl_skip_error.test
@@ -3,6 +3,14 @@
#########################################
# Note that errors are ignored by opt file.
source include/master-slave.inc;
+source include/have_binlog_format_mixed_or_statement.inc;
+
+#
+# Bug #30594
+# Skipping error due to applying Row-based repliation events
+# should be checked with another test file
+# consider names like rpl_row_skip_error
+#
create table t1 (n int not null primary key);
save_master_pos;
diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt b/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt
new file mode 100644
index 00000000000..627becdbfb5
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt
@@ -0,0 +1 @@
+--innodb
diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip.test b/mysql-test/suite/rpl/t/rpl_slave_skip.test
index b19d6a2730b..6783098fd7c 100644
--- a/mysql-test/suite/rpl/t/rpl_slave_skip.test
+++ b/mysql-test/suite/rpl/t/rpl_slave_skip.test
@@ -1,7 +1,9 @@
source include/master-slave.inc;
+source include/have_innodb.inc;
--echo **** On Slave ****
connection slave;
+source include/have_innodb.inc;
STOP SLAVE;
--echo **** On Master ****
@@ -69,3 +71,240 @@ query_vertical SHOW SLAVE STATUS;
connection master;
DROP TABLE t1, t2;
sync_slave_with_master;
+
+#
+# More tests for BUG#28618
+#
+# Case 1.
+# ROW binlog format and non-transactional tables.
+# Create the group of events via triggers and try to skip
+# some items of that group.
+#
+
+connection master;
+SET SESSION BINLOG_FORMAT=ROW;
+SET AUTOCOMMIT=0;
+
+CREATE TABLE t1 (a INT, b VARCHAR(20)) ENGINE=myisam;
+CREATE TABLE t2 (a INT, b VARCHAR(20)) ENGINE=myisam;
+CREATE TABLE t3 (a INT, b VARCHAR(20)) ENGINE=myisam;
+
+INSERT INTO t1 VALUES (1,'master/slave');
+INSERT INTO t2 VALUES (1,'master/slave');
+INSERT INTO t3 VALUES (1,'master/slave');
+
+DELIMITER |;
+
+CREATE TRIGGER tr1 AFTER UPDATE on t1 FOR EACH ROW
+BEGIN
+ INSERT INTO t2 VALUES (NEW.a,NEW.b);
+ DELETE FROM t2 WHERE a < NEW.a;
+END|
+
+CREATE TRIGGER tr2 AFTER INSERT on t2 FOR EACH ROW
+BEGIN
+ UPDATE t3 SET a =2, b = 'master only';
+END|
+
+DELIMITER ;|
+
+--echo **** On Slave ****
+sync_slave_with_master;
+STOP SLAVE;
+source include/wait_for_slave_to_stop.inc;
+
+--echo **** On Master ****
+connection master;
+UPDATE t1 SET a = 2, b = 'master only' WHERE a = 1;
+DROP TRIGGER tr1;
+DROP TRIGGER tr2;
+INSERT INTO t1 VALUES (3,'master/slave');
+INSERT INTO t2 VALUES (3,'master/slave');
+INSERT INTO t3 VALUES (3,'master/slave');
+
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+SELECT * FROM t3 ORDER BY a;
+
+save_master_pos;
+
+--echo *** On Slave ***
+connection slave;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+source include/wait_for_slave_to_start.inc;
+sync_with_master;
+
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+SELECT * FROM t3 ORDER BY a;
+
+connection master;
+DROP TABLE t1, t2, t3;
+sync_slave_with_master;
+
+--echo **** Case 2: Row binlog format and transactional tables ****
+
+# Create the transaction and try to skip some
+# queries from one.
+
+--echo *** On Master ***
+connection master;
+CREATE TABLE t4 (a INT, b VARCHAR(20)) ENGINE=innodb;
+CREATE TABLE t5 (a INT, b VARCHAR(20)) ENGINE=innodb;
+CREATE TABLE t6 (a INT, b VARCHAR(20)) ENGINE=innodb;
+
+--echo **** On Slave ****
+sync_slave_with_master;
+STOP SLAVE;
+source include/wait_for_slave_to_stop.inc;
+
+--echo *** On Master ***
+connection master;
+BEGIN;
+INSERT INTO t4 VALUES (2, 'master only');
+INSERT INTO t5 VALUES (2, 'master only');
+INSERT INTO t6 VALUES (2, 'master only');
+COMMIT;
+
+BEGIN;
+INSERT INTO t4 VALUES (3, 'master/slave');
+INSERT INTO t5 VALUES (3, 'master/slave');
+INSERT INTO t6 VALUES (3, 'master/slave');
+COMMIT;
+
+SELECT * FROM t4 ORDER BY a;
+SELECT * FROM t5 ORDER BY a;
+SELECT * FROM t6 ORDER BY a;
+
+save_master_pos;
+
+--echo *** On Slave ***
+connection slave;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+source include/wait_for_slave_to_start.inc;
+sync_with_master;
+
+SELECT * FROM t4 ORDER BY a;
+SELECT * FROM t5 ORDER BY a;
+SELECT * FROM t6 ORDER BY a;
+
+# Test skipping two groups
+
+--echo **** On Slave ****
+connection slave;
+STOP SLAVE;
+source include/wait_for_slave_to_stop.inc;
+
+--echo *** On Master ***
+connection master;
+BEGIN;
+INSERT INTO t4 VALUES (6, 'master only');
+INSERT INTO t5 VALUES (6, 'master only');
+INSERT INTO t6 VALUES (6, 'master only');
+COMMIT;
+
+BEGIN;
+INSERT INTO t4 VALUES (7, 'master only');
+INSERT INTO t5 VALUES (7, 'master only');
+INSERT INTO t6 VALUES (7, 'master only');
+COMMIT;
+
+SELECT * FROM t4 ORDER BY a;
+SELECT * FROM t5 ORDER BY a;
+SELECT * FROM t6 ORDER BY a;
+
+save_master_pos;
+
+--echo *** On Slave ***
+connection slave;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=10;
+START SLAVE;
+source include/wait_for_slave_to_start.inc;
+sync_with_master;
+
+SELECT * FROM t4 ORDER BY a;
+SELECT * FROM t5 ORDER BY a;
+SELECT * FROM t6 ORDER BY a;
+
+#
+# And the same, but with autocommit = 0
+#
+connection slave;
+STOP SLAVE;
+source include/wait_for_slave_to_stop.inc;
+
+connection master;
+SET AUTOCOMMIT=0;
+
+INSERT INTO t4 VALUES (4, 'master only');
+INSERT INTO t5 VALUES (4, 'master only');
+INSERT INTO t6 VALUES (4, 'master only');
+COMMIT;
+
+INSERT INTO t4 VALUES (5, 'master/slave');
+INSERT INTO t5 VALUES (5, 'master/slave');
+INSERT INTO t6 VALUES (5, 'master/slave');
+COMMIT;
+
+SELECT * FROM t4 ORDER BY a;
+SELECT * FROM t5 ORDER BY a;
+SELECT * FROM t6 ORDER BY a;
+
+save_master_pos;
+
+--echo *** On Slave ***
+connection slave;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+source include/wait_for_slave_to_start.inc;
+sync_with_master;
+
+SELECT * FROM t4 ORDER BY a;
+SELECT * FROM t5 ORDER BY a;
+SELECT * FROM t6 ORDER BY a;
+
+connection master;
+DROP TABLE t4, t5, t6;
+sync_slave_with_master;
+
+--echo **** Case 3: Statement logging format and LOAD DATA with non-transactional table ****
+
+# LOAD DATA creates two events in binary log for statement binlog format.
+# Try to skip the first.
+
+--echo *** On Master ***
+connection master;
+CREATE TABLE t10 (a INT, b VARCHAR(20)) ENGINE=myisam;
+
+--echo *** On Slave ***
+sync_slave_with_master;
+STOP SLAVE;
+source include/wait_for_slave_to_stop.inc;
+
+--echo *** On Master ***
+connection master;
+SET SESSION BINLOG_FORMAT=STATEMENT;
+exec cp ./suite/rpl/data/rpl_bug28618.dat $MYSQLTEST_VARDIR/tmp/;
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat' INTO TABLE t10 FIELDS TERMINATED BY '|';
+remove_file $MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat;
+
+SELECT * FROM t10 ORDER BY a;
+
+save_master_pos;
+
+--echo *** On Slave ***
+connection slave;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
+START SLAVE;
+source include/wait_for_slave_to_start.inc;
+sync_with_master;
+
+SELECT * FROM t10 ORDER BY a;
+
+connection master;
+DROP TABLE t10;
+sync_slave_with_master;
+
diff --git a/mysql-test/suite/rpl/t/rpl_sp_effects.test b/mysql-test/suite/rpl/t/rpl_sp_effects.test
index 027bfd69f36..c1092e3260f 100644
--- a/mysql-test/suite/rpl/t/rpl_sp_effects.test
+++ b/mysql-test/suite/rpl/t/rpl_sp_effects.test
@@ -201,6 +201,10 @@ sync_slave_with_master;
connection slave;
SELECT 'slave', a FROM t1 ORDER BY a;
+#
+# cleanup
+#
+
connection master;
drop table t1;
drop function f1;
@@ -208,4 +212,50 @@ drop function f2;
drop procedure p1;
sync_slave_with_master;
+#
+# bug#26199 Replication Failure on Slave when using stored procs
+# with bit-type parameters
+
+connection master;
+
+create table t2 (b BIT(7));
+delimiter //;
+create procedure sp_bug26199(bitvalue BIT(7))
+begin
+ insert into t2 set b = bitvalue;
+end //
+
+create function sf_bug26199(b BIT(7)) returns int
+begin
+ insert into t2 values(b);
+ return 0;
+end//
+
+DELIMITER ;//
+
+
+
+call sp_bug26199(b'1110');
+call sp_bug26199('\0');
+select sf_bug26199(b'1111111');
+select sf_bug26199(b'101111111');
+select sf_bug26199('\'');
+select hex(b) from t2;
+
+sync_slave_with_master;
+#connection slave;
+select hex(b) from t2;
+
+#
+# cleanup bug#26199
+#
+connection master;
+drop table t2;
+drop procedure sp_bug26199;
+drop function sf_bug26199;
+
+sync_slave_with_master;
+
SET GLOBAL log_bin_trust_function_creators = 0;
+
+--echo end of the tests
diff --git a/mysql-test/suite/rpl/t/rpl_stm_mystery22.test b/mysql-test/suite/rpl/t/rpl_stm_mystery22.test
index 017593fdfba..b43a734fffc 100644
--- a/mysql-test/suite/rpl/t/rpl_stm_mystery22.test
+++ b/mysql-test/suite/rpl/t/rpl_stm_mystery22.test
@@ -28,7 +28,7 @@ insert into t1 values(NULL,'new');
save_master_pos;
connection slave;
# wait until the slave tries to run the query, fails and aborts slave thread
-wait_for_slave_to_stop;
+source include/wait_for_slave_sql_error.inc;
select * from t1 order by n;
delete from t1 where n = 2;
--disable_warnings
diff --git a/mysql-test/suite/rpl/t/rpl_stm_until.test b/mysql-test/suite/rpl/t/rpl_stm_until.test
index 98e7e0e5eac..c8d3cb1823d 100644
--- a/mysql-test/suite/rpl/t/rpl_stm_until.test
+++ b/mysql-test/suite/rpl/t/rpl_stm_until.test
@@ -12,6 +12,8 @@ save_master_pos;
connection slave;
sync_with_master;
stop slave;
+# Make sure the slave sql and io thread has stopped
+--source include/wait_for_slave_to_stop.inc
connection master;
# create some events on master
@@ -51,6 +53,8 @@ save_master_pos;
connection slave;
sync_with_master;
stop slave;
+# Make sure the slave sql and io thread has stopped
+--source include/wait_for_slave_to_stop.inc
# this should stop immediately as we are already there
start slave until master_log_file='master-bin.000001', master_log_pos=776;
diff --git a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test
index b0012827db8..05dcb91ca28 100644
--- a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test
+++ b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test
@@ -518,6 +518,42 @@ CREATE TABLE t12 (data LONG);
LOCK TABLES t12 WRITE;
INSERT INTO t12 VALUES(UUID());
UNLOCK TABLES;
+sync_slave_with_master;
+
+#
+# BUG#28086: SBR of USER() becomes corrupted on slave
+#
+
+connection master;
+
+# Just to get something that is non-trivial, albeit still simple, we
+# stuff the result of USER() and CURRENT_USER() into a variable.
+--delimiter $$
+CREATE FUNCTION my_user()
+ RETURNS CHAR(64)
+BEGIN
+ DECLARE user CHAR(64);
+ SELECT USER() INTO user;
+ RETURN user;
+END $$
+--delimiter ;
+
+--delimiter $$
+CREATE FUNCTION my_current_user()
+ RETURNS CHAR(64)
+BEGIN
+ DECLARE user CHAR(64);
+ SELECT CURRENT_USER() INTO user;
+ RETURN user;
+END $$
+--delimiter ;
+
+DROP TABLE IF EXISTS t13;
+CREATE TABLE t13 (data CHAR(64));
+INSERT INTO t13 VALUES (USER());
+INSERT INTO t13 VALUES (my_user());
+INSERT INTO t13 VALUES (CURRENT_USER());
+INSERT INTO t13 VALUES (my_current_user());
source include/show_binlog_events.inc;
sync_slave_with_master;
diff --git a/mysql-test/suite/rpl/t/rpl_temporary.test b/mysql-test/suite/rpl/t/rpl_temporary.test
index 09b8b83f25f..852dfdbc25c 100644
--- a/mysql-test/suite/rpl/t/rpl_temporary.test
+++ b/mysql-test/suite/rpl/t/rpl_temporary.test
@@ -208,8 +208,9 @@ select * from t1;
connection master;
drop table t1;
+--remove_file $MYSQLTEST_VARDIR/tmp/bug14157.sql
# Delete the anonymous users
source include/delete_anonymous_users.inc;
-# End of 5.1 tests
+# End of tests
diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt b/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt
new file mode 100644
index 00000000000..80c171170f6
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt
@@ -0,0 +1,3 @@
+--loose-debug="+d,all_errors_are_temporary_errors" --slave-transaction-retries=2
+
+
diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors.test b/mysql-test/suite/rpl/t/rpl_temporary_errors.test
new file mode 100644
index 00000000000..6a57f3cc167
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_temporary_errors.test
@@ -0,0 +1,27 @@
+source include/master-slave.inc;
+
+--echo **** On Master ****
+connection master;
+SET SESSION BINLOG_FORMAT=ROW;
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
+INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4);
+--echo **** On Slave ****
+sync_slave_with_master;
+SHOW STATUS LIKE 'Slave_retried_transactions';
+UPDATE t1 SET a = 5, b = 47 WHERE a = 1;
+SELECT * FROM t1;
+--echo **** On Master ****
+connection master;
+UPDATE t1 SET a = 5, b = 5 WHERE a = 1;
+SELECT * FROM t1;
+#SHOW BINLOG EVENTS;
+--echo **** On Slave ****
+sync_slave_with_master;
+SHOW STATUS LIKE 'Slave_retried_transactions';
+SELECT * FROM t1;
+source include/show_slave_status.inc;
+DROP TABLE t1;
+
+--echo **** On Master ****
+connection master;
+DROP TABLE t1;
diff --git a/mysql-test/suite/rpl/t/rpl_trigger.test b/mysql-test/suite/rpl/t/rpl_trigger.test
index 9f5f6fc9b4c..4a496ea4923 100644
--- a/mysql-test/suite/rpl/t/rpl_trigger.test
+++ b/mysql-test/suite/rpl/t/rpl_trigger.test
@@ -316,8 +316,13 @@ SELECT * FROM t2;
# 2. Check that the trigger is non-SUID on the slave;
# 3. Check that the trigger can be activated on the slave.
+#
+# We disable warnings here since it affects the result file in
+# different ways depending on the mode being used.
+disable_warnings;
INSERT INTO t1 VALUES(2);
+enable_warnings;
SELECT * FROM t1;
SELECT * FROM t2;
diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result
index 41e888827b1..d6d805daf70 100644
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result
@@ -615,6 +615,66 @@ c1 c2 c3 c4 c5 c6 c7
1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle NULL CURRENT_TIMESTAMP
2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE NULL CURRENT_TIMESTAMP
3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA NULL CURRENT_TIMESTAMP
+*** Create t14a on slave ***
+STOP SLAVE;
+RESET SLAVE;
+CREATE TABLE t14a (c1 INT KEY, c4 BLOB, c5 CHAR(5),
+c6 INT DEFAULT '1',
+c7 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
+)ENGINE='NDB';
+*** Create t14a on Master ***
+CREATE TABLE t14a (c1 INT PRIMARY KEY, c4 BLOB, c5 CHAR(5)
+) ENGINE='NDB';
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14a () VALUES(1,@b1,'Kyle'),
+(2,@b1,'JOE'),
+(3,@b1,'QA');
+SELECT * FROM t14a ORDER BY c1;
+c1 c4 c5
+1 b1b1b1b1b1b1b1b1 Kyle
+2 b1b1b1b1b1b1b1b1 JOE
+3 b1b1b1b1b1b1b1b1 QA
+*** Select on Slave ****
+SELECT * FROM t14a ORDER BY c1;
+c1 c4 c5 c6 c7
+1 b1b1b1b1b1b1b1b1 Kyle NULL CURRENT_TIMESTAMP
+2 b1b1b1b1b1b1b1b1 JOE NULL CURRENT_TIMESTAMP
+3 b1b1b1b1b1b1b1b1 QA NULL CURRENT_TIMESTAMP
+STOP SLAVE;
+RESET SLAVE;
+*** Master Drop c5 ***
+ALTER TABLE t14a DROP COLUMN c5;
+RESET MASTER;
+*** Start Slave ***
+START SLAVE;
+*** Master Data Insert ***
+set @b1 = 'b1b1b1b1';
+set @b1 = concat(@b1,@b1);
+INSERT INTO t14a () VALUES(4,@b1),
+(5,@b1),
+(6,@b1);
+SELECT * FROM t14a ORDER BY c1;
+c1 c4
+1 b1b1b1b1b1b1b1b1
+2 b1b1b1b1b1b1b1b1
+3 b1b1b1b1b1b1b1b1
+4 b1b1b1b1b1b1b1b1
+5 b1b1b1b1b1b1b1b1
+6 b1b1b1b1b1b1b1b1
+*** Select on Slave ****
+SELECT * FROM t14a ORDER BY c1;
+c1 c4 c5 c6 c7
+1 b1b1b1b1b1b1b1b1 Kyle NULL CURRENT_TIMESTAMP
+2 b1b1b1b1b1b1b1b1 JOE NULL CURRENT_TIMESTAMP
+3 b1b1b1b1b1b1b1b1 QA NULL CURRENT_TIMESTAMP
+4 b1b1b1b1b1b1b1b1 NULL NULL CURRENT_TIMESTAMP
+5 b1b1b1b1b1b1b1b1 NULL NULL CURRENT_TIMESTAMP
+6 b1b1b1b1b1b1b1b1 NULL NULL CURRENT_TIMESTAMP
*** connect to master and drop columns ***
ALTER TABLE t14 DROP COLUMN c2;
ALTER TABLE t14 DROP COLUMN c4;
@@ -707,7 +767,7 @@ Last_IO_Errno #
Last_IO_Error #
Last_SQL_Errno 1060
Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5'
-SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
START SLAVE;
*** Try to insert in master ****
INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2);
diff --git a/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result b/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result
index 5519e0dcd0c..abd5bad8e49 100644
--- a/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result
+++ b/mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result
@@ -415,4 +415,23 @@ a b c
2 4 8
3 6 9
99 99 99
+**** Test for BUG#31552 ****
+**** On Master ****
+DELETE FROM t1;
+**** Resetting master and slave ****
+STOP SLAVE;
+RESET SLAVE;
+RESET MASTER;
+START SLAVE;
+**** On Master ****
+INSERT INTO t1 VALUES ('K','K'), ('L','L'), ('M','M');
+**** On Master ****
+DELETE FROM t1 WHERE C1 = 'L';
+DELETE FROM t1;
+SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
+COUNT(*) 0
+Last_SQL_Error
+0
+SELECT COUNT(*) FROM t1 ORDER BY c1,c2;
+COUNT(*) 0
DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8;
diff --git a/mysql-test/suite/rpl_ndb/t/disabled.def b/mysql-test/suite/rpl_ndb/t/disabled.def
index 05e8297bf0e..3832fe49cb9 100644
--- a/mysql-test/suite/rpl_ndb/t/disabled.def
+++ b/mysql-test/suite/rpl_ndb/t/disabled.def
@@ -15,8 +15,6 @@ rpl_ndb_2innodb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb faile
rpl_ndb_2myisam : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue
rpl_ndb_2other : BUG#21842 2007-08-30 tsmith test has never worked on bigendian (sol10-sparc-a, powermacg5
rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD
-rpl_ndb_innodb2ndb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue
-rpl_ndb_myisam2ndb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue
rpl_ndb_ddl : BUG#28798 2007-05-31 lars Valgrind failure in NDB
rpl_ndb_mix_innodb : BUG#28123 rpl_ndb_mix_innodb.test casue slave to core on sol10-sparc-a
rpl_ndb_ctype_ucs2_def : BUG#27404 util thd mysql_parse sig11 when mysqld default multibyte charset
diff --git a/mysql-test/t/ctype_euckr.test b/mysql-test/t/ctype_euckr.test
index 56939817b2f..05e4b04eded 100644
--- a/mysql-test/t/ctype_euckr.test
+++ b/mysql-test/t/ctype_euckr.test
@@ -31,3 +31,26 @@ SELECT hex(a) FROM t1 ORDER BY a;
DROP TABLE t1;
# End of 4.1 tests
+
+#
+#Bug #30315 Character sets: insertion of euckr code value 0xa141 fails
+#
+create table t1 (s1 varchar(5) character set euckr);
+# Insert some valid characters
+insert into t1 values (0xA141);
+insert into t1 values (0xA15A);
+insert into t1 values (0xA161);
+insert into t1 values (0xA17A);
+insert into t1 values (0xA181);
+insert into t1 values (0xA1FE);
+# Insert some invalid characters
+insert into t1 values (0xA140);
+insert into t1 values (0xA15B);
+insert into t1 values (0xA160);
+insert into t1 values (0xA17B);
+insert into t1 values (0xA180);
+insert into t1 values (0xA1FF);
+select hex(s1), hex(convert(s1 using utf8)) from t1 order by binary s1;
+drop table t1;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test
index 695a21adbf5..0d917428efb 100644
--- a/mysql-test/t/ctype_uca.test
+++ b/mysql-test/t/ctype_uca.test
@@ -538,4 +538,8 @@ alter table t1 convert to character set ucs2 collate ucs2_czech_ci;
select * from t1 where a like 'c%';
drop table t1;
+set collation_connection=ucs2_unicode_ci;
+--source include/ctype_regex.inc
+set names utf8;
+
-- echo End for 5.0 tests
diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index 5525a5beb6f..b837f53a17f 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -651,6 +651,9 @@ select * from t1 where a=if(b<10,_ucs2 0x00C0,_ucs2 0x0062);
select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0);
drop table t1;
+set collation_connection=ucs2_general_ci;
+--source include/ctype_regex.inc
+set names latin1;
#
# Bug#30981 CHAR(0x41 USING ucs2) doesn't add leading zero
#
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index 5c35bf82343..d18a7d22a0e 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -186,6 +186,13 @@ select * from t1 where a = 'b' and a != 'b';
drop table t1;
#
+# Testing regexp
+#
+set collation_connection=utf8_general_ci;
+--source include/ctype_regex.inc
+set names utf8;
+
+#
# Bug #3928 regexp [[:>:]] and UTF-8
#
set names utf8;
diff --git a/mysql-test/t/func_regexp.test b/mysql-test/t/func_regexp.test
index 5eff404bc0f..1b35fab9d54 100644
--- a/mysql-test/t/func_regexp.test
+++ b/mysql-test/t/func_regexp.test
@@ -6,28 +6,9 @@
drop table if exists t1;
--enable_warnings
-create table t1 (s1 char(64),s2 char(64));
+set names latin1;
+--source include/ctype_regex.inc
-insert into t1 values('aaa','aaa');
-insert into t1 values('aaa|qqq','qqq');
-insert into t1 values('gheis','^[^a-dXYZ]+$');
-insert into t1 values('aab','^aa?b');
-insert into t1 values('Baaan','^Ba*n');
-insert into t1 values('aaa','qqq|aaa');
-insert into t1 values('qqq','qqq|aaa');
-
-insert into t1 values('bbb','qqq|aaa');
-insert into t1 values('bbb','qqq');
-insert into t1 values('aaa','aba');
-
-insert into t1 values(null,'abc');
-insert into t1 values('def',null);
-insert into t1 values(null,null);
-insert into t1 values('ghi','ghi[');
-
-select HIGH_PRIORITY s1 regexp s2 from t1;
-
-drop table t1;
#
# This test a bug in regexp on Alpha
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index cc1ef6f9730..c7fe033fd36 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -754,6 +754,38 @@ select * from t2;
drop table t1,t2;
#
+# Bug #29136 erred multi-delete on trans table does not rollback
+#
+
+# prepare
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+CREATE TABLE t1 (a int, PRIMARY KEY (a));
+CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
+create trigger trg_del_t2 after delete on t2 for each row
+ insert into t1 values (1);
+insert into t1 values (1);
+insert into t2 values (1),(2);
+
+
+# exec cases A, B - see multi_update.test
+
+# A. send_error() w/o send_eof() branch
+
+--error ER_DUP_ENTRY
+delete t2 from t2;
+
+# check
+
+select count(*) from t2 /* must be 2 as restored after rollback caused by the error */;
+
+# cleanup bug#29136
+
+drop table t1, t2;
+
+
+#
# Testing of IFNULL
#
create table t1 (a int, b int) engine=innodb;
diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test
index 6f5ac70a34b..331663dceb5 100644
--- a/mysql-test/t/multi_update.test
+++ b/mysql-test/t/multi_update.test
@@ -588,6 +588,7 @@ CREATE TABLE `t2` (
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
# as the test is about to see erroed queries in binlog
+set @sav_binlog_format= @@session.binlog_format;
set @@session.binlog_format= mixed;
@@ -614,5 +615,42 @@ show master status /* there must be the UPDATE query event */;
# cleanup bug#27716
drop table t1, t2;
+set @@session.binlog_format= @sav_binlog_format;
+
+#
+# Bug #29136 erred multi-delete on trans table does not rollback
+#
+
+# prepare
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+CREATE TABLE t1 (a int, PRIMARY KEY (a));
+CREATE TABLE t2 (a int, PRIMARY KEY (a));
+CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM;
+create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1);
+
+insert into t2 values (1),(2);
+insert into t3 values (1),(2);
+reset master;
+
+# exec cases B, A - see innodb.test
+
+# B. send_eof() and send_error() afterward
+
+--error ER_DUP_ENTRY
+delete t3.* from t2,t3 where t2.a=t3.a;
+
+# check
+select count(*) from t1 /* must be 1 */;
+select count(*) from t3 /* must be 1 */;
+
+# cleanup bug#29136
+drop table t1, t2, t3;
+
+#
+# Add further tests from here
+#
+
--echo end of tests
diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test
index 3ee04f32640..a7c3eda92df 100644
--- a/mysql-test/t/mysql.test
+++ b/mysql-test/t/mysql.test
@@ -282,6 +282,15 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug21412.sql;
#
--exec $MYSQL test -e "/*! \C latin1 */ select 1;"
+#
+# Bug#29323 mysql client only accetps ANSI encoded files
+#
+--write_file $MYSQLTEST_VARDIR/tmp/bug29323.sql
+select "This is a file starting with UTF8 BOM 0xEFBBBF";
+EOF
+--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug29323.sql 2>&1
+remove_file $MYSQLTEST_VARDIR/tmp/bug29323.sql;
+
--echo End of 5.0 tests
#
diff --git a/sql/field.cc b/sql/field.cc
index e04162d5e14..e3c01bf195a 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1394,20 +1394,85 @@ int Field::store(const char *to, uint length, CHARSET_INFO *cs,
/**
+ Pack the field into a format suitable for storage and transfer.
+
+ To implement packing functionality, only the virtual function
+ should be overridden. The other functions are just convenience
+ functions and hence should not be overridden.
+
+ The value of <code>low_byte_first</code> is dependent on how the
+ packed data is going to be used: for local use, e.g., temporary
+ store on disk or in memory, use the native format since that is
+ faster. For data that is going to be transfered to other machines
+ (e.g., when writing data to the binary log), data should always be
+ stored in little-endian format.
+
+ @note The default method for packing fields just copy the raw bytes
+ of the record into the destination, but never more than
+ <code>max_length</code> characters.
+
+ @param to
+ Pointer to memory area where representation of field should be put.
+
+ @param from
+ Pointer to memory area where record representation of field is
+ stored.
+
+ @param max_length
+ Maximum length of the field, as given in the column definition. For
+ example, for <code>CHAR(1000)</code>, the <code>max_length</code>
+ is 1000. This information is sometimes needed to decide how to pack
+ the data.
+
+ @param low_byte_first
+ @c TRUE if integers should be stored little-endian, @c FALSE if
+ native format should be used. Note that for little-endian machines,
+ the value of this flag is a moot point since the native format is
+ little-endian.
+*/
+uchar *
+Field::pack(uchar *to, const uchar *from, uint max_length,
+ bool low_byte_first __attribute__((unused)))
+{
+ uint32 length= pack_length();
+ set_if_smaller(length, max_length);
+ memcpy(to, from, length);
+ return to+length;
+}
+
+/**
Unpack a field from row data.
- This method is used to unpack a field from a master whose size
- of the field is less than that of the slave.
-
+ This method is used to unpack a field from a master whose size of
+ the field is less than that of the slave.
+
+ The <code>param_data</code> parameter is a two-byte integer (stored
+ in the least significant 16 bits of the unsigned integer) usually
+ consisting of two parts: the real type in the most significant byte
+ and a original pack length in the least significant byte.
+
+ The exact layout of the <code>param_data</code> field is given by
+ the <code>Table_map_log_event::save_field_metadata()</code>.
+
+ This is the default method for unpacking a field. It just copies
+ the memory block in byte order (of original pack length bytes or
+ length of field, whichever is smaller).
+
@param to Destination of the data
@param from Source of the data
- @param param_data Pack length of the field data
+ @param param_data Real type and original pack length of the field
+ data
+
+ @param low_byte_first
+ If this flag is @c true, all composite entities (e.g., lengths)
+ should be unpacked in little-endian format; otherwise, the entities
+ are unpacked in native order.
@return New pointer into memory based on from + length of the data
*/
-const uchar *Field::unpack(uchar* to,
- const uchar *from,
- uint param_data)
+const uchar *
+Field::unpack(uchar* to, const uchar *from, uint param_data,
+ bool low_byte_first __attribute__((unused)))
{
uint length=pack_length();
int from_type= 0;
@@ -1420,19 +1485,18 @@ const uchar *Field::unpack(uchar* to,
from_type= (param_data & 0xff00) >> 8U; // real_type.
param_data= param_data & 0x00ff; // length.
}
+
+ if ((param_data == 0) ||
+ (length == param_data) ||
+ (from_type != real_type()))
+ {
+ memcpy(to, from, length);
+ return from+length;
+ }
+
uint len= (param_data && (param_data < length)) ?
param_data : length;
- /*
- If the length is the same, use old unpack method.
- If the param_data is 0, use the old unpack method.
- This is possible if the table map was generated from a down-level
- master or if the data was not available on the master.
- If the real_types are not the same, use the old unpack method.
- */
- if ((length == param_data) ||
- (param_data == 0) ||
- (from_type != real_type()))
- return(unpack(to, from));
+
memcpy(to, from, param_data > length ? length : len);
return from+len;
}
@@ -2814,10 +2878,15 @@ uint Field_new_decimal::is_equal(Create_field *new_field)
@return New pointer into memory based on from + length of the data
*/
-const uchar *Field_new_decimal::unpack(uchar* to,
- const uchar *from,
- uint param_data)
+const uchar *
+Field_new_decimal::unpack(uchar* to,
+ const uchar *from,
+ uint param_data,
+ bool low_byte_first)
{
+ if (param_data == 0)
+ return Field::unpack(to, from, param_data, low_byte_first);
+
uint from_precision= (param_data & 0xff00) >> 8U;
uint from_decimal= param_data & 0x00ff;
uint length=pack_length();
@@ -3959,6 +4028,49 @@ void Field_longlong::sql_type(String &res) const
}
+/*
+ Floating-point numbers
+ */
+
+uchar *
+Field_real::pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first)
+{
+ DBUG_ENTER("Field_real::pack");
+ DBUG_ASSERT(max_length >= pack_length());
+ DBUG_PRINT("debug", ("pack_length(): %u", pack_length()));
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first != table->s->db_low_byte_first)
+ {
+ const uchar *dptr= from + pack_length();
+ while (dptr-- > from)
+ *to++ = *dptr;
+ DBUG_RETURN(to);
+ }
+ else
+#endif
+ DBUG_RETURN(Field::pack(to, from, max_length, low_byte_first));
+}
+
+const uchar *
+Field_real::unpack(uchar *to, const uchar *from,
+ uint param_data, bool low_byte_first)
+{
+ DBUG_ENTER("Field_real::unpack");
+ DBUG_PRINT("debug", ("pack_length(): %u", pack_length()));
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first != table->s->db_low_byte_first)
+ {
+ const uchar *dptr= from + pack_length();
+ while (dptr-- > from)
+ *to++ = *dptr;
+ DBUG_RETURN(from + pack_length());
+ }
+ else
+#endif
+ DBUG_RETURN(Field::unpack(to, from, param_data, low_byte_first));
+}
+
/****************************************************************************
single precision float
****************************************************************************/
@@ -6363,6 +6475,11 @@ int Field_longstr::store_decimal(const my_decimal *d)
return store(str.ptr(), str.length(), str.charset());
}
+uint32 Field_longstr::max_data_length() const
+{
+ return field_length + (field_length > 255 ? 2 : 1);
+}
+
double Field_string::val_real(void)
{
@@ -6507,7 +6624,9 @@ void Field_string::sql_type(String &res) const
}
-uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
+uchar *Field_string::pack(uchar *to, const uchar *from,
+ uint max_length,
+ bool low_byte_first __attribute__((unused)))
{
uint length= min(field_length,max_length);
uint local_char_length= max_length/field_charset->mbmaxlen;
@@ -6515,11 +6634,15 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
local_char_length= my_charpos(field_charset, from, from+length,
local_char_length);
set_if_smaller(length, local_char_length);
- while (length && from[length-1] == ' ')
+ while (length && from[length-1] == field_charset->pad_char)
length--;
+
+ // Length always stored little-endian
*to++= (uchar) length;
if (field_length > 255)
*to++= (uchar) (length >> 8);
+
+ // Store the actual bytes of the string
memcpy(to, from, length);
return to+length;
}
@@ -6541,34 +6664,27 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
@return New pointer into memory based on from + length of the data
*/
-const uchar *Field_string::unpack(uchar *to,
- const uchar *from,
- uint param_data)
-{
- uint from_len= param_data & 0x00ff; // length.
- uint length= 0;
- uint f_length;
- f_length= (from_len < field_length) ? from_len : field_length;
- DBUG_ASSERT(f_length <= 255);
- length= (uint) *from++;
- bitmap_set_bit(table->write_set,field_index);
- store((const char *)from, length, system_charset_info);
- return from+length;
-}
-
-
-const uchar *Field_string::unpack(uchar *to, const uchar *from)
-{
+const uchar *
+Field_string::unpack(uchar *to,
+ const uchar *from,
+ uint param_data,
+ bool low_byte_first __attribute__((unused)))
+{
+ uint from_length=
+ param_data ? min(param_data & 0x00ff, field_length) : field_length;
uint length;
- if (field_length > 255)
+
+ if (from_length > 255)
{
length= uint2korr(from);
from+= 2;
}
else
length= (uint) *from++;
- memcpy(to, from, (int) length);
- bfill(to+length, field_length - length, ' ');
+
+ memcpy(to, from, length);
+ // Pad the string with the pad character of the fields charset
+ bfill(to + length, field_length - length, field_charset->pad_char);
return from+length;
}
@@ -6758,6 +6874,7 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16;
int Field_varstring::do_save_field_metadata(uchar *metadata_ptr)
{
char *ptr= (char *)metadata_ptr;
+ DBUG_ASSERT(field_length <= 65535);
int2store(ptr, field_length);
return 2;
}
@@ -6985,22 +7102,30 @@ uint32 Field_varstring::data_length()
Here the number of length bytes are depending on the given max_length
*/
-uchar *Field_varstring::pack(uchar *to, const uchar *from, uint max_length)
+uchar *Field_varstring::pack(uchar *to, const uchar *from,
+ uint max_length,
+ bool low_byte_first __attribute__((unused)))
{
uint length= length_bytes == 1 ? (uint) *from : uint2korr(from);
set_if_smaller(max_length, field_length);
if (length > max_length)
length=max_length;
- *to++= (char) (length & 255);
+
+ /* Length always stored little-endian */
+ *to++= length & 0xFF;
if (max_length > 255)
- *to++= (char) (length >> 8);
- if (length)
+ *to++= (length >> 8) & 0xFF;
+
+ /* Store bytes of string */
+ if (length > 0)
memcpy(to, from+length_bytes, length);
return to+length;
}
-uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length)
+uchar *
+Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length,
+ bool low_byte_first __attribute__((unused)))
{
uint length= length_bytes == 1 ? (uint) *key : uint2korr(key);
uint local_char_length= ((field_charset->mbmaxlen > 1) ?
@@ -7039,8 +7164,9 @@ uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length)
Pointer to end of 'key' (To the next key part if multi-segment key)
*/
-const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key,
- uint max_length)
+const uchar *
+Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length,
+ bool low_byte_first __attribute__((unused)))
{
/* get length of the blob key */
uint32 length= *key++;
@@ -7069,8 +7195,9 @@ const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key,
end of key storage
*/
-uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from,
- uint max_length)
+uchar *
+Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length,
+ bool low_byte_first __attribute__((unused)))
{
/* Key length is always stored as 2 bytes */
uint length= uint2korr(from);
@@ -7090,6 +7217,9 @@ uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from,
This method is used to unpack a varstring field from a master
whose size of the field is less than that of the slave.
+
+ @note
+ The string length is always packed little-endian.
@param to Destination of the data
@param from Source of the data
@@ -7097,9 +7227,10 @@ uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from,
@return New pointer into memory based on from + length of the data
*/
-const uchar *Field_varstring::unpack(uchar *to,
- const uchar *from,
- uint param_data)
+const uchar *
+Field_varstring::unpack(uchar *to, const uchar *from,
+ uint param_data,
+ bool low_byte_first __attribute__((unused)))
{
uint length;
uint l_bytes= (param_data && (param_data < field_length)) ?
@@ -7111,28 +7242,7 @@ const uchar *Field_varstring::unpack(uchar *to,
if (length_bytes == 2)
to[1]= 0;
}
- else
- {
- length= uint2korr(from);
- to[0]= *from++;
- to[1]= *from++;
- }
- if (length)
- memcpy(to+ length_bytes, from, length);
- return from+length;
-}
-
-
-/*
- unpack field packed with Field_varstring::pack()
-*/
-
-const uchar *Field_varstring::unpack(uchar *to, const uchar *from)
-{
- uint length;
- if (length_bytes == 1)
- length= (uint) (*to= *from++);
- else
+ else /* l_bytes == 2 */
{
length= uint2korr(from);
to[0]= *from++;
@@ -7381,9 +7491,9 @@ void Field_blob::store_length(uchar *i_ptr,
}
-uint32 Field_blob::get_length(const uchar *pos, bool low_byte_first)
+uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg, bool low_byte_first)
{
- switch (packlength) {
+ switch (packlength_arg) {
case 1:
return (uint32) pos[0];
case 2:
@@ -7814,26 +7924,37 @@ void Field_blob::sql_type(String &res) const
}
}
-
-uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length)
+uchar *Field_blob::pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first)
{
+ DBUG_ENTER("Field_blob::pack");
+ DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;"
+ " max_length: %u; low_byte_first: %d",
+ (ulong) to, (ulong) from,
+ max_length, low_byte_first));
+ DBUG_DUMP("record", from, table->s->reclength);
uchar *save= ptr;
ptr= (uchar*) from;
uint32 length=get_length(); // Length of from string
- if (length > max_length)
- {
- length=max_length;
- store_length(to,packlength,length,TRUE);
- }
- else
- memcpy(to,from,packlength); // Copy length
- if (length)
+
+ /*
+ Store max length, which will occupy packlength bytes. If the max
+ length given is smaller than the actual length of the blob, we
+ just store the initial bytes of the blob.
+ */
+ store_length(to, packlength, min(length, max_length), low_byte_first);
+
+ /*
+ Store the actual blob data, which will occupy 'length' bytes.
+ */
+ if (length > 0)
{
get_ptr((uchar**) &from);
memcpy(to+packlength, from,length);
}
ptr=save; // Restore org row pointer
- return to+packlength+length;
+ DBUG_DUMP("packed", to, packlength + length);
+ DBUG_RETURN(to+packlength+length);
}
@@ -7848,28 +7969,30 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length)
@param to Destination of the data
@param from Source of the data
- @param param_data not used
+ @param param_data @c TRUE if base types should be stored in little-
+ endian format, @c FALSE if native format should
+ be used.
@return New pointer into memory based on from + length of the data
*/
const uchar *Field_blob::unpack(uchar *to,
const uchar *from,
- uint param_data)
-{
- return unpack(to, from);
-}
-
-
-const uchar *Field_blob::unpack(uchar *to, const uchar *from)
-{
- uint32 length=get_length(from);
- memcpy(to,from,packlength);
- from+=packlength;
- if (length)
- memcpy_fixed(to+packlength, &from, sizeof(from));
- else
- bzero(to+packlength,sizeof(from));
- return from+length;
+ uint param_data,
+ bool low_byte_first)
+{
+ DBUG_ENTER("Field_blob::unpack");
+ DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;"
+ " param_data: %u; low_byte_first: %d",
+ (ulong) to, (ulong) from, param_data, low_byte_first));
+ uint const master_packlength=
+ param_data > 0 ? param_data & 0xFF : packlength;
+ uint32 const length= get_length(from, master_packlength, low_byte_first);
+ DBUG_DUMP("packed", from, length + master_packlength);
+ bitmap_set_bit(table->write_set, field_index);
+ store(reinterpret_cast<const char*>(from) + master_packlength,
+ length, field_charset);
+ DBUG_DUMP("record", to, table->s->reclength);
+ DBUG_RETURN(from + master_packlength + length);
}
/* Keys for blobs are like keys on varchars */
@@ -7919,7 +8042,9 @@ int Field_blob::pack_cmp(const uchar *b, uint key_length_arg,
/* Create a packed key that will be used for storage from a MySQL row */
-uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length)
+uchar *
+Field_blob::pack_key(uchar *to, const uchar *from, uint max_length,
+ bool low_byte_first __attribute__((unused)))
{
uchar *save= ptr;
ptr= (uchar*) from;
@@ -7964,8 +8089,9 @@ uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length)
Pointer into 'from' past the last byte copied from packed key.
*/
-const uchar *Field_blob::unpack_key(uchar *to, const uchar *from,
- uint max_length)
+const uchar *
+Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length,
+ bool low_byte_first __attribute__((unused)))
{
/* get length of the blob key */
uint32 length= *from++;
@@ -7988,8 +8114,9 @@ const uchar *Field_blob::unpack_key(uchar *to, const uchar *from,
/* Create a packed key that will be used for storage from a MySQL key */
-uchar *Field_blob::pack_key_from_key_image(uchar *to, const uchar *from,
- uint max_length)
+uchar *
+Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length,
+ bool low_byte_first __attribute__((unused)))
{
uint length=uint2korr(from);
if (length > max_length)
@@ -8936,9 +9063,11 @@ void Field_bit::sql_type(String &res) const
}
-uchar *Field_bit::pack(uchar *to, const uchar *from, uint max_length)
+uchar *
+Field_bit::pack(uchar *to, const uchar *from, uint max_length,
+ bool low_byte_first __attribute__((unused)))
{
- DBUG_ASSERT(max_length);
+ DBUG_ASSERT(max_length > 0);
uint length;
if (bit_len > 0)
{
@@ -8973,28 +9102,44 @@ uchar *Field_bit::pack(uchar *to, const uchar *from, uint max_length)
/**
Unpack a bit field from row data.
- This method is used to unpack a bit field from a master whose size
+ This method is used to unpack a bit field from a master whose size
of the field is less than that of the slave.
-
+
@param to Destination of the data
@param from Source of the data
@param param_data Bit length (upper) and length (lower) values
@return New pointer into memory based on from + length of the data
*/
-const uchar *Field_bit::unpack(uchar *to,
- const uchar *from,
- uint param_data)
+const uchar *
+Field_bit::unpack(uchar *to, const uchar *from, uint param_data,
+ bool low_byte_first __attribute__((unused)))
{
uint const from_len= (param_data >> 8U) & 0x00ff;
uint const from_bit_len= param_data & 0x00ff;
/*
- If the master and slave have the same sizes, then use the old
- unpack() method.
+ If the parameter data is zero (i.e., undefined), or if the master
+ and slave have the same sizes, then use the old unpack() method.
*/
- if ((from_bit_len == bit_len) &&
- (from_len == bytes_in_rec))
- return(unpack(to, from));
+ if (param_data == 0 ||
+ (from_bit_len == bit_len) && (from_len == bytes_in_rec))
+ {
+ if (bit_len > 0)
+ {
+ /*
+ set_rec_bits is a macro, don't put the post-increment in the
+ argument since that might cause strange side-effects.
+
+ For the choice of the second argument, see the explanation for
+ Field_bit::pack().
+ */
+ set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, bit_len);
+ from++;
+ }
+ memcpy(to, from, bytes_in_rec);
+ return from + bytes_in_rec;
+ }
+
/*
We are converting a smaller bit field to a larger one here.
To do that, we first need to construct a raw value for the original
@@ -9022,25 +9167,6 @@ const uchar *Field_bit::unpack(uchar *to,
}
-const uchar *Field_bit::unpack(uchar *to, const uchar *from)
-{
- if (bit_len > 0)
- {
- /*
- set_rec_bits is a macro, don't put the post-increment in the
- argument since that might cause strange side-effects.
-
- For the choice of the second argument, see the explanation for
- Field_bit::pack().
- */
- set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, bit_len);
- from++;
- }
- memcpy(to, from, bytes_in_rec);
- return from + bytes_in_rec;
-}
-
-
void Field_bit::set_default()
{
if (bit_len > 0)
diff --git a/sql/field.h b/sql/field.h
index d0d867d0b32..4b09f50a59a 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -175,6 +175,17 @@ public:
*/
virtual uint32 data_length() { return pack_length(); }
virtual uint32 sort_length() const { return pack_length(); }
+
+ /**
+ Get the maximum size of the data in packed format.
+
+ @return Maximum data length of the field when packed using the
+ Field::pack() function.
+ */
+ virtual uint32 max_data_length() const {
+ return pack_length();
+ };
+
virtual int reset(void) { bzero(ptr,pack_length()); return 0; }
virtual void reset_fields() {}
virtual void set_default()
@@ -357,32 +368,45 @@ public:
return str;
}
virtual bool send_binary(Protocol *protocol);
- virtual uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0)
+
+ virtual uchar *pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first);
+ /**
+ @overload Field::pack(uchar*, const uchar*, uint, bool)
+ */
+ uchar *pack(uchar *to, const uchar *from)
{
- uint32 length=pack_length();
- memcpy(to,from,length);
- return to+length;
+ DBUG_ENTER("Field::pack");
+ uchar *result= this->pack(to, from, UINT_MAX, table->s->db_low_byte_first);
+ DBUG_RETURN(result);
}
- virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data);
- virtual const uchar *unpack(uchar* to, const uchar *from)
+
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first);
+ /**
+ @overload Field::unpack(uchar*, const uchar*, uint, bool)
+ */
+ const uchar *unpack(uchar* to, const uchar *from)
{
- uint length=pack_length();
- memcpy(to,from,length);
- return from+length;
+ DBUG_ENTER("Field::unpack");
+ const uchar *result= unpack(to, from, 0U, table->s->db_low_byte_first);
+ DBUG_RETURN(result);
}
- virtual uchar *pack_key(uchar* to, const uchar *from, uint max_length)
+
+ virtual uchar *pack_key(uchar* to, const uchar *from,
+ uint max_length, bool low_byte_first)
{
- return pack(to,from,max_length);
+ return pack(to, from, max_length, low_byte_first);
}
virtual uchar *pack_key_from_key_image(uchar* to, const uchar *from,
- uint max_length)
+ uint max_length, bool low_byte_first)
{
- return pack(to,from,max_length);
+ return pack(to, from, max_length, low_byte_first);
}
virtual const uchar *unpack_key(uchar* to, const uchar *from,
- uint max_length)
+ uint max_length, bool low_byte_first)
{
- return unpack(to,from);
+ return unpack(to, from, max_length, low_byte_first);
}
virtual uint packed_col_length(const uchar *to, uint length)
{ return length;}
@@ -567,6 +591,7 @@ public:
{}
int store_decimal(const my_decimal *d);
+ uint32 max_data_length() const;
};
/* base class for float and double and decimal (old one) */
@@ -587,6 +612,10 @@ public:
int truncate(double *nr, double max_length);
uint32 max_display_length() { return field_length; }
uint size_of() const { return sizeof(*this); }
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first);
+ virtual uchar *pack(uchar* to, const uchar *from,
+ uint max_length, bool low_byte_first);
};
@@ -615,6 +644,16 @@ public:
void overflow(bool negative);
bool zero_pack() const { return 0; }
void sql_type(String &str) const;
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first)
+ {
+ return Field::unpack(to, from, param_data, low_byte_first);
+ }
+ virtual uchar *pack(uchar* to, const uchar *from,
+ uint max_length, bool low_byte_first)
+ {
+ return Field::pack(to, from, max_length, low_byte_first);
+ }
};
@@ -665,7 +704,8 @@ public:
uint row_pack_length() { return pack_length(); }
int compatible_field_size(uint field_metadata);
uint is_equal(Create_field *new_field);
- virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data);
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first);
};
@@ -696,6 +736,20 @@ public:
uint32 pack_length() const { return 1; }
void sql_type(String &str) const;
uint32 max_display_length() { return 4; }
+
+ virtual uchar *pack(uchar* to, const uchar *from,
+ uint max_length, bool low_byte_first)
+ {
+ *to= *from;
+ return to + 1;
+ }
+
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first)
+ {
+ *to= *from;
+ return from + 1;
+ }
};
@@ -731,8 +785,47 @@ public:
uint32 pack_length() const { return 2; }
void sql_type(String &str) const;
uint32 max_display_length() { return 6; }
-};
+ virtual uchar *pack(uchar* to, const uchar *from,
+ uint max_length, bool low_byte_first)
+ {
+ int16 val;
+#ifdef WORDS_BIGENDIAN
+ if (table->s->db_low_byte_first)
+ val = sint2korr(from);
+ else
+#endif
+ shortget(val, from);
+
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first)
+ int2store(to, val);
+ else
+#endif
+ shortstore(to, val);
+ return to + sizeof(val);
+ }
+
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first)
+ {
+ int16 val;
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first)
+ val = sint2korr(from);
+ else
+#endif
+ shortget(val, from);
+
+#ifdef WORDS_BIGENDIAN
+ if (table->s->db_low_byte_first)
+ int2store(to, val);
+ else
+#endif
+ shortstore(to, val);
+ return from + sizeof(val);
+ }
+};
class Field_medium :public Field_num {
public:
@@ -761,6 +854,18 @@ public:
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
uint32 max_display_length() { return 8; }
+
+ virtual uchar *pack(uchar* to, const uchar *from,
+ uint max_length, bool low_byte_first)
+ {
+ return Field::pack(to, from, max_length, low_byte_first);
+ }
+
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first)
+ {
+ return Field::unpack(to, from, param_data, low_byte_first);
+ }
};
@@ -796,6 +901,45 @@ public:
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; }
+ virtual uchar *pack(uchar* to, const uchar *from,
+ uint max_length, bool low_byte_first)
+ {
+ int32 val;
+#ifdef WORDS_BIGENDIAN
+ if (table->s->db_low_byte_first)
+ val = sint4korr(from);
+ else
+#endif
+ longget(val, from);
+
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first)
+ int4store(to, val);
+ else
+#endif
+ longstore(to, val);
+ return to + sizeof(val);
+ }
+
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first)
+ {
+ int32 val;
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first)
+ val = sint4korr(from);
+ else
+#endif
+ longget(val, from);
+
+#ifdef WORDS_BIGENDIAN
+ if (table->s->db_low_byte_first)
+ int4store(to, val);
+ else
+#endif
+ longstore(to, val);
+ return from + sizeof(val);
+ }
};
@@ -838,6 +982,45 @@ public:
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
uint32 max_display_length() { return 20; }
+ virtual uchar *pack(uchar* to, const uchar *from,
+ uint max_length, bool low_byte_first)
+ {
+ int64 val;
+#ifdef WORDS_BIGENDIAN
+ if (table->s->db_low_byte_first)
+ val = sint8korr(from);
+ else
+#endif
+ longlongget(val, from);
+
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first)
+ int8store(to, val);
+ else
+#endif
+ longlongstore(to, val);
+ return to + sizeof(val);
+ }
+
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first)
+ {
+ int64 val;
+#ifdef WORDS_BIGENDIAN
+ if (low_byte_first)
+ val = sint8korr(from);
+ else
+#endif
+ longlongget(val, from);
+
+#ifdef WORDS_BIGENDIAN
+ if (table->s->db_low_byte_first)
+ int8store(to, val);
+ else
+#endif
+ longlongstore(to, val);
+ return from + sizeof(val);
+ }
};
#endif
@@ -1218,9 +1401,10 @@ public:
int cmp(const uchar *,const uchar *);
void sort_string(uchar *buff,uint length);
void sql_type(String &str) const;
- uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0);
- virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data);
- const uchar *unpack(uchar* to, const uchar *from);
+ virtual uchar *pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first);
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first);
uint pack_length_from_metadata(uint field_metadata)
{ return (field_metadata & 0x00ff); }
uint row_pack_length() { return (field_length + 1); }
@@ -1298,13 +1482,15 @@ public:
uint get_key_image(uchar *buff,uint length, imagetype type);
void set_key_image(const uchar *buff,uint length);
void sql_type(String &str) const;
- uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0);
- uchar *pack_key(uchar *to, const uchar *from, uint max_length);
+ virtual uchar *pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first);
+ uchar *pack_key(uchar *to, const uchar *from, uint max_length, bool low_byte_first);
uchar *pack_key_from_key_image(uchar* to, const uchar *from,
- uint max_length);
- virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data);
- const uchar *unpack(uchar* to, const uchar *from);
- const uchar *unpack_key(uchar* to, const uchar *from, uint max_length);
+ uint max_length, bool low_byte_first);
+ virtual const uchar *unpack(uchar* to, const uchar *from,
+ uint param_data, bool low_byte_first);
+ const uchar *unpack_key(uchar* to, const uchar *from,
+ uint max_length, bool low_byte_first);
int pack_cmp(const uchar *a, const uchar *b, uint key_length,
my_bool insert_or_update);
int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update);
@@ -1397,7 +1583,7 @@ public:
{ return (uint32) (packlength); }
uint row_pack_length() { return pack_length_no_ptr(); }
uint32 sort_length() const;
- inline uint32 max_data_length() const
+ virtual uint32 max_data_length() const
{
return (uint32) (((ulonglong) 1 << (packlength*8)) -1);
}
@@ -1425,13 +1611,13 @@ public:
@returns The length in the row plus the size of the data.
*/
uint32 get_packed_size(const uchar *ptr_arg, bool low_byte_first)
- {return packlength + get_length(ptr_arg, low_byte_first);}
+ {return packlength + get_length(ptr_arg, packlength, low_byte_first);}
inline uint32 get_length(uint row_offset= 0)
- { return get_length(ptr+row_offset, table->s->db_low_byte_first); }
- uint32 get_length(const uchar *ptr, bool low_byte_first);
+ { return get_length(ptr+row_offset, this->packlength, table->s->db_low_byte_first); }
+ uint32 get_length(const uchar *ptr, uint packlength, bool low_byte_first);
uint32 get_length(const uchar *ptr_arg)
- { return get_length(ptr_arg, table->s->db_low_byte_first); }
+ { return get_length(ptr_arg, this->packlength, table->s->db_low_byte_first); }
void put_length(uchar *pos, uint32 length);
inline void get_ptr(uchar **str)
{
@@ -1472,13 +1658,16 @@ public:
memcpy_fixed(ptr+packlength,&tmp,sizeof(char*));
return 0;
}
- uchar *pack(uchar *to, const uchar *from, uint max_length= ~(uint) 0);
- uchar *pack_key(uchar *to, const uchar *from, uint max_length);
+ virtual uchar *pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first);
+ uchar *pack_key(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first);
uchar *pack_key_from_key_image(uchar* to, const uchar *from,
- uint max_length);
- virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data);
- const uchar *unpack(uchar *to, const uchar *from);
- const uchar *unpack_key(uchar* to, const uchar *from, uint max_length);
+ uint max_length, bool low_byte_first);
+ virtual const uchar *unpack(uchar *to, const uchar *from,
+ uint param_data, bool low_byte_first);
+ const uchar *unpack_key(uchar* to, const uchar *from,
+ uint max_length, bool low_byte_first);
int pack_cmp(const uchar *a, const uchar *b, uint key_length,
my_bool insert_or_update);
int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update);
@@ -1630,6 +1819,7 @@ public:
enum_field_types type() const { return MYSQL_TYPE_BIT; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
uint32 key_length() const { return (uint32) (field_length + 7) / 8; }
+ uint32 max_data_length() const { return (field_length + 7) / 8; }
uint32 max_display_length() { return field_length; }
uint size_of() const { return sizeof(*this); }
Item_result result_type () const { return INT_RESULT; }
@@ -1671,9 +1861,10 @@ public:
{ return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); }
int compatible_field_size(uint field_metadata);
void sql_type(String &str) const;
- uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0);
- virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data);
- const uchar *unpack(uchar* to, const uchar *from);
+ virtual uchar *pack(uchar *to, const uchar *from,
+ uint max_length, bool low_byte_first);
+ virtual const uchar *unpack(uchar *to, const uchar *from,
+ uint param_data, bool low_byte_first);
virtual void set_default();
Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 436710e3dee..5fe688acfcd 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -416,7 +416,7 @@ Ndb *ha_ndbcluster::get_ndb()
void ha_ndbcluster::set_rec_per_key()
{
- DBUG_ENTER("ha_ndbcluster::get_status_const");
+ DBUG_ENTER("ha_ndbcluster::set_rec_per_key");
for (uint i=0 ; i < table_share->keys ; i++)
{
table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]= 1;
@@ -563,7 +563,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans)
THD *thd= current_thd;
int res;
NdbError err= trans->getNdbError();
- DBUG_ENTER("ndb_err");
+ DBUG_ENTER("ha_ndbcluster::ndb_err");
set_ndb_err(thd, err);
@@ -700,7 +700,7 @@ static bool field_type_forces_var_part(enum_field_types type)
bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op,
uint fieldnr, const uchar *field_ptr)
{
- DBUG_ENTER("set_hidden_key");
+ DBUG_ENTER("ha_ndbcluster::set_hidden_key");
DBUG_RETURN(ndb_op->equal(fieldnr, (char*)field_ptr) != 0);
}
@@ -713,7 +713,7 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field,
uint fieldnr, const uchar *field_ptr)
{
uint32 pack_len= field->pack_length();
- DBUG_ENTER("set_ndb_key");
+ DBUG_ENTER("ha_ndbcluster::set_ndb_key");
DBUG_PRINT("enter", ("%d: %s, ndb_type: %u, len=%d",
fieldnr, field->field_name, field->type(),
pack_len));
@@ -736,7 +736,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
{
const uchar* field_ptr= field->ptr + row_offset;
uint32 pack_len= field->pack_length();
- DBUG_ENTER("set_ndb_value");
+ DBUG_ENTER("ha_ndbcluster::set_ndb_value");
DBUG_PRINT("enter", ("%d: %s type: %u len=%d is_null=%s",
fieldnr, field->field_name, field->type(),
pack_len, field->is_null(row_offset) ? "Y" : "N"));
@@ -939,7 +939,7 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
uint fieldnr, uchar* buf)
{
- DBUG_ENTER("get_ndb_value");
+ DBUG_ENTER("ha_ndbcluster::get_ndb_value");
DBUG_PRINT("enter", ("fieldnr: %d flags: %o", fieldnr,
(int)(field != NULL ? field->flags : 0)));
@@ -990,7 +990,7 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
*/
int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op)
{
- DBUG_ENTER("get_ndb_partition_id");
+ DBUG_ENTER("ha_ndbcluster::get_ndb_partition_id");
DBUG_RETURN(ndb_op->getValue(NdbDictionary::Column::FRAGMENT,
(char *)&m_part_id) == NULL);
}
@@ -1049,7 +1049,7 @@ int ha_ndbcluster::get_metadata(const char *path)
NDBDICT *dict= ndb->getDictionary();
const NDBTAB *tab;
int error;
- DBUG_ENTER("get_metadata");
+ DBUG_ENTER("ha_ndbcluster::get_metadata");
DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path));
DBUG_ASSERT(m_table == NULL);
@@ -1468,7 +1468,7 @@ void ha_ndbcluster::release_metadata(THD *thd, Ndb *ndb)
{
uint i;
- DBUG_ENTER("release_metadata");
+ DBUG_ENTER("ha_ndbcluster::release_metadata");
DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
NDBDICT *dict= ndb->getDictionary();
@@ -1609,7 +1609,7 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op, const uchar *key)
KEY* key_info= table->key_info + table_share->primary_key;
KEY_PART_INFO* key_part= key_info->key_part;
KEY_PART_INFO* end= key_part+key_info->key_parts;
- DBUG_ENTER("set_primary_key");
+ DBUG_ENTER("ha_ndbcluster::set_primary_key");
for (; key_part != end; key_part++)
{
@@ -1631,7 +1631,7 @@ int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const uchar *re
KEY* key_info= table->key_info + table_share->primary_key;
KEY_PART_INFO* key_part= key_info->key_part;
KEY_PART_INFO* end= key_part+key_info->key_parts;
- DBUG_ENTER("set_primary_key_from_record");
+ DBUG_ENTER("ha_ndbcluster::set_primary_key_from_record");
for (; key_part != end; key_part++)
{
@@ -1670,7 +1670,7 @@ int ha_ndbcluster::set_index_key_from_record(NdbOperation *op,
KEY_PART_INFO* key_part= key_info->key_part;
KEY_PART_INFO* end= key_part+key_info->key_parts;
uint i;
- DBUG_ENTER("set_index_key_from_record");
+ DBUG_ENTER("ha_ndbcluster::set_index_key_from_record");
for (i= 0; key_part != end; key_part++, i++)
{
@@ -1709,7 +1709,7 @@ inline
int ha_ndbcluster::define_read_attrs(uchar* buf, NdbOperation* op)
{
uint i;
- DBUG_ENTER("define_read_attrs");
+ DBUG_ENTER("ha_ndbcluster::define_read_attrs");
// Define attributes to read
for (i= 0; i < table_share->fields; i++)
@@ -1756,7 +1756,7 @@ int ha_ndbcluster::pk_read(const uchar *key, uint key_len, uchar *buf,
NdbOperation *op;
int res;
- DBUG_ENTER("pk_read");
+ DBUG_ENTER("ha_ndbcluster::pk_read");
DBUG_PRINT("enter", ("key_len: %u", key_len));
DBUG_DUMP("key", key, key_len);
m_write_op= FALSE;
@@ -1823,7 +1823,7 @@ int ha_ndbcluster::complemented_read(const uchar *old_data, uchar *new_data,
uint no_fields= table_share->fields, i;
NdbTransaction *trans= m_active_trans;
NdbOperation *op;
- DBUG_ENTER("complemented_read");
+ DBUG_ENTER("ha_ndbcluster::complemented_read");
m_write_op= FALSE;
if (bitmap_is_set_all(table->read_set))
@@ -1989,7 +1989,7 @@ int ha_ndbcluster::peek_indexed_rows(const uchar *record,
const NdbOperation *first, *last;
uint i;
int res;
- DBUG_ENTER("peek_indexed_rows");
+ DBUG_ENTER("ha_ndbcluster::peek_indexed_rows");
NdbOperation::LockMode lm=
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
@@ -2134,7 +2134,7 @@ int ha_ndbcluster::unique_index_read(const uchar *key,
inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
{
- DBUG_ENTER("fetch_next");
+ DBUG_ENTER("ha_ndbcluster::fetch_next");
int local_check;
NdbTransaction *trans= m_active_trans;
@@ -2243,7 +2243,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
inline int ha_ndbcluster::next_result(uchar *buf)
{
int res;
- DBUG_ENTER("next_result");
+ DBUG_ENTER("ha_ndbcluster::next_result");
if (!m_active_cursor)
DBUG_RETURN(HA_ERR_END_OF_FILE);
@@ -2286,7 +2286,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
uint tot_len;
uint i, j;
- DBUG_ENTER("set_bounds");
+ DBUG_ENTER("ha_ndbcluster::set_bounds");
DBUG_PRINT("info", ("key_parts=%d", key_parts));
for (j= 0; j <= 1; j++)
@@ -2573,7 +2573,7 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info,
NdbTransaction *trans= m_active_trans;
part_id_range part_spec;
- DBUG_ENTER("unique_index_scan");
+ DBUG_ENTER("ha_ndbcluster::unique_index_scan");
DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname));
NdbOperation::LockMode lm=
@@ -2647,7 +2647,7 @@ int ha_ndbcluster::full_table_scan(uchar *buf)
NdbTransaction *trans= m_active_trans;
part_id_range part_spec;
- DBUG_ENTER("full_table_scan");
+ DBUG_ENTER("ha_ndbcluster::full_table_scan");
DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname));
m_write_op= FALSE;
@@ -2980,7 +2980,7 @@ int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data)
longlong func_value;
bool pk_update= (table_share->primary_key != MAX_KEY &&
key_cmp(table_share->primary_key, old_data, new_data));
- DBUG_ENTER("update_row");
+ DBUG_ENTER("ha_ndbcluster::update_row");
m_write_op= TRUE;
/*
@@ -3185,7 +3185,7 @@ int ha_ndbcluster::delete_row(const uchar *record)
NdbOperation *op;
uint32 part_id;
int error;
- DBUG_ENTER("delete_row");
+ DBUG_ENTER("ha_ndbcluster::delete_row");
m_write_op= TRUE;
ha_statistic_increment(&SSV::ha_delete_count);
@@ -3465,7 +3465,7 @@ void ha_ndbcluster::unpack_record(uchar *buf)
void ha_ndbcluster::print_results()
{
- DBUG_ENTER("print_results");
+ DBUG_ENTER("ha_ndbcluster::print_results");
#ifndef DBUG_OFF
@@ -3732,7 +3732,7 @@ int ha_ndbcluster::read_range_next()
int ha_ndbcluster::rnd_init(bool scan)
{
NdbScanOperation *cursor= m_active_cursor;
- DBUG_ENTER("rnd_init");
+ DBUG_ENTER("ha_ndbcluster::rnd_init");
DBUG_PRINT("enter", ("scan: %d", scan));
// Check if scan is to be restarted
if (cursor)
@@ -3752,7 +3752,7 @@ int ha_ndbcluster::rnd_init(bool scan)
int ha_ndbcluster::close_scan()
{
NdbTransaction *trans= m_active_trans;
- DBUG_ENTER("close_scan");
+ DBUG_ENTER("ha_ndbcluster::close_scan");
m_multi_cursor= 0;
if (!m_active_cursor && !m_multi_cursor)
@@ -3801,14 +3801,14 @@ int ha_ndbcluster::close_scan()
int ha_ndbcluster::rnd_end()
{
- DBUG_ENTER("rnd_end");
+ DBUG_ENTER("ha_ndbcluster::rnd_end");
DBUG_RETURN(close_scan());
}
int ha_ndbcluster::rnd_next(uchar *buf)
{
- DBUG_ENTER("rnd_next");
+ DBUG_ENTER("ha_ndbcluster::rnd_next");
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
if (!m_active_cursor)
@@ -3826,7 +3826,7 @@ int ha_ndbcluster::rnd_next(uchar *buf)
int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos)
{
- DBUG_ENTER("rnd_pos");
+ DBUG_ENTER("ha_ndbcluster::rnd_pos");
ha_statistic_increment(&SSV::ha_read_rnd_count);
// The primary key for the record is stored in pos
// Perform a pk_read using primary key "index"
@@ -3878,7 +3878,7 @@ void ha_ndbcluster::position(const uchar *record)
uchar *buff;
uint key_length;
- DBUG_ENTER("position");
+ DBUG_ENTER("ha_ndbcluster::position");
if (table_share->primary_key != MAX_KEY)
{
@@ -3962,7 +3962,7 @@ void ha_ndbcluster::position(const uchar *record)
int ha_ndbcluster::info(uint flag)
{
int result= 0;
- DBUG_ENTER("info");
+ DBUG_ENTER("ha_ndbcluster::info");
DBUG_PRINT("enter", ("flag: %d", flag));
if (flag & HA_STATUS_POS)
@@ -4063,7 +4063,7 @@ void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO *stat_info,
int ha_ndbcluster::extra(enum ha_extra_function operation)
{
- DBUG_ENTER("extra");
+ DBUG_ENTER("ha_ndbcluster::extra");
switch (operation) {
case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/
DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY"));
@@ -4156,7 +4156,7 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows)
int bytes, batch;
const NDBTAB *tab= m_table;
- DBUG_ENTER("start_bulk_insert");
+ DBUG_ENTER("ha_ndbcluster::start_bulk_insert");
DBUG_PRINT("enter", ("rows: %d", (int)rows));
m_rows_inserted= (ha_rows) 0;
@@ -4205,7 +4205,7 @@ int ha_ndbcluster::end_bulk_insert()
{
int error= 0;
- DBUG_ENTER("end_bulk_insert");
+ DBUG_ENTER("ha_ndbcluster::end_bulk_insert");
// Check if last inserts need to be flushed
if (m_bulk_insert_not_flushed)
{
@@ -4246,7 +4246,7 @@ int ha_ndbcluster::end_bulk_insert()
int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size)
{
- DBUG_ENTER("extra_opt");
+ DBUG_ENTER("ha_ndbcluster::extra_opt");
DBUG_PRINT("enter", ("cache_size: %lu", cache_size));
DBUG_RETURN(extra(operation));
}
@@ -4288,7 +4288,7 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd,
THR_LOCK_DATA **to,
enum thr_lock_type lock_type)
{
- DBUG_ENTER("store_lock");
+ DBUG_ENTER("ha_ndbcluster::store_lock");
if (lock_type != TL_IGNORE && m_lock.type == TL_UNLOCK)
{
@@ -4506,7 +4506,7 @@ int ha_ndbcluster::init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb)
int ha_ndbcluster::external_lock(THD *thd, int lock_type)
{
int error=0;
- DBUG_ENTER("external_lock");
+ DBUG_ENTER("ha_ndbcluster::external_lock");
/*
Check that this handler instance has a connection
@@ -4619,7 +4619,7 @@ error:
void ha_ndbcluster::unlock_row()
{
- DBUG_ENTER("unlock_row");
+ DBUG_ENTER("ha_ndbcluster::unlock_row");
DBUG_PRINT("info", ("Unlocking row"));
m_lock_tuple= FALSE;
@@ -4637,7 +4637,7 @@ void ha_ndbcluster::unlock_row()
int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type)
{
int error=0;
- DBUG_ENTER("start_stmt");
+ DBUG_ENTER("ha_ndbcluster::start_stmt");
Thd_ndb *thd_ndb= get_thd_ndb(thd);
transaction_checks(thd);
@@ -5480,7 +5480,7 @@ int ha_ndbcluster::create_handler_files(const char *file,
size_t length, pack_length;
int error= 0;
- DBUG_ENTER("create_handler_files");
+ DBUG_ENTER("ha_ndbcluster::create_handler_files");
if (action_flag != CHF_INDEX_FLAG)
{
@@ -6165,7 +6165,7 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment,
{
int cache_size;
Uint64 auto_value;
- DBUG_ENTER("get_auto_increment");
+ DBUG_ENTER("ha_ndbcluster::get_auto_increment");
DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
Ndb *ndb= get_ndb();
@@ -6272,7 +6272,7 @@ ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg):
{
int i;
- DBUG_ENTER("ha_ndbcluster");
+ DBUG_ENTER("ha_ndbcluster::ha_ndbcluster");
m_tabname[0]= '\0';
m_dbname[0]= '\0';
@@ -6305,7 +6305,7 @@ ha_ndbcluster::~ha_ndbcluster()
{
THD *thd= current_thd;
Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb;
- DBUG_ENTER("~ha_ndbcluster");
+ DBUG_ENTER("ha_ndbcluster::~ha_ndbcluster");
if (m_share)
{
@@ -6460,7 +6460,7 @@ void ha_ndbcluster::set_part_info(partition_info *part_info)
int ha_ndbcluster::close(void)
{
- DBUG_ENTER("close");
+ DBUG_ENTER("ha_ndbcluster::close");
THD *thd= table->in_use;
Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb;
/* ndb_share reference handler free */
@@ -6476,7 +6476,7 @@ int ha_ndbcluster::close(void)
Thd_ndb* ha_ndbcluster::seize_thd_ndb()
{
Thd_ndb *thd_ndb;
- DBUG_ENTER("seize_thd_ndb");
+ DBUG_ENTER("ha_ndbcluster::seize_thd_ndb");
thd_ndb= new Thd_ndb();
if (thd_ndb == NULL)
@@ -6502,7 +6502,7 @@ Thd_ndb* ha_ndbcluster::seize_thd_ndb()
void ha_ndbcluster::release_thd_ndb(Thd_ndb* thd_ndb)
{
- DBUG_ENTER("release_thd_ndb");
+ DBUG_ENTER("ha_ndbcluster::release_thd_ndb");
delete thd_ndb;
DBUG_VOID_RETURN;
}
@@ -6532,7 +6532,7 @@ Ndb* check_ndb_in_thd(THD* thd)
int ha_ndbcluster::check_ndb_connection(THD* thd)
{
Ndb *ndb;
- DBUG_ENTER("check_ndb_connection");
+ DBUG_ENTER("ha_ndbcluster::check_ndb_connection");
if (!(ndb= check_ndb_in_thd(thd)))
DBUG_RETURN(HA_ERR_NO_CONNECTION);
@@ -7583,7 +7583,7 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key,
uint key_length= key_info->key_length;
NDB_INDEX_TYPE idx_type= get_index_type(inx);
- DBUG_ENTER("records_in_range");
+ DBUG_ENTER("ha_ndbcluster::records_in_range");
// Prevent partial read of hash indexes by returning HA_POS_ERROR
if ((idx_type == UNIQUE_INDEX || idx_type == PRIMARY_KEY_INDEX) &&
((min_key && min_key->length < key_length) ||
@@ -8543,7 +8543,7 @@ int ha_ndbcluster::write_ndb_file(const char *name)
bool error=1;
char path[FN_REFLEN];
- DBUG_ENTER("write_ndb_file");
+ DBUG_ENTER("ha_ndbcluster::write_ndb_file");
DBUG_PRINT("enter", ("name: %s", name));
(void)strxnmov(path, FN_REFLEN-1,
@@ -8587,7 +8587,7 @@ ha_ndbcluster::null_value_index_search(KEY_MULTI_RANGE *ranges,
KEY_MULTI_RANGE *end_range,
HANDLER_BUFFER *buffer)
{
- DBUG_ENTER("null_value_index_search");
+ DBUG_ENTER("ha_ndbcluster::null_value_index_search");
KEY* key_info= table->key_info + active_index;
KEY_MULTI_RANGE *range= ranges;
ulong reclength= table->s->reclength;
@@ -8982,7 +8982,7 @@ found_next:
int
ha_ndbcluster::setup_recattr(const NdbRecAttr* curr)
{
- DBUG_ENTER("setup_recattr");
+ DBUG_ENTER("ha_ndbcluster::setup_recattr");
Field **field, **end;
NdbValue *value= m_value;
@@ -9353,7 +9353,7 @@ const
COND*
ha_ndbcluster::cond_push(const COND *cond)
{
- DBUG_ENTER("cond_push");
+ DBUG_ENTER("ha_ndbcluster::cond_push");
if (!m_cond)
m_cond= new ha_ndbcluster_cond;
if (!m_cond)
@@ -9588,7 +9588,7 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info)
uint i;
int error= 0;
bool unsigned_flag= part_info->part_expr->unsigned_flag;
- DBUG_ENTER("set_range_data");
+ DBUG_ENTER("ha_ndbcluster::set_range_data");
if (!range_data)
{
@@ -9627,7 +9627,7 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info)
uint32 *part_id, i;
int error= 0;
bool unsigned_flag= part_info->part_expr->unsigned_flag;
- DBUG_ENTER("set_list_data");
+ DBUG_ENTER("ha_ndbcluster::set_list_data");
if (!list_data)
{
@@ -9958,7 +9958,7 @@ int ndbcluster_alter_tablespace(handlerton *hton,
int error;
const char *errmsg;
Ndb *ndb;
- DBUG_ENTER("ha_ndbcluster::alter_tablespace");
+ DBUG_ENTER("alter_tablespace");
LINT_INIT(errmsg);
ndb= check_ndb_in_thd(thd);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 04e0011f1a7..47649006ccf 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -4381,6 +4381,51 @@ void Item_func_like::cleanup()
#ifdef USE_REGEX
bool
+Item_func_regex::regcomp(bool send_error)
+{
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff),&my_charset_bin);
+ String *res= args[1]->val_str(&tmp);
+ int error;
+
+ if (args[1]->null_value)
+ return TRUE;
+
+ if (regex_compiled)
+ {
+ if (!stringcmp(res, &prev_regexp))
+ return FALSE;
+ prev_regexp.copy(*res);
+ my_regfree(&preg);
+ regex_compiled= 0;
+ }
+
+ if (cmp_collation.collation != regex_lib_charset)
+ {
+ /* Convert UCS2 strings to UTF8 */
+ uint dummy_errors;
+ if (conv.copy(res->ptr(), res->length(), res->charset(),
+ regex_lib_charset, &dummy_errors))
+ return TRUE;
+ res= &conv;
+ }
+
+ if ((error= my_regcomp(&preg, res->c_ptr_safe(),
+ regex_lib_flags, regex_lib_charset)))
+ {
+ if (send_error)
+ {
+ (void) my_regerror(error, &preg, buff, sizeof(buff));
+ my_error(ER_REGEXP_ERROR, MYF(0), buff);
+ }
+ return TRUE;
+ }
+ regex_compiled= 1;
+ return FALSE;
+}
+
+
+bool
Item_func_regex::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
@@ -4396,35 +4441,34 @@ Item_func_regex::fix_fields(THD *thd, Item **ref)
if (agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1))
return TRUE;
+ regex_lib_flags= (cmp_collation.collation->state &
+ (MY_CS_BINSORT | MY_CS_CSSORT)) ?
+ REG_EXTENDED | REG_NOSUB :
+ REG_EXTENDED | REG_NOSUB | REG_ICASE;
+ /*
+ If the case of UCS2 and other non-ASCII character sets,
+ we will convert patterns and strings to UTF8.
+ */
+ regex_lib_charset= (cmp_collation.collation->mbminlen > 1) ?
+ &my_charset_utf8_general_ci :
+ cmp_collation.collation;
+
used_tables_cache=args[0]->used_tables() | args[1]->used_tables();
not_null_tables_cache= (args[0]->not_null_tables() |
args[1]->not_null_tables());
const_item_cache=args[0]->const_item() && args[1]->const_item();
if (!regex_compiled && args[1]->const_item())
{
- char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff),&my_charset_bin);
- String *res=args[1]->val_str(&tmp);
if (args[1]->null_value)
{ // Will always return NULL
maybe_null=1;
fixed= 1;
return FALSE;
}
- int error;
- if ((error= my_regcomp(&preg,res->c_ptr(),
- ((cmp_collation.collation->state &
- (MY_CS_BINSORT | MY_CS_CSSORT)) ?
- REG_EXTENDED | REG_NOSUB :
- REG_EXTENDED | REG_NOSUB | REG_ICASE),
- cmp_collation.collation)))
- {
- (void) my_regerror(error,&preg,buff,sizeof(buff));
- my_error(ER_REGEXP_ERROR, MYF(0), buff);
+ if (regcomp(TRUE))
return TRUE;
- }
- regex_compiled=regex_is_const=1;
- maybe_null=args[0]->maybe_null;
+ regex_is_const= 1;
+ maybe_null= args[0]->maybe_null;
}
else
maybe_null=1;
@@ -4437,47 +4481,25 @@ longlong Item_func_regex::val_int()
{
DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
- String *res, tmp(buff,sizeof(buff),&my_charset_bin);
+ String tmp(buff,sizeof(buff),&my_charset_bin);
+ String *res= args[0]->val_str(&tmp);
- res=args[0]->val_str(&tmp);
- if (args[0]->null_value)
- {
- null_value=1;
+ if ((null_value= (args[0]->null_value ||
+ (!regex_is_const && regcomp(FALSE)))))
return 0;
- }
- if (!regex_is_const)
- {
- char buff2[MAX_FIELD_WIDTH];
- String *res2, tmp2(buff2,sizeof(buff2),&my_charset_bin);
- res2= args[1]->val_str(&tmp2);
- if (args[1]->null_value)
+ if (cmp_collation.collation != regex_lib_charset)
+ {
+ /* Convert UCS2 strings to UTF8 */
+ uint dummy_errors;
+ if (conv.copy(res->ptr(), res->length(), res->charset(),
+ regex_lib_charset, &dummy_errors))
{
- null_value=1;
+ null_value= 1;
return 0;
}
- if (!regex_compiled || stringcmp(res2,&prev_regexp))
- {
- prev_regexp.copy(*res2);
- if (regex_compiled)
- {
- my_regfree(&preg);
- regex_compiled=0;
- }
- if (my_regcomp(&preg,res2->c_ptr_safe(),
- ((cmp_collation.collation->state &
- (MY_CS_BINSORT | MY_CS_CSSORT)) ?
- REG_EXTENDED | REG_NOSUB :
- REG_EXTENDED | REG_NOSUB | REG_ICASE),
- cmp_collation.collation))
- {
- null_value=1;
- return 0;
- }
- regex_compiled=1;
- }
+ res= &conv;
}
- null_value=0;
return my_regexec(&preg,res->c_ptr_safe(),0,(my_regmatch_t*) 0,0) ? 0 : 1;
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index e9aeef7fc3e..8df0e1af331 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1382,6 +1382,10 @@ class Item_func_regex :public Item_bool_func
bool regex_is_const;
String prev_regexp;
DTCollation cmp_collation;
+ CHARSET_INFO *regex_lib_charset;
+ int regex_lib_flags;
+ String conv;
+ bool regcomp(bool send_error);
public:
Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b),
regex_compiled(0),regex_is_const(0) {}
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 1a6c15a4d2e..68d85418324 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -2612,35 +2612,27 @@ typedef struct
uint level;
String *pxml; // parsed XML
uint pos[MAX_LEVEL]; // Tag position stack
+ uint parent; // Offset of the parent of the current node
} MY_XML_USER_DATA;
-/*
- Find the parent node
-
- SYNOPSYS
- Find the parent node, i.e. a tag or attrubute node on the given level.
-
- RETURN
- 1 - success
- 0 - failure
-*/
-static uint xml_parent_tag(MY_XML_NODE *items, uint nitems, uint level)
+static bool
+append_node(String *str, MY_XML_NODE *node)
{
- if (!nitems)
- return 0;
-
- MY_XML_NODE *p, *last= &items[nitems-1];
- for (p= last; p >= items; p--)
- {
- if (p->level == level &&
- (p->type == MY_XML_NODE_TAG ||
- p->type == MY_XML_NODE_ATTR))
- {
- return p - items;
- }
- }
- return 0;
+ /*
+ If "str" doesn't have space for a new node,
+ it will allocate two times more space that it has had so far.
+ (2*len+512) is a heuristic value,
+ which gave the best performance during tests.
+ The ideas behind this formula are:
+ - It allows to have a very small number of reallocs:
+ about 10 reallocs on a 1Mb-long XML value.
+ - At the same time, it avoids excessive memory use.
+ */
+ if (str->reserve(sizeof(MY_XML_NODE), 2 * str->length() + 512))
+ return TRUE;
+ str->q_append((const char*) node, sizeof(MY_XML_NODE));
+ return FALSE;
}
@@ -2662,19 +2654,17 @@ extern "C" int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len);
int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len)
{
MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
- MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr();
uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE);
- uint parent= xml_parent_tag(nodes, numnodes, data->level - 1);
MY_XML_NODE node;
+ node.parent= data->parent; // Set parent for the new node to old parent
+ data->parent= numnodes; // Remember current node as new parent
data->pos[data->level]= numnodes;
node.level= data->level++;
node.type= st->current_node_type; // TAG or ATTR
node.beg= attr;
node.end= attr + len;
- node.parent= parent;
- data->pxml->append((const char*) &node, sizeof(MY_XML_NODE));
- return MY_XML_OK;
+ return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK;
}
@@ -2695,18 +2685,14 @@ extern "C" int xml_value(MY_XML_PARSER *st,const char *attr, size_t len);
int xml_value(MY_XML_PARSER *st,const char *attr, size_t len)
{
MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
- MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr();
- uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE);
- uint parent= xml_parent_tag(nodes, numnodes, data->level - 1);
MY_XML_NODE node;
+ node.parent= data->parent; // Set parent for the new text node to old parent
node.level= data->level;
node.type= MY_XML_NODE_TEXT;
node.beg= attr;
node.end= attr + len;
- node.parent= parent;
- data->pxml->append((const char*) &node, sizeof(MY_XML_NODE));
- return MY_XML_OK;
+ return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK;
}
@@ -2731,6 +2717,7 @@ int xml_leave(MY_XML_PARSER *st,const char *attr, size_t len)
data->level--;
MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr();
+ data->parent= nodes[data->parent].parent;
nodes+= data->pos[data->level];
nodes->tagend= st->cur;
@@ -2761,6 +2748,7 @@ String *Item_xml_str_func::parse_xml(String *raw_xml, String *parsed_xml_buf)
p.flags= MY_XML_FLAG_RELATIVE_NAMES | MY_XML_FLAG_SKIP_TEXT_NORMALIZATION;
user_data.level= 0;
user_data.pxml= parsed_xml_buf;
+ user_data.parent= 0;
my_xml_set_enter_handler(&p, xml_enter);
my_xml_set_value_handler(&p, xml_value);
my_xml_set_leave_handler(&p, xml_leave);
diff --git a/sql/log.cc b/sql/log.cc
index 688ed03d5d1..9fdede9ef2c 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2158,13 +2158,9 @@ const char *MYSQL_LOG::generate_name(const char *log_name,
{
if (!log_name || !log_name[0])
{
- /*
- TODO: The following should be using fn_format(); We just need to
- first change fn_format() to cut the file name if it's too long.
- */
- strmake(buff, pidfile_name, FN_REFLEN - 5);
- strmov(fn_ext(buff), suffix);
- return (const char *)buff;
+ strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1);
+ return (const char *)
+ fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR));
}
// get rid of extension if the log is binary to avoid problems
if (strip_ext)
@@ -3569,9 +3565,6 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
(!binlog_filter->db_ok(local_db)))
{
VOID(pthread_mutex_unlock(&LOCK_log));
- DBUG_PRINT("info",("OPTION_BIN_LOG is %s, db_ok('%s') == %d",
- (thd->options & OPTION_BIN_LOG) ? "set" : "clear",
- local_db, binlog_filter->db_ok(local_db)));
DBUG_RETURN(0);
}
#endif /* HAVE_REPLICATION */
diff --git a/sql/log.h b/sql/log.h
index bef0101c8b5..20a1b7e8e6d 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -130,7 +130,13 @@ typedef struct st_log_info
my_off_t pos;
bool fatal; // if the purge happens to give us a negative offset
pthread_mutex_t lock;
- st_log_info():fatal(0) { pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);}
+ st_log_info()
+ : index_file_offset(0), index_file_start_offset(0),
+ pos(0), fatal(0)
+ {
+ log_file_name[0] = '\0';
+ pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);
+ }
~st_log_info() { pthread_mutex_destroy(&lock);}
} LOG_INFO;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index a6d07e72033..9ad85be8a91 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -36,6 +36,64 @@
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) && !defined(DBUG_OFF) && !defined(_lint)
+static const char *HA_ERR(int i)
+{
+ switch (i) {
+ case HA_ERR_KEY_NOT_FOUND: return "HA_ERR_KEY_NOT_FOUND";
+ case HA_ERR_FOUND_DUPP_KEY: return "HA_ERR_FOUND_DUPP_KEY";
+ case HA_ERR_RECORD_CHANGED: return "HA_ERR_RECORD_CHANGED";
+ case HA_ERR_WRONG_INDEX: return "HA_ERR_WRONG_INDEX";
+ case HA_ERR_CRASHED: return "HA_ERR_CRASHED";
+ case HA_ERR_WRONG_IN_RECORD: return "HA_ERR_WRONG_IN_RECORD";
+ case HA_ERR_OUT_OF_MEM: return "HA_ERR_OUT_OF_MEM";
+ case HA_ERR_NOT_A_TABLE: return "HA_ERR_NOT_A_TABLE";
+ case HA_ERR_WRONG_COMMAND: return "HA_ERR_WRONG_COMMAND";
+ case HA_ERR_OLD_FILE: return "HA_ERR_OLD_FILE";
+ case HA_ERR_NO_ACTIVE_RECORD: return "HA_ERR_NO_ACTIVE_RECORD";
+ case HA_ERR_RECORD_DELETED: return "HA_ERR_RECORD_DELETED";
+ case HA_ERR_RECORD_FILE_FULL: return "HA_ERR_RECORD_FILE_FULL";
+ case HA_ERR_INDEX_FILE_FULL: return "HA_ERR_INDEX_FILE_FULL";
+ case HA_ERR_END_OF_FILE: return "HA_ERR_END_OF_FILE";
+ case HA_ERR_UNSUPPORTED: return "HA_ERR_UNSUPPORTED";
+ case HA_ERR_TO_BIG_ROW: return "HA_ERR_TO_BIG_ROW";
+ case HA_WRONG_CREATE_OPTION: return "HA_WRONG_CREATE_OPTION";
+ case HA_ERR_FOUND_DUPP_UNIQUE: return "HA_ERR_FOUND_DUPP_UNIQUE";
+ case HA_ERR_UNKNOWN_CHARSET: return "HA_ERR_UNKNOWN_CHARSET";
+ case HA_ERR_WRONG_MRG_TABLE_DEF: return "HA_ERR_WRONG_MRG_TABLE_DEF";
+ case HA_ERR_CRASHED_ON_REPAIR: return "HA_ERR_CRASHED_ON_REPAIR";
+ case HA_ERR_CRASHED_ON_USAGE: return "HA_ERR_CRASHED_ON_USAGE";
+ case HA_ERR_LOCK_WAIT_TIMEOUT: return "HA_ERR_LOCK_WAIT_TIMEOUT";
+ case HA_ERR_LOCK_TABLE_FULL: return "HA_ERR_LOCK_TABLE_FULL";
+ case HA_ERR_READ_ONLY_TRANSACTION: return "HA_ERR_READ_ONLY_TRANSACTION";
+ case HA_ERR_LOCK_DEADLOCK: return "HA_ERR_LOCK_DEADLOCK";
+ case HA_ERR_CANNOT_ADD_FOREIGN: return "HA_ERR_CANNOT_ADD_FOREIGN";
+ case HA_ERR_NO_REFERENCED_ROW: return "HA_ERR_NO_REFERENCED_ROW";
+ case HA_ERR_ROW_IS_REFERENCED: return "HA_ERR_ROW_IS_REFERENCED";
+ case HA_ERR_NO_SAVEPOINT: return "HA_ERR_NO_SAVEPOINT";
+ case HA_ERR_NON_UNIQUE_BLOCK_SIZE: return "HA_ERR_NON_UNIQUE_BLOCK_SIZE";
+ case HA_ERR_NO_SUCH_TABLE: return "HA_ERR_NO_SUCH_TABLE";
+ case HA_ERR_TABLE_EXIST: return "HA_ERR_TABLE_EXIST";
+ case HA_ERR_NO_CONNECTION: return "HA_ERR_NO_CONNECTION";
+ case HA_ERR_NULL_IN_SPATIAL: return "HA_ERR_NULL_IN_SPATIAL";
+ case HA_ERR_TABLE_DEF_CHANGED: return "HA_ERR_TABLE_DEF_CHANGED";
+ case HA_ERR_NO_PARTITION_FOUND: return "HA_ERR_NO_PARTITION_FOUND";
+ case HA_ERR_RBR_LOGGING_FAILED: return "HA_ERR_RBR_LOGGING_FAILED";
+ case HA_ERR_DROP_INDEX_FK: return "HA_ERR_DROP_INDEX_FK";
+ case HA_ERR_FOREIGN_DUPLICATE_KEY: return "HA_ERR_FOREIGN_DUPLICATE_KEY";
+ case HA_ERR_TABLE_NEEDS_UPGRADE: return "HA_ERR_TABLE_NEEDS_UPGRADE";
+ case HA_ERR_TABLE_READONLY: return "HA_ERR_TABLE_READONLY";
+ case HA_ERR_AUTOINC_READ_FAILED: return "HA_ERR_AUTOINC_READ_FAILED";
+ case HA_ERR_AUTOINC_ERANGE: return "HA_ERR_AUTOINC_ERANGE";
+ case HA_ERR_GENERIC: return "HA_ERR_GENERIC";
+ case HA_ERR_RECORD_IS_THE_SAME: return "HA_ERR_RECORD_IS_THE_SAME";
+ case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE";
+ case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT";
+ }
+ return "<unknown error>";
+}
+#endif
+
/*
Cache that will automatically be written to a dedicated file on
destruction.
@@ -114,6 +172,9 @@ private:
flag_set m_flags;
};
+#ifndef DBUG_OFF
+uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation
+#endif
/*
pretty_print_str()
@@ -555,8 +616,32 @@ int Log_event::do_update_pos(Relay_log_info *rli)
Matz: I don't think we will need this check with this refactoring.
*/
if (rli)
- rli->stmt_done(log_pos, when);
-
+ {
+ /*
+ bug#29309 simulation: resetting the flag to force
+ wrong behaviour of artificial event to update
+ rli->last_master_timestamp for only one time -
+ the first FLUSH LOGS in the test.
+ */
+ DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp",
+ if (debug_not_change_ts_if_art_event == 1
+ && is_artificial_event())
+ {
+ debug_not_change_ts_if_art_event= 0;
+ });
+#ifndef DBUG_OFF
+ rli->stmt_done(log_pos,
+ is_artificial_event() &&
+ debug_not_change_ts_if_art_event > 0 ? 0 : when);
+#else
+ rli->stmt_done(log_pos, is_artificial_event()? 0 : when);
+#endif
+ DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp",
+ if (debug_not_change_ts_if_art_event == 0)
+ {
+ debug_not_change_ts_if_art_event= 2;
+ });
+ }
return 0; // Cannot fail currently
}
@@ -570,7 +655,8 @@ Log_event::do_shall_skip(Relay_log_info *rli)
(ulong) server_id, (ulong) ::server_id,
rli->replicate_same_server_id,
rli->slave_skip_counter));
- if (server_id == ::server_id && !rli->replicate_same_server_id)
+ if (server_id == ::server_id && !rli->replicate_same_server_id ||
+ rli->slave_skip_counter == 1 && rli->is_in_group())
return EVENT_SKIP_IGNORE;
else if (rli->slave_skip_counter > 0)
return EVENT_SKIP_COUNT;
@@ -1227,6 +1313,16 @@ void Log_event::print_timestamp(IO_CACHE* file, time_t* ts)
#endif /* MYSQL_CLIENT */
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+inline Log_event::enum_skip_reason
+Log_event::continue_group(Relay_log_info *rli)
+{
+ if (rli->slave_skip_counter == 1)
+ return Log_event::EVENT_SKIP_IGNORE;
+ return Log_event::do_shall_skip(rli);
+}
+#endif
+
/**************************************************************************
Query_log_event methods
**************************************************************************/
@@ -1290,6 +1386,11 @@ static void write_str_with_code_and_len(char **dst, const char *src,
bool Query_log_event::write(IO_CACHE* file)
{
+ /**
+ @todo if catalog can be of length FN_REFLEN==512, then we are not
+ replicating it correctly, since the length is stored in a byte
+ /sven
+ */
uchar buf[QUERY_HEADER_LEN+
1+4+ // code of flags2 and flags2
1+8+ // code of sql_mode and sql_mode
@@ -1516,6 +1617,10 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
time(&end_time);
exec_time = (ulong) (end_time - thd_arg->start_time);
+ /**
+ @todo this means that if we have no catalog, then it is replicated
+ as an existing catalog of length zero. is that safe? /sven
+ */
catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
/* status_vars_len is set just before writing the event */
db_len = (db) ? (uint32) strlen(db) : 0;
@@ -1525,7 +1630,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
/*
If we don't use flags2 for anything else than options contained in
thd_arg->options, it would be more efficient to flags2=thd_arg->options
- (OPTIONS_WRITTEN_TO_BINLOG would be used only at reading time).
+ (OPTIONS_WRITTEN_TO_BIN_LOG would be used only at reading time).
But it's likely that we don't want to use 32 bits for 3 bits; in the future
we will probably want to reclaim the 29 bits. So we need the &.
*/
@@ -1726,6 +1831,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
DBUG_VOID_RETURN;
if (catalog_len) // If catalog is given
{
+ /**
+ @todo we should clean up and do only copy_str_and_move; it
+ works for both cases. Then we can remove the catalog_nz
+ flag. /sven
+ */
if (likely(catalog_nz)) // true except if event comes from 5.0.0|1|2|3.
copy_str_and_move(&catalog, &start, catalog_len);
else
@@ -1738,6 +1848,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
if (time_zone_len)
copy_str_and_move(&time_zone_str, &start, time_zone_len);
+ /**
+ if time_zone_len or catalog_len are 0, then time_zone and catalog
+ are uninitialized at this point. shouldn't they point to the
+ zero-length null-terminated strings we allocated space for in the
+ my_alloc call above? /sven
+ */
+
/* A 2nd variable part; this is common to all versions */
memcpy((char*) start, end, data_len); // Copy db and query
start[data_len]= '\0'; // End query with \0 (For safetly)
@@ -2235,6 +2352,30 @@ int Query_log_event::do_update_pos(Relay_log_info *rli)
}
+Log_event::enum_skip_reason
+Query_log_event::do_shall_skip(Relay_log_info *rli)
+{
+ DBUG_ENTER("Query_log_event::do_shall_skip");
+ DBUG_PRINT("debug", ("query: %s; q_len: %d", query, q_len));
+ DBUG_ASSERT(query && q_len > 0);
+
+ if (rli->slave_skip_counter > 0)
+ {
+ if (strcmp("BEGIN", query) == 0)
+ {
+ thd->options|= OPTION_BEGIN;
+ DBUG_RETURN(Log_event::continue_group(rli));
+ }
+
+ if (strcmp("COMMIT", query) == 0 || strcmp("ROLLBACK", query) == 0)
+ {
+ thd->options&= ~OPTION_BEGIN;
+ DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
+ }
+ }
+ DBUG_RETURN(Log_event::do_shall_skip(rli));
+}
+
#endif
@@ -2774,7 +2915,7 @@ uint Load_log_event::get_query_buffer_length()
21 + sql_ex.field_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'"
23 + sql_ex.enclosed_len*4 + 2 + // " OPTIONALLY ENCLOSED BY 'str'"
12 + sql_ex.escaped_len*4 + 2 + // " ESCAPED BY 'str'"
- 21 + sql_ex.line_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'"
+ 21 + sql_ex.line_term_len*4 + 2 + // " LINES TERMINATED BY 'str'"
19 + sql_ex.line_start_len*4 + 2 + // " LINES STARTING BY 'str'"
15 + 22 + // " IGNORE xxx LINES"
3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)"
@@ -3871,10 +4012,7 @@ Intvar_log_event::do_shall_skip(Relay_log_info *rli)
that we do not change the value of the slave skip counter since it
will be decreased by the following insert event.
*/
- if (rli->slave_skip_counter == 1)
- return Log_event::EVENT_SKIP_IGNORE;
- else
- return Log_event::do_shall_skip(rli);
+ return continue_group(rli);
}
#endif
@@ -3970,10 +4108,7 @@ Rand_log_event::do_shall_skip(Relay_log_info *rli)
that we do not change the value of the slave skip counter since it
will be decreased by the following insert event.
*/
- if (rli->slave_skip_counter == 1)
- return Log_event::EVENT_SKIP_IGNORE;
- else
- return Log_event::do_shall_skip(rli);
+ return continue_group(rli);
}
#endif /* !MYSQL_CLIENT */
@@ -4049,6 +4184,17 @@ int Xid_log_event::do_apply_event(Relay_log_info const *rli)
"COMMIT /* implicit, from Xid_log_event */");
return end_trans(thd, COMMIT);
}
+
+Log_event::enum_skip_reason
+Xid_log_event::do_shall_skip(Relay_log_info *rli)
+{
+ DBUG_ENTER("Xid_log_event::do_shall_skip");
+ if (rli->slave_skip_counter > 0) {
+ thd->options&= ~OPTION_BEGIN;
+ DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
+ }
+ DBUG_RETURN(Log_event::do_shall_skip(rli));
+}
#endif /* !MYSQL_CLIENT */
@@ -4427,10 +4573,7 @@ User_var_log_event::do_shall_skip(Relay_log_info *rli)
that we do not change the value of the slave skip counter since it
will be decreased by the following insert event.
*/
- if (rli->slave_skip_counter == 1)
- return Log_event::EVENT_SKIP_IGNORE;
- else
- return Log_event::do_shall_skip(rli);
+ return continue_group(rli);
}
#endif /* !MYSQL_CLIENT */
@@ -5366,6 +5509,19 @@ int Begin_load_query_log_event::get_create_or_append() const
#endif /* defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+Log_event::enum_skip_reason
+Begin_load_query_log_event::do_shall_skip(Relay_log_info *rli)
+{
+ /*
+ If the slave skip counter is 1, then we should not start executing
+ on the next event.
+ */
+ return continue_group(rli);
+}
+#endif
+
+
/**************************************************************************
Execute_load_query_log_event methods
**************************************************************************/
@@ -5374,12 +5530,13 @@ int Begin_load_query_log_event::get_create_or_append() const
#ifndef MYSQL_CLIENT
Execute_load_query_log_event::
Execute_load_query_log_event(THD *thd_arg, const char* query_arg,
- ulong query_length_arg, uint fn_pos_start_arg,
- uint fn_pos_end_arg,
- enum_load_dup_handling dup_handling_arg,
- bool using_trans, bool suppress_use):
+ ulong query_length_arg, uint fn_pos_start_arg,
+ uint fn_pos_end_arg,
+ enum_load_dup_handling dup_handling_arg,
+ bool using_trans, bool suppress_use,
+ THD::killed_state killed_err_arg):
Query_log_event(thd_arg, query_arg, query_length_arg, using_trans,
- suppress_use),
+ suppress_use, killed_err_arg),
file_id(thd_arg->file_id), fn_pos_start(fn_pos_start_arg),
fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg)
{
@@ -5577,6 +5734,10 @@ bool sql_ex_info::write_data(IO_CACHE* file)
}
else
{
+ /**
+ @todo This is sensitive to field padding. We should write a
+ char[7], not an old_sql_ex. /sven
+ */
old_sql_ex old_ex;
old_ex.field_term= *field_term;
old_ex.enclosed= *enclosed;
@@ -6146,14 +6307,19 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
table->in_use = old_thd;
switch (error)
{
- /* Some recoverable errors */
- case HA_ERR_RECORD_CHANGED:
- case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if
- tuple does not exist */
- error= 0;
case 0:
break;
+ /* Some recoverable errors */
+ case HA_ERR_RECORD_CHANGED:
+ case HA_ERR_RECORD_DELETED:
+ case HA_ERR_KEY_NOT_FOUND:
+ case HA_ERR_END_OF_FILE:
+ /* Idempotency support: OK if tuple does not exist */
+ DBUG_PRINT("info", ("error: %s", HA_ERR(error)));
+ error= 0;
+ break;
+
default:
rli->report(ERROR_LEVEL, thd->net.last_errno,
"Error in %s event: row application failed. %s",
@@ -6170,6 +6336,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
m_curr_row_end.
*/
+ DBUG_PRINT("info", ("error: %d", error));
+ DBUG_PRINT("info", ("curr_row: 0x%lu; curr_row_end: 0x%lu; rows_end: 0x%lu",
+ (ulong) m_curr_row, (ulong) m_curr_row_end, (ulong) m_rows_end));
+
if (!m_curr_row_end && !error)
unpack_current_row(rli);
@@ -6469,6 +6639,16 @@ void Rows_log_event::print_helper(FILE *file,
data) in the table map are initialized as zero (0). The array size is the
same as the columns for the table on the slave.
+ Additionally, values saved for field metadata on the master are saved as a
+ string of bytes (uchar) in the binlog. A field may require 1 or more bytes
+ to store the information. In cases where values require multiple bytes
+ (e.g. values > 255), the endian-safe methods are used to properly encode
+ the values on the master and decode them on the slave. When the field
+ metadata values are captured on the slave, they are stored in an array of
+ type uint16. This allows the least number of casts to prevent casting bugs
+ when the field metadata is used in comparisons of field attributes. When
+ the field metadata is used for calculating addresses in pointer math, the
+ type used is uint32.
*/
/**
@@ -6866,10 +7046,7 @@ Table_map_log_event::do_shall_skip(Relay_log_info *rli)
If the slave skip counter is 1, then we should not start executing
on the next event.
*/
- if (rli->slave_skip_counter == 1)
- return Log_event::EVENT_SKIP_IGNORE;
- else
- return Log_event::do_shall_skip(rli);
+ return continue_group(rli);
}
int Table_map_log_event::do_update_pos(Relay_log_info *rli)
@@ -7383,6 +7560,9 @@ static bool record_compare(TABLE *table)
records. Check that the other engines also return correct records.
*/
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+ DBUG_DUMP("record[1]", table->record[1], table->s->reclength);
+
bool result= FALSE;
uchar saved_x[2], saved_filler[2];
@@ -7471,7 +7651,7 @@ record_compare_exit:
int Rows_log_event::find_row(const Relay_log_info *rli)
{
- DBUG_ENTER("find_row");
+ DBUG_ENTER("Rows_log_event::find_row");
DBUG_ASSERT(m_table && m_table->in_use != NULL);
@@ -7700,7 +7880,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli)
DBUG_DUMP("record found", table->record[0], table->s->reclength);
table->file->ha_rnd_end();
- DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0);
+ DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == HA_ERR_RECORD_DELETED || error == 0);
DBUG_RETURN(error);
}
@@ -7900,7 +8080,15 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli)
int error= find_row(rli);
if (error)
+ {
+ /*
+ We need to read the second image in the event of error to be
+ able to skip to the next pair of updates
+ */
+ m_curr_row= m_curr_row_end;
+ unpack_current_row(rli);
return error;
+ }
/*
This is the situation after locating BI:
diff --git a/sql/log_event.h b/sql/log_event.h
index 0c66d1b190f..4bd496af2a4 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -18,8 +18,10 @@
@{
@file
-
- Binary log event definitions.
+
+ @brief Binary log event definitions. This includes generic code
+ common to all types of log events, as well as specific code for each
+ type of log event.
*/
@@ -37,6 +39,23 @@
#include "rpl_reporting.h"
#endif
+/**
+ Either assert or return an error.
+
+ In debug build, the condition will be checked, but in non-debug
+ builds, the error code given will be returned instead.
+
+ @param COND Condition to check
+ @param ERRNO Error number to return in non-debug builds
+*/
+#ifdef DBUG_OFF
+#define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \
+ do { if (!(COND)) return ERRNO; } while (0)
+#else
+#define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \
+ DBUG_ASSERT(COND)
+#endif
+
#define LOG_READ_EOF -1
#define LOG_READ_BOGUS -2
#define LOG_READ_IO -3
@@ -394,15 +413,19 @@ struct sql_ex_info
#define LOG_EVENT_BINLOG_IN_USE_F 0x1
-/*
- If the query depends on the thread (for example: TEMPORARY TABLE).
- Currently this is used by mysqlbinlog to know it must print
- SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it
- for every query but this would be slow).
+/**
+ @def LOG_EVENT_THREAD_SPECIFIC_F
+
+ If the query depends on the thread (for example: TEMPORARY TABLE).
+ Currently this is used by mysqlbinlog to know it must print
+ SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it
+ for every query but this would be slow).
*/
#define LOG_EVENT_THREAD_SPECIFIC_F 0x4
-/*
+/**
+ @def LOG_EVENT_SUPPRESS_USE_F
+
Suppress the generation of 'USE' statements before the actual
statement. This flag should be set for any events that does not need
the current database set to function correctly. Most notable cases
@@ -421,23 +444,26 @@ struct sql_ex_info
*/
#define LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F 0x10
-/*
- OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must be
- written to the binlog. OPTIONS_WRITTEN_TO_BINLOG could be written
- into the Format_description_log_event, so that if later we don't want
- to replicate a variable we did replicate, or the contrary, it's
- doable. But it should not be too hard to decide once for all of what
- we replicate and what we don't, among the fixed 32 bits of
- thd->options.
- I (Guilhem) have read through every option's usage, and it looks like
- OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only ones
- which alter how the query modifies the table. It's good to replicate
- OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the slave may
- insert data slower than the master, in InnoDB.
- OPTION_BIG_SELECTS is not needed (the slave thread runs with
- max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed
- either, as the manual says (because a too big in-memory temp table is
- automatically written to disk).
+/**
+ @def OPTIONS_WRITTEN_TO_BIN_LOG
+
+ OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must
+ be written to the binlog. OPTIONS_WRITTEN_TO_BIN_LOG could be
+ written into the Format_description_log_event, so that if later we
+ don't want to replicate a variable we did replicate, or the
+ contrary, it's doable. But it should not be too hard to decide once
+ for all of what we replicate and what we don't, among the fixed 32
+ bits of thd->options.
+
+ I (Guilhem) have read through every option's usage, and it looks
+ like OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only
+ ones which alter how the query modifies the table. It's good to
+ replicate OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the
+ slave may insert data slower than the master, in InnoDB.
+ OPTION_BIG_SELECTS is not needed (the slave thread runs with
+ max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed
+ either, as the manual says (because a too big in-memory temp table
+ is automatically written to disk).
*/
#define OPTIONS_WRITTEN_TO_BIN_LOG \
(OPTION_AUTO_IS_NULL | OPTION_NO_FOREIGN_KEY_CHECKS | \
@@ -452,6 +478,11 @@ struct sql_ex_info
#endif
#undef EXPECTED_OPTIONS /* You shouldn't use this one */
+/**
+ @enum Log_event_type
+
+ Enumeration type for the different types of log events.
+*/
enum Log_event_type
{
/*
@@ -612,13 +643,90 @@ typedef struct st_print_event_info
#endif
-/*****************************************************************************
-
- Log_event class
+/**
+ @class Log_event
This is the abstract base class for binary log events.
-
- ****************************************************************************/
+
+ @section Log_event_binary_format Binary Format
+
+ Any Log_event saved on disk consists of the following three
+ components.
+
+ @li Common-Header
+ @li Post-Header
+ @li Body
+
+ The Common-Header, documented below, always has the same form and
+ length within one version of MySQL. Each event type specifies a
+ form and length of the Post-Header common to all events of the type.
+ The Body may be of different form and length even for different
+ events of the same type. The binary formats of Post-Header and Body
+ are documented separately in each subclass. The binary format of
+ Common-Header is as follows.
+
+ <table>
+ <caption>Common-Header</caption>
+
+ <tr>
+ <th>Name</th>
+ <th>Format<br/></th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>timestamp</td>
+ <td>4 byte unsigned integer</td>
+ <td>The number of seconds since 1970.
+ </td>
+ </tr>
+
+ <tr>
+ <td>type</td>
+ <td>1 byte enumeration</td>
+ <td>See enum #Log_event_type.</td>
+ </tr>
+
+ <tr>
+ <td>master_id</td>
+ <td>4 byte integer</td>
+ <td>Server ID of the server that created the event.</td>
+ </tr>
+
+ <tr>
+ <td>total_size</td>
+ <td>4 byte integer</td>
+ <td>The total size of this event, in bytes. In other words, this
+ is the sum of the sizes of Common-Header, Post-Header, and Body.
+ </td>
+ </tr>
+
+ <tr>
+ <td>master_position</td>
+ <td>4 byte integer</td>
+ <td>The position of the next event in the master binary log, in
+ bytes from the beginning of the file.
+ </td>
+ </tr>
+
+ <tr>
+ <td>flags</td>
+ <td>2 byte bitfield</td>
+ <td>See Log_event::flags.</td>
+ </tr>
+ </table>
+
+ Summing up the numbers above, we see that the total size of the
+ common header is 19 bytes.
+
+ @subsection Log_event_endianness_and_string_formats Endianness and String Formats
+
+ All numbers, whether they are 16-, 32-, or 64-bit, are stored in
+ little endian, i.e., the least significant byte first.
+
+ Strings are stored in various formats. The format of each string is
+ documented separately.
+*/
class Log_event
{
public:
@@ -692,8 +800,8 @@ public:
*/
uint32 server_id;
- /*
- Some 16 flags. Look above for LOG_EVENT_TIME_F,
+ /**
+ Some 16 flags. See the definitions above for LOG_EVENT_TIME_F,
LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, and
LOG_EVENT_SUPPRESS_USE_F for notes.
*/
@@ -871,6 +979,25 @@ public:
protected:
/**
+ Helper function to ignore an event w.r.t. the slave skip counter.
+
+ This function can be used inside do_shall_skip() for functions
+ that cannot end a group. If the slave skip counter is 1 when
+ seeing such an event, the event shall be ignored, the counter
+ left intact, and processing continue with the next event.
+
+ A typical usage is:
+ @code
+ enum_skip_reason do_shall_skip(Relay_log_info *rli) {
+ return continue_group(rli);
+ }
+ @endcode
+
+ @return Skip reason
+ */
+ enum_skip_reason continue_group(Relay_log_info *rli);
+
+ /**
Primitive to apply an event to the database.
This is where the change to the database is made.
@@ -950,6 +1077,7 @@ protected:
#endif
};
+
/*
One class for each type of event.
Two constructors for each class:
@@ -963,13 +1091,332 @@ protected:
mysqlbinlog. This constructor must be format-tolerant.
*/
-/*****************************************************************************
-
- Query Log Event class
-
- Logs SQL queries
+/**
+ @class Query_log_event
+
+ Logs SQL queries.
+
+ @section Query_log_event_binary_format Binary format
+
+ The Post-Header has five components:
+
+ <table>
+ <caption>Post-Header for Query_log_event</caption>
+
+ <tr>
+ <th>Name</th>
+ <th>Size<br/></th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>slave_proxy_id</td>
+ <td>4 byte unsigned integer</td>
+ <td>An integer identifying the client thread, which is unique on
+ the server. (Note, however, that two threads on different servers
+ may have the same slave_proxy_id.) This is used when a client
+ thread creates a temporary table. Temporary tables are local to
+ the client, and the slave_proxy_id is used to distinguish
+ temporary tables belonging to different clients.
+ </td>
+ </tr>
+
+ <tr>
+ <td>exec_time</td>
+ <td>4 byte integer</td>
+ <td>???TODO</td>
+ </tr>
+
+ <tr>
+ <td>db_len</td>
+ <td>1 byte integer</td>
+ <td>The length of the name of the currently selected
+ database.
+ </td>
+ </tr>
+
+ <tr>
+ <td>error_code</td>
+ <td>2 byte integer</td>
+ <td>Error code generated by the master. If the master fails, the
+ slave will fail with the same error code, except for the error
+ codes ER_DB_CREATE_EXISTS==1007 and ER_DB_DROP_EXISTS==1008.
+ </td>
+ </tr>
+
+ <tr>
+ <td>status_vars_len</td>
+ <td>2 byte integer</td>
+ <td>The length of the status_vars block of the Body, in bytes. See
+ <a href="#query_log_event_status_vars">below</a>.
+ </td>
+ </tr>
+
+ <tr>
+ <td>Post-Header-For-Derived</td>
+ <td>0 bytes</td>
+ <td>This field is only written by the subclass
+ Execute_load_query_log_event. In this base class, it takes 0
+ bytes. See separate documentation for
+ Execute_load_query_log_event.
+ </td>
+ </tr>
+ </table>
+
+ The Body has the following components:
+
+ <table>
+ <caption>Body for Query_log_event</caption>
+
+ <tr>
+ <th>Name</th>
+ <th>Size<br/></th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td><a name="query_log_event_status_vars" /> status_vars</td>
+ <td>variable length</td>
+ <td>Zero or more status variables. Each status variable consists
+ of one byte identifying the variable stored, followed by the value
+ of the variable. The possible variables are listed separately in
+ the table below. MySQL always writes events in the order defined
+ below; however, it is capable of reading them in any order.
+ </td>
+ </tr>
+
+ <tr>
+ <td>db</td>
+ <td>db_len+1</td>
+ <td>The currently selected database, as a null-terminated string.
+
+ (The trailing zero is redundant since the length is already known;
+ it is db_len from Post-Header.)
+ </td>
+ </tr>
+
+ <tr>
+ <td>query</td>
+ <td>variable length string without trailing zero, extending to the
+ end of the event (determined by the length field of the
+ Common-Header)
+ </td>
+ <td>The SQL query.</td>
+ </tr>
+ </table>
+
+ The following table lists the status variables that may appear in
+ the status_vars field.
+
+ <table>
+ <caption>Status variables for Query_log_event</caption>
+
+ <tr>
+ <th>Status variable</th>
+ <th>1-byte identifier</th>
+ <th>Size<br/></th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>flags2</td>
+ <td>Q_FLAGS2_CODE == 0</td>
+ <td>4 byte bitfield</td>
+ <td>The flags in thd->options, binary AND-ed with
+ OPTIONS_WRITTEN_TO_BIN_LOG. The thd->options bitfield contains
+ options for SELECT. OPTIONS_WRITTEN identifies those options that
+ need to be written to the binlog (not all do). Specifically,
+ OPTIONS_WRITTEN_TO_BIN_LOG equals (OPTION_AUTO_IS_NULL |
+ OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS |
+ OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex.
+
+ These flags correspond to the SQL variables SQL_AUTO_IS_NULL,
+ FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and AUTOCOMMIT, documented in
+ the "SET Syntax" section of the MySQL Manual.
+
+ This field is always written to the binlog in version >= 5.0, and
+ never written in version < 5.0.
+ </td>
+ </tr>
+
+ <tr>
+ <td>sql_mode</td>
+ <td>Q_SQL_MODE_CODE == 1</td>
+ <td>8 byte integer</td>
+ <td>The sql_mode variable. See the section "SQL Modes" in the
+ MySQL manual, and see mysql_priv.h for a list of the possible
+ flags. Currently (2007-10-04), the following flags are available:
+ <pre>
+ MODE_REAL_AS_FLOAT==0x1
+ MODE_PIPES_AS_CONCAT==0x2
+ MODE_ANSI_QUOTES==0x4
+ MODE_IGNORE_SPACE==0x8
+ MODE_NOT_USED==0x10
+ MODE_ONLY_FULL_GROUP_BY==0x20
+ MODE_NO_UNSIGNED_SUBTRACTION==0x40
+ MODE_NO_DIR_IN_CREATE==0x80
+ MODE_POSTGRESQL==0x100
+ MODE_ORACLE==0x200
+ MODE_MSSQL==0x400
+ MODE_DB2==0x800
+ MODE_MAXDB==0x1000
+ MODE_NO_KEY_OPTIONS==0x2000
+ MODE_NO_TABLE_OPTIONS==0x4000
+ MODE_NO_FIELD_OPTIONS==0x8000
+ MODE_MYSQL323==0x10000
+ MODE_MYSQL323==0x20000
+ MODE_MYSQL40==0x40000
+ MODE_ANSI==0x80000
+ MODE_NO_AUTO_VALUE_ON_ZERO==0x100000
+ MODE_NO_BACKSLASH_ESCAPES==0x200000
+ MODE_STRICT_TRANS_TABLES==0x400000
+ MODE_STRICT_ALL_TABLES==0x800000
+ MODE_NO_ZERO_IN_DATE==0x1000000
+ MODE_NO_ZERO_DATE==0x2000000
+ MODE_INVALID_DATES==0x4000000
+ MODE_ERROR_FOR_DIVISION_BY_ZERO==0x8000000
+ MODE_TRADITIONAL==0x10000000
+ MODE_NO_AUTO_CREATE_USER==0x20000000
+ MODE_HIGH_NOT_PRECEDENCE==0x40000000
+ MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000
+ </pre>
+ All these flags are replicated from the server. However, all
+ flags except MODE_NO_DIR_IN_CREATE are honored by the slave; the
+ slave always preserves its old value of MODE_NO_DIR_IN_CREATE.
+ For a rationale, see comment in Query_log_event::do_apply_event in
+ log_event.cc.
+
+ This field is always written to the binlog.
+ </td>
+ </tr>
+
+ <tr>
+ <td>catalog</td>
+ <td>Q_CATALOG_NZ_CODE == 6</td>
+ <td>Variable-length string: the length in bytes (1 byte) followed
+ by the characters (at most 255 bytes)
+ </td>
+ <td>Stores the client's current catalog. Every database belongs
+ to a catalog, the same way that every table belongs to a
+ database. Currently, there is only one catalog, 'std'.
+
+ This field is written if the length of the catalog is > 0;
+ otherwise it is not written.
+ </td>
+ </tr>
+
+ <tr>
+ <td>auto_increment</td>
+ <td>Q_AUTO_INCREMENT == 3</td>
+ <td>two 2 byte unsigned integers, totally 2+2=4 bytes</td>
+
+ <td>The two variables auto_increment_increment and
+ auto_increment_offset, in that order. For more information, see
+ "System variables" in the MySQL manual.
+
+ This field is written if auto_increment>1; otherwise it is not
+ written.
+ </td>
+ </tr>
+
+ <tr>
+ <td>charset</td>
+ <td>Q_CHARSET_CODE == 4</td>
+ <td>three 2-byte unsigned integers (i.e., 6 bytes)</td>
+ <td>The three variables character_set_client,
+ collation_connection, and collation_server, in that order.
+ `character_set_client' is a code identifying the character set and
+ collation used by the client to encode the query.
+ `collation_connection' identifies the character set and collation
+ that the master converts the query to when it receives it; this is
+ useful when comparing literal strings. `collation_server' is the
+ default character set and collation used when a new database is
+ created.
+
+ See also "Connection Character Sets and Collations" in the MySQL
+ 5.1 manual.
+
+ All three variables are codes identifying a (character set,
+ collation) pair. To see which codes map to which pairs, run the
+ query "SELECT id, character_set_name, collation_name FROM
+ COLLATIONS".
+
+ Cf. Q_CHARSET_DATABASE_NUMBER below.
+
+ This field is always written.
+ </td>
+ </tr>
+
+ <tr>
+ <td>time_zone</td>
+ <td>Q_TIME_ZONE_CODE == 5</td>
+ <td>Variable-length string: the length in bytes (1 byte) followed
+ by the characters (at most 255 bytes).
+ <td>The time_zone of the master.
+
+ See also "System Variables" and "MySQL Server Time Zone Support"
+ in the MySQL manual.
+
+ This field is written if the length of the time zone string is >
+ 0; otherwise, it is not written.
+ </td>
+ </tr>
+
+ <tr>
+ <td>lc_time_names_number</td>
+ <td>Q_LC_TIME_NAMES_CODE == 7</td>
+ <td>2 byte integer</td>
+ <td>A code identifying a table of month and day names. The
+ mapping from codes to languages is defined in sql_locale.cc.
+
+ This field is written if it is != 0, i.e., if the locale is not
+ en_US.
+ </td>
+ </tr>
+
+ <tr>
+ <td>charset_database_number</td>
+ <td>Q_CHARSET_DATABASE_NUMBER == 8</td>
+ <td>2 byte integer</td>
+
+ <td>The value of the collation_database system variable (in the
+ source code stored in thd->variables.collation_database), which
+ holds the code for a (character set, collation) pair as described
+ above (see Q_CHARSET_CODE).
+
+ `collation_database' was used in old versions (???WHEN). Its
+ value was loaded when issuing a "use db" command and could be
+ changed by issuing a "SET collation_database=xxx" command. It
+ used to affect the "LOAD DATA INFILE" and "CREATE TABLE" commands.
+
+ In newer versions, "CREATE TABLE" has been changed to take the
+ character set from the database of the created table, rather than
+ the database of the current database. This makes a difference
+ when creating a table in another database than the current one.
+ "LOAD DATA INFILE" has not yet changed to do this, but there are
+ plans to eventually do it, and to make collation_database
+ read-only.
+
+ This field is written if it is not 0.
+ </td>
+ </tr>
+ </table>
+
+ @subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions
+
+ @li Status vars were introduced in version 5.0. To read earlier
+ versions correctly, check the length of the Post-Header.
+
+ @li The status variable Q_CATALOG_CODE == 2 existed in MySQL 5.0.x,
+ where 0<=x<=3. It was identical to Q_CATALOG_CODE, except that the
+ string had a trailing '\0'. The '\0' was removed in 5.0.4 since it
+ was redundant (the string length is stored before the string). The
+ Q_CATALOG_CODE will never be written by a new master, but can still
+ be understood by a new slave.
+
+ @li See Q_CHARSET_DATABASE_NUMBER in the table above.
- ****************************************************************************/
+*/
class Query_log_event: public Log_event
{
protected:
@@ -1027,7 +1474,7 @@ public:
/*
'flags2' is a second set of flags (on top of those in Log_event), for
session variables. These are thd->options which is & against a mask
- (OPTIONS_WRITTEN_TO_BINLOG).
+ (OPTIONS_WRITTEN_TO_BIN_LOG).
flags2_inited helps make a difference between flags2==0 (3.23 or 4.x
master, we don't know flags2, so use the slave server's global options) and
flags2==0 (5.0 master, we know this has a meaning of flags all down which
@@ -1086,6 +1533,7 @@ public:
public: /* !!! Public in this patch to allow old usage */
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
virtual int do_apply_event(Relay_log_info const *rli);
virtual int do_update_pos(Relay_log_info *rli);
@@ -1096,13 +1544,16 @@ public: /* !!! Public in this patch to allow old usage */
};
-/*****************************************************************************
+/**
+ @class Muted_query_log_event
- Muted Query Log Event class
+ Pretends to log SQL queries, but doesn't actually do so.
- Pretends to Log SQL queries, but doesn't actually do so.
+ @section Muted_query_log_event_binary_format Binary Format
- ****************************************************************************/
+ This log event is not stored, and thus the binary format is 0 bytes
+ long. Note that not even the Common-Header is stored.
+*/
class Muted_query_log_event: public Query_log_event
{
public:
@@ -1119,14 +1570,54 @@ public:
#ifdef HAVE_REPLICATION
-/*****************************************************************************
+/**
+ @class Slave_log_event
- Slave Log Event class
Note that this class is currently not used at all; no code writes a
- Slave_log_event (though some code in repl_failsafe.cc reads Slave_log_event).
- So it's not a problem if this code is not maintained.
-
- ****************************************************************************/
+ Slave_log_event (though some code in repl_failsafe.cc reads
+ Slave_log_event). So it's not a problem if this code is not
+ maintained.
+
+ @section Slave_log_event_binary_format Binary Format
+
+ This event type has no Post-Header. The Body has the following
+ four components.
+
+ <table>
+ <caption>Body for Slave_log_event</caption>
+
+ <tr>
+ <th>Name</th>
+ <th>Size<br/></th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>master_pos</td>
+ <td>8 byte integer</td>
+ <td>???TODO
+ </td>
+ </tr>
+
+ <tr>
+ <td>master_port</td>
+ <td>2 byte integer</td>
+ <td>???TODO</td>
+ </tr>
+
+ <tr>
+ <td>master_host</td>
+ <td>null-terminated string</td>
+ <td>???TODO</td>
+ </tr>
+
+ <tr>
+ <td>master_log</td>
+ <td>null-terminated string</td>
+ <td>???TODO</td>
+ </tr>
+ </table>
+*/
class Slave_log_event: public Log_event
{
protected:
@@ -1165,11 +1656,202 @@ private:
#endif /* HAVE_REPLICATION */
-/*****************************************************************************
-
- Load Log Event class
+/**
+ @class Load_log_event
+
+ This log event corresponds to a "LOAD DATA INFILE" SQL query on the
+ following form:
+
+ @verbatim
+ (1) USE db;
+ (2) LOAD DATA [LOCAL] INFILE 'file_name'
+ (3) [REPLACE | IGNORE]
+ (4) INTO TABLE 'table_name'
+ (5) [FIELDS
+ (6) [TERMINATED BY 'field_term']
+ (7) [[OPTIONALLY] ENCLOSED BY 'enclosed']
+ (8) [ESCAPED BY 'escaped']
+ (9) ]
+ (10) [LINES
+ (11) [TERMINATED BY 'line_term']
+ (12) [LINES STARTING BY 'line_start']
+ (13) ]
+ (14) [IGNORE skip_lines LINES]
+ (15) (field_1, field_2, ..., field_n)@endverbatim
+
+ @section Load_log_event_binary_format Binary Format
+
+ The Post-Header consists of the following six components.
+
+ <table>
+ <caption>Post-Header for Load_log_event</caption>
+
+ <tr>
+ <th>Name</th>
+ <th>Size<br/></th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>slave_proxy_id</td>
+ <td>4 byte unsigned integer</td>
+ <td>An integer identifying the client thread, which is unique on
+ the server. (Note, however, that the same slave_proxy_id may
+ appear on different servers.) This is used when a client thread
+ creates a temporary table. Temporary tables are local to the
+ client, and the slave_proxy_id is used to distinguish temporary
+ tables belonging to different clients.
+ </td>
+ </tr>
+
+ <tr>
+ <td>exec_time</td>
+ <td>4 byte unsigned integer</td>
+ <td>???TODO</td>
+ </tr>
+
+ <tr>
+ <td>skip_lines</td>
+ <td>4 byte unsigned integer</td>
+ <td>The number on line (14) above, if present, or 0 if line (14)
+ is left out.
+ </td>
+ </tr>
+
+ <tr>
+ <td>table_name_len</td>
+ <td>1 byte unsigned integer</td>
+ <td>The length of 'table_name' on line (4) above.</td>
+ </tr>
+
+ <tr>
+ <td>db_len</td>
+ <td>1 byte unsigned integer</td>
+ <td>The length of 'db' on line (1) above.</td>
+ </tr>
+
+ <tr>
+ <td>num_fields</td>
+ <td>4 byte unsigned integer</td>
+ <td>The number n of fields on line (15) above.</td>
+ </tr>
+ </table>
+
+ The Body contains the following components.
+
+ <table>
+ <caption>Body of Load_log_event</caption>
+
+ <tr>
+ <th>Name</th>
+ <th>Size<br/></th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>sql_ex</td>
+ <td>variable length</td>
+
+ <td>Describes the part of the query on lines (3) and
+ (5)&ndash;(13) above. More precisely, it stores the five strings
+ (on lines) field_term (6), enclosed (7), escaped (8), line_term
+ (11), and line_start (12); as well as a bitfield indicating the
+ presence of the keywords REPLACE (3), IGNORE (3), and OPTIONALLY
+ (7).
+
+ The data is stored in one of two formats, called "old" and "new".
+ The type field of Common-Header determines which of these two
+ formats is used: type LOAD_EVENT means that the old format is
+ used, and type NEW_LOAD_EVENT means that the new format is used.
+ When MySQL writes a Load_log_event, it uses the new format if at
+ least one of the five strings is two or more bytes long.
+ Otherwise (i.e., if all strings are 0 or 1 bytes long), the old
+ format is used.
+
+ The new and old format differ in the way the five strings are
+ stored.
+
+ <ul>
+ <li> In the new format, the strings are stored in the order
+ field_term, enclosed, escaped, line_term, line_start. Each string
+ consists of a length (1 byte), followed by a sequence of
+ characters (0-255 bytes). Finally, a boolean combination of the
+ following flags is stored in 1 byte: REPLACE_FLAG==0x4,
+ IGNORE_FLAG==0x8, and OPT_ENCLOSED_FLAG==0x2. If a flag is set,
+ it indicates the presence of the corresponding keyword in the SQL
+ query.
+
+ <li> In the old format, we know that each string has length 0 or
+ 1. Therefore, only the first byte of each string is stored. The
+ order of the strings is the same as in the new format. These five
+ bytes are followed by the same 1-byte bitfield as in the new
+ format. Finally, a 1 byte bitfield called empty_flags is stored.
+ The low 5 bits of empty_flags indicate which of the five strings
+ have length 0. For each of the following flags that is set, the
+ corresponding string has length 0; for the flags that are not set,
+ the string has length 1: FIELD_TERM_EMPTY==0x1,
+ ENCLOSED_EMPTY==0x2, LINE_TERM_EMPTY==0x4, LINE_START_EMPTY==0x8,
+ ESCAPED_EMPTY==0x10.
+ </ul>
+
+ Thus, the size of the new format is 6 bytes + the sum of the sizes
+ of the five strings. The size of the old format is always 7
+ bytes.
+ </td>
+ </tr>
+
+ <tr>
+ <td>field_lens</td>
+ <td>num_fields 1-byte unsigned integers</td>
+ <td>An array of num_fields integers representing the length of
+ each field in the query. (num_fields is from the Post-Header).
+ </td>
+ </tr>
+
+ <tr>
+ <td>fields</td>
+ <td>num_fields null-terminated strings</td>
+ <td>An array of num_fields null-terminated strings, each
+ representing a field in the query. (The trailing zero is
+ redundant, since the length are stored in the num_fields array.)
+ The total length of all strings equals to the sum of all
+ field_lens, plus num_fields bytes for all the trailing zeros.
+ </td>
+ </tr>
+
+ <tr>
+ <td>table_name</td>
+ <td>null-terminated string of length table_len+1 bytes</td>
+ <td>The 'table_name' from the query, as a null-terminated string.
+ (The trailing zero is actually redundant since the table_len is
+ known from Post-Header.)
+ </td>
+ </tr>
+
+ <tr>
+ <td>db</td>
+ <td>null-terminated string of length db_len+1 bytes</td>
+ <td>The 'db' from the query, as a null-terminated string.
+ (The trailing zero is actually redundant since the db_len is known
+ from Post-Header.)
+ </td>
+ </tr>
+
+ <tr>
+ <td>file_name</td>
+ <td>variable length string without trailing zero, extending to the
+ end of the event (determined by the length field of the
+ Common-Header)
+ </td>
+ <td>The 'file_name' from the query.
+ </td>
+ </tr>
+
+ </table>
+
+ @subsection Load_log_event_notes_on_previous_versions Notes on Previous Versions
- ****************************************************************************/
+*/
class Load_log_event: public Log_event
{
private:
@@ -1276,9 +1958,8 @@ public: /* !!! Public in this patch to allow old usage */
extern char server_version[SERVER_VERSION_LENGTH];
-/*****************************************************************************
-
- Start Log Event_v3 class
+/**
+ @class Start_log_event_v3
Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and
4.x).
@@ -1288,8 +1969,8 @@ extern char server_version[SERVER_VERSION_LENGTH];
MySQL 5.0 whenever it starts sending a new binlog if the requested position
is >4 (otherwise if ==4 the event will be sent naturally).
- ****************************************************************************/
-
+ @section Start_log_event_v3_binary_format Binary Format
+*/
class Start_log_event_v3: public Log_event
{
public:
@@ -1372,10 +2053,14 @@ protected:
};
-/*
- For binlog version 4.
- This event is saved by threads which read it, as they need it for future
- use (to decode the ordinary events).
+/**
+ @class Format_description_log_event
+
+ For binlog version 4.
+ This event is saved by threads which read it, as they need it for future
+ use (to decode the ordinary events).
+
+ @section Format_description_log_event_binary_format Binary Format
*/
class Format_description_log_event: public Start_log_event_v3
@@ -1429,13 +2114,41 @@ protected:
};
-/*****************************************************************************
+/**
+ @class Intvar_log_event
- Intvar Log Event class
+ Logs special variables related to auto_increment values.
- Logs special variables such as auto_increment values
+ @section Intvar_log_event_binary_format Binary Format
- ****************************************************************************/
+ The Post-Header has two components:
+
+ <table>
+ <caption>Post-Header for Intvar_log_event</caption>
+
+ <tr>
+ <th>Name</th>
+ <th>Size<br/></th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>Type</td>
+ <td>1 byte enumeration</td>
+ <td>One byte identifying the type of variable stored. Currently,
+ two identifiers are supported: LAST_INSERT_ID_EVENT==1 and
+ INSERT_ID_EVENT==2.
+ </td>
+ </tr>
+
+ <tr>
+ <td>value</td>
+ <td>8 byte unsigned integer</td>
+ <td>The value of the variable.</td>
+ </tr>
+
+ </table>
+*/
class Intvar_log_event: public Log_event
{
@@ -1474,16 +2187,24 @@ private:
};
-/*****************************************************************************
-
- Rand Log Event class
+/**
+ @class Rand_log_event
Logs random seed used by the next RAND(), and by PASSWORD() in 4.1.0.
4.1.1 does not need it (it's repeatable again) so this event needn't be
written in 4.1.1 for PASSWORD() (but the fact that it is written is just a
waste, it does not cause bugs).
- ****************************************************************************/
+ @section Rand_log_event_binary_format Binary Format
+ This event type has no Post-Header. The Body of this event type has
+ two components:
+
+ @li seed1 (8 bytes): 64 bit random seed1.
+ @li seed2 (8 bytes): 64 bit random seed2.
+
+ The state of the random number generation consists of 128 bits,
+ which are stored internally as two 64-bit numbers.
+*/
class Rand_log_event: public Log_event
{
@@ -1520,14 +2241,14 @@ private:
#endif
};
-/*****************************************************************************
-
- Xid Log Event class
+/**
+ @class Xid_log_event
Logs xid of the transaction-to-be-committed in the 2pc protocol.
Has no meaning in replication, slaves ignore it.
- ****************************************************************************/
+ @section Xid_log_event_binary_format Binary Format
+*/
#ifdef MYSQL_CLIENT
typedef ulonglong my_xid; // this line is the same as in handler.h
#endif
@@ -1559,17 +2280,18 @@ class Xid_log_event: public Log_event
private:
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
+ enum_skip_reason do_shall_skip(Relay_log_info *rli);
#endif
};
-/*****************************************************************************
-
- User var Log Event class
+/**
+ @class User_var_log_event
Every time a query uses the value of a user variable, a User_var_log_event is
written before the Query_log_event, to set the user variable.
- ****************************************************************************/
+ @section User_var_log_event_binary_format Binary Format
+*/
class User_var_log_event: public Log_event
{
@@ -1611,11 +2333,14 @@ private:
};
-/*****************************************************************************
+/**
+ @class Stop_log_event
- Stop Log Event class
+ @section Stop_log_event_binary_format Binary Format
- ****************************************************************************/
+ The Post-Header and Body for this event type are empty; it only has
+ the Common-Header.
+*/
class Stop_log_event: public Log_event
{
public:
@@ -1651,13 +2376,54 @@ private:
#endif
};
-/*****************************************************************************
-
- Rotate Log Event class
+/**
+ @class Rotate_log_event
This will be deprecated when we move to using sequence ids.
- ****************************************************************************/
+ @section Rotate_log_event_binary_format Binary Format
+
+ The Post-Header has one component:
+
+ <table>
+ <caption>Post-Header for Rotate_log_event</caption>
+
+ <tr>
+ <th>Name</th>
+ <th>Size<br/></th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>pos</td>
+ <td>8 byte integer</td>
+ <td>???TODO</td>
+ </tr>
+
+ </table>
+
+ The Body has one component:
+
+ <table>
+ <caption>Body for Rotate_log_event</caption>
+
+ <tr>
+ <th>Name</th>
+ <th>Size<br/></th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>new_log_ident</td>
+ <td>variable length string without trailing zero, extending to the
+ end of the event (determined by the length field of the
+ Common-Header)
+ </td>
+ <td>???TODO</td>
+ </tr>
+
+ </table>
+*/
class Rotate_log_event: public Log_event
{
@@ -1704,9 +2470,11 @@ private:
/* the classes below are for the new LOAD DATA INFILE logging */
-/*****************************************************************************
- Create File Log Event class
- ****************************************************************************/
+/**
+ @class Create_file_log_event
+
+ @section Create_file_log_event_binary_format Binary Format
+*/
class Create_file_log_event: public Load_log_event
{
@@ -1775,11 +2543,11 @@ private:
};
-/*****************************************************************************
-
- Append Block Log Event class
+/**
+ @class Append_block_log_event
- ****************************************************************************/
+ @section Append_block_log_event_binary_format Binary Format
+*/
class Append_block_log_event: public Log_event
{
@@ -1830,11 +2598,11 @@ private:
};
-/*****************************************************************************
-
- Delete File Log Event class
+/**
+ @class Delete_file_log_event
- ****************************************************************************/
+ @section Delete_file_log_event_binary_format Binary Format
+*/
class Delete_file_log_event: public Log_event
{
@@ -1871,11 +2639,11 @@ private:
};
-/*****************************************************************************
-
- Execute Load Log Event class
+/**
+ @class Execute_load_log_event
- ****************************************************************************/
+ @section Delete_file_log_event_binary_format Binary Format
+*/
class Execute_load_log_event: public Log_event
{
@@ -1911,15 +2679,15 @@ private:
};
-/***************************************************************************
-
- Begin load query Log Event class
+/**
+ @class Begin_load_query_log_event
Event for the first block of file to be loaded, its only difference from
Append_block event is that this event creates or truncates existing file
before writing data.
-****************************************************************************/
+ @section Begin_load_query_log_event_binary_format Binary Format
+*/
class Begin_load_query_log_event: public Append_block_log_event
{
public:
@@ -1937,6 +2705,10 @@ public:
*description_event);
~Begin_load_query_log_event() {}
Log_event_type get_type_code() { return BEGIN_LOAD_QUERY_EVENT; }
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual enum_skip_reason do_shall_skip(Relay_log_info *rli);
+#endif
};
@@ -1946,15 +2718,15 @@ public:
enum enum_load_dup_handling { LOAD_DUP_ERROR= 0, LOAD_DUP_IGNORE,
LOAD_DUP_REPLACE };
-/****************************************************************************
-
- Execute load query Log Event class
+/**
+ @class Execute_load_query_log_event
Event responsible for LOAD DATA execution, it similar to Query_log_event
but before executing the query it substitutes original filename in LOAD DATA
query with name of temporary file.
-****************************************************************************/
+ @section Execute_load_query_log_event_binary_format Binary Format
+*/
class Execute_load_query_log_event: public Query_log_event
{
public:
@@ -1972,10 +2744,12 @@ public:
#ifndef MYSQL_CLIENT
Execute_load_query_log_event(THD* thd, const char* query_arg,
- ulong query_length, uint fn_pos_start_arg,
- uint fn_pos_end_arg,
- enum_load_dup_handling dup_handling_arg,
- bool using_trans, bool suppress_use);
+ ulong query_length, uint fn_pos_start_arg,
+ uint fn_pos_end_arg,
+ enum_load_dup_handling dup_handling_arg,
+ bool using_trans, bool suppress_use,
+ THD::killed_state
+ killed_err_arg= THD::KILLED_NO_VALUE);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
@@ -2006,6 +2780,11 @@ private:
#ifdef MYSQL_CLIENT
+/**
+ @class Unknown_log_event
+
+ @section Unknown_log_event_binary_format Binary Format
+*/
class Unknown_log_event: public Log_event
{
public:
@@ -2026,14 +2805,14 @@ public:
#endif
char *str_to_hex(char *to, const char *from, uint len);
-/*****************************************************************************
-
- Table map log event class
+/**
+ @class Table_map_log_event
Create a mapping from a (database name, table name) couple to a table
identifier (an integer number).
- ****************************************************************************/
+ @section Table_map_log_event_binary_format Binary Format
+*/
class Table_map_log_event : public Log_event
{
public:
@@ -2143,9 +2922,8 @@ private:
};
-/*****************************************************************************
-
- Row level log event class.
+/**
+ @class Rows_log_event
Common base class for all row-containing log events.
@@ -2155,7 +2933,8 @@ private:
- Write data header and data body to an IO_CACHE.
- Provide an interface for adding an individual row to the event.
- ****************************************************************************/
+ @section Rows_log_event_binary_format Binary Format
+*/
class Rows_log_event : public Log_event
@@ -2300,7 +3079,7 @@ protected:
uchar *m_rows_cur; /* One-after the end of the data */
uchar *m_rows_end; /* One-after the end of the allocated space */
- flag_set m_flags; /* Flags for row-level events */
+ flag_set m_flags; /* Flags for row-level events */
/* helper functions */
@@ -2316,8 +3095,11 @@ protected:
int unpack_current_row(const Relay_log_info *const rli)
{
DBUG_ASSERT(m_table);
- return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols,
- &m_curr_row_end, &m_master_reclength);
+ ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
+ int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols,
+ &m_curr_row_end, &m_master_reclength);
+ ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
+ return result;
}
#endif
@@ -2383,15 +3165,15 @@ private:
friend class Old_rows_log_event;
};
-/*****************************************************************************
-
- Write row log event class
+/**
+ @class Write_rows_log_event
Log row insertions and updates. The event contain several
insert/update rows for a table. Note that each event contains only
rows for one table.
- ****************************************************************************/
+ @section Write_rows_log_event_binary_format Binary Format
+*/
class Write_rows_log_event : public Rows_log_event
{
public:
@@ -2438,9 +3220,8 @@ private:
};
-/*****************************************************************************
-
- Update rows log event class
+/**
+ @class Update_rows_log_event
Log row updates with a before image. The event contain several
update rows for a table. Note that each event contains only rows for
@@ -2449,7 +3230,8 @@ private:
Also note that the row data consists of pairs of row data: one row
for the old data and one row for the new data.
- ****************************************************************************/
+ @section Update_rows_log_event_binary_format Binary Format
+*/
class Update_rows_log_event : public Rows_log_event
{
public:
@@ -2511,9 +3293,8 @@ protected:
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
};
-/*****************************************************************************
-
- Delete rows log event class.
+/**
+ @class Delete_rows_log_event
Log row deletions. The event contain several delete rows for a
table. Note that each event contains only rows for one table.
@@ -2530,7 +3311,8 @@ protected:
Row_reader
Extract the rows from the event.
- ****************************************************************************/
+ @section Delete_rows_log_event_binary_format Binary Format
+*/
class Delete_rows_log_event : public Rows_log_event
{
public:
@@ -2580,6 +3362,8 @@ protected:
#include "log_event_old.h"
/**
+ @class Incident_log_event
+
Class representing an incident, an occurance out of the ordinary,
that happened on the master.
@@ -2591,7 +3375,7 @@ protected:
<caption>Incident event format</caption>
<tr>
<th>Symbol</th>
- <th>Size<br>(bytes)</th>
+ <th>Size<br/>(bytes)</th>
<th>Description</th>
</tr>
<tr>
@@ -2610,7 +3394,9 @@ protected:
<td>The message, if present. Not null terminated.</td>
</tr>
</table>
- */
+
+ @section Delete_rows_log_event_binary_format Binary Format
+*/
class Incident_log_event : public Log_event {
public:
#ifndef MYSQL_CLIENT
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 4cf6e05751f..9e947470ca1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2936,7 +2936,6 @@ static int init_common_variables(const char *conf_file_name, int argc,
global_system_variables.collation_connection= default_charset_info;
global_system_variables.character_set_results= default_charset_info;
global_system_variables.character_set_client= default_charset_info;
- global_system_variables.collation_connection= default_charset_info;
if (!(character_set_filesystem=
get_charset_by_csname(character_set_filesystem_name,
diff --git a/sql/records.cc b/sql/records.cc
index 81c26da4b4d..0bf815e4073 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -55,6 +55,7 @@ static int rr_index(READ_RECORD *info);
void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
bool print_error, uint idx)
{
+ empty_record(table);
bzero((char*) info,sizeof(*info));
info->table= table;
info->file= table->file;
@@ -161,6 +162,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
}
else
{
+ empty_record(table);
info->record= table->record[0];
info->ref_length= table->file->ref_length;
}
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
index 65c8e106112..ed0dc82cf01 100644
--- a/sql/rpl_record.cc
+++ b/sql/rpl_record.cc
@@ -65,6 +65,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
my_ptrdiff_t const rec_offset= record - table->record[0];
my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
+ DBUG_ENTER("pack_row");
+
/*
We write the null bits and the packed records using one pass
through all the fields. The null bytes are written little-endian,
@@ -96,26 +98,17 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
For big-endian machines, we have to make sure that the
length is stored in little-endian format, since this is the
format used for the binlog.
-
- We do this by setting the db_low_byte_first, which is used
- inside some store_length() to decide what order to write the
- bytes in.
-
- In reality, db_log_byte_first is only set for legacy table
- type Isam, but in the event of a bug, we need to guarantee
- the endianess when writing to the binlog.
-
- This is currently broken for NDB due to BUG#29549, so we
- will fix it when NDB has fixed their way of handling BLOBs.
*/
-#if 0
- bool save= table->s->db_low_byte_first;
- table->s->db_low_byte_first= TRUE;
-#endif
- pack_ptr= field->pack(pack_ptr, field->ptr + offset);
-#if 0
- table->s->db_low_byte_first= save;
+#ifndef DBUG_OFF
+ const uchar *old_pack_ptr= pack_ptr;
#endif
+ pack_ptr= field->pack(pack_ptr, field->ptr + offset,
+ field->max_data_length(), TRUE);
+ DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;"
+ " pack_ptr':0x%lx; bytes: %d",
+ field->field_name, (ulong) old_pack_ptr,
+ (ulong) pack_ptr,
+ (int) (pack_ptr - old_pack_ptr)));
}
null_mask <<= 1;
@@ -143,8 +136,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
packed data. If it doesn't, something is very wrong.
*/
DBUG_ASSERT(null_ptr == row_data + null_byte_count);
-
- return static_cast<size_t>(pack_ptr - row_data);
+ DBUG_DUMP("row_data", row_data, pack_ptr - row_data);
+ DBUG_RETURN(static_cast<size_t>(pack_ptr - row_data));
}
#endif
@@ -242,18 +235,16 @@ unpack_row(Relay_log_info const *rli,
Use the master's size information if available else call
normal unpack operation.
*/
-#if 0
- bool save= table->s->db_low_byte_first;
- table->s->db_low_byte_first= TRUE;
-#endif
uint16 const metadata= tabledef->field_metadata(i);
- if (tabledef && metadata)
- pack_ptr= f->unpack(f->ptr, pack_ptr, metadata);
- else
- pack_ptr= f->unpack(f->ptr, pack_ptr);
-#if 0
- table->s->db_low_byte_first= save;
+#ifndef DBUG_OFF
+ uchar const *const old_pack_ptr= pack_ptr;
#endif
+ pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE);
+ DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;"
+ " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d",
+ f->field_name, metadata,
+ (ulong) old_pack_ptr, (ulong) pack_ptr,
+ (int) (pack_ptr - old_pack_ptr)));
}
null_mask <<= 1;
@@ -289,6 +280,8 @@ unpack_row(Relay_log_info const *rli,
*/
DBUG_ASSERT(null_ptr == row_data + master_null_byte_count);
+ DBUG_DUMP("row_data", row_data, pack_ptr - row_data);
+
*row_end = pack_ptr;
if (master_reclength)
{
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 867d55a60a3..15d7d97affd 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1082,6 +1082,9 @@ bool Relay_log_info::cached_charset_compare(char *charset) const
void Relay_log_info::stmt_done(my_off_t event_master_log_pos,
time_t event_creation_time)
{
+#ifndef DBUG_OFF
+ extern uint debug_not_change_ts_if_art_event;
+#endif
clear_flag(IN_STMT);
/*
@@ -1121,7 +1124,12 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos,
is that value may take some time to display in
Seconds_Behind_Master - not critical).
*/
- last_master_timestamp= event_creation_time;
+#ifndef DBUG_OFF
+ if (!(event_creation_time == 0 && debug_not_change_ts_if_art_event > 0))
+#else
+ if (event_creation_time != 0)
+#endif
+ last_master_timestamp= event_creation_time;
}
}
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 10ecf1a43d4..a3a57ad4ce9 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -366,6 +366,18 @@ public:
}
/**
+ Get the value of a replication state flag.
+
+ @param flag Flag to get value of
+
+ @return @c true if the flag was set, @c false otherwise.
+ */
+ bool get_flag(enum_state_flag flag)
+ {
+ return m_flags & (1UL << flag);
+ }
+
+ /**
Clear the value of a replication state flag.
@param flag Flag to clear
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index d1ce5bf3b7b..b3ca26d4c2c 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -31,31 +31,34 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const
switch (type(col)) {
case MYSQL_TYPE_NEWDECIMAL:
length= my_decimal_get_binary_size(m_field_metadata[col] >> 8,
- m_field_metadata[col] - ((m_field_metadata[col] >> 8) << 8));
+ m_field_metadata[col] & 0xff);
break;
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
length= m_field_metadata[col];
break;
+ /*
+ The cases for SET and ENUM are include for completeness, however
+ both are mapped to type MYSQL_TYPE_STRING and their real types
+ are encoded in the field metadata.
+ */
case MYSQL_TYPE_SET:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_STRING:
{
- if (((m_field_metadata[col] & 0xff00) == (MYSQL_TYPE_SET << 8)) ||
- ((m_field_metadata[col] & 0xff00) == (MYSQL_TYPE_ENUM << 8)))
+ uchar type= m_field_metadata[col] >> 8U;
+ if ((type == MYSQL_TYPE_SET) || (type == MYSQL_TYPE_ENUM))
length= m_field_metadata[col] & 0x00ff;
else
{
- length= m_field_metadata[col] & 0x00ff;
- DBUG_ASSERT(length > 0);
- if (length > 255)
- {
- DBUG_ASSERT(uint2korr(master_data) > 0);
- length= uint2korr(master_data) + 2;
- }
- else
- length= (uint) *master_data + 1;
+ /*
+ We are reading the actual size from the master_data record
+ because this field has the actual lengh stored in the first
+ byte.
+ */
+ length= (uint) *master_data + 1;
+ DBUG_ASSERT(length != 0);
}
break;
}
@@ -95,6 +98,13 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const
break;
case MYSQL_TYPE_BIT:
{
+ /*
+ Decode the size of the bit field from the master.
+ from_len is the length in bytes from the master
+ from_bit_len is the number of extra bits stored in the master record
+ If from_bit_len is not 0, add 1 to the length to account for accurate
+ number of bytes needed.
+ */
uint from_len= (m_field_metadata[col] >> 8U) & 0x00ff;
uint from_bit_len= m_field_metadata[col] & 0x00ff;
DBUG_ASSERT(from_bit_len <= 7);
@@ -136,7 +146,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const
length= *master_data;
break;
case 2:
- length= sint2korr(master_data);
+ length= uint2korr(master_data);
break;
case 3:
length= uint3korr(master_data);
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index 26edbdd1405..375715c7858 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -99,7 +99,7 @@ public:
/*
These types store a single byte.
*/
- m_field_metadata[i]= (uchar)field_metadata[index];
+ m_field_metadata[i]= field_metadata[index];
index++;
break;
}
@@ -107,14 +107,14 @@ public:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_STRING:
{
- short int x= field_metadata[index++] << 8U; // real_type
- x = x + field_metadata[index++]; // pack or field length
+ uint16 x= field_metadata[index++] << 8U; // real_type
+ x+= field_metadata[index++]; // pack or field length
m_field_metadata[i]= x;
break;
}
case MYSQL_TYPE_BIT:
{
- short int x= field_metadata[index++];
+ uint16 x= field_metadata[index++];
x = x + (field_metadata[index++] << 8U);
m_field_metadata[i]= x;
break;
@@ -125,14 +125,14 @@ public:
These types store two bytes.
*/
char *ptr= (char *)&field_metadata[index];
- m_field_metadata[i]= sint2korr(ptr);
+ m_field_metadata[i]= uint2korr(ptr);
index= index + 2;
break;
}
case MYSQL_TYPE_NEWDECIMAL:
{
- short int x= field_metadata[index++] << 8U; // precision
- x = x + field_metadata[index++]; // decimals
+ uint16 x= field_metadata[index++] << 8U; // precision
+ x+= field_metadata[index++]; // decimals
m_field_metadata[i]= x;
break;
}
diff --git a/sql/slave.cc b/sql/slave.cc
index 7abcf50fa75..d681da23491 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1714,7 +1714,14 @@ static int has_temporary_error(THD *thd)
DBUG_ENTER("has_temporary_error");
if (thd->is_fatal_error)
+ {
+ DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno)));
DBUG_RETURN(0);
+ }
+
+ DBUG_EXECUTE_IF("all_errors_are_temporary_errors",
+ if (thd->net.last_errno)
+ thd->net.last_errno= ER_LOCK_DEADLOCK;);
/*
Temporary error codes:
@@ -1723,7 +1730,10 @@ static int has_temporary_error(THD *thd)
*/
if (thd->net.last_errno == ER_LOCK_DEADLOCK ||
thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT)
+ {
+ DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno)));
DBUG_RETURN(1);
+ }
#ifdef HAVE_NDB_BINLOG
/*
@@ -1794,9 +1804,6 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
int const type_code= ev->get_type_code();
int exec_res= 0;
- /*
- */
-
DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)",
ev->get_type_str(), type_code, ev->server_id));
DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu",
@@ -1805,7 +1812,6 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
rli->last_event_start_time));
-
/*
Execute the event to change the database and update the binary
log coordinates, but first we set some data that is needed for
@@ -1853,10 +1859,13 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
// EVENT_SKIP_NOT,
"not skipped",
// EVENT_SKIP_IGNORE,
- "skipped because event originated from this server",
+ "skipped because event should be ignored",
// EVENT_SKIP_COUNT
"skipped because event skip counter was non-zero"
};
+ DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d",
+ thd->options & OPTION_BEGIN ? 1 : 0,
+ rli->get_flag(Relay_log_info::IN_STMT)));
DBUG_PRINT("skip_event", ("%s event was %s",
ev->get_type_str(), explain[reason]));
#endif
@@ -1905,7 +1914,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
}
if (slave_trans_retries)
{
- if (exec_res && has_temporary_error(thd))
+ int temp_err;
+ if (exec_res && (temp_err= has_temporary_error(thd)))
{
const char *errmsg;
/*
@@ -1953,15 +1963,19 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
"the slave_transaction_retries variable.",
slave_trans_retries);
}
- else if (!((thd->options & OPTION_BEGIN) && opt_using_transactions))
+ else if (exec_res && !temp_err ||
+ (opt_using_transactions &&
+ rli->group_relay_log_pos == rli->event_relay_log_pos))
{
/*
- Only reset the retry counter if the event succeeded or
- failed with a non-transient error. On a successful event,
- the execution will proceed as usual; in the case of a
+ Only reset the retry counter if the entire group succeeded
+ or failed with a non-transient error. On a successful
+ event, the execution will proceed as usual; in the case of a
non-transient error, the slave will stop with an error.
*/
rli->trans_retries= 0; // restart from fresh
+ DBUG_PRINT("info", ("Resetting retry counter, rli->trans_retries: %lu",
+ rli->trans_retries));
}
}
DBUG_RETURN(exec_res);
@@ -2450,6 +2464,7 @@ pthread_handler_t handle_slave_sql(void *arg)
rli->ignore_log_space_limit= 0;
pthread_mutex_unlock(&rli->log_space_lock);
rli->trans_retries= 0; // start from "no error"
+ DBUG_PRINT("info", ("rli->trans_retries: %lu", rli->trans_retries));
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
@@ -3581,7 +3596,16 @@ static Log_event* next_event(Relay_log_info* rli)
a new event and is queuing it; the false "0" will exist until SQL
finishes executing the new event; it will be look abnormal only if
the events have old timestamps (then you get "many", 0, "many").
- Transient phases like this can't really be fixed.
+
+ Transient phases like this can be fixed with implemeting
+ Heartbeat event which provides the slave the status of the
+ master at time the master does not have any new update to send.
+ Seconds_Behind_Master would be zero only when master has no
+ more updates in binlog for slave. The heartbeat can be sent
+ in a (small) fraction of slave_net_timeout. Until it's done
+ rli->last_master_timestamp is temporarely (for time of
+ waiting for the following event) reset whenever EOF is
+ reached.
*/
time_t save_timestamp= rli->last_master_timestamp;
rli->last_master_timestamp= 0;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index c0ea73a6c00..9babbcd49d8 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -102,8 +102,9 @@ sp_get_item_value(THD *thd, Item *item, String *str)
case REAL_RESULT:
case INT_RESULT:
case DECIMAL_RESULT:
- return item->val_str(str);
-
+ if (item->field_type() != MYSQL_TYPE_BIT)
+ return item->val_str(str);
+ else {/* Bit type is handled as binary string */}
case STRING_RESULT:
{
String *result= item->val_str(str);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 632c440266f..439f451814f 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1264,14 +1264,16 @@ public:
We follow this logic:
- when stmt starts, first_successful_insert_id_in_prev_stmt contains the
first insert id successfully inserted by the previous stmt.
- - as stmt makes progress, handler::insert_id_for_cur_row changes; every
- time get_auto_increment() is called, auto_inc_intervals_for_binlog is
- augmented with the reserved interval (if statement-based binlogging).
+ - as stmt makes progress, handler::insert_id_for_cur_row changes;
+ every time get_auto_increment() is called,
+ auto_inc_intervals_in_cur_stmt_for_binlog is augmented with the
+ reserved interval (if statement-based binlogging).
- at first successful insertion of an autogenerated value,
first_successful_insert_id_in_cur_stmt is set to
handler::insert_id_for_cur_row.
- - when stmt goes to binlog, auto_inc_intervals_for_binlog is
- binlogged if non-empty.
+ - when stmt goes to binlog,
+ auto_inc_intervals_in_cur_stmt_for_binlog is binlogged if
+ non-empty.
- when stmt ends, first_successful_insert_id_in_prev_stmt is set to
first_successful_insert_id_in_cur_stmt.
*/
@@ -2469,6 +2471,11 @@ class multi_delete :public select_result_interceptor
/* True if at least one table we delete from is not transactional */
bool normal_tables;
bool delete_while_scanning;
+ /*
+ error handling (rollback and binlogging) can happen in send_eof()
+ so that afterward send_error() needs to find out that.
+ */
+ bool error_handled;
public:
multi_delete(TABLE_LIST *dt, uint num_of_tables);
@@ -2504,6 +2511,11 @@ class multi_update :public select_result_interceptor
/* True if the update operation has made a change in a transactional table */
bool transactional_tables;
bool ignore;
+ /*
+ error handling (rollback and binlogging) can happen in send_eof()
+ so that afterward send_error() needs to find out that.
+ */
+ bool error_handled;
public:
multi_update(TABLE_LIST *ut, TABLE_LIST *leaves_list,
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index f183cb3142f..d80f1fe0d13 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -39,6 +39,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
ha_rows deleted= 0;
uint usable_index= MAX_KEY;
SELECT_LEX *select_lex= &thd->lex->select_lex;
+ THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("mysql_delete");
if (open_and_lock_tables(thd, table_list))
@@ -307,7 +308,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
else
table->file->unlock_row(); // Row failed selection, release lock on it
}
- if (thd->killed || thd->is_error())
+ killed_status= thd->killed;
+ if (killed_status == THD::NOT_KILLED || thd->is_error())
error= 1; // Aborted
if (will_batch && (loc_error= table->file->end_bulk_delete()))
{
@@ -352,13 +354,12 @@ cleanup:
thd->transaction.stmt.modified_non_trans_table= TRUE;
/* See similar binlogging code in sql_update.cc, for comments */
- if ((error < 0) || (deleted && !transactional_table))
+ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
{
if (mysql_bin_log.is_open())
{
if (error < 0)
thd->clear_error();
-
/*
[binlog]: If 'handler::delete_all_rows()' was called and the
storage engine does not inject the rows itself, we replicate
@@ -367,7 +368,7 @@ cleanup:
*/
int log_result= thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_table, FALSE);
+ transactional_table, FALSE, killed_status);
if (log_result && transactional_table)
{
@@ -548,7 +549,7 @@ bool mysql_multi_delete_prepare(THD *thd)
multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg)
: delete_tables(dt), deleted(0), found(0),
num_of_tables(num_of_tables_arg), error(0),
- do_delete(0), transactional_tables(0), normal_tables(0)
+ do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0)
{
tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
}
@@ -727,12 +728,14 @@ void multi_delete::send_error(uint errcode,const char *err)
/* First send error what ever it is ... */
my_message(errcode, err, MYF(0));
- /* If nothing deleted return */
- if (!deleted)
+ /* the error was handled or nothing deleted and no side effects return */
+ if (error_handled ||
+ !thd->transaction.stmt.modified_non_trans_table && !deleted)
DBUG_VOID_RETURN;
/* Something already deleted so we have to invalidate cache */
- query_cache_invalidate3(thd, delete_tables, 1);
+ if (deleted)
+ query_cache_invalidate3(thd, delete_tables, 1);
/*
If rows from the first table only has been deleted and it is
@@ -752,12 +755,30 @@ void multi_delete::send_error(uint errcode,const char *err)
*/
error= 1;
send_eof();
+ DBUG_ASSERT(error_handled);
+ DBUG_VOID_RETURN;
}
- DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);
+
+ if (thd->transaction.stmt.modified_non_trans_table)
+ {
+ /*
+ there is only side effects; to binlog with the error
+ */
+ if (mysql_bin_log.is_open())
+ {
+ thd->binlog_query(THD::ROW_QUERY_TYPE,
+ thd->query, thd->query_length,
+ transactional_tables, FALSE);
+ }
+ thd->transaction.all.modified_non_trans_table= true;
+ }
+ DBUG_ASSERT(!normal_tables || !deleted ||
+ thd->transaction.stmt.modified_non_trans_table);
DBUG_VOID_RETURN;
}
+
/*
Do delete from other tables.
Returns values:
@@ -850,6 +871,7 @@ int multi_delete::do_deletes()
bool multi_delete::send_eof()
{
+ THD::killed_state killed_status= THD::NOT_KILLED;
thd->proc_info="deleting from reference tables";
/* Does deletes for the last n - 1 tables, returns 0 if ok */
@@ -857,7 +879,7 @@ bool multi_delete::send_eof()
/* compute a total error to know if something failed */
local_error= local_error || error;
-
+ killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed;
/* reset used flags */
thd->proc_info="end";
@@ -869,7 +891,9 @@ bool multi_delete::send_eof()
{
query_cache_invalidate3(thd, delete_tables, 1);
}
- if ((local_error == 0) || (deleted && normal_tables))
+ DBUG_ASSERT(!normal_tables || !deleted ||
+ thd->transaction.stmt.modified_non_trans_table);
+ if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table)
{
if (mysql_bin_log.is_open())
{
@@ -877,7 +901,7 @@ bool multi_delete::send_eof()
thd->clear_error();
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_tables, FALSE) &&
+ transactional_tables, FALSE, killed_status) &&
!normal_tables)
{
local_error=1; // Log write failed: roll back the SQL statement
@@ -886,7 +910,8 @@ bool multi_delete::send_eof()
if (thd->transaction.stmt.modified_non_trans_table)
thd->transaction.all.modified_non_trans_table= TRUE;
}
- DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);
+ if (local_error != 0)
+ error_handled= TRUE; // to force early leave from ::send_error()
/* Commit or rollback the current SQL statement */
if (transactional_tables)
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index d3010e4309b..b7806c21466 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -837,59 +837,58 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
}
transactional_table= table->file->has_transactions();
- if ((changed= (info.copied || info.deleted || info.updated)) ||
- was_insert_delayed)
+ if ((changed= (info.copied || info.deleted || info.updated)))
{
/*
Invalidate the table in the query cache if something changed.
For the transactional algorithm to work the invalidation must be
before binlog writing and ha_autocommit_or_rollback
*/
- if (changed)
- query_cache_invalidate3(thd, table_list, 1);
- if (error <= 0 || !transactional_table)
+ query_cache_invalidate3(thd, table_list, 1);
+ }
+ if (changed && error <= 0 || thd->transaction.stmt.modified_non_trans_table
+ || was_insert_delayed)
+ {
+ if (mysql_bin_log.is_open())
{
- if (mysql_bin_log.is_open())
+ if (error <= 0)
{
- if (error <= 0)
- {
- /*
- [Guilhem wrote] Temporary errors may have filled
- thd->net.last_error/errno. For example if there has
- been a disk full error when writing the row, and it was
- MyISAM, then thd->net.last_error/errno will be set to
- "disk full"... and the my_pwrite() will wait until free
- space appears, and so when it finishes then the
- write_row() was entirely successful
- */
- /* todo: consider removing */
- thd->clear_error();
- }
- /* bug#22725:
-
- A query which per-row-loop can not be interrupted with
- KILLED, like INSERT, and that does not invoke stored
- routines can be binlogged with neglecting the KILLED error.
-
- If there was no error (error == zero) until after the end of
- inserting loop the KILLED flag that appeared later can be
- disregarded since previously possible invocation of stored
- routines did not result in any error due to the KILLED. In
- such case the flag is ignored for constructing binlog event.
- */
- DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0);
- if (thd->binlog_query(THD::ROW_QUERY_TYPE,
- thd->query, thd->query_length,
- transactional_table, FALSE,
- (error>0) ? thd->killed : THD::NOT_KILLED) &&
- transactional_table)
- {
- error=1;
- }
- }
- if (thd->transaction.stmt.modified_non_trans_table)
- thd->transaction.all.modified_non_trans_table= TRUE;
+ /*
+ [Guilhem wrote] Temporary errors may have filled
+ thd->net.last_error/errno. For example if there has
+ been a disk full error when writing the row, and it was
+ MyISAM, then thd->net.last_error/errno will be set to
+ "disk full"... and the my_pwrite() will wait until free
+ space appears, and so when it finishes then the
+ write_row() was entirely successful
+ */
+ /* todo: consider removing */
+ thd->clear_error();
+ }
+ /* bug#22725:
+
+ A query which per-row-loop can not be interrupted with
+ KILLED, like INSERT, and that does not invoke stored
+ routines can be binlogged with neglecting the KILLED error.
+
+ If there was no error (error == zero) until after the end of
+ inserting loop the KILLED flag that appeared later can be
+ disregarded since previously possible invocation of stored
+ routines did not result in any error due to the KILLED. In
+ such case the flag is ignored for constructing binlog event.
+ */
+ DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0);
+ if (thd->binlog_query(THD::ROW_QUERY_TYPE,
+ thd->query, thd->query_length,
+ transactional_table, FALSE,
+ (error>0) ? thd->killed : THD::NOT_KILLED) &&
+ transactional_table)
+ {
+ error=1;
+ }
}
+ if (thd->transaction.stmt.modified_non_trans_table)
+ thd->transaction.all.modified_non_trans_table= TRUE;
}
DBUG_ASSERT(transactional_table || !changed ||
thd->transaction.stmt.modified_non_trans_table);
@@ -3089,6 +3088,7 @@ bool select_insert::send_eof()
bool const trans_table= table->file->has_transactions();
ulonglong id;
bool changed;
+ THD::killed_state killed_status= thd->killed;
DBUG_ENTER("select_insert::send_eof");
DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
trans_table, table->file->table_type()));
@@ -3123,7 +3123,7 @@ bool select_insert::send_eof()
thd->clear_error();
thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- trans_table, FALSE);
+ trans_table, FALSE, killed_status);
}
/*
We will call ha_autocommit_or_rollback() also for
@@ -3175,6 +3175,7 @@ void select_insert::abort() {
*/
if (table)
{
+ bool changed, transactional_table;
/*
If we are not in prelocked mode, we end the bulk insert started
before.
@@ -3196,20 +3197,20 @@ void select_insert::abort() {
If table creation failed, the number of rows modified will also be
zero, so no check for that is made.
*/
- if (info.copied || info.deleted || info.updated)
+ changed= (info.copied || info.deleted || info.updated);
+ transactional_table= table->file->has_transactions();
+ if (thd->transaction.stmt.modified_non_trans_table)
{
- DBUG_ASSERT(table != NULL);
- if (!table->file->has_transactions())
- {
if (mysql_bin_log.is_open())
thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length,
- table->file->has_transactions(), FALSE);
- if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table &&
- !can_rollback_data())
+ transactional_table, FALSE);
+ if (!thd->current_stmt_binlog_row_based && !can_rollback_data())
thd->transaction.all.modified_non_trans_table= TRUE;
- query_cache_invalidate3(thd, table, 1);
- }
+ if (changed)
+ query_cache_invalidate3(thd, table, 1);
}
+ DBUG_ASSERT(transactional_table || !changed ||
+ thd->transaction.stmt.modified_non_trans_table);
table->file->ha_release_auto_increment();
}
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 8bbe1e413b3..c96fbb80b0c 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -85,7 +85,8 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
#ifndef EMBEDDED_LIBRARY
static bool write_execute_load_query_log_event(THD *thd,
bool duplicates, bool ignore,
- bool transactional_table);
+ bool transactional_table,
+ THD::killed_state killed_status);
#endif /* EMBEDDED_LIBRARY */
/*
@@ -134,6 +135,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
char *tdb= thd->db ? thd->db : db; // Result is never null
ulong skip_lines= ex->skip_lines;
bool transactional_table;
+ THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("mysql_load");
#ifdef EMBEDDED_LIBRARY
@@ -403,7 +405,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
free_blobs(table); /* if pack_blob was used */
table->copy_blobs=0;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
-
+ /*
+ simulated killing in the middle of per-row loop
+ must be effective for binlogging
+ */
+ DBUG_EXECUTE_IF("simulate_kill_bug27571",
+ {
+ error=1;
+ thd->killed= THD::KILL_QUERY;
+ };);
+ killed_status= (error == 0)? THD::NOT_KILLED : thd->killed;
/*
We must invalidate the table in query cache before binlog writing and
ha_autocommit_...
@@ -445,9 +456,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
/* If the file was not empty, wrote_create_file is true */
if (lf_info.wrote_create_file)
{
- if ((info.copied || info.deleted) && !transactional_table)
+ if (thd->transaction.stmt.modified_non_trans_table)
write_execute_load_query_log_event(thd, handle_duplicates,
- ignore, transactional_table);
+ ignore, transactional_table,
+ killed_status);
else
{
Delete_file_log_event d(thd, db, transactional_table);
@@ -492,8 +504,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
read_info.end_io_cache();
if (lf_info.wrote_create_file)
{
- write_execute_load_query_log_event(thd, handle_duplicates,
- ignore, transactional_table);
+ write_execute_load_query_log_event(thd, handle_duplicates, ignore,
+ transactional_table,killed_status);
}
}
}
@@ -523,7 +535,8 @@ err:
/* Not a very useful function; just to avoid duplication of code */
static bool write_execute_load_query_log_event(THD *thd,
bool duplicates, bool ignore,
- bool transactional_table)
+ bool transactional_table,
+ THD::killed_state killed_err_arg)
{
Execute_load_query_log_event
e(thd, thd->query, thd->query_length,
@@ -531,7 +544,7 @@ static bool write_execute_load_query_log_event(THD *thd,
(char*)thd->lex->fname_end - (char*)thd->query,
(duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
(ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
- transactional_table, FALSE);
+ transactional_table, FALSE, killed_err_arg);
e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
return mysql_bin_log.write(&e);
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 7e194ac76dc..c15370411f0 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2080,7 +2080,16 @@ mysql_execute_command(THD *thd)
if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
goto error;
pthread_mutex_lock(&LOCK_active_mi);
- res = show_master_info(thd,active_mi);
+ if (active_mi != NULL)
+ {
+ res = show_master_info(thd, active_mi);
+ }
+ else
+ {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
+ "the master info structure does not exist");
+ send_ok(thd);
+ }
pthread_mutex_unlock(&LOCK_active_mi);
break;
}
@@ -2935,6 +2944,13 @@ end_with_restore_list:
SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE,
del_result, unit, select_lex);
+ res|= thd->net.report_error;
+ if (unlikely(res))
+ {
+ /* If we had a another error reported earlier then this will be ignored */
+ del_result->send_error(ER_UNKNOWN_ERROR, "Execution of the query failed");
+ del_result->abort();
+ }
delete del_result;
}
else
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 0249af147b0..88040e2933c 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -369,7 +369,6 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
name=0; // Find first log
linfo.index_file_offset = 0;
- thd->current_linfo = &linfo;
if (mysql_bin_log.find_log_pos(&linfo, name, 1))
{
@@ -378,6 +377,10 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
goto err;
}
+ pthread_mutex_lock(&LOCK_thread_count);
+ thd->current_linfo = &linfo;
+ pthread_mutex_unlock(&LOCK_thread_count);
+
if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0)
{
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
@@ -1359,7 +1362,6 @@ bool mysql_show_binlog_events(THD* thd)
name=0; // Find first log
linfo.index_file_offset = 0;
- thd->current_linfo = &linfo;
if (mysql_bin_log.find_log_pos(&linfo, name, 1))
{
@@ -1367,6 +1369,10 @@ bool mysql_show_binlog_events(THD* thd)
goto err;
}
+ pthread_mutex_lock(&LOCK_thread_count);
+ thd->current_linfo = &linfo;
+ pthread_mutex_unlock(&LOCK_thread_count);
+
if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0)
goto err;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 049c050c288..b2837ce246d 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -29,6 +29,8 @@
#include "event_data_objects.h"
#include <my_dir.h>
+#define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
@@ -3135,8 +3137,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
goto err;
}
DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'",
- lookup_field_vals.db_value.str,
- lookup_field_vals.table_value.str));
+ STR_OR_NIL(lookup_field_vals.db_value.str),
+ STR_OR_NIL(lookup_field_vals.table_value.str)));
if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
{
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 46022c9f743..ecb7acda61b 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -203,6 +203,7 @@ int mysql_update(THD *thd,
bool need_reopen;
ulonglong id;
List<Item> all_fields;
+ THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("mysql_update");
for ( ; ; )
@@ -714,45 +715,25 @@ int mysql_update(THD *thd,
thd->row_count++;
}
dup_key_found= 0;
-
- if (!transactional_table && updated > 0)
- thd->transaction.stmt.modified_non_trans_table= TRUE;
-
-
/*
- todo bug#27571: to avoid asynchronization of `error' and
- `error_code' of binlog event constructor
-
- The concept, which is a bit different for insert(!), is to
- replace `error' assignment with the following lines
-
- killed_status= thd->killed; // get the status of the volatile
-
- Notice: thd->killed is type of "state" whereas the lhs has
- "status" the suffix which translates according to WordNet: a state
- at a particular time - at the time of the end of per-row loop in
- our case. Binlogging ops are conducted with the status.
-
- error= (killed_status == THD::NOT_KILLED)? error : 1;
-
- which applies to most mysql_$query functions.
- Event's constructor will accept `killed_status' as an argument:
-
- Query_log_event qinfo(..., killed_status);
-
- thd->killed might be changed after killed_status had got cached and this
- won't affect binlogging event but other effects remain.
-
- Open issue: In a case the error happened not because of KILLED -
- and then KILLED was caught later still within the loop - we shall
- do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN
- error_code.
+ Caching the killed status to pass as the arg to query event constuctor;
+ The cached value can not change whereas the killed status can
+ (externally) since this point and change of the latter won't affect
+ binlogging.
+ It's assumed that if an error was set in combination with an effective
+ killed status then the error is due to killing.
*/
-
- if (thd->killed && !error)
- error= 1; // Aborted
- else if (will_batch &&
- (loc_error= table->file->exec_bulk_update(&dup_key_found)))
+ killed_status= thd->killed; // get the status of the volatile
+ // simulated killing after the loop must be ineffective for binlogging
+ DBUG_EXECUTE_IF("simulate_kill_bug27571",
+ {
+ thd->killed= THD::KILL_QUERY;
+ };);
+ error= (killed_status == THD::NOT_KILLED)? error : 1;
+
+ if (error &&
+ will_batch &&
+ (loc_error= table->file->exec_bulk_update(&dup_key_found)))
/*
An error has occurred when a batched update was performed and returned
an error indication. It cannot be an allowed duplicate key error since
@@ -774,6 +755,10 @@ int mysql_update(THD *thd,
if (will_batch)
table->file->end_bulk_update();
table->file->try_semi_consistent_read(0);
+
+ if (!transactional_table && updated > 0)
+ thd->transaction.stmt.modified_non_trans_table= TRUE;
+
end_read_record(&info);
delete select;
thd->proc_info= "end";
@@ -797,7 +782,7 @@ int mysql_update(THD *thd,
Sometimes we want to binlog even if we updated no rows, in case user used
it to be sure master and slave are in same state.
*/
- if ((error < 0) || (updated && !transactional_table))
+ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
{
if (mysql_bin_log.is_open())
{
@@ -805,7 +790,7 @@ int mysql_update(THD *thd,
thd->clear_error();
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_table, FALSE) &&
+ transactional_table, FALSE, killed_status) &&
transactional_table)
{
error=1; // Rollback update
@@ -1215,8 +1200,8 @@ multi_update::multi_update(TABLE_LIST *table_list,
:all_tables(table_list), leaves(leaves_list), update_tables(0),
tmp_tables(0), updated(0), found(0), fields(field_list),
values(value_list), table_count(0), copy_field(0),
- handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0),
- transactional_tables(1), ignore(ignore_arg)
+ handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1),
+ transactional_tables(1), ignore(ignore_arg), error_handled(0)
{}
@@ -1418,7 +1403,6 @@ multi_update::initialize_tables(JOIN *join)
if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
DBUG_RETURN(1);
main_table=join->join_tab->table;
- trans_safe= transactional_tables= main_table->file->has_transactions();
table_to_update= 0;
/* Any update has at least one pair (field, value) */
@@ -1713,12 +1697,14 @@ void multi_update::send_error(uint errcode,const char *err)
/* First send error what ever it is ... */
my_error(errcode, MYF(0), err);
- /* If nothing updated return */
- if (updated == 0) /* the counter might be reset in send_eof */
- return; /* and then the query has been binlogged */
+ /* the error was handled or nothing deleted and no side effects return */
+ if (error_handled ||
+ !thd->transaction.stmt.modified_non_trans_table && !updated)
+ return;
/* Something already updated so we have to invalidate cache */
- query_cache_invalidate3(thd, update_tables, 1);
+ if (updated)
+ query_cache_invalidate3(thd, update_tables, 1);
/*
If all tables that has been updated are trans safe then just do rollback.
If not attempt to do remaining updates.
@@ -1750,12 +1736,16 @@ void multi_update::send_error(uint errcode,const char *err)
*/
if (mysql_bin_log.is_open())
{
+ /*
+ THD::killed status might not have been set ON at time of an error
+ got caught and if happens later the killed error is written
+ into repl event.
+ */
thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
transactional_tables, FALSE);
}
- if (!trans_safe)
- thd->transaction.all.modified_non_trans_table= TRUE;
+ thd->transaction.all.modified_non_trans_table= TRUE;
}
DBUG_ASSERT(trans_safe || !updated || thd->transaction.stmt.modified_non_trans_table);
@@ -1947,11 +1937,20 @@ bool multi_update::send_eof()
{
char buff[STRING_BUFFER_USUAL_SIZE];
ulonglong id;
+ THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("multi_update::send_eof");
thd->proc_info="updating reference tables";
- /* Does updates for the last n - 1 tables, returns 0 if ok */
+ /*
+ Does updates for the last n - 1 tables, returns 0 if ok;
+ error takes into account killed status gained in do_updates()
+ */
int local_error = (table_count) ? do_updates(0) : 0;
+ /*
+ if local_error is not set ON until after do_updates() then
+ later carried out killing should not affect binlogging.
+ */
+ killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed;
thd->proc_info= "end";
/* We must invalidate the query cache before binlog writing and
@@ -1978,11 +1977,9 @@ bool multi_update::send_eof()
{
if (local_error == 0)
thd->clear_error();
- else
- updated= 0; /* if there's an error binlog it here not in ::send_error */
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_tables, FALSE) &&
+ transactional_tables, FALSE, killed_status) &&
trans_safe)
{
local_error= 1; // Rollback update
@@ -1991,6 +1988,8 @@ bool multi_update::send_eof()
if (thd->transaction.stmt.modified_non_trans_table)
thd->transaction.all.modified_non_trans_table= TRUE;
}
+ if (local_error != 0)
+ error_handled= TRUE; // to force early leave from ::send_error()
if (transactional_tables)
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index b337f82dec3..5d4ac9c75b3 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -6745,6 +6745,7 @@ function_call_keyword:
| CURRENT_USER optional_braces
{
$$= new (YYTHD->mem_root) Item_func_current_user(Lex->current_context());
+ Lex->set_stmt_unsafe();
Lex->safe_to_cache_query= 0;
}
| DATE_SYM '(' expr ')'
@@ -6790,6 +6791,7 @@ function_call_keyword:
| USER '(' ')'
{
$$= new (YYTHD->mem_root) Item_func_user();
+ Lex->set_stmt_unsafe();
Lex->safe_to_cache_query=0;
}
| YEAR_SYM '(' expr ')'
diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c
index fd783015bf4..247fb041896 100644
--- a/strings/ctype-euc_kr.c
+++ b/strings/ctype-euc_kr.c
@@ -179,20 +179,40 @@ static uchar NEAR sort_order_euc_kr[]=
/* Support for Korean(EUC_KR) characters, by powerm90@tinc.co.kr and mrpark@tinc.co.kr */
-#define iseuc_kr(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe))
+/*
+ Unicode mapping is done according to:
+ ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/KSC/KSC5601.TXT
+
+ Valid multi-byte characters:
+
+ [A1..FE][41..5A,61..7A,81..FE]
+
+ Note, 0x5C is not a valid MB tail,
+ so escape_with_backslash_is_dangerous is not set.
+*/
+
+#define iseuc_kr_head(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe))
+
+#define iseuc_kr_tail1(c) ((uchar) (c) >= 0x41 && (uchar) (c) <= 0x5A)
+#define iseuc_kr_tail2(c) ((uchar) (c) >= 0x61 && (uchar) (c) <= 0x7A)
+#define iseuc_kr_tail3(c) ((uchar) (c) >= 0x81 && (uchar) (c) <= 0xFE)
+
+#define iseuc_kr_tail(c) (iseuc_kr_tail1(c) || \
+ iseuc_kr_tail2(c) || \
+ iseuc_kr_tail3(c))
static uint ismbchar_euc_kr(CHARSET_INFO *cs __attribute__((unused)),
const char* p, const char *e)
{
return ((*(uchar*)(p)<0x80)? 0:\
- iseuc_kr(*(p)) && (e)-(p)>1 && iseuc_kr(*((p)+1))? 2:\
+ iseuc_kr_head(*(p)) && (e)-(p)>1 && iseuc_kr_tail(*((p)+1))? 2:\
0);
}
static uint mbcharlen_euc_kr(CHARSET_INFO *cs __attribute__((unused)),uint c)
{
- return (iseuc_kr(c) ? 2 : 1);
+ return (iseuc_kr_head(c) ? 2 : 1);
}
@@ -8654,7 +8674,7 @@ my_well_formed_len_euckr(CHARSET_INFO *cs __attribute__((unused)),
/* Single byte ascii character */
b++;
}
- else if (b < emb && iseuc_kr(*b) && iseuc_kr(b[1]))
+ else if (b < emb && iseuc_kr_head(*b) && iseuc_kr_tail(b[1]))
{
/* Double byte character */
b+= 2;