summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraelkin/elkin@koti.dsl.inet.fi <>2007-10-30 11:31:03 +0200
committeraelkin/elkin@koti.dsl.inet.fi <>2007-10-30 11:31:03 +0200
commite65d20b5f4e6e4929a74d93086f4f1760962c5d0 (patch)
treef5e6986d61bf71321559f4a770993fbb5aa8da16
parent70488d7dfe70ca9834d54cd8d034554340686594 (diff)
parentf974872f5c6380145c8bdfb6e5308b02d0b8c81a (diff)
downloadmariadb-git-e65d20b5f4e6e4929a74d93086f4f1760962c5d0.tar.gz
Merge koti.dsl.inet.fi:/home/elkin/MySQL/TEAM/FIXES/5.0/bug27571_asyn_killed_flags
into koti.dsl.inet.fi:/home/elkin/MySQL/5.1-merge-bug27571
-rw-r--r--mysql-test/r/rpl_slave_skip.result144
-rw-r--r--mysql-test/suite/binlog/r/binlog_killed.result106
-rw-r--r--mysql-test/suite/binlog/t/binlog_killed.test297
-rw-r--r--mysql-test/suite/rpl/t/rpl_sp_effects.test50
-rw-r--r--mysql-test/t/binlog_killed_bug27571-master.opt1
-rw-r--r--mysql-test/t/binlog_killed_bug27571.test68
-rw-r--r--mysql-test/t/binlog_killed_simulate-master.opt1
-rw-r--r--mysql-test/t/binlog_killed_simulate.test65
-rw-r--r--mysql-test/t/rpl_slave_skip-slave.opt1
-rw-r--r--mysql-test/t/rpl_slave_skip.test203
-rw-r--r--sql/item_cmpfunc.cc2
-rw-r--r--sql/log_event.cc11
-rw-r--r--sql/log_event.h10
-rw-r--r--sql/slave.cc154
-rw-r--r--sql/sp_head.cc5
-rw-r--r--sql/sql_delete.cc34
-rw-r--r--sql/sql_insert.cc25
-rw-r--r--sql/sql_load.cc58
-rw-r--r--sql/sql_update.cc120
19 files changed, 1208 insertions, 147 deletions
diff --git a/mysql-test/r/rpl_slave_skip.result b/mysql-test/r/rpl_slave_skip.result
new file mode 100644
index 00000000000..a59ac3eb884
--- /dev/null
+++ b/mysql-test/r/rpl_slave_skip.result
@@ -0,0 +1,144 @@
+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 ****
+CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB;
+CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM;
+==== Skipping normal transactions ====
+**** On Slave ****
+STOP SLAVE;
+**** On Master ****
+BEGIN;
+INSERT INTO t1 VALUES (1, 'master');
+INSERT INTO t1 VALUES (2, 'master');
+INSERT INTO t1 VALUES (3, 'master');
+COMMIT;
+BEGIN;
+INSERT INTO t1 VALUES (4, 'master,slave');
+INSERT INTO t1 VALUES (5, 'master,slave');
+INSERT INTO t1 VALUES (6, 'master,slave');
+COMMIT;
+SELECT * FROM t1 ORDER BY a;
+a b
+1 master
+2 master
+3 master
+4 master,slave
+5 master,slave
+6 master,slave
+**** On Slave ****
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+SELECT * FROM t1 ORDER BY a;
+a b
+4 master,slave
+5 master,slave
+6 master,slave
+**** On Master ****
+DELETE FROM t1;
+==== Skipping two normal transactions ====
+**** On Slave ****
+STOP SLAVE;
+**** On Master ****
+BEGIN;
+INSERT INTO t1 VALUES (1, 'master');
+INSERT INTO t1 VALUES (2, 'master');
+INSERT INTO t1 VALUES (3, 'master');
+COMMIT;
+BEGIN;
+INSERT INTO t1 VALUES (4, 'master');
+INSERT INTO t1 VALUES (5, 'master');
+INSERT INTO t1 VALUES (6, 'master');
+COMMIT;
+BEGIN;
+INSERT INTO t1 VALUES (7, 'master,slave');
+INSERT INTO t1 VALUES (8, 'master,slave');
+INSERT INTO t1 VALUES (9, 'master,slave');
+COMMIT;
+SELECT * FROM t1 ORDER BY a;
+a b
+1 master
+2 master
+3 master
+4 master
+5 master
+6 master
+7 master,slave
+8 master,slave
+9 master,slave
+**** On Slave ****
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
+START SLAVE;
+SELECT * FROM t1 ORDER BY a;
+a b
+7 master,slave
+8 master,slave
+9 master,slave
+**** On Master ****
+DELETE FROM t1;
+==== Skipping without autocommit ====
+**** On Slave ****
+STOP SLAVE;
+**** On Master ****
+SET AUTOCOMMIT=0;
+INSERT INTO t1 VALUES (1, 'master');
+INSERT INTO t1 VALUES (2, 'master');
+INSERT INTO t1 VALUES (3, 'master');
+COMMIT;
+INSERT INTO t1 VALUES (4, 'master,slave');
+INSERT INTO t1 VALUES (5, 'master,slave');
+INSERT INTO t1 VALUES (6, 'master,slave');
+COMMIT;
+SELECT * FROM t1 ORDER BY a;
+a b
+1 master
+2 master
+3 master
+4 master,slave
+5 master,slave
+6 master,slave
+**** On Slave ****
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+SELECT * FROM t1 ORDER BY a;
+a b
+4 master,slave
+5 master,slave
+6 master,slave
+==== Rollback of transaction with non-transactional change ====
+**** On Master ****
+DELETE FROM t1;
+SET AUTOCOMMIT=1;
+**** On Slave ****
+STOP SLAVE;
+**** On Master ****
+BEGIN;
+INSERT INTO t1 VALUES (1, '');
+INSERT INTO t2 VALUES (2, 'master');
+INSERT INTO t1 VALUES (3, '');
+ROLLBACK;
+BEGIN;
+INSERT INTO t1 VALUES (4, '');
+INSERT INTO t2 VALUES (5, 'master,slave');
+INSERT INTO t1 VALUES (6, '');
+ROLLBACK;
+SELECT * FROM t1 ORDER BY a;
+a b
+SELECT * FROM t2 ORDER BY a;
+a b
+2 master
+5 master,slave
+**** On Slave ****
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+SELECT * FROM t1 ORDER BY a;
+a b
+SELECT * FROM t2 ORDER BY a;
+a b
+5 master,slave
+==== Cleanup ====
+**** On Master ****
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/binlog/r/binlog_killed.result b/mysql-test/suite/binlog/r/binlog_killed.result
index ba4f38fb4c1..ddd80283eca 100644
--- a/mysql-test/suite/binlog/r/binlog_killed.result
+++ b/mysql-test/suite/binlog/r/binlog_killed.result
@@ -9,4 +9,110 @@ insert into t2 values (null, null), (null, get_lock("a", 10));
select @result /* must be zero either way */;
@result
0
+delete from t1;
+delete from t2;
+insert into t1 values (1,1),(2,2);
+begin;
+update t1 set b=11 where a=2;
+update t1 set b=b+10;
+kill query ID;
+rollback;
+ERROR 70100: Query execution was interrupted
+select * from t1 /* must be the same as before (1,1),(2,2) */;
+a b
+1 1
+2 2
+begin;
+delete from t1 where a=2;
+delete from t1 where a=2;
+kill query ID;
+rollback;
+ERROR 70100: Query execution was interrupted
+select * from t1 /* 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;
+ERROR 70100: Query execution was interrupted
+rollback;
+select * from t1 /* must be the same as before (1,1),(2,2) */;
+a b
+1 1
+2 2
+drop table t4;
+create function bug27563(n int)
+RETURNS int(11)
+DETERMINISTIC
+begin
+if n > 1 then
+select get_lock("a", 10) into @a;
+end if;
+return n;
+end|
+delete from t2;
+insert into t2 values (1,1), (2,2);
+reset master;
+select get_lock("a", 20);
+get_lock("a", 20)
+1
+update t2 set b=b + bug27563(b) order by a;
+kill query ID;
+ERROR 70100: Query execution was interrupted
+select * from t2 /* must be (1,2), (2,2) */;
+a b
+1 2
+2 2
+show master status /* must have the update event more to FD */;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000001 211
+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 t2;
+insert into t2 values (1,1), (2,2);
+reset master;
+select get_lock("a", 20);
+get_lock("a", 20)
+1
+delete from t2 where a=1 or a=bug27563(2) order by a;
+kill query ID;
+ERROR 70100: Query execution was interrupted
+select * from t2 /* must be (1,2), (2,2) */;
+a b
+1 1
+2 2
+show master status /* must have the update event more to FD */;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000001 98
+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 function bug27563;
drop table t1,t2,t3;
+end of the tests
diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test
index 6c0b4b46a4e..89028d1c6b7 100644
--- a/mysql-test/suite/binlog/t/binlog_killed.test
+++ b/mysql-test/suite/binlog/t/binlog_killed.test
@@ -55,194 +55,239 @@ 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 ;|
-
-reset master;
+--remove_file $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog
-### ta table case: killing causes rollback
+#
+# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code
+#
-# A. autocommit ON
-connection con1;
-select get_lock("a", 20);
+# checking that killing inside of select loops is safe as before
+# killing after the loop can be only simulated - another test
-connection con2;
+delete from t1;
+delete from t2;
+insert into t1 values (1,1),(2,2);
let $ID= `select connection_id()`;
-send insert into t1 values (bug27563(),1);
+#
+# simple update
+#
connection con1;
-eval kill query $ID;
+begin; update t1 set b=11 where a=2;
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
-connection con2;
-let $ID= `select connection_id()`;
-begin;
-send insert into t1 values (bug27563(),1);
+send update t1 set b=b+10;
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
+--error ER_QUERY_INTERRUPTED
reap;
---disable_info
-select count(*) from t1 /* must be zero unless Bug#27563 */;
-commit;
+select * from t1 /* 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;
-### non-ta table case: killing must be recorded in binlog
+# connection con1;
+# --replace_result $ID ID
+# eval kill query $ID;
+# rollback;
-reset master;
+# 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()`;
-send insert into t2 values (bug27563(),1);
+send delete from t1 where a=2;
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
+--error 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
+select * from t1 /* must be the same as before (1,1),(2,2) */;
-connection con1;
-select RELEASE_LOCK("a");
+#
+# multi delete
+# the same as for multi-update
+#
+# connection con1;
+# begin; delete from t1 where a=2;
-### test with effective killing of SF()
+# connection con2;
+# send delete t1 from t1 where t1.a=2;
-delete from t1;
-delete from t2;
-insert into t1 values (1,1);
-insert into t2 values (1,1);
+# connection con1;
+# --replace_result $ID ID
+# eval kill query $ID;
+# rollback;
-#
-# 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;
+# 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 update t2 set b=bug27565()-1 where a=1;
+begin;
+send insert into t1 select * from t4 for update;
connection con1;
+--replace_result $ID ID
eval kill query $ID;
-commit;
+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 * from t1 /* must be: (1,0) */;
-select * from t2 /* must be as before: (1,1) */;
+--error ER_QUERY_INTERRUPTED
+reap;
+rollback;
+select * from t1 /* must be the same as before (1,1),(2,2) */;
+
+drop table t4; # cleanup for the sub-case
+
+###
+## non-ta table case: killing must be recorded in binlog
+###
+delimiter |;
+create function bug27563(n int)
+RETURNS int(11)
+DETERMINISTIC
+begin
+ if n > 1 then
+ select get_lock("a", 10) into @a;
+ end if;
+ return n;
+end|
+delimiter ;|
-## bug#22725 with effective and propagating killing
#
-# top-level ta-table
-connection con1;
-delete from t3;
+# update
+#
+
+delete from t2;
+insert into t2 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());
+send update t2 set b=b + bug27563(b) order by a;
connection con1;
+--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
+--error ER_QUERY_INTERRUPTED
+reap;
+select * from t2 /* must be (1,2), (2,2) */;
+show master status /* must have the update event more to FD */;
+
+# a proof the query is binlogged with an error
+
+--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
connection con1;
+select RELEASE_LOCK("a");
+--remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
+
+#
+# delete
+#
+
delete from t2;
+insert into t2 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 intrurrupted
-send insert into t2 values (0,0),(1,bug27565()) /* non-ta t2 */;
+send delete from t2 where a=1 or a=bug27563(2) order by a;
connection con1;
+--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
+--error ER_QUERY_INTERRUPTED
+reap;
+select * from t2 /* must be (1,2), (2,2) */;
+show master status /* must have the update event more to FD */;
-select count(*) from t2 /* count must be one */;
-show master status /* insert into non-ta must be in binlog */;
+# a proof the query is binlogged with an error
+
+--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
+connection con1;
+select RELEASE_LOCK("a");
+--remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.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/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/t/binlog_killed_bug27571-master.opt b/mysql-test/t/binlog_killed_bug27571-master.opt
new file mode 100644
index 00000000000..d269cf246d5
--- /dev/null
+++ b/mysql-test/t/binlog_killed_bug27571-master.opt
@@ -0,0 +1 @@
+--loose-debug=d,stop_after_row_loop_done
diff --git a/mysql-test/t/binlog_killed_bug27571.test b/mysql-test/t/binlog_killed_bug27571.test
new file mode 100644
index 00000000000..6fa3c6d256f
--- /dev/null
+++ b/mysql-test/t/binlog_killed_bug27571.test
@@ -0,0 +1,68 @@
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source include/have_log_bin.inc
+
+#
+# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code
+#
+# Checking that if killing happens inbetween of the end of rows loop and
+# recording into binlog that will not lead to recording any error incl
+# the killed error.
+#
+
+connect (looser, localhost, root,,);
+connect (killer, localhost, root,,);
+
+create table t1 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB;
+
+delete from t1;
+insert into t1 values (1,1),(2,2);
+reset master;
+
+connection looser;
+let $ID= `select connection_id()`;
+send update t1 set b=11 where a=2;
+
+connection killer;
+sleep 1; # let 1 second for the update to get to the sleeping point
+--replace_result $ID ID
+eval kill query $ID;
+
+connection looser;
+--error 0 # zero even though the query must be got killed while it was sleepin for 5 secs
+reap;
+
+#
+# this is another possible artifact. The killed error was not caught
+# as that is logical as killing was not effective:
+# data are ok and well as binlog event is without killed error (further).
+# The reason of the following `show error' is to prove that
+# killing simulation was effective
+#
+show errors;
+
+connection killer;
+
+# nothing is rolled back
+
+select * from t1 where a=2 /* must be 11 */;
+
+# a proof the query is binlogged with an error
+
+--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%"`;
+
+eval select $error_code /* must return 1*/;
+
+#
+# cleanup
+#
+
+drop table t1;
+
+--echo end of the tests
diff --git a/mysql-test/t/binlog_killed_simulate-master.opt b/mysql-test/t/binlog_killed_simulate-master.opt
new file mode 100644
index 00000000000..90c70ecee29
--- /dev/null
+++ b/mysql-test/t/binlog_killed_simulate-master.opt
@@ -0,0 +1 @@
+--loose-debug=d,simulate_kill_bug27571
diff --git a/mysql-test/t/binlog_killed_simulate.test b/mysql-test/t/binlog_killed_simulate.test
new file mode 100644
index 00000000000..d6234d1bfd7
--- /dev/null
+++ b/mysql-test/t/binlog_killed_simulate.test
@@ -0,0 +1,65 @@
+#
+# 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
+
+--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 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/t/rpl_slave_skip-slave.opt b/mysql-test/t/rpl_slave_skip-slave.opt
new file mode 100644
index 00000000000..627becdbfb5
--- /dev/null
+++ b/mysql-test/t/rpl_slave_skip-slave.opt
@@ -0,0 +1 @@
+--innodb
diff --git a/mysql-test/t/rpl_slave_skip.test b/mysql-test/t/rpl_slave_skip.test
new file mode 100644
index 00000000000..04aafc51129
--- /dev/null
+++ b/mysql-test/t/rpl_slave_skip.test
@@ -0,0 +1,203 @@
+source include/have_innodb.inc;
+source include/master-slave.inc;
+
+# This test is for checking that the use of SQL_SLAVE_SKIP_COUNTER
+# behaves as expected, i.e., that it is guaranteed to skip an entire
+# group and not start executing in the middle of a transaction.
+
+# We are checking the correct behaviour when using both a
+# transactional and non-transactional table. The non-transactional
+# table comes into play when rolling back a transaction containing a
+# write to this table. In that case, the transaction should still be
+# written to the binary log, and the slave will apply it and then roll
+# it back to get the non-transactional change into the table.
+
+--echo **** On Master ****
+CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB;
+CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM;
+
+--echo ==== Skipping normal transactions ====
+
+--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 t1 VALUES (1, 'master');
+INSERT INTO t1 VALUES (2, 'master');
+INSERT INTO t1 VALUES (3, 'master');
+COMMIT;
+
+BEGIN;
+INSERT INTO t1 VALUES (4, 'master,slave');
+INSERT INTO t1 VALUES (5, 'master,slave');
+INSERT INTO t1 VALUES (6, 'master,slave');
+COMMIT;
+
+save_master_pos;
+
+SELECT * FROM t1 ORDER BY a;
+
+# This will skip a begin event and the first INSERT of the
+# transaction, and it should keep skipping until it has reached the
+# transaction terminator.
+
+--echo **** On Slave ****
+connection slave;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+source include/wait_for_slave_to_start.inc;
+sync_with_master;
+SELECT * FROM t1 ORDER BY a;
+
+--echo **** On Master ****
+connection master;
+DELETE FROM t1;
+sync_slave_with_master;
+
+--echo ==== Skipping two normal transactions ====
+
+--echo **** On Slave ****
+connection slave;
+STOP SLAVE;
+source include/wait_for_slave_to_stop.inc;
+
+--echo **** On Master ****
+connection master;
+
+BEGIN;
+INSERT INTO t1 VALUES (1, 'master');
+INSERT INTO t1 VALUES (2, 'master');
+INSERT INTO t1 VALUES (3, 'master');
+COMMIT;
+
+BEGIN;
+INSERT INTO t1 VALUES (4, 'master');
+INSERT INTO t1 VALUES (5, 'master');
+INSERT INTO t1 VALUES (6, 'master');
+COMMIT;
+
+BEGIN;
+INSERT INTO t1 VALUES (7, 'master,slave');
+INSERT INTO t1 VALUES (8, 'master,slave');
+INSERT INTO t1 VALUES (9, 'master,slave');
+COMMIT;
+
+save_master_pos;
+
+SELECT * FROM t1 ORDER BY a;
+
+# This will skip a begin event and the first INSERT of the
+# transaction, and it should keep skipping until it has reached the
+# transaction terminator.
+
+--echo **** On Slave ****
+connection slave;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8;
+START SLAVE;
+source include/wait_for_slave_to_start.inc;
+sync_with_master;
+SELECT * FROM t1 ORDER BY a;
+
+--echo **** On Master ****
+connection master;
+DELETE FROM t1;
+sync_slave_with_master;
+
+--echo ==== Skipping without autocommit ====
+
+# Testing without using autocommit instead. It should still write a
+# BEGIN event, so the behaviour should be the same
+
+--echo **** On Slave ****
+connection slave;
+STOP SLAVE;
+source include/wait_for_slave_to_stop.inc;
+
+--echo **** On Master ****
+connection master;
+SET AUTOCOMMIT=0;
+
+INSERT INTO t1 VALUES (1, 'master');
+INSERT INTO t1 VALUES (2, 'master');
+INSERT INTO t1 VALUES (3, 'master');
+COMMIT;
+
+INSERT INTO t1 VALUES (4, 'master,slave');
+INSERT INTO t1 VALUES (5, 'master,slave');
+INSERT INTO t1 VALUES (6, 'master,slave');
+COMMIT;
+
+save_master_pos;
+
+SELECT * FROM t1 ORDER BY a;
+
+# This will skip a begin event and the first INSERT of the
+# transaction, and it should keep skipping until it has reached the
+# transaction terminator.
+
+--echo **** On Slave ****
+connection slave;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+START SLAVE;
+source include/wait_for_slave_to_start.inc;
+sync_with_master;
+SELECT * FROM t1 ORDER BY a;
+
+# Testing with a non-transactional table in the transaction. This will
+# log a ROLLBACK as a transaction terminator, which is a normal Query
+# log event.
+
+--echo ==== Rollback of transaction with non-transactional change ====
+
+--echo **** On Master ****
+connection master;
+DELETE FROM t1;
+SET AUTOCOMMIT=1;
+
+--echo **** On Slave ****
+sync_slave_with_master;
+STOP SLAVE;
+source include/wait_for_slave_to_stop.inc;
+
+--echo **** On Master ****
+connection master;
+disable_warnings;
+BEGIN;
+INSERT INTO t1 VALUES (1, '');
+INSERT INTO t2 VALUES (2, 'master');
+INSERT INTO t1 VALUES (3, '');
+ROLLBACK;
+
+BEGIN;
+INSERT INTO t1 VALUES (4, '');
+INSERT INTO t2 VALUES (5, 'master,slave');
+INSERT INTO t1 VALUES (6, '');
+ROLLBACK;
+enable_warnings;
+
+save_master_pos;
+
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+
+--echo **** On Slave ****
+connection slave;
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
+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;
+
+--echo ==== Cleanup ====
+
+--echo **** On Master ****
+connection master;
+DROP TABLE t1, t2;
+sync_slave_with_master;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index e27127a5804..47649006ccf 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -4410,7 +4410,7 @@ Item_func_regex::regcomp(bool send_error)
res= &conv;
}
- if ((error= my_regcomp(&preg, res->c_ptr(),
+ if ((error= my_regcomp(&preg, res->c_ptr_safe(),
regex_lib_flags, regex_lib_charset)))
{
if (send_error)
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 53c877f28c0..e300de353b0 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -5472,12 +5472,13 @@ Begin_load_query_log_event::do_shall_skip(Relay_log_info *rli)
#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)
{
diff --git a/sql/log_event.h b/sql/log_event.h
index ab2424d8466..4bd496af2a4 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -2744,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 */
diff --git a/sql/slave.cc b/sql/slave.cc
index 3b80a58676b..a3ac0c2f34f 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1807,6 +1807,58 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
/*
*/
+<<<<<<< gca sql/slave.cc 1.241.1.61
+ DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id));
+
+ if ((ev->server_id == (uint32) ::server_id &&
+ !replicate_same_server_id &&
+ type_code != FORMAT_DESCRIPTION_EVENT) ||
+ (rli->slave_skip_counter &&
+ type_code != ROTATE_EVENT && type_code != STOP_EVENT &&
+ type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT))
+ {
+ DBUG_PRINT("info", ("event skipped"));
+ if (thd->options & OPTION_BEGIN)
+ rli->inc_event_relay_log_pos();
+ else
+ {
+ rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT ||
+ type_code == STOP_EVENT ||
+ type_code == FORMAT_DESCRIPTION_EVENT) ?
+ LL(0) : ev->log_pos,
+ 1/* skip lock*/);
+ flush_relay_log_info(rli);
+ }
+
+ /*
+ Protect against common user error of setting the counter to 1
+ instead of 2 while recovering from an insert which used auto_increment,
+ rand or user var.
+ */
+ if (rli->slave_skip_counter &&
+ !((type_code == INTVAR_EVENT ||
+ type_code == RAND_EVENT ||
+ type_code == USER_VAR_EVENT) &&
+ rli->slave_skip_counter == 1) &&
+ /*
+ The events from ourselves which have something to do with the relay
+ log itself must be skipped, true, but they mustn't decrement
+ rli->slave_skip_counter, because the user is supposed to not see
+ these events (they are not in the master's binlog) and if we
+ decremented, START SLAVE would for example decrement when it sees
+ the Rotate, so the event which the user probably wanted to skip
+ would not be skipped.
+ */
+ !(ev->server_id == (uint32) ::server_id &&
+ (type_code == ROTATE_EVENT || type_code == STOP_EVENT ||
+ type_code == START_EVENT_V3 || type_code == FORMAT_DESCRIPTION_EVENT)))
+ --rli->slave_skip_counter;
+ pthread_mutex_unlock(&rli->data_lock);
+ delete ev;
+ return 0; // avoid infinite update loops
+ }
+ pthread_mutex_unlock(&rli->data_lock);
+<<<<<<< local sql/slave.cc 1.321
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",
@@ -1839,6 +1891,108 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
log (remember that now the relay log starts with its Format_desc,
has a Rotate etc).
*/
+<<<<<<< remote sql/slave.cc 1.241.1.62
+ DBUG_PRINT("info",("type_code: %d; server_id: %d; slave_skip_counter: %d",
+ type_code, ev->server_id, rli->slave_skip_counter));
+
+ /*
+ If the slave skip counter is positive, we still need to set the
+ OPTION_BEGIN flag correctly and not skip the log events that
+ start or end a transaction. If we do this, the slave will not
+ notice that it is inside a transaction, and happily start
+ executing from inside the transaction.
+
+ Note that the code block below is strictly 5.0.
+ */
+#if MYSQL_VERSION_ID < 50100
+ if (unlikely(rli->slave_skip_counter > 0))
+ {
+ switch (type_code)
+ {
+ case QUERY_EVENT:
+ {
+ Query_log_event* const qev= (Query_log_event*) ev;
+ DBUG_PRINT("info", ("QUERY_EVENT { query: '%s', q_len: %u }",
+ qev->query, qev->q_len));
+ if (memcmp("BEGIN", qev->query, qev->q_len+1) == 0)
+ thd->options|= OPTION_BEGIN;
+ else if (memcmp("COMMIT", qev->query, qev->q_len+1) == 0 ||
+ memcmp("ROLLBACK", qev->query, qev->q_len+1) == 0)
+ thd->options&= ~OPTION_BEGIN;
+ }
+ break;
+
+ case XID_EVENT:
+ DBUG_PRINT("info", ("XID_EVENT"));
+ thd->options&= ~OPTION_BEGIN;
+ break;
+ }
+ }
+#endif
+
+ if ((ev->server_id == (uint32) ::server_id &&
+ !replicate_same_server_id &&
+ type_code != FORMAT_DESCRIPTION_EVENT) ||
+ (rli->slave_skip_counter &&
+ type_code != ROTATE_EVENT && type_code != STOP_EVENT &&
+ type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT))
+ {
+ DBUG_PRINT("info", ("event skipped"));
+ if (thd->options & OPTION_BEGIN)
+ rli->inc_event_relay_log_pos();
+ else
+ {
+ rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT ||
+ type_code == STOP_EVENT ||
+ type_code == FORMAT_DESCRIPTION_EVENT) ?
+ LL(0) : ev->log_pos,
+ 1/* skip lock*/);
+ flush_relay_log_info(rli);
+ }
+
+ DBUG_PRINT("info", ("thd->options: %s",
+ (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : ""))
+
+ /*
+ Protect against common user error of setting the counter to 1
+ instead of 2 while recovering from an insert which used auto_increment,
+ rand or user var.
+ */
+ if (rli->slave_skip_counter &&
+ !((type_code == INTVAR_EVENT ||
+ type_code == RAND_EVENT ||
+ type_code == USER_VAR_EVENT) &&
+ rli->slave_skip_counter == 1) &&
+#if MYSQL_VERSION_ID < 50100
+ /*
+ Decrease the slave skip counter only if we are not inside
+ a transaction or the slave skip counter is more than
+ 1. The slave skip counter will be decreased from 1 to 0
+ when reaching the final ROLLBACK, COMMIT, or XID_EVENT.
+ */
+ (!(thd->options & OPTION_BEGIN) || rli->slave_skip_counter > 1) &&
+#endif
+ /*
+ The events from ourselves which have something to do with the relay
+ log itself must be skipped, true, but they mustn't decrement
+ rli->slave_skip_counter, because the user is supposed to not see
+ these events (they are not in the master's binlog) and if we
+ decremented, START SLAVE would for example decrement when it sees
+ the Rotate, so the event which the user probably wanted to skip
+ would not be skipped.
+ */
+ !(ev->server_id == (uint32) ::server_id &&
+ (type_code == ROTATE_EVENT ||
+ type_code == STOP_EVENT ||
+ type_code == START_EVENT_V3 ||
+ type_code == FORMAT_DESCRIPTION_EVENT)))
+ --rli->slave_skip_counter;
+ pthread_mutex_unlock(&rli->data_lock);
+ delete ev;
+ return 0; // avoid infinite update loops
+ }
+ pthread_mutex_unlock(&rli->data_lock);
+>>>>>>>
thd->server_id = ev->server_id; // use the original server id for logging
thd->set_time(); // time the query
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 093544cdd0a..5f92dd3b3a5 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_delete.cc b/sql/sql_delete.cc
index 0746a261de1..33d19852371 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -38,6 +38,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))
@@ -300,8 +301,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 && !error)
- error= 1; // Aborted
+ killed_status= thd->killed;
+ error= (killed_status == THD::NOT_KILLED)? error : 1;
if (will_batch && (loc_error= table->file->end_bulk_delete()))
{
if (error != 1)
@@ -351,6 +352,11 @@ cleanup:
{
if (error < 0)
thd->clear_error();
+<<<<<<< gca sql/sql_delete.cc 1.144.1.57
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_table, FALSE);
+ if (mysql_bin_log.write(&qinfo) && transactional_table)
+<<<<<<< local sql/sql_delete.cc 1.230
/*
[binlog]: If 'handler::delete_all_rows()' was called and the
@@ -364,6 +370,11 @@ cleanup:
if (log_result && transactional_table)
{
+<<<<<<< remote sql/sql_delete.cc 1.144.1.58
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_table, FALSE, killed_status);
+ if (mysql_bin_log.write(&qinfo) && transactional_table)
+>>>>>>>
error=1;
}
}
@@ -764,7 +775,8 @@ void multi_delete::send_error(uint errcode,const char *err)
}
thd->transaction.all.modified_non_trans_table= true;
}
- DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);
+ DBUG_ASSERT(!normal_tables || !deleted ||
+ thd->transaction.stmt.modified_non_trans_table);
DBUG_VOID_RETURN;
}
@@ -862,6 +874,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 */
@@ -869,7 +882,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";
@@ -881,18 +894,29 @@ bool multi_delete::send_eof()
{
query_cache_invalidate3(thd, delete_tables, 1);
}
- DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);
+ 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())
{
if (local_error == 0)
thd->clear_error();
+<<<<<<< gca sql/sql_delete.cc 1.144.1.57
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_tables, FALSE);
+ if (mysql_bin_log.write(&qinfo) && !normal_tables)
+<<<<<<< local sql/sql_delete.cc 1.230
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
transactional_tables, FALSE) &&
!normal_tables)
{
+<<<<<<< remote sql/sql_delete.cc 1.144.1.58
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_tables, FALSE, killed_status);
+ if (mysql_bin_log.write(&qinfo) && !normal_tables)
+>>>>>>>
local_error=1; // Log write failed: roll back the SQL statement
}
}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 7e438ac3a7c..a631a82be1e 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -3084,10 +3084,19 @@ void select_insert::send_error(uint errcode,const char *err)
bool select_insert::send_eof()
{
+<<<<<<< gca sql/sql_insert.cc 1.146.1.105
+ int error, error2;
+ bool changed, transactional_table= table->file->has_transactions();
+<<<<<<< local sql/sql_insert.cc 1.300
int error;
bool const trans_table= table->file->has_transactions();
ulonglong id;
bool changed;
+<<<<<<< remote sql/sql_insert.cc 1.146.1.106
+ int error, error2;
+ bool changed, transactional_table= table->file->has_transactions();
+ 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()));
@@ -3120,6 +3129,14 @@ bool select_insert::send_eof()
{
if (!error)
thd->clear_error();
+<<<<<<< gca sql/sql_insert.cc 1.146.1.105
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_table, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
+ if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
+ error=error2;
+<<<<<<< local sql/sql_insert.cc 1.300
thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
trans_table, FALSE);
@@ -3138,6 +3155,14 @@ bool select_insert::send_eof()
}
table->file->ha_release_auto_increment();
+<<<<<<< remote sql/sql_insert.cc 1.146.1.106
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_table, FALSE, killed_status);
+ mysql_bin_log.write(&qinfo);
+ }
+ if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
+ error=error2;
+>>>>>>>
if (error)
{
table->file->print_error(error,MYF(0));
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 23547349a37..3a4df7ccc9b 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_...
@@ -419,6 +430,12 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (mysql_bin_log.is_open())
{
{
+<<<<<<< gca sql/sql_load.cc 1.78.1.39
+ if (thd->transaction.stmt.modified_non_trans_table)
+ write_execute_load_query_log_event(thd, handle_duplicates,
+ ignore, transactional_table);
+ else
+<<<<<<< local sql/sql_load.cc 1.131
/*
Make sure last block (the one which caused the error) gets
logged. This is needed because otherwise after write of (to
@@ -444,6 +461,13 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
read_info.end_io_cache();
/* If the file was not empty, wrote_create_file is true */
if (lf_info.wrote_create_file)
+<<<<<<< remote sql/sql_load.cc 1.78.1.40
+ if (thd->transaction.stmt.modified_non_trans_table)
+ write_execute_load_query_log_event(thd, handle_duplicates,
+ ignore, transactional_table,
+ killed_status);
+ else
+>>>>>>>
{
if (thd->transaction.stmt.modified_non_trans_table)
write_execute_load_query_log_event(thd, handle_duplicates,
@@ -473,6 +497,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (mysql_bin_log.is_open())
{
/*
+<<<<<<< gca sql/sql_load.cc 1.78.1.39
+ As already explained above, we need to call end_io_cache() or the last
+ block will be logged only after Execute_load_query_log_event (which is
+ wrong), when read_info is destroyed.
+ */
+ read_info.end_io_cache();
+ if (lf_info.wrote_create_file)
+ write_execute_load_query_log_event(thd, handle_duplicates,
+ ignore, transactional_table);
+<<<<<<< local sql/sql_load.cc 1.131
We need to do the job that is normally done inside
binlog_query() here, which is to ensure that the pending event
is written before tables are unlocked and before any other
@@ -496,6 +530,17 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
ignore, transactional_table);
}
}
+<<<<<<< remote sql/sql_load.cc 1.78.1.40
+ As already explained above, we need to call end_io_cache() or the last
+ block will be logged only after Execute_load_query_log_event (which is
+ wrong), when read_info is destroyed.
+ */
+ read_info.end_io_cache();
+ if (lf_info.wrote_create_file)
+ write_execute_load_query_log_event(thd, handle_duplicates,
+ ignore, transactional_table,
+ killed_status);
+>>>>>>>
}
#endif /*!EMBEDDED_LIBRARY*/
if (transactional_table)
@@ -523,7 +568,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,8 +577,14 @@ 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),
+<<<<<<< gca sql/sql_load.cc 1.78.1.39
+ transactional_table, FALSE);
+<<<<<<< local sql/sql_load.cc 1.131
transactional_table, FALSE);
e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
+<<<<<<< remote sql/sql_load.cc 1.78.1.40
+ transactional_table, FALSE, killed_err_arg);
+>>>>>>>
return mysql_bin_log.write(&e);
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 0b97930efb9..f07437f044f 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -200,9 +200,18 @@ int mysql_update(THD *thd,
SQL_SELECT *select;
READ_RECORD info;
SELECT_LEX *select_lex= &thd->lex->select_lex;
+<<<<<<< gca sql/sql_update.cc 1.154.2.70
+ bool need_reopen;
+ List<Item> all_fields;
+<<<<<<< local sql/sql_update.cc 1.258
bool need_reopen;
ulonglong id;
List<Item> all_fields;
+<<<<<<< remote sql/sql_update.cc 1.154.2.71
+ bool need_reopen;
+ List<Item> all_fields;
+ THD::killed_state killed_status= THD::NOT_KILLED;
+>>>>>>>
DBUG_ENTER("mysql_update");
for ( ; ; )
@@ -713,11 +722,66 @@ int mysql_update(THD *thd,
table->file->unlock_row();
thd->row_count++;
}
+<<<<<<< gca sql/sql_update.cc 1.154.2.70
+<<<<<<< local sql/sql_update.cc 1.258
dup_key_found= 0;
+<<<<<<< remote sql/sql_update.cc 1.154.2.71
+ /*
+ 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.
+ */
+ 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 (!transactional_table && updated > 0)
thd->transaction.stmt.modified_non_trans_table= TRUE;
+<<<<<<< gca sql/sql_update.cc 1.154.2.70
+
+ /*
+ 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.
+ */
+
+ if (thd->killed && !error)
+ error= 1; // Aborted
+<<<<<<< local sql/sql_update.cc 1.258
/*
todo bug#27571: to avoid asynchronization of `error' and
@@ -774,6 +838,8 @@ int mysql_update(THD *thd,
if (will_batch)
table->file->end_bulk_update();
table->file->try_semi_consistent_read(0);
+<<<<<<< remote sql/sql_update.cc 1.154.2.71
+>>>>>>>
end_read_record(&info);
delete select;
thd->proc_info= "end";
@@ -803,6 +869,12 @@ int mysql_update(THD *thd,
{
if (error < 0)
thd->clear_error();
+<<<<<<< gca sql/sql_update.cc 1.154.2.70
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_table, FALSE);
+ if (mysql_bin_log.write(&qinfo) && transactional_table)
+ error=1; // Rollback update
+<<<<<<< local sql/sql_update.cc 1.258
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
transactional_table, FALSE) &&
@@ -810,6 +882,12 @@ int mysql_update(THD *thd,
{
error=1; // Rollback update
}
+<<<<<<< remote sql/sql_update.cc 1.154.2.71
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_table, FALSE, killed_status);
+ if (mysql_bin_log.write(&qinfo) && transactional_table)
+ error=1; // Rollback update
+>>>>>>>
}
if (thd->transaction.stmt.modified_non_trans_table)
thd->transaction.all.modified_non_trans_table= TRUE;
@@ -1751,9 +1829,24 @@ void multi_update::send_error(uint errcode,const char *err)
*/
if (mysql_bin_log.is_open())
{
+<<<<<<< gca sql/sql_update.cc 1.154.2.70
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_tables, FALSE);
+ mysql_bin_log.write(&qinfo);
+<<<<<<< local sql/sql_update.cc 1.258
thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
transactional_tables, FALSE);
+<<<<<<< remote sql/sql_update.cc 1.154.2.71
+ /*
+ 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.
+ */
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_tables, FALSE);
+ mysql_bin_log.write(&qinfo);
+>>>>>>>
}
thd->transaction.all.modified_non_trans_table= TRUE;
}
@@ -1946,12 +2039,25 @@ err2:
bool multi_update::send_eof()
{
char buff[STRING_BUFFER_USUAL_SIZE];
+<<<<<<< gca sql/sql_update.cc 1.154.2.70
+<<<<<<< local sql/sql_update.cc 1.258
ulonglong id;
DBUG_ENTER("multi_update::send_eof");
+<<<<<<< remote sql/sql_update.cc 1.154.2.71
+ THD::killed_state killed_status= THD::NOT_KILLED;
+>>>>>>>
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,6 +2084,12 @@ bool multi_update::send_eof()
{
if (local_error == 0)
thd->clear_error();
+<<<<<<< gca sql/sql_update.cc 1.154.2.70
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_tables, FALSE);
+ if (mysql_bin_log.write(&qinfo) && trans_safe)
+ local_error= 1; // Rollback update
+<<<<<<< local sql/sql_update.cc 1.258
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
transactional_tables, FALSE) &&
@@ -1985,6 +2097,12 @@ bool multi_update::send_eof()
{
local_error= 1; // Rollback update
}
+<<<<<<< remote sql/sql_update.cc 1.154.2.71
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ transactional_tables, FALSE, killed_status);
+ if (mysql_bin_log.write(&qinfo) && trans_safe)
+ local_error= 1; // Rollback update
+>>>>>>>
}
if (thd->transaction.stmt.modified_non_trans_table)
thd->transaction.all.modified_non_trans_table= TRUE;