Commit 200f0531 authored by unknown's avatar unknown

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


client/mysql.cc:
  Auto merged
mysql-test/r/ctype_euckr.result:
  Auto merged
mysql-test/r/ctype_uca.result:
  Auto merged
mysql-test/suite/binlog/r/binlog_killed.result:
  Auto merged
mysql-test/suite/binlog/t/binlog_killed.test:
  Auto merged
sql/item_cmpfunc.cc:
  Auto merged
sql/log_event.cc:
  Auto merged
sql/log_event.h:
  Auto merged
sql/mysqld.cc:
  Auto merged
sql/sp_head.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
strings/ctype-euc_kr.c:
  Auto merged
mysql-test/suite/rpl/r/rpl_sp_effects.result:
  manual merge ul
mysql-test/suite/rpl/t/rpl_sp_effects.test:
  manual merge
sql/slave.cc:
  leaving for manual merge
sql/sql_delete.cc:
  leaving for manual merge
sql/sql_insert.cc:
  leaving for manual merge
sql/sql_load.cc:
  leaving for manual merge
sql/sql_update.cc:
  leaving for manual merge
parents a3b60d2d 5e314d06
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;
...@@ -9,4 +9,110 @@ insert into t2 values (null, null), (null, get_lock("a", 10)); ...@@ -9,4 +9,110 @@ insert into t2 values (null, null), (null, get_lock("a", 10));
select @result /* must be zero either way */; select @result /* must be zero either way */;
@result @result
0 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; drop table t1,t2,t3;
end of the tests
...@@ -55,194 +55,239 @@ enable_result_log; ...@@ -55,194 +55,239 @@ enable_result_log;
select @result /* must be zero either way */; 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 # checking that killing inside of select loops is safe as before
connection con1; # killing after the loop can be only simulated - another test
select get_lock("a", 20);
connection con2; delete from t1;
delete from t2;
insert into t1 values (1,1),(2,2);
let $ID= `select connection_id()`; let $ID= `select connection_id()`;
send insert into t1 values (bug27563(),1);
#
# simple update
#
connection con1; connection con1;
eval kill query $ID; begin; update t1 set b=11 where a=2;
connection con2; connection con2;
# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero send update t1 set b=b+10;
--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);
connection con1; connection con1;
--replace_result $ID ID
eval kill query $ID; eval kill query $ID;
rollback;
connection con2; connection con2;
# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero --error ER_QUERY_INTERRUPTED
--enable_info
# todo: remove 0 return after fixing Bug#27563
--error 0,ER_QUERY_INTERRUPTED
reap; reap;
--disable_info select * from t1 /* must be the same as before (1,1),(2,2) */;
select count(*) from t1 /* must be zero unless Bug#27563 */;
commit; #
# 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; connection con2;
let $ID= `select connection_id()`; send delete from t1 where a=2;
send insert into t2 values (bug27563(),1);
connection con1; connection con1;
--replace_result $ID ID
eval kill query $ID; eval kill query $ID;
rollback;
connection con2; connection con2;
# todo: remove 0 return after fixing Bug#27563 --error ER_QUERY_INTERRUPTED
--error 0,ER_QUERY_INTERRUPTED
reap; reap;
select count(*) from t2 /* must be one */; select * from t1 /* must be the same as before (1,1),(2,2) */;
#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
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; # connection con1;
delete from t2; # --replace_result $ID ID
insert into t1 values (1,1); # eval kill query $ID;
insert into t2 values (1,1); # rollback;
# # connection con2;
# Bug#27565 # --error 0,ER_QUERY_INTERRUPTED
# test where KILL is propagated as error to the top level # reap;
# still another bug with the error message to the user # select * from t1 /* must be the same as before (1,1),(2,2) */;
# todo: fix reexecute the result file after fixing #
# # insert select
begin; update t1 set b=0 where a=1; #
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; connection con2;
let $ID= `select connection_id()`; begin;
send update t2 set b=bug27565()-1 where a=1; send insert into t1 select * from t4 for update;
connection con1; connection con1;
--replace_result $ID ID
eval kill query $ID; eval kill query $ID;
commit; rollback;
connection con2; connection con2;
# todo: fix Bug #27565 killed query of SF() is not reported correctly and --error ER_QUERY_INTERRUPTED
# remove 1105 (wrong) reap;
#--error ER_QUERY_INTERRUPTED rollback;
--error 1105,ER_QUERY_INTERRUPTED select * from t1 /* must be the same as before (1,1),(2,2) */;
reap; ### pb: wrong error
select * from t1 /* must be: (1,0) */; drop table t4; # cleanup for the sub-case
select * from t2 /* must be as before: (1,1) */;
###
## 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 # update
connection con1; #
delete from t3;
delete from t2;
insert into t2 values (1,1), (2,2);
reset master; reset master;
begin; update t1 set b=0 where a=1; connection con1;
select get_lock("a", 20);
connection con2; connection con2;
let $ID= `select connection_id()`; let $ID= `select connection_id()`;
# the query won't perform completely since the function gets interrupted send update t2 set b=b + bug27563(b) order by a;
send insert into t3 values (0,0),(1,bug27565());
connection con1; connection con1;
--replace_result $ID ID
eval kill query $ID; eval kill query $ID;
rollback;
connection con2; connection con2;
# todo: fix Bug #27565 killed query of SF() is not reported correctly and --error ER_QUERY_INTERRUPTED
# remove 1105 (wrong) reap;
#--error ER_QUERY_INTERRUPTED select * from t2 /* must be (1,2), (2,2) */;
--error 1105,ER_QUERY_INTERRUPTED show master status /* must have the update event more to FD */;
reap; ### pb: wrong error
select count(*) from t3 /* must be zero */; # a proof the query is binlogged with an error
show master status /* nothing in binlog */;
--exec $MYSQL_BINLOG --start-position=98 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
# top-level non-ta-table --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; connection con1;
select RELEASE_LOCK("a");
--remove_file $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
#
# delete
#
delete from t2; delete from t2;
insert into t2 values (1,1), (2,2);
reset master; reset master;
begin; update t1 set b=0 where a=1; connection con1;
select get_lock("a", 20);
connection con2; connection con2;
let $ID= `select connection_id()`; let $ID= `select connection_id()`;
# the query won't perform completely since the function gets intrurrupted send delete from t2 where a=1 or a=bug27563(2) order by a;
send insert into t2 values (0,0),(1,bug27565()) /* non-ta t2 */;
connection con1; connection con1;
--replace_result $ID ID
eval kill query $ID; eval kill query $ID;
rollback;
connection con2; connection con2;
# todo: fix Bug #27565 killed query of SF() is not reported correctly and --error ER_QUERY_INTERRUPTED
# remove 1105 (wrong) reap;
#--error ER_QUERY_INTERRUPTED select * from t2 /* must be (1,2), (2,2) */;
--error 1105,ER_QUERY_INTERRUPTED show master status /* must have the update event more to FD */;
reap; ### pb: wrong error
select count(*) from t2 /* count must be one */; # a proof the query is binlogged with an error
show master status /* insert into non-ta must be in binlog */;
--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 bug27563;
drop function bug27565;
}
system rm $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog ;
#
# common cleanup
#
drop table t1,t2,t3; drop table t1,t2,t3;
--echo end of the tests
...@@ -201,6 +201,10 @@ sync_slave_with_master; ...@@ -201,6 +201,10 @@ sync_slave_with_master;
connection slave; connection slave;
SELECT 'slave', a FROM t1 ORDER BY a; SELECT 'slave', a FROM t1 ORDER BY a;
#
# cleanup
#
connection master; connection master;
drop table t1; drop table t1;
drop function f1; drop function f1;
...@@ -208,4 +212,50 @@ drop function f2; ...@@ -208,4 +212,50 @@ drop function f2;
drop procedure p1; drop procedure p1;
sync_slave_with_master; 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; SET GLOBAL log_bin_trust_function_creators = 0;
--echo end of the tests
--loose-debug=d,stop_after_row_loop_done
--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
--loose-debug=d,simulate_kill_bug27571
#
# 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
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;
...@@ -4410,7 +4410,7 @@ Item_func_regex::regcomp(bool send_error) ...@@ -4410,7 +4410,7 @@ Item_func_regex::regcomp(bool send_error)
res= &conv; 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))) regex_lib_flags, regex_lib_charset)))
{ {
if (send_error) if (send_error)
......
...@@ -5472,12 +5472,13 @@ Begin_load_query_log_event::do_shall_skip(Relay_log_info *rli) ...@@ -5472,12 +5472,13 @@ Begin_load_query_log_event::do_shall_skip(Relay_log_info *rli)
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
Execute_load_query_log_event:: Execute_load_query_log_event::
Execute_load_query_log_event(THD *thd_arg, const char* query_arg, Execute_load_query_log_event(THD *thd_arg, const char* query_arg,
ulong query_length_arg, uint fn_pos_start_arg, ulong query_length_arg, uint fn_pos_start_arg,
uint fn_pos_end_arg, uint fn_pos_end_arg,
enum_load_dup_handling dup_handling_arg, enum_load_dup_handling dup_handling_arg,
bool using_trans, bool suppress_use): bool using_trans, bool suppress_use,
THD::killed_state killed_err_arg):
Query_log_event(thd_arg, query_arg, query_length_arg, using_trans, 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), 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) fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg)
{ {
......
...@@ -2744,10 +2744,12 @@ public: ...@@ -2744,10 +2744,12 @@ public:
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
Execute_load_query_log_event(THD* thd, const char* query_arg, Execute_load_query_log_event(THD* thd, const char* query_arg,
ulong query_length, uint fn_pos_start_arg, ulong query_length, uint fn_pos_start_arg,
uint fn_pos_end_arg, uint fn_pos_end_arg,
enum_load_dup_handling dup_handling_arg, enum_load_dup_handling dup_handling_arg,
bool using_trans, bool suppress_use); bool using_trans, bool suppress_use,
THD::killed_state
killed_err_arg= THD::KILLED_NO_VALUE);
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol); void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */ #endif /* HAVE_REPLICATION */
......
...@@ -1807,6 +1807,58 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) ...@@ -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)", DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)",
ev->get_type_str(), type_code, ev->server_id)); ev->get_type_str(), type_code, ev->server_id));
DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu", 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) ...@@ -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, log (remember that now the relay log starts with its Format_desc,
has a Rotate etc). 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->server_id = ev->server_id; // use the original server id for logging
thd->set_time(); // time the query thd->set_time(); // time the query
......
...@@ -102,8 +102,9 @@ sp_get_item_value(THD *thd, Item *item, String *str) ...@@ -102,8 +102,9 @@ sp_get_item_value(THD *thd, Item *item, String *str)
case REAL_RESULT: case REAL_RESULT:
case INT_RESULT: case INT_RESULT:
case DECIMAL_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: case STRING_RESULT:
{ {
String *result= item->val_str(str); String *result= item->val_str(str);
......
...@@ -38,6 +38,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -38,6 +38,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
ha_rows deleted= 0; ha_rows deleted= 0;
uint usable_index= MAX_KEY; uint usable_index= MAX_KEY;
SELECT_LEX *select_lex= &thd->lex->select_lex; SELECT_LEX *select_lex= &thd->lex->select_lex;
THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("mysql_delete"); DBUG_ENTER("mysql_delete");
if (open_and_lock_tables(thd, table_list)) if (open_and_lock_tables(thd, table_list))
...@@ -300,8 +301,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -300,8 +301,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
else else
table->file->unlock_row(); // Row failed selection, release lock on it table->file->unlock_row(); // Row failed selection, release lock on it
} }
if (thd->killed && !error) killed_status= thd->killed;
error= 1; // Aborted error= (killed_status == THD::NOT_KILLED)? error : 1;
if (will_batch && (loc_error= table->file->end_bulk_delete())) if (will_batch && (loc_error= table->file->end_bulk_delete()))
{ {
if (error != 1) if (error != 1)
...@@ -351,6 +352,11 @@ cleanup: ...@@ -351,6 +352,11 @@ cleanup:
{ {
if (error < 0) if (error < 0)
thd->clear_error(); 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 [binlog]: If 'handler::delete_all_rows()' was called and the
...@@ -364,6 +370,11 @@ cleanup: ...@@ -364,6 +370,11 @@ cleanup:
if (log_result && transactional_table) 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; error=1;
} }
} }
...@@ -764,7 +775,8 @@ void multi_delete::send_error(uint errcode,const char *err) ...@@ -764,7 +775,8 @@ void multi_delete::send_error(uint errcode,const char *err)
} }
thd->transaction.all.modified_non_trans_table= true; 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; DBUG_VOID_RETURN;
} }
...@@ -862,6 +874,7 @@ int multi_delete::do_deletes() ...@@ -862,6 +874,7 @@ int multi_delete::do_deletes()
bool multi_delete::send_eof() bool multi_delete::send_eof()
{ {
THD::killed_state killed_status= THD::NOT_KILLED;
thd->proc_info="deleting from reference tables"; thd->proc_info="deleting from reference tables";
/* Does deletes for the last n - 1 tables, returns 0 if ok */ /* Does deletes for the last n - 1 tables, returns 0 if ok */
...@@ -869,7 +882,7 @@ bool multi_delete::send_eof() ...@@ -869,7 +882,7 @@ bool multi_delete::send_eof()
/* compute a total error to know if something failed */ /* compute a total error to know if something failed */
local_error= local_error || error; local_error= local_error || error;
killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed;
/* reset used flags */ /* reset used flags */
thd->proc_info="end"; thd->proc_info="end";
...@@ -881,18 +894,29 @@ bool multi_delete::send_eof() ...@@ -881,18 +894,29 @@ bool multi_delete::send_eof()
{ {
query_cache_invalidate3(thd, delete_tables, 1); 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 ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table)
{ {
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
if (local_error == 0) if (local_error == 0)
thd->clear_error(); 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, if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length, thd->query, thd->query_length,
transactional_tables, FALSE) && transactional_tables, FALSE) &&
!normal_tables) !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 local_error=1; // Log write failed: roll back the SQL statement
} }
} }
......
...@@ -3084,10 +3084,19 @@ void select_insert::send_error(uint errcode,const char *err) ...@@ -3084,10 +3084,19 @@ void select_insert::send_error(uint errcode,const char *err)
bool select_insert::send_eof() 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; int error;
bool const trans_table= table->file->has_transactions(); bool const trans_table= table->file->has_transactions();
ulonglong id; ulonglong id;
bool changed; 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_ENTER("select_insert::send_eof");
DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'", DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
trans_table, table->file->table_type())); trans_table, table->file->table_type()));
...@@ -3120,6 +3129,14 @@ bool select_insert::send_eof() ...@@ -3120,6 +3129,14 @@ bool select_insert::send_eof()
{ {
if (!error) if (!error)
thd->clear_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->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length, thd->query, thd->query_length,
trans_table, FALSE); trans_table, FALSE);
...@@ -3138,6 +3155,14 @@ bool select_insert::send_eof() ...@@ -3138,6 +3155,14 @@ bool select_insert::send_eof()
} }
table->file->ha_release_auto_increment(); 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) if (error)
{ {
table->file->print_error(error,MYF(0)); table->file->print_error(error,MYF(0));
......
...@@ -85,7 +85,8 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -85,7 +85,8 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
static bool write_execute_load_query_log_event(THD *thd, static bool write_execute_load_query_log_event(THD *thd,
bool duplicates, bool ignore, bool duplicates, bool ignore,
bool transactional_table); bool transactional_table,
THD::killed_state killed_status);
#endif /* EMBEDDED_LIBRARY */ #endif /* EMBEDDED_LIBRARY */
/* /*
...@@ -134,6 +135,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -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 char *tdb= thd->db ? thd->db : db; // Result is never null
ulong skip_lines= ex->skip_lines; ulong skip_lines= ex->skip_lines;
bool transactional_table; bool transactional_table;
THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("mysql_load"); DBUG_ENTER("mysql_load");
#ifdef EMBEDDED_LIBRARY #ifdef EMBEDDED_LIBRARY
...@@ -403,7 +405,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -403,7 +405,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
free_blobs(table); /* if pack_blob was used */ free_blobs(table); /* if pack_blob was used */
table->copy_blobs=0; table->copy_blobs=0;
thd->count_cuted_fields= CHECK_FIELD_IGNORE; 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 We must invalidate the table in query cache before binlog writing and
ha_autocommit_... ha_autocommit_...
...@@ -419,6 +430,12 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -419,6 +430,12 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (mysql_bin_log.is_open()) 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 Make sure last block (the one which caused the error) gets
logged. This is needed because otherwise after write of (to 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, ...@@ -444,6 +461,13 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
read_info.end_io_cache(); read_info.end_io_cache();
/* If the file was not empty, wrote_create_file is true */ /* If the file was not empty, wrote_create_file is true */
if (lf_info.wrote_create_file) 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) if (thd->transaction.stmt.modified_non_trans_table)
write_execute_load_query_log_event(thd, handle_duplicates, 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, ...@@ -473,6 +497,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (mysql_bin_log.is_open()) 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 We need to do the job that is normally done inside
binlog_query() here, which is to ensure that the pending event binlog_query() here, which is to ensure that the pending event
is written before tables are unlocked and before any other 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, ...@@ -496,6 +530,17 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
ignore, transactional_table); 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*/ #endif /*!EMBEDDED_LIBRARY*/
if (transactional_table) if (transactional_table)
...@@ -523,7 +568,8 @@ err: ...@@ -523,7 +568,8 @@ err:
/* Not a very useful function; just to avoid duplication of code */ /* Not a very useful function; just to avoid duplication of code */
static bool write_execute_load_query_log_event(THD *thd, static bool write_execute_load_query_log_event(THD *thd,
bool duplicates, bool ignore, bool duplicates, bool ignore,
bool transactional_table) bool transactional_table,
THD::killed_state killed_err_arg)
{ {
Execute_load_query_log_event Execute_load_query_log_event
e(thd, thd->query, thd->query_length, e(thd, thd->query, thd->query_length,
...@@ -531,8 +577,14 @@ static bool write_execute_load_query_log_event(THD *thd, ...@@ -531,8 +577,14 @@ static bool write_execute_load_query_log_event(THD *thd,
(char*)thd->lex->fname_end - (char*)thd->query, (char*)thd->lex->fname_end - (char*)thd->query,
(duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
(ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), (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); transactional_table, FALSE);
e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F; 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); return mysql_bin_log.write(&e);
} }
......
...@@ -200,9 +200,18 @@ int mysql_update(THD *thd, ...@@ -200,9 +200,18 @@ int mysql_update(THD *thd,
SQL_SELECT *select; SQL_SELECT *select;
READ_RECORD info; READ_RECORD info;
SELECT_LEX *select_lex= &thd->lex->select_lex; 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; bool need_reopen;
ulonglong id; ulonglong id;
List<Item> all_fields; 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"); DBUG_ENTER("mysql_update");
for ( ; ; ) for ( ; ; )
...@@ -713,11 +722,66 @@ int mysql_update(THD *thd, ...@@ -713,11 +722,66 @@ int mysql_update(THD *thd,
table->file->unlock_row(); table->file->unlock_row();
thd->row_count++; thd->row_count++;
} }
<<<<<<< gca sql/sql_update.cc 1.154.2.70
<<<<<<< local sql/sql_update.cc 1.258
dup_key_found= 0; 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) if (!transactional_table && updated > 0)
thd->transaction.stmt.modified_non_trans_table= TRUE; 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 todo bug#27571: to avoid asynchronization of `error' and
...@@ -774,6 +838,8 @@ int mysql_update(THD *thd, ...@@ -774,6 +838,8 @@ int mysql_update(THD *thd,
if (will_batch) if (will_batch)
table->file->end_bulk_update(); table->file->end_bulk_update();
table->file->try_semi_consistent_read(0); table->file->try_semi_consistent_read(0);
<<<<<<< remote sql/sql_update.cc 1.154.2.71
>>>>>>>
end_read_record(&info); end_read_record(&info);
delete select; delete select;
thd->proc_info= "end"; thd->proc_info= "end";
...@@ -803,6 +869,12 @@ int mysql_update(THD *thd, ...@@ -803,6 +869,12 @@ int mysql_update(THD *thd,
{ {
if (error < 0) if (error < 0)
thd->clear_error(); 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, if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length, thd->query, thd->query_length,
transactional_table, FALSE) && transactional_table, FALSE) &&
...@@ -810,6 +882,12 @@ int mysql_update(THD *thd, ...@@ -810,6 +882,12 @@ int mysql_update(THD *thd,
{ {
error=1; // Rollback update 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) if (thd->transaction.stmt.modified_non_trans_table)
thd->transaction.all.modified_non_trans_table= TRUE; thd->transaction.all.modified_non_trans_table= TRUE;
...@@ -1751,9 +1829,24 @@ void multi_update::send_error(uint errcode,const char *err) ...@@ -1751,9 +1829,24 @@ void multi_update::send_error(uint errcode,const char *err)
*/ */
if (mysql_bin_log.is_open()) 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->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length, thd->query, thd->query_length,
transactional_tables, FALSE); 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; thd->transaction.all.modified_non_trans_table= TRUE;
} }
...@@ -1946,12 +2039,25 @@ err2: ...@@ -1946,12 +2039,25 @@ err2:
bool multi_update::send_eof() bool multi_update::send_eof()
{ {
char buff[STRING_BUFFER_USUAL_SIZE]; char buff[STRING_BUFFER_USUAL_SIZE];
<<<<<<< gca sql/sql_update.cc 1.154.2.70
<<<<<<< local sql/sql_update.cc 1.258
ulonglong id; ulonglong id;
DBUG_ENTER("multi_update::send_eof"); 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"; 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; 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"; thd->proc_info= "end";
/* We must invalidate the query cache before binlog writing and /* We must invalidate the query cache before binlog writing and
...@@ -1978,6 +2084,12 @@ bool multi_update::send_eof() ...@@ -1978,6 +2084,12 @@ bool multi_update::send_eof()
{ {
if (local_error == 0) if (local_error == 0)
thd->clear_error(); 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, if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length, thd->query, thd->query_length,
transactional_tables, FALSE) && transactional_tables, FALSE) &&
...@@ -1985,6 +2097,12 @@ bool multi_update::send_eof() ...@@ -1985,6 +2097,12 @@ bool multi_update::send_eof()
{ {
local_error= 1; // Rollback update 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) if (thd->transaction.stmt.modified_non_trans_table)
thd->transaction.all.modified_non_trans_table= TRUE; thd->transaction.all.modified_non_trans_table= TRUE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment