Below is the list of changes that have just been committed into a local
5.0 repository of elkin. When elkin does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-10-29 13:38:49+02:00, aelkin@stripped +12 -0
Bug #27571 asynchronousity in setting mysql_`query`::error and
Query_log_event::error_code
A query can perform completely having the local var error of mysql_$query
zero, where $query in insert, update, delete, load,
and be binlogged with error_code e.g KILLED_QUERY while there is no
reason do to so.
That can happen because Query_log_event consults thd->killed flag to
evaluate error_code.
Fixed with implementing a scheme suggested and partly implemented at
time of bug@22725 work-on. error_status is cached immediatly after the
control leaves the main rows-loop and that instance always corresponds
to `error' the local of mysql_$query functions. The cached value
is passed to Query_log_event constructor, not the default thd->killed
which can be changed in between of the caching and the constructing.
mysql-test/r/binlog_killed.result@stripped, 2007-10-29 13:38:44+02:00,
aelkin@stripped +106 -0
results changed
mysql-test/t/binlog_killed.test@stripped, 2007-10-29 13:38:44+02:00, aelkin@stripped
+170 -125
Demonstrating that effective killing during rows-loop execution leads to the speficied
actions:
binlogging with the error for a query modified a not-transactional table or
rolling back effects for transactional table;
fixing possible non-determinism with ID when query_log_enabled;
leave commented out tests for multi-update,delete due to another bug;
removing an obsolete tests template.
mysql-test/t/binlog_killed_bug27571-master.opt@stripped, 2007-10-29 13:38:46+02:00,
aelkin@stripped +1 -0
post rows-loop killing simulation's options
mysql-test/t/binlog_killed_bug27571-master.opt@stripped, 2007-10-29 13:38:46+02:00,
aelkin@stripped +0 -0
mysql-test/t/binlog_killed_bug27571.test@stripped, 2007-10-29 13:38:46+02:00,
aelkin@stripped +68 -0
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.
mysql-test/t/binlog_killed_bug27571.test@stripped, 2007-10-29 13:38:46+02:00,
aelkin@stripped +0 -0
mysql-test/t/binlog_killed_simulate-master.opt@stripped, 2007-10-29 13:38:46+02:00,
aelkin@stripped +1 -0
simulation options
mysql-test/t/binlog_killed_simulate-master.opt@stripped, 2007-10-29 13:38:46+02:00,
aelkin@stripped +0 -0
mysql-test/t/binlog_killed_simulate.test@stripped, 2007-10-29 13:38:46+02:00,
aelkin@stripped +65 -0
tests for
a query (update is choosen) being killed after the row-loop;
load data killed within the loop - effective killed error in the event is gained.
mysql-test/t/binlog_killed_simulate.test@stripped, 2007-10-29 13:38:46+02:00,
aelkin@stripped +0 -0
sql/log_event.cc@stripped, 2007-10-29 13:38:44+02:00, aelkin@stripped +6 -5
adding killed status arg
sql/log_event.h@stripped, 2007-10-29 13:38:44+02:00, aelkin@stripped +6 -4
added killed status arg
sql/sql_delete.cc@stripped, 2007-10-29 13:38:45+02:00, aelkin@stripped +11 -7
deploying the update part patch for delete, multi-delete
sql/sql_insert.cc@stripped, 2007-10-29 13:38:45+02:00, aelkin@stripped +2 -1
deploying the update-part patch for insert..select
sql/sql_load.cc@stripped, 2007-10-29 13:38:45+02:00, aelkin@stripped +20 -6
deploying the update-part patch for load data.
simulation added.
sql/sql_update.cc@stripped, 2007-10-29 13:38:46+02:00, aelkin@stripped +34 -36
Impementing the fix as described in the comments left by bug@22725.
Also simulation of killing after the loop that would affect binlogging in the old
code.
diff -Nrup a/mysql-test/r/binlog_killed.result b/mysql-test/r/binlog_killed.result
--- a/mysql-test/r/binlog_killed.result 2007-05-30 10:54:48 +03:00
+++ b/mysql-test/r/binlog_killed.result 2007-10-29 13:38:44 +02:00
@@ -9,4 +9,110 @@ insert into t2 values (null, null), (nul
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 -Nrup a/mysql-test/t/binlog_killed.test b/mysql-test/t/binlog_killed.test
--- a/mysql-test/t/binlog_killed.test 2007-06-07 21:25:21 +03:00
+++ b/mysql-test/t/binlog_killed.test 2007-10-29 13:38:44 +02:00
@@ -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 ;|
+system rm $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog ;
-reset master;
+#
+# bug#27571 asynchronous setting mysql_`query`::error and Query_log_e::error_code
+#
+# checking that killing inside of select loops is safe as before
+# killing after the loop can be only simulated - another test
-### ta table case: killing causes rollback
+delete from t1;
+delete from t2;
+insert into t1 values (1,1),(2,2);
+let $ID= `select connection_id()`;
-# A. autocommit ON
+#
+# simple update
+#
connection con1;
-select get_lock("a", 20);
+begin; update t1 set b=11 where a=2;
connection con2;
-let $ID= `select connection_id()`;
-send insert into t1 values (bug27563(),1);
+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
-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 */;
+--error ER_QUERY_INTERRUPTED
+reap;
+select * from t1 /* must be the same as before (1,1),(2,2) */;
-# M. multi-statement-ta
-connection con2;
-let $ID= `select connection_id()`;
-begin;
-send insert into t1 values (bug27563(),1);
+#
+# 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 con1;
-eval kill query $ID;
-connection con2;
-# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero
---enable_info
-# todo: remove 0 return after fixing Bug#27563
---error 0,ER_QUERY_INTERRUPTED
-reap;
---disable_info
-select count(*) from t1 /* must be zero unless Bug#27563 */;
-commit;
+# connection con2;
+# send update t1 as t_1,t1 as t_2 set t_1.b=11 where t_2.a=2;
+# connection con1;
+# --replace_result $ID ID
+# eval kill query $ID;
+# rollback;
-### non-ta table case: killing must be recorded in binlog
+# disable_abort_on_error;
-reset master;
+# 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");
-
-### test with effective killing of SF()
+#
+# multi delete
+# the same as for multi-update
+#
+# connection con1;
+# begin; delete from t1 where a=2;
-delete from t1;
-delete from t2;
-insert into t1 values (1,1);
-insert into t2 values (1,1);
+# connection con2;
+# send delete t1 from t1 where t1.a=2;
-#
-# 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 con1;
+# --replace_result $ID ID
+# eval kill query $ID;
+# rollback;
+
+# connection con2;
+# --error 0,ER_QUERY_INTERRUPTED
+# reap;
+# select * from t1 /* must be the same as before (1,1),(2,2) */;
+#
+# insert select
+#
+connection con1;
+--disable_warnings
+drop table if exists t4;
+--enable_warnings
+create table t4 (a int, b int) engine=innodb;
+insert into t4 values (3, 3);
+begin; insert into t1 values (3, 3);
connection con2;
-let $ID= `select connection_id()`;
-send 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 */;
+--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 */;
-# top-level non-ta-table
+# 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");
+system rm $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 */;
+
+# a proof the query is binlogged with an error
-select count(*) from t2 /* count must be one */;
-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");
+system rm $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 -Nrup a/mysql-test/t/binlog_killed_bug27571-master.opt
b/mysql-test/t/binlog_killed_bug27571-master.opt
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/mysql-test/t/binlog_killed_bug27571-master.opt 2007-10-29 13:38:46 +02:00
@@ -0,0 +1 @@
+--loose-debug=d,stop_after_row_loop_done
diff -Nrup a/mysql-test/t/binlog_killed_bug27571.test
b/mysql-test/t/binlog_killed_bug27571.test
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/mysql-test/t/binlog_killed_bug27571.test 2007-10-29 13:38:46 +02:00
@@ -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 -Nrup a/mysql-test/t/binlog_killed_simulate-master.opt
b/mysql-test/t/binlog_killed_simulate-master.opt
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/mysql-test/t/binlog_killed_simulate-master.opt 2007-10-29 13:38:46 +02:00
@@ -0,0 +1 @@
+--loose-debug=d,simulate_kill_bug27571
diff -Nrup a/mysql-test/t/binlog_killed_simulate.test
b/mysql-test/t/binlog_killed_simulate.test
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/mysql-test/t/binlog_killed_simulate.test 2007-10-29 13:38:46 +02:00
@@ -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 -Nrup a/sql/log_event.cc b/sql/log_event.cc
--- a/sql/log_event.cc 2007-10-04 18:46:28 +03:00
+++ b/sql/log_event.cc 2007-10-29 13:38:44 +02:00
@@ -4994,12 +4994,13 @@ int Begin_load_query_log_event::get_crea
#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 -Nrup a/sql/log_event.h b/sql/log_event.h
--- a/sql/log_event.h 2007-05-28 22:20:19 +03:00
+++ b/sql/log_event.h 2007-10-29 13:38:44 +02:00
@@ -1619,10 +1619,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);
int exec_event(struct st_relay_log_info* rli);
diff -Nrup a/sql/sql_delete.cc b/sql/sql_delete.cc
--- a/sql/sql_delete.cc 2007-10-13 15:49:38 +03:00
+++ b/sql/sql_delete.cc 2007-10-29 13:38:45 +02:00
@@ -38,6 +38,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
ha_rows deleted;
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))
@@ -280,8 +281,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *
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;
thd->proc_info="end";
end_read_record(&info);
free_io_cache(table); // Will not do any harm
@@ -326,7 +327,7 @@ cleanup:
if (error < 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- transactional_table, FALSE);
+ transactional_table, FALSE, killed_status);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1;
}
@@ -729,7 +730,8 @@ void multi_delete::send_error(uint errco
}
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;
}
@@ -817,6 +819,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 */
@@ -824,7 +827,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";
@@ -836,7 +839,8 @@ 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())
@@ -844,7 +848,7 @@ bool multi_delete::send_eof()
if (local_error == 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- transactional_tables, FALSE);
+ 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 -Nrup a/sql/sql_insert.cc b/sql/sql_insert.cc
--- a/sql/sql_insert.cc 2007-09-10 14:15:01 +03:00
+++ b/sql/sql_insert.cc 2007-10-29 13:38:45 +02:00
@@ -2936,6 +2936,7 @@ bool select_insert::send_eof()
{
int error, error2;
bool changed, transactional_table= table->file->has_transactions();
+ THD::killed_state killed_status= thd->killed;
DBUG_ENTER("select_insert::send_eof");
error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0;
@@ -2964,7 +2965,7 @@ bool select_insert::send_eof()
if (!error)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- transactional_table, FALSE);
+ transactional_table, FALSE, killed_status);
mysql_bin_log.write(&qinfo);
}
if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
diff -Nrup a/sql/sql_load.cc b/sql/sql_load.cc
--- a/sql/sql_load.cc 2007-08-21 15:16:52 +03:00
+++ b/sql/sql_load.cc 2007-10-29 13:38:45 +02:00
@@ -85,7 +85,8 @@ static int read_sep_field(THD *thd, COPY
#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 */
/*
@@ -135,6 +136,7 @@ bool mysql_load(THD *thd,sql_exchange *e
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
@@ -404,7 +406,16 @@ bool mysql_load(THD *thd,sql_exchange *e
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_...
@@ -446,7 +457,8 @@ bool mysql_load(THD *thd,sql_exchange *e
{
if (thd->transaction.stmt.modified_non_trans_table)
write_execute_load_query_log_event(thd, handle_duplicates,
- ignore, transactional_table);
+ ignore, transactional_table,
+ killed_status);
else
{
Delete_file_log_event d(thd, db, transactional_table);
@@ -477,7 +489,8 @@ bool mysql_load(THD *thd,sql_exchange *e
read_info.end_io_cache();
if (lf_info.wrote_create_file)
write_execute_load_query_log_event(thd, handle_duplicates,
- ignore, transactional_table);
+ ignore, transactional_table,
+ killed_status);
}
#endif /*!EMBEDDED_LIBRARY*/
if (transactional_table)
@@ -504,7 +517,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,
@@ -512,7 +526,7 @@ static bool write_execute_load_query_log
(char*)thd->lex->fname_end - (char*)thd->query,
(duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
(ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
- transactional_table, FALSE);
+ transactional_table, FALSE, killed_err_arg);
return mysql_bin_log.write(&e);
}
diff -Nrup a/sql/sql_update.cc b/sql/sql_update.cc
--- a/sql/sql_update.cc 2007-10-13 15:49:39 +03:00
+++ b/sql/sql_update.cc 2007-10-29 13:38:46 +02:00
@@ -134,6 +134,7 @@ int mysql_update(THD *thd,
SELECT_LEX *select_lex= &thd->lex->select_lex;
bool need_reopen;
List<Item> all_fields;
+ THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("mysql_update");
LINT_INIT(timestamp_query_id);
@@ -519,43 +520,26 @@ int mysql_update(THD *thd,
table->file->unlock_row();
thd->row_count++;
}
+ /*
+ 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;
-
- /*
- 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
end_read_record(&info);
free_io_cache(table); // If ORDER BY
delete select;
@@ -587,7 +571,7 @@ int mysql_update(THD *thd,
if (error < 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- transactional_table, FALSE);
+ transactional_table, FALSE, killed_status);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1; // Rollback update
}
@@ -1522,6 +1506,11 @@ void multi_update::send_error(uint errco
*/
if (mysql_bin_log.is_open())
{
+ /*
+ THD::killed status might not have been set ON at time of an error
+ got caught and if happens later the killed error is written
+ into repl event.
+ */
Query_log_event qinfo(thd, thd->query, thd->query_length,
transactional_tables, FALSE);
mysql_bin_log.write(&qinfo);
@@ -1709,10 +1698,19 @@ err2:
bool multi_update::send_eof()
{
char buff[STRING_BUFFER_USUAL_SIZE];
+ 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
@@ -1740,7 +1738,7 @@ bool multi_update::send_eof()
if (local_error == 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- transactional_tables, FALSE);
+ transactional_tables, FALSE, killed_status);
if (mysql_bin_log.write(&qinfo) && trans_safe)
local_error= 1; // Rollback update
}
| Thread |
|---|
| • bk commit into 5.0 tree (aelkin:1.2542) BUG#27571 | Andrei Elkin | 29 Oct |