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

Merge mkindahl@bk-internal.mysql.com:/home/bk/mysql-5.0-rpl

into  capulet.net:/home/bk/mysql-5.0-rpl
parents 9b838a6e 86c3c0b0
...@@ -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
# test where KILL is propagated as error to the top level
# still another bug with the error message to the user
# todo: fix reexecute the result file after fixing
#
begin; update t1 set b=0 where a=1;
connection con2; #
let $ID= `select connection_id()`; # multi delete
send update t2 set b=bug27565()-1 where a=1; # the same as for multi-update
#
# connection con1;
# begin; delete from t1 where a=2;
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)
......
...@@ -4994,12 +4994,13 @@ int Begin_load_query_log_event::get_create_or_append() const ...@@ -4994,12 +4994,13 @@ int Begin_load_query_log_event::get_create_or_append() const
#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)
{ {
......
...@@ -1619,10 +1619,12 @@ class Execute_load_query_log_event: public Query_log_event ...@@ -1619,10 +1619,12 @@ class Execute_load_query_log_event: public Query_log_event
#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);
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 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -326,7 +327,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
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 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -504,7 +517,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
/* 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++;
} }
/*
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;
/*
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); 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 @@ int multi_update::do_updates(bool from_send_error) ...@@ -1709,10 +1698,19 @@ int multi_update::do_updates(bool from_send_error)
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