Commit a88babcb authored by mats@capulet.net's avatar mats@capulet.net

Merge capulet.net:/home/bk/mysql-5.0-rpl

into  capulet.net:/home/mats/devel/b31793-mysql-5.0-rpl
parents a432d3de d5ccec26
...@@ -9,4 +9,48 @@ insert into t2 values (null, null), (null, get_lock("a", 10)); ...@@ -9,4 +9,48 @@ 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
select RELEASE_LOCK("a");
RELEASE_LOCK("a")
1
delete from t1;
delete from t2;
insert into t1 values (1,1),(2,2);
begin;
update t1 set b=11 where a=2;
begin;
update t1 set b=b+10;
kill query ID;
rollback;
rollback;
select * from t1 order by a /* must be the same as before (1,1),(2,2) */;
a b
1 1
2 2
begin;
delete from t1 where a=2;
begin;
delete from t1 where a=2;
kill query ID;
rollback;
rollback;
select * from t1 order by a /* must be the same as before (1,1),(2,2) */;
a b
1 1
2 2
drop table if exists t4;
create table t4 (a int, b int) engine=innodb;
insert into t4 values (3, 3);
begin;
insert into t1 values (3, 3);
begin;
insert into t1 select * from t4 for update;
kill query ID;
rollback;
rollback;
select * from t1 /* must be the same as before (1,1),(2,2) */;
a b
1 1
2 2
drop table t4;
drop table t1,t2,t3; drop table t1,t2,t3;
end of the tests
drop table if exists t1,t2;
create table t1 (a int) engine=MyISAM;
insert into t1 set a=1;
reset master;
update t1 set a=2 /* will be "killed" after work has been done */;
select
(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
is not null;
(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
is not null
1
select 1 /* must return 1 as query completed before got killed*/;
1
1
create table t2 (a int, b int) ENGINE=MyISAM;
reset master;
load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */;
ERROR 70100: Query execution was interrupted
show binlog events from 98;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 98 Begin_load_query 1 # ;file_id=1;block_len=12
master-bin.000001 133 Execute_load_query 1 # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */ ;file_id=1
select
(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
is not null;
(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
is not null
1
select 0 /* must return 0 to mean the killed query is in */;
0
0
drop table t1,t2;
end of the tests
...@@ -55,194 +55,162 @@ enable_result_log; ...@@ -55,194 +55,162 @@ 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
connection con1;
select RELEASE_LOCK("a");
### 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;
let $ID= `select connection_id()`; delete from t2;
send insert into t1 values (bug27563(),1); insert into t1 values (1,1),(2,2);
#
# simple update
#
connection con1; 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; connection con2;
let $ID= `select connection_id()`; let $ID= `select connection_id()`;
begin; begin;
send insert into t1 values (bug27563(),1); send update t1 set b=b+10;
connection con1; connection con1;
--replace_result $ID ID
eval kill query $ID; eval kill query $ID;
rollback;
# Bug #32148 killi query may be ineffective
# forced to comment out the test's outcome
# and mask out ineffective ER_QUERY_INTERRUPTED
# todo1: revert back upon fixing bug#32148
# todo2: the tests need refining in that
# killing should wait till the victim requested
# its lock (wait_condition available in 5.1 tests)
connection con2; 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 0,ER_QUERY_INTERRUPTED
reap; reap;
--disable_info rollback;
select count(*) from t1 /* must be zero unless Bug#27563 */; select * from t1 order by a /* must be the same as before (1,1),(2,2) */;
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;
### non-ta table case: killing must be recorded in binlog # connection con2;
# send update t1 as t_1,t1 as t_2 set t_1.b=11 where t_2.a=2;
reset master; # connection con1;
# --replace_result $ID ID
# eval kill query $ID;
# rollback;
# disable_abort_on_error;
# connection con2;
# --error HY000,ER_QUERY_INTERRUPTED
# reap;
# select * from t1 /* must be the same as before (1,1),(2,2) */;
# enable_abort_on_error;
#
# simple delete
#
connection con1;
begin; delete from t1 where a=2;
connection con2; connection con2;
let $ID= `select connection_id()`; let $ID= `select connection_id()`;
send insert into t2 values (bug27563(),1); begin;
send delete from t1 where a=2;
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 0,ER_QUERY_INTERRUPTED --error 0,ER_QUERY_INTERRUPTED
reap; reap;
select count(*) from t2 /* must be one */; rollback;
#show binlog events from 98 /* must have the insert on non-ta table */; # todo1,2 above
show master status /* must have the insert event more to FD */; select * from t1 order by a /* must be the same as before (1,1),(2,2) */;
# the value of the error flag of KILLED_QUERY is tested further
connection con1;
select RELEASE_LOCK("a");
### test with effective killing of SF()
delete from t1;
delete from t2;
insert into t1 values (1,1);
insert into t2 values (1,1);
# #
# Bug#27565 # multi delete
# test where KILL is propagated as error to the top level # the same as for multi-update
# 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;
# begin; delete from t1 where a=2;
connection con2;
let $ID= `select connection_id()`;
send update t2 set b=bug27565()-1 where a=1;
connection con1; # connection con2;
eval kill query $ID; # send delete t1 from t1 where t1.a=2;
commit;
connection con2; # connection con1;
# todo: fix Bug #27565 killed query of SF() is not reported correctly and # --replace_result $ID ID
# remove 1105 (wrong) # eval kill query $ID;
#--error ER_QUERY_INTERRUPTED # rollback;
--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) */;
## bug#22725 with effective and propagating killing # connection con2;
# --error 0,ER_QUERY_INTERRUPTED
# reap;
# select * from t1 /* must be the same as before (1,1),(2,2) */;
#
# insert select
# #
# top-level ta-table
connection con1; connection con1;
delete from t3; --disable_warnings
reset master; drop table if exists t4;
begin; update t1 set b=0 where a=1; --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()`; let $ID= `select connection_id()`;
# the query won't perform completely since the function gets interrupted begin;
send insert into t3 values (0,0),(1,bug27565()); 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;
rollback; rollback;
connection con2; connection con2;
# todo: fix Bug #27565 killed query of SF() is not reported correctly and --error 0,ER_QUERY_INTERRUPTED
# remove 1105 (wrong) reap;
#--error ER_QUERY_INTERRUPTED # todo 1,2 above
--error 1105,ER_QUERY_INTERRUPTED
reap; ### pb: wrong error
select count(*) from t3 /* must be zero */;
show master status /* nothing in binlog */;
# top-level non-ta-table
connection con1;
delete from t2;
reset master;
begin; update t1 set b=0 where a=1;
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 */;
connection con1;
eval kill query $ID;
rollback; rollback;
select * from t1 /* must be the same as before (1,1),(2,2) */;
connection con2; drop table t4; # cleanup for the sub-case
# todo: fix Bug #27565 killed query of SF() is not reported correctly and
# remove 1105 (wrong) ###
#--error ER_QUERY_INTERRUPTED ## non-ta table case: killing must be recorded in binlog
--error 1105,ER_QUERY_INTERRUPTED ###
reap; ### pb: wrong error
select count(*) from t2 /* count must be one */; # In order to be deterministic the test needs INFORMATION_SCHEMA.PROCESSLIST
show master status /* insert into non-ta must be in binlog */; # which is not available on 5.0 at this time.
# Therefore, skip this part on 5.0.
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
--loose-debug=d,simulate_kill_bug27571
-- source include/have_debug.inc
#
# bug#27571 asynchronous setting mysql_$query()'s local error and
# Query_log_event::error_code
#
--disable_warnings
drop table if exists t1,t2;
--enable_warnings
#
# Checking that killing upon successful row-loop does not affect binlogging
#
create table t1 (a int) engine=MyISAM;
insert into t1 set a=1;
reset master;
update t1 set a=2 /* will be "killed" after work has been done */;
# a proof the query is binlogged with no error
--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
...@@ -106,9 +106,3 @@ connection slave; ...@@ -106,9 +106,3 @@ connection slave;
sync_with_master; sync_with_master;
# End of 4.1 tests # End of 4.1 tests
# Cleanup
# The A->B->A replication causes the master to start writing relay logs
# in var/run, remove them
remove_file $MYSQLTEST_VARDIR/run/master-relay-bin.000001;
remove_file $MYSQLTEST_VARDIR/run/master-relay-bin.index;
...@@ -211,6 +211,8 @@ select * from t1; ...@@ -211,6 +211,8 @@ select * from t1;
connection master; connection master;
drop table t1; drop table t1;
--remove_file $MYSQLTEST_VARDIR/tmp/bug14157.sql
# Delete the anonymous users # Delete the anonymous users
source include/delete_anonymous_users.inc; source include/delete_anonymous_users.inc;
......
...@@ -448,13 +448,10 @@ const char *MYSQL_LOG::generate_name(const char *log_name, ...@@ -448,13 +448,10 @@ const char *MYSQL_LOG::generate_name(const char *log_name,
{ {
if (!log_name || !log_name[0]) if (!log_name || !log_name[0])
{ {
/* strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1);
TODO: The following should be using fn_format(); We just need to return (const char *)
first change fn_format() to cut the file name if it's too long. fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR));
*/
strmake(buff, pidfile_name,FN_REFLEN-5);
strmov(fn_ext(buff),suffix);
return (const char *)buff;
} }
// get rid of extension if the log is binary to avoid problems // get rid of extension if the log is binary to avoid problems
if (strip_ext) if (strip_ext)
......
...@@ -5070,9 +5070,10 @@ Execute_load_query_log_event(THD* thd_arg, const char* query_arg, ...@@ -5070,9 +5070,10 @@ 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)
{ {
......
...@@ -1622,7 +1622,9 @@ public: ...@@ -1622,7 +1622,9 @@ public:
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);
int exec_event(struct st_relay_log_info* rli); int exec_event(struct st_relay_log_info* rli);
......
...@@ -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; ha_rows deleted;
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))
...@@ -280,8 +281,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -280,8 +281,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;
thd->proc_info="end"; thd->proc_info="end";
end_read_record(&info); end_read_record(&info);
free_io_cache(table); // Will not do any harm free_io_cache(table); // Will not do any harm
...@@ -326,7 +327,7 @@ cleanup: ...@@ -326,7 +327,7 @@ cleanup:
if (error < 0) if (error < 0)
thd->clear_error(); thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 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) if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1; error=1;
} }
...@@ -729,7 +730,8 @@ void multi_delete::send_error(uint errcode,const char *err) ...@@ -729,7 +730,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;
} }
...@@ -817,6 +819,7 @@ int multi_delete::do_deletes() ...@@ -817,6 +819,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 */
...@@ -824,7 +827,7 @@ bool multi_delete::send_eof() ...@@ -824,7 +827,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";
...@@ -836,7 +839,8 @@ bool multi_delete::send_eof() ...@@ -836,7 +839,8 @@ 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())
...@@ -844,7 +848,7 @@ bool multi_delete::send_eof() ...@@ -844,7 +848,7 @@ bool multi_delete::send_eof()
if (local_error == 0) if (local_error == 0)
thd->clear_error(); thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 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) 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
} }
......
...@@ -2938,6 +2938,7 @@ bool select_insert::send_eof() ...@@ -2938,6 +2938,7 @@ bool select_insert::send_eof()
{ {
int error, error2; int error, error2;
bool changed, transactional_table= table->file->has_transactions(); 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");
error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0; error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0;
...@@ -2967,7 +2968,7 @@ bool select_insert::send_eof() ...@@ -2967,7 +2968,7 @@ bool select_insert::send_eof()
if (!error) if (!error)
thd->clear_error(); thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, Query_log_event qinfo(thd, thd->query, thd->query_length,
transactional_table, FALSE); transactional_table, FALSE, killed_status);
mysql_bin_log.write(&qinfo); mysql_bin_log.write(&qinfo);
} }
if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error) if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
......
...@@ -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 */
/* /*
...@@ -135,6 +136,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -135,6 +136,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
...@@ -404,7 +406,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -404,7 +406,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_...
...@@ -446,7 +457,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -446,7 +457,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
{ {
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,
ignore, transactional_table); ignore, transactional_table,
killed_status);
else else
{ {
Delete_file_log_event d(thd, db, transactional_table); Delete_file_log_event d(thd, db, transactional_table);
...@@ -477,7 +489,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -477,7 +489,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
read_info.end_io_cache(); read_info.end_io_cache();
if (lf_info.wrote_create_file) if (lf_info.wrote_create_file)
write_execute_load_query_log_event(thd, handle_duplicates, write_execute_load_query_log_event(thd, handle_duplicates,
ignore, transactional_table); ignore, transactional_table,
killed_status);
} }
#endif /*!EMBEDDED_LIBRARY*/ #endif /*!EMBEDDED_LIBRARY*/
if (transactional_table) if (transactional_table)
...@@ -504,7 +517,8 @@ err: ...@@ -504,7 +517,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,
...@@ -512,7 +526,7 @@ static bool write_execute_load_query_log_event(THD *thd, ...@@ -512,7 +526,7 @@ 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),
transactional_table, FALSE); transactional_table, FALSE, killed_err_arg);
return mysql_bin_log.write(&e); return mysql_bin_log.write(&e);
} }
......
...@@ -134,6 +134,7 @@ int mysql_update(THD *thd, ...@@ -134,6 +134,7 @@ int mysql_update(THD *thd,
SELECT_LEX *select_lex= &thd->lex->select_lex; SELECT_LEX *select_lex= &thd->lex->select_lex;
bool need_reopen; bool need_reopen;
List<Item> all_fields; List<Item> all_fields;
THD::killed_state killed_status= THD::NOT_KILLED;
DBUG_ENTER("mysql_update"); DBUG_ENTER("mysql_update");
LINT_INIT(timestamp_query_id); LINT_INIT(timestamp_query_id);
...@@ -519,43 +520,26 @@ int mysql_update(THD *thd, ...@@ -519,43 +520,26 @@ int mysql_update(THD *thd,
table->file->unlock_row(); table->file->unlock_row();
thd->row_count++; thd->row_count++;
} }
if (!transactional_table && updated > 0)
thd->transaction.stmt.modified_non_trans_table= TRUE;
/* /*
todo bug#27571: to avoid asynchronization of `error' and Caching the killed status to pass as the arg to query event constuctor;
`error_code' of binlog event constructor The cached value can not change whereas the killed status can
(externally) since this point and change of the latter won't affect
The concept, which is a bit different for insert(!), is to binlogging.
replace `error' assignment with the following lines 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 killed_status= thd->killed; // get the status of the volatile
// simulated killing after the loop must be ineffective for binlogging
Notice: thd->killed is type of "state" whereas the lhs has DBUG_EXECUTE_IF("simulate_kill_bug27571",
"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 thd->killed= THD::KILL_QUERY;
our case. Binlogging ops are conducted with the status. };);
error= (killed_status == THD::NOT_KILLED)? error : 1; 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 - if (!transactional_table && updated > 0)
and then KILLED was caught later still within the loop - we shall thd->transaction.stmt.modified_non_trans_table= TRUE;
do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN
error_code.
*/
if (thd->killed && !error)
error= 1; // Aborted
end_read_record(&info); end_read_record(&info);
free_io_cache(table); // If ORDER BY free_io_cache(table); // If ORDER BY
delete select; delete select;
...@@ -587,7 +571,7 @@ int mysql_update(THD *thd, ...@@ -587,7 +571,7 @@ int mysql_update(THD *thd,
if (error < 0) if (error < 0)
thd->clear_error(); thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 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) if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1; // Rollback update error=1; // Rollback update
} }
...@@ -1522,6 +1506,11 @@ void multi_update::send_error(uint errcode,const char *err) ...@@ -1522,6 +1506,11 @@ void multi_update::send_error(uint errcode,const char *err)
*/ */
if (mysql_bin_log.is_open()) 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, Query_log_event qinfo(thd, thd->query, thd->query_length,
transactional_tables, FALSE); transactional_tables, FALSE);
mysql_bin_log.write(&qinfo); mysql_bin_log.write(&qinfo);
...@@ -1709,10 +1698,19 @@ err2: ...@@ -1709,10 +1698,19 @@ err2:
bool multi_update::send_eof() bool multi_update::send_eof()
{ {
char buff[STRING_BUFFER_USUAL_SIZE]; char buff[STRING_BUFFER_USUAL_SIZE];
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
...@@ -1740,7 +1738,7 @@ bool multi_update::send_eof() ...@@ -1740,7 +1738,7 @@ bool multi_update::send_eof()
if (local_error == 0) if (local_error == 0)
thd->clear_error(); thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 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) if (mysql_bin_log.write(&qinfo) && trans_safe)
local_error= 1; // Rollback update local_error= 1; // Rollback update
} }
......
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