diff options
-rw-r--r-- | client/mysqltest.c | 21 | ||||
-rw-r--r-- | mysql-test/include/diff_master_slave.inc | 21 | ||||
-rw-r--r-- | mysql-test/include/kill_query.inc | 68 | ||||
-rw-r--r-- | mysql-test/include/kill_query_and_diff_master_slave.inc | 43 | ||||
-rwxr-xr-x | mysql-test/mysql-test-run.pl | 14 | ||||
-rw-r--r-- | mysql-test/r/rpl_killed_ddl.result | 146 | ||||
-rw-r--r-- | mysql-test/t/rpl_killed_ddl-master.opt | 1 | ||||
-rw-r--r-- | mysql-test/t/rpl_killed_ddl.test | 271 | ||||
-rw-r--r-- | sql/item_func.cc | 4 | ||||
-rw-r--r-- | sql/log.cc | 15 | ||||
-rw-r--r-- | sql/log_event.cc | 3 | ||||
-rw-r--r-- | sql/log_event.h | 6 | ||||
-rw-r--r-- | sql/mysql_priv.h | 7 | ||||
-rw-r--r-- | sql/sp.cc | 8 | ||||
-rw-r--r-- | sql/sp_head.cc | 3 | ||||
-rw-r--r-- | sql/sql_acl.cc | 24 | ||||
-rw-r--r-- | sql/sql_base.cc | 16 | ||||
-rw-r--r-- | sql/sql_db.cc | 8 | ||||
-rw-r--r-- | sql/sql_delete.cc | 4 | ||||
-rw-r--r-- | sql/sql_insert.cc | 5 | ||||
-rw-r--r-- | sql/sql_parse.cc | 12 | ||||
-rw-r--r-- | sql/sql_rename.cc | 3 | ||||
-rw-r--r-- | sql/sql_table.cc | 24 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 2 | ||||
-rw-r--r-- | sql/sql_update.cc | 2 | ||||
-rw-r--r-- | sql/sql_view.cc | 6 |
26 files changed, 674 insertions, 63 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c index 312012d7b8d..865c1d9a717 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -4093,13 +4093,20 @@ int select_connection(struct st_command *command) if (!*p) die("Missing connection name in connect"); - name= p; - while (*p && !my_isspace(charset_info,*p)) - p++; - if (*p) - *p++= 0; - command->last_argument= p; - return select_connection_name(name); + + static DYNAMIC_STRING ds_connection; + const struct command_arg connection_args[] = { + { "connection_name", ARG_STRING, TRUE, &ds_connection, "Name of the connection that we switch to." } + }; + check_command_args(command, command->first_argument, connection_args, + sizeof(connection_args)/sizeof(struct command_arg), + ','); + + DBUG_PRINT("info", ("changing connection: %s", ds_connection.str)); + + int ret= select_connection_name(ds_connection.str); + dynstr_free(&ds_connection); + return ret; } diff --git a/mysql-test/include/diff_master_slave.inc b/mysql-test/include/diff_master_slave.inc new file mode 100644 index 00000000000..b6d79190671 --- /dev/null +++ b/mysql-test/include/diff_master_slave.inc @@ -0,0 +1,21 @@ +# ==== Purpose ==== +# +# Diff the output of a statement on master and slave +# +# ==== Usage ===== +# +# let $diff_statement= SELECT * FROM t1 WHERE a < 100; +# source include/diff_master_slave.inc; + +--echo source include/diff_master_slave.inc; +disable_query_log; +disable_result_log; + +exec $MYSQL test -e "$diff_statement" > $MYSQLTEST_VARDIR/tmp/diff_master.out; +sync_slave_with_master; +exec $MYSQL_SLAVE test -e "$diff_statement" > $MYSQLTEST_VARDIR/tmp/diff_slave.out; + +diff_files $MYSQLTEST_VARDIR/tmp/diff_master.out $MYSQLTEST_VARDIR/tmp/diff_slave.out; + +enable_result_log; +enable_query_log; diff --git a/mysql-test/include/kill_query.inc b/mysql-test/include/kill_query.inc new file mode 100644 index 00000000000..341c3b93535 --- /dev/null +++ b/mysql-test/include/kill_query.inc @@ -0,0 +1,68 @@ +# ==== Purpose ==== +# +# Kill a query in the master connection, and then try to reap the +# result of the killed query. +# +# ==== Usage ==== +# +# The following variables should be set before sourcing this file. +# +# $debug_lock: name of the debug user lock, if set, will release/lock +# the specified debug lock accordingly, and before +# sourcing this, connection 'master' should get the user +# lock and run a query in another thread, which will +# block before creating statement event. +# +# $connection_name: name of the connection that is waiting for the +# lock, this can not be 'master' +# +# $connection_id: id of the connection that is waiting for the lock +# +# Example: +# let $debug_lock=; +# connection master1; +# let $connection_name= master1; +# let $connection_id= `SELECT CONNECTION_ID()`; +# send CREATE TABLE t1; +# source kill_query.inc; +# +# let $debug_lock= "debug_lock.before_query_log_event"; +# connection master; +# eval SELECT GET_LOCK($debug_lock, 10); +# connection master1; +# let $connection_name= master1; +# let $connection_id= `SELECT CONNECTION_ID()`; +# send CREATE TABLE t1; +# source kill_query.inc; + + +--echo source include/kill_query.inc; +disable_query_log; +disable_result_log; +connection master; + +# kill the query that is waiting +eval kill query $connection_id; + +if (`SELECT '$debug_lock' != ''`) +{ + # release the lock to allow binlog continue + eval SELECT RELEASE_LOCK($debug_lock); +} + +# reap the result of the waiting query +connection $connection_name; +error 0, 1317, 1307, 1306, 1334, 1305; +reap; + +connection master; + +if (`SELECT '$debug_lock' != ''`) +{ + # get lock again to make the next query wait + eval SELECT GET_LOCK($debug_lock, 10); +} + +connection $connection_name; +enable_query_log; +enable_result_log; diff --git a/mysql-test/include/kill_query_and_diff_master_slave.inc b/mysql-test/include/kill_query_and_diff_master_slave.inc new file mode 100644 index 00000000000..611d6929c99 --- /dev/null +++ b/mysql-test/include/kill_query_and_diff_master_slave.inc @@ -0,0 +1,43 @@ +# ==== Purpose ==== +# +# Kill a query, sync master with slave, and diff the output of a +# statement on master and slave to check if statement is correctly +# replicated. +# +# ==== Usage ==== +# +# connection <CONNECTION>; +# let $connection_name=<CONNECTION> +# let $connection_id=`SELECT CONNECTION_ID()`; +# let $diff_statement=<SQL COMMAND>; +# send <SQL COMMAND>; +# source include/kill_query_and_diff_master_slave.inc; +# +# Note: <CONNECTION> must not be 'master'. +# +# See also kill_query.inc and diff_master_slave.inc for more +# information + +source include/kill_query.inc; + +# Release the debug lock if used, so that the statements in +# diff_master_slave.inc will not be blocked. +connection master; +disable_query_log; +disable_result_log; +if (`SELECT '$debug_lock' != ''`) +{ + eval SELECT RELEASE_LOCK($debug_lock); +} +enable_result_log; +enable_query_log; + +source include/diff_master_slave.inc; + +# Acquire the debug lock again if used +connection master; +disable_query_log; disable_result_log; if (`SELECT '$debug_lock' != +''`) { eval SELECT GET_LOCK($debug_lock, 10); } enable_result_log; +enable_query_log; + +connection $connection_name; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 0948c973e9b..ffa9b4cb1d3 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2063,7 +2063,7 @@ sub environment_setup () { $ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog; # ---------------------------------------------------- - # Setup env so childs can execute mysql + # Setup env so childs can execute mysql against master # ---------------------------------------------------- my $cmdline_mysql= mtr_native_path($exe_mysql) . @@ -2075,6 +2075,18 @@ sub environment_setup () { $ENV{'MYSQL'}= $cmdline_mysql; # ---------------------------------------------------- + # Setup env so childs can execute mysql against slave + # ---------------------------------------------------- + my $cmdline_mysql_slave= + mtr_native_path($exe_mysql) . + " --no-defaults --host=localhost --user=root --password= " . + "--port=$slave->[0]->{'port'} " . + "--socket=$slave->[0]->{'path_sock'} ". + "--character-sets-dir=$path_charsetsdir"; + + $ENV{'MYSQL_SLAVE'}= $cmdline_mysql_slave; + + # ---------------------------------------------------- # Setup env so childs can execute bug25714 # ---------------------------------------------------- $ENV{'MYSQL_BUG25714'}= $exe_bug25714; diff --git a/mysql-test/r/rpl_killed_ddl.result b/mysql-test/r/rpl_killed_ddl.result new file mode 100644 index 00000000000..aa419a8556e --- /dev/null +++ b/mysql-test/r/rpl_killed_ddl.result @@ -0,0 +1,146 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +DROP DATABASE IF EXISTS d1; +DROP DATABASE IF EXISTS d2; +DROP DATABASE IF EXISTS d3; +DROP DATABASE IF EXISTS d4; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; +DROP TRIGGER IF EXISTS tr1; +DROP TRIGGER IF EXISTS tr2; +DROP TRIGGER IF EXISTS tr3; +DROP TRIGGER IF EXISTS tr4; +CREATE DATABASE d1; +CREATE FUNCTION f1 () RETURNS INT DETERMINISTIC +RETURN 1; +CREATE PROCEDURE p1 (OUT rows INT) +BEGIN +SELECT COUNT(*) INTO rows FROM t1; +END; +// +CREATE TABLE t1 (a int); +CREATE TABLE t3 (a int); +CREATE TRIGGER tr1 BEFORE INSERT ON t1 +FOR EACH ROW BEGIN +DELETE FROM t4 WHERE a=NEW.a; +END; +// +CREATE INDEX i1 ON t1 (a); +CREATE VIEW v1 AS SELECT a FROM t1 WHERE a < 100; +[on master] +[on master1] +CREATE DATABASE d2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +ALTER DATABASE d1 +DEFAULT CHARACTER SET = 'utf8'; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP DATABASE d1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP DATABASE d2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE FUNCTION f2 () RETURNS INT DETERMINISTIC +RETURN 1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +ALTER FUNCTION f1 SQL SECURITY INVOKER; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP FUNCTION IF EXISTS f1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP FUNCTION IF EXISTS f2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE PROCEDURE p2 (OUT rows INT) +BEGIN +SELECT COUNT(*) INTO rows FROM t2; +END; +// +source include/kill_query.inc; +source include/diff_master_slave.inc; +ALTER PROCEDURE p1 SQL SECURITY INVOKER COMMENT 'return rows of table t1'; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP PROCEDURE IF EXISTS p1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP PROCEDURE IF EXISTS p2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE TABLE t2 (b int); +source include/kill_query.inc; +source include/diff_master_slave.inc; +ALTER TABLE t1 ADD (d int); +source include/kill_query.inc; +source include/diff_master_slave.inc; +RENAME TABLE t3 TO t4; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE INDEX i2 on t1 (a); +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP INDEX i1 on t1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE TRIGGER tr2 BEFORE INSERT ON t4 +FOR EACH ROW BEGIN +DELETE FROM t1 WHERE a=NEW.a; +END; +// +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP TRIGGER tr1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP TRIGGER IF EXISTS tr2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +CREATE VIEW v2 AS SELECT a FROM t1 WHERE a > 100; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP VIEW v1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP VIEW IF EXISTS v2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP TABLE t1; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP TABLE IF EXISTS t2; +source include/kill_query.inc; +source include/diff_master_slave.inc; +DROP DATABASE IF EXISTS d1; +DROP DATABASE IF EXISTS d2; +DROP DATABASE IF EXISTS d3; +DROP DATABASE IF EXISTS d4; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; diff --git a/mysql-test/t/rpl_killed_ddl-master.opt b/mysql-test/t/rpl_killed_ddl-master.opt new file mode 100644 index 00000000000..aaf2d8a4251 --- /dev/null +++ b/mysql-test/t/rpl_killed_ddl-master.opt @@ -0,0 +1 @@ +--debug=d,debug_lock_before_query_log_event diff --git a/mysql-test/t/rpl_killed_ddl.test b/mysql-test/t/rpl_killed_ddl.test new file mode 100644 index 00000000000..f4f2f6ac320 --- /dev/null +++ b/mysql-test/t/rpl_killed_ddl.test @@ -0,0 +1,271 @@ +# ==== Purpose ==== +# +# This test check if DDL statements are correctly binlogged when the +# thread is killed +# +# ==== Method ==== +# +# Start a DDL query and kill it, check if the error code of the binlog +# event is correct. +# +# DDL statements tested: +# CREATE/ALTER/RENAME/DROP DATABASE +# CREATE/ALTER/DROP FUNCTION +# CREATE/ALTER/DROP PROCEDURE +# CREATE/ALTER/RENAME/DROP TABLE +# CREATE/DROP TRIGGER +# CREATE/ALTER/DROP VIEW +# +# ==== Bugs ===== +# + +source include/have_debug.inc; +source include/master-slave.inc; + +# Use the DBUG_SYNC_POINT to make sure the thread running the DDL is +# waiting before creating the query log event + +let $debug_lock= "debug_lock.before_query_log_event"; + +######## INITIALIZATION ######## + +disable_warnings; +DROP DATABASE IF EXISTS d1; +DROP DATABASE IF EXISTS d2; +DROP DATABASE IF EXISTS d3; +DROP DATABASE IF EXISTS d4; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; +DROP TRIGGER IF EXISTS tr1; +DROP TRIGGER IF EXISTS tr2; +DROP TRIGGER IF EXISTS tr3; +DROP TRIGGER IF EXISTS tr4; +enable_warnings; + +CREATE DATABASE d1; + +CREATE FUNCTION f1 () RETURNS INT DETERMINISTIC + RETURN 1; + +DELIMITER //; +CREATE PROCEDURE p1 (OUT rows INT) + BEGIN + SELECT COUNT(*) INTO rows FROM t1; + END; + // +DELIMITER ;// + +CREATE TABLE t1 (a int); +CREATE TABLE t3 (a int); + +DELIMITER //; +CREATE TRIGGER tr1 BEFORE INSERT ON t1 + FOR EACH ROW BEGIN + DELETE FROM t4 WHERE a=NEW.a; + END; + // +DELIMITER ;// + +CREATE INDEX i1 ON t1 (a); + +CREATE VIEW v1 AS SELECT a FROM t1 WHERE a < 100; + +sync_slave_with_master; + +connection master1; +let $connection_name= master1; +let $connection_id= `SELECT CONNECTION_ID()`; + +connection master; +echo [on master]; + +# This will block the execution of a statement at the DBUG_SYNC_POINT +# with given lock name +if (`SELECT '$debug_lock' != ''`) +{ + disable_query_log; + disable_result_log; + eval SELECT IS_FREE_LOCK($debug_lock); + eval SELECT GET_LOCK($debug_lock, 10); + eval SELECT IS_FREE_LOCK($debug_lock); + enable_query_log; + enable_result_log; +} + +######## START TEST ######## + +connection master1; +echo [on master1]; + +disable_warnings; + +######## DATABASE ######## + +let $diff_statement= SHOW DATABASES LIKE 'd%'; + +send CREATE DATABASE d2; +source include/kill_query_and_diff_master_slave.inc; + +send ALTER DATABASE d1 + DEFAULT CHARACTER SET = 'utf8'; +source include/kill_query_and_diff_master_slave.inc; + +send DROP DATABASE d1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP DATABASE d2; +source include/kill_query_and_diff_master_slave.inc; + +######## FUNCTION ######## + +let $diff_statement= SHOW FUNCTION STATUS LIKE 'f%'; + +send CREATE FUNCTION f2 () RETURNS INT DETERMINISTIC + RETURN 1; +source include/kill_query_and_diff_master_slave.inc; + +send ALTER FUNCTION f1 SQL SECURITY INVOKER; +source include/kill_query_and_diff_master_slave.inc; + +# function f1 probably does not exist because the ALTER query was +# killed +send DROP FUNCTION IF EXISTS f1; +source include/kill_query_and_diff_master_slave.inc; + +# function f2 probably does not exist because the CREATE query was +# killed +send DROP FUNCTION IF EXISTS f2; +source include/kill_query_and_diff_master_slave.inc; + +######## PROCEDURE ######## + +let $diff_statement= SHOW PROCEDURE STATUS LIKE 'p%'; + +DELIMITER //; +send CREATE PROCEDURE p2 (OUT rows INT) + BEGIN + SELECT COUNT(*) INTO rows FROM t2; + END; + // +DELIMITER ;// +source include/kill_query_and_diff_master_slave.inc; + +send ALTER PROCEDURE p1 SQL SECURITY INVOKER COMMENT 'return rows of table t1'; +source include/kill_query_and_diff_master_slave.inc; + +send DROP PROCEDURE IF EXISTS p1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP PROCEDURE IF EXISTS p2; +source include/kill_query_and_diff_master_slave.inc; + +######## TABLE ######## + +let $diff_statement= SHOW TABLES LIKE 't%'; + +send CREATE TABLE t2 (b int); +source include/kill_query_and_diff_master_slave.inc; + +send ALTER TABLE t1 ADD (d int); +source include/kill_query_and_diff_master_slave.inc; + +send RENAME TABLE t3 TO t4; +source include/kill_query_and_diff_master_slave.inc; + +######## INDEX ######## + +let $diff_statement= SHOW INDEX FROM t1; + +send CREATE INDEX i2 on t1 (a); +source include/kill_query_and_diff_master_slave.inc; + +send DROP INDEX i1 on t1; +source include/kill_query_and_diff_master_slave.inc; + +######## TRIGGER ######## + +let $diff_statement= SHOW TRIGGERS LIKE 'v%'; + +DELIMITER //; +send CREATE TRIGGER tr2 BEFORE INSERT ON t4 + FOR EACH ROW BEGIN + DELETE FROM t1 WHERE a=NEW.a; + END; + // +DELIMITER ;// +source include/kill_query_and_diff_master_slave.inc; + +send DROP TRIGGER tr1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP TRIGGER IF EXISTS tr2; +source include/kill_query_and_diff_master_slave.inc; + +######## VIEW ######## + +let $diff_statement= SHOW TABLES LIKE 'v%'; + +send CREATE VIEW v2 AS SELECT a FROM t1 WHERE a > 100; +source include/kill_query_and_diff_master_slave.inc; + +send DROP VIEW v1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP VIEW IF EXISTS v2; +source include/kill_query_and_diff_master_slave.inc; + +######## DROP TABLE ######## + +# Because of BUG#43529, we cannot use the DBUG_SYNC_POINT for DROP +# TABLE statements on 5.0 +connection master; +disable_query_log; +disable_result_log; +eval SELECT RELEASE_LOCK($debug_lock); +enable_result_log; +enable_query_log; +let $debug_lock=; + +connection master1; + +let $diff_statement= SHOW TABLES LIKE 't%'; + +send DROP TABLE t1; +source include/kill_query_and_diff_master_slave.inc; + +send DROP TABLE IF EXISTS t2; +source include/kill_query_and_diff_master_slave.inc; + +######## CLEAN UP ######## + +# The DROP statements above are killed during the process, so they +# does not make sure the objects are dropped. + +disable_warnings; +DROP DATABASE IF EXISTS d1; +DROP DATABASE IF EXISTS d2; +DROP DATABASE IF EXISTS d3; +DROP DATABASE IF EXISTS d4; +DROP FUNCTION IF EXISTS f1; +DROP FUNCTION IF EXISTS f2; +DROP FUNCTION IF EXISTS f3; +DROP FUNCTION IF EXISTS f4; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +DROP TABLE IF EXISTS t4; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +DROP PROCEDURE IF EXISTS p3; +DROP PROCEDURE IF EXISTS p4; +enable_warnings; diff --git a/sql/item_func.cc b/sql/item_func.cc index 47e16a1bcc3..e7e75ecd020 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3377,6 +3377,10 @@ longlong Item_master_pos_wait::val_int() } #ifdef EXTRA_DEBUG +/** + This will release the user lock that the thread currently locked, + please see also the comment of DEBUG_SYNC_POINT. +*/ void debug_sync_point(const char* lock_name, uint lock_timeout) { THD* thd=current_thd; diff --git a/sql/log.cc b/sql/log.cc index d979dd101e0..b16303ee232 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -158,7 +158,8 @@ static int binlog_commit(THD *thd, bool all) */ if (all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE); + Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), + TRUE, FALSE, THD::KILLED_NO_VALUE); qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) DBUG_RETURN(binlog_end_trans(thd, trans_log, &qev)); } @@ -202,7 +203,8 @@ static int binlog_rollback(THD *thd, bool all) */ if (unlikely(thd->transaction.all.modified_non_trans_table)) { - Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE); + Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), + TRUE, FALSE, THD::KILLED_NO_VALUE); qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) error= binlog_end_trans(thd, trans_log, &qev); } @@ -240,7 +242,8 @@ static int binlog_savepoint_set(THD *thd, void *sv) *(my_off_t *)sv= my_b_tell(trans_log); /* Write it to the binary log */ - Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + TRUE, FALSE, THD::KILLED_NO_VALUE); DBUG_RETURN(mysql_bin_log.write(&qinfo)); } @@ -257,7 +260,8 @@ static int binlog_savepoint_rollback(THD *thd, void *sv) */ if (unlikely(thd->transaction.all.modified_non_trans_table)) { - Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + TRUE, FALSE, THD::KILLED_NO_VALUE); DBUG_RETURN(mysql_bin_log.write(&qinfo)); } reinit_io_cache(trans_log, WRITE_CACHE, *(my_off_t *)sv, 0, 0); @@ -2089,7 +2093,8 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) transaction is either a BEGIN..COMMIT block or a single statement in autocommit mode. */ - Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE); + Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), + TRUE, FALSE, THD::KILLED_NO_VALUE); /* Imagine this is rollback due to net timeout, after all statements of the transaction succeeded. Then we want a diff --git a/sql/log_event.cc b/sql/log_event.cc index c4cdfc27fa0..7856e1458ef 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1358,6 +1358,9 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, { time_t end_time; + DBUG_EXECUTE_IF("debug_lock_before_query_log_event", + DBUG_SYNC_POINT("debug_lock.before_query_log_event", 10);); + if (killed_status_arg == THD::KILLED_NO_VALUE) killed_status_arg= thd_arg->killed; error_code= diff --git a/sql/log_event.h b/sql/log_event.h index 6ccbf8e4d5c..45e3d11b48c 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -813,9 +813,13 @@ public: #ifndef MYSQL_CLIENT + /* + for argument killed_err_arg, use ` THD::NOT_KILLED ' if the killed + status should be ignored, otherwise use `THD::KILLED_NO_VALUE' + */ Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans, bool suppress_use, - THD::killed_state killed_err_arg= THD::KILLED_NO_VALUE); + THD::killed_state killed_err_arg); const char* get_db() { return db; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b855af9a8d3..37ba0611ee0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -451,6 +451,13 @@ MY_LOCALE *my_locale_by_number(uint number); The client tells the server to block with SELECT GET_LOCK() and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult concurrency problems + + NOTE: This will release the user lock that the thread currently + locked, which can cause problem if users want to use user locks for + other purposes. In order to overcome this problem, it's adviced to + wrap the call to DBUG_SYNC_POINT() within the DBUG_EXECUTE_IF(), so + that it will only be activated if the given keyword is included in + the 'debug' option, and will not fiddle user locks otherwise. */ #define DBUG_SYNC_POINT(lock_name,lock_timeout) \ debug_sync_point(lock_name,lock_timeout) diff --git a/sql/sp.cc b/sql/sp.cc index 3af51b82521..2450e9564d0 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -646,7 +646,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) /* Such a statement can always go directly to binlog, no trans cache */ Query_log_event qinfo(thd, log_query.c_ptr(), log_query.length(), 0, - FALSE); + FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } @@ -680,7 +680,8 @@ db_drop_routine(THD *thd, int type, sp_name *name) if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -725,7 +726,8 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index b51d97e66c5..7da52458f26 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1601,7 +1601,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, if (need_binlog_call && thd->binlog_evt_union.unioned_events) { Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(), - thd->binlog_evt_union.unioned_events_trans, FALSE); + thd->binlog_evt_union.unioned_events_trans, + FALSE, THD::KILLED_NO_VALUE); if (mysql_bin_log.write(&qinfo) && thd->binlog_evt_union.unioned_events_trans) { diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b2d0304f007..f61304a1e26 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1506,7 +1506,8 @@ bool change_password(THD *thd, const char *host, const char *user, acl_user->host.hostname ? acl_user->host.hostname : "", new_password)); thd->clear_error(); - Query_log_event qinfo(thd, buff, query_length, 0, FALSE); + Query_log_event qinfo(thd, buff, query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } end: @@ -3014,7 +3015,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -3181,7 +3183,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -3294,7 +3297,8 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -5404,7 +5408,8 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) if (some_users_created && mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } @@ -5473,7 +5478,8 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) if (some_users_deleted && mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } @@ -5553,7 +5559,8 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) if (some_users_renamed && mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } @@ -5731,7 +5738,8 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0cf3e023be9..8f60c02a08c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -793,18 +793,9 @@ void close_temporary_tables(THD *thd) thd->variables.character_set_client= system_charset_info; Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, - 0, FALSE); + 0, FALSE, THD::NOT_KILLED); thd->variables.character_set_client= cs_save; - /* - Imagine the thread had created a temp table, then was doing a SELECT, and - the SELECT was killed. Then it's not clever to mark the statement above as - "killed", because it's not really a statement updating data, and there - are 99.99% chances it will succeed on slave. - If a real update (one updating a persistent table) was killed on the - master, then this real update will be logged with error_code=killed, - rightfully causing the slave to stop. - */ - qinfo.error_code= 0; + DBUG_ASSERT(qinfo.error_code == 0); mysql_bin_log.write(&qinfo); } else @@ -2578,7 +2569,8 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, { end = strxmov(strmov(query, "DELETE FROM `"), db,"`.`",name,"`", NullS); - Query_log_event qinfo(thd, query, (ulong)(end-query), 0, FALSE); + Query_log_event qinfo(thd, query, (ulong)(end-query), + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); my_free(query, MYF(0)); } diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 80fea3ef1b1..be538783458 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -70,7 +70,7 @@ static byte* dboptions_get_key(my_dbopt_t *opt, uint *length, static inline void write_to_binlog(THD *thd, char *query, uint q_len, char *db, uint db_len) { - Query_log_event qinfo(thd, query, q_len, 0, 0); + Query_log_event qinfo(thd, query, q_len, 0, 0, THD::NOT_KILLED); qinfo.error_code= 0; qinfo.db= db; qinfo.db_len= db_len; @@ -562,7 +562,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, query, query_length, 0, - /* suppress_use */ TRUE); + /* suppress_use */ TRUE, THD::NOT_KILLED); /* Write should use the database being created as the "current @@ -645,7 +645,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, 0, - /* suppress_use */ TRUE); + /* suppress_use */ TRUE, THD::NOT_KILLED); /* Write should use the database being created as the "current @@ -770,7 +770,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, query, query_length, 0, - /* suppress_use */ TRUE); + /* suppress_use */ TRUE, THD::NOT_KILLED); /* Write should use the database being created as the "current database" and not the threads current database, which is the diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 38f89683065..a757b7c28a5 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -730,7 +730,7 @@ void multi_delete::send_error(uint errcode,const char *err) if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); + transactional_tables, FALSE, THD::KILLED_NO_VALUE); mysql_bin_log.write(&qinfo); } thd->transaction.all.modified_non_trans_table= true; @@ -958,7 +958,7 @@ end: { thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - 0, FALSE); + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } send_ok(thd); // This should return record count diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b79f979df05..dcee47f6518 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2537,7 +2537,8 @@ bool Delayed_insert::handle_inserts(void) thd.variables.time_zone = row->time_zone; } - Query_log_event qinfo(&thd, row->query, row->query_length, 0, FALSE); + Query_log_event qinfo(&thd, row->query, row->query_length, + 0, FALSE, THD::KILLED_NO_VALUE); mysql_bin_log.write(&qinfo); thd.time_zone_used = backup_time_zone_used; @@ -3099,7 +3100,7 @@ void select_insert::abort() if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE); + transactional_table, FALSE, THD::KILLED_NO_VALUE); mysql_bin_log.write(&qinfo); } if (thd->transaction.stmt.modified_non_trans_table) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2297283c92d..a946a6afb35 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3551,7 +3551,8 @@ end_with_restore_list: if (mysql_bin_log.is_open()) { thd->clear_error(); // No binlog error generated - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -3586,7 +3587,8 @@ end_with_restore_list: if (mysql_bin_log.is_open()) { thd->clear_error(); // No binlog error generated - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -3612,7 +3614,8 @@ end_with_restore_list: if (mysql_bin_log.is_open()) { thd->clear_error(); // No binlog error generated - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -4394,7 +4397,8 @@ end_with_restore_list: { if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index f6766aec285..cec9e4c39de 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -84,7 +84,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } send_ok(thd); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 963a98cfb59..eec6ad626f0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -333,7 +333,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { if (!error) thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } @@ -1814,7 +1815,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, if (!internal_tmp_table && mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } error= FALSE; @@ -2903,7 +2905,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST *src_table, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } res= FALSE; @@ -3012,7 +3015,8 @@ mysql_discard_or_import_tablespace(THD *thd, goto err; if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } err: @@ -3168,7 +3172,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } send_ok(thd); @@ -3360,7 +3365,8 @@ view_err: if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } send_ok(thd); @@ -3872,7 +3878,8 @@ view_err: if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } goto end_temporary; @@ -4007,7 +4014,8 @@ view_err: if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + FALSE, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } broadcast_refresh(); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 930e3601699..d2ae494d4eb 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -304,7 +304,7 @@ end: /* Such a statement can always go directly to binlog, no trans cache. */ Query_log_event qinfo(thd, stmt_query.ptr(), stmt_query.length(), 0, - FALSE); + FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 8a3f5bcdc26..0da0b6e6635 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1575,7 +1575,7 @@ void multi_update::send_error(uint errcode,const char *err) into repl event. */ Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); + transactional_tables, FALSE, THD::KILLED_NO_VALUE); mysql_bin_log.write(&qinfo); } thd->transaction.all.modified_non_trans_table= TRUE; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 9e0fa87d5f5..9e1e2a20dc6 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -655,7 +655,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, else if (views->with_check == VIEW_CHECK_CASCADED) buff.append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION")); - Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE); + Query_log_event qinfo(thd, buff.ptr(), buff.length(), + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } @@ -1544,7 +1545,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) { if (!something_wrong) thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + Query_log_event qinfo(thd, thd->query, thd->query_length, + 0, FALSE, THD::NOT_KILLED); mysql_bin_log.write(&qinfo); } |