From abb201c131a6ea390e3f9974a603e43742c73445 Mon Sep 17 00:00:00 2001 From: Date: Sun, 28 Nov 2010 17:43:36 +0800 Subject: [PATCH] BUG#54903 BINLOG statement toggles session variables When using BINLOG statement to execute rows log events, session variables foreign_key_checks and unique_checks are changed temporarily. As each rows log event has their own special session environment and its own foreign_key_checks and unique_checks can be different from current session which executing the BINLOG statement. But these variables are not restored correctly after BINLOG statement. This problem will cause that the following statements fail or generate unexpected data. In this patch, code is added to backup and restore these two variables. So BINLOG statement will not affect current session's variables again. --- mysql-test/extra/binlog_tests/binlog.test | 53 +++++++++++++++++ .../suite/binlog/r/binlog_row_binlog.result | 59 +++++++++++++++++++ .../suite/binlog/r/binlog_stm_binlog.result | 59 +++++++++++++++++++ sql/sql_binlog.cc | 8 +++ 4 files changed, 179 insertions(+) diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test index 7f48341077e..fd6ba1c17fa 100644 --- a/mysql-test/extra/binlog_tests/binlog.test +++ b/mysql-test/extra/binlog_tests/binlog.test @@ -302,5 +302,58 @@ BINLOG ' SHOW BINLOG EVENTS; DROP TABLE t1; + +--echo +--echo # BUG#54903 BINLOG statement toggles session variables +--echo # ---------------------------------------------------------------------- +--echo # This test verify that BINLOG statement doesn't change current session's +--echo # variables foreign_key_checks and unique_checks. +--echo +CREATE TABLE t1 (c1 INT KEY); + +SET @@SESSION.foreign_key_checks= ON; +SET @@SESSION.unique_checks= ON; + +--echo # INSERT INTO t1 VALUES (1) +--echo # foreign_key_checks=0 and unique_checks=0 +BINLOG ' +dfLtTBMBAAAAKQAAANcAAAAAABcAAAAAAAEABHRlc3QAAnQxAAEDAAE= +dfLtTBcBAAAAIgAAAPkAAAAAABcAAAAAAAcAAf/+AQAAAA== +'; + +SELECT * FROM t1; +--echo # Their values should be ON +SHOW SESSION VARIABLES LIKE "%_checks"; + +--echo +SET @@SESSION.foreign_key_checks= OFF; +SET @@SESSION.unique_checks= OFF; + +--echo # INSERT INTO t1 VALUES(2) +--echo # foreign_key_checks=1 and unique_checks=1 +BINLOG ' +dfLtTBMBAAAAKQAAAKsBAAAAABcAAAAAAAEABHRlc3QAAnQxAAEDAAE= +dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA== +'; + +SELECT * FROM t1; +--echo # Their values should be OFF +SHOW SESSION VARIABLES LIKE "%_checks"; + +--echo # INSERT INTO t1 VALUES(2) +--echo # foreign_key_checks=1 and unique_checks=1 +--echo # It should not change current session's variables, even error happens +--error 1062 +BINLOG ' +dfLtTBMBAAAAKQAAAKsBAAAAABcAAAAAAAEABHRlc3QAAnQxAAEDAAE= +dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA== +'; + +SELECT * FROM t1; +--echo # Their values should be OFF +SHOW SESSION VARIABLES LIKE "%_checks"; + +DROP TABLE t1; + disconnect fresh; diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index d612e7adde1..1678f8add58 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -1330,3 +1330,62 @@ Log_name Pos Event_type Server_id End_log_pos Info # # Write_rows 1 # table_id: # flags: STMT_END_F # # Query 1 # COMMIT DROP TABLE t1; + +# BUG#54903 BINLOG statement toggles session variables +# ---------------------------------------------------------------------- +# This test verify that BINLOG statement doesn't change current session's +# variables foreign_key_checks and unique_checks. + +CREATE TABLE t1 (c1 INT KEY); +SET @@SESSION.foreign_key_checks= ON; +SET @@SESSION.unique_checks= ON; +# INSERT INTO t1 VALUES (1) +# foreign_key_checks=0 and unique_checks=0 +BINLOG ' +dfLtTBMBAAAAKQAAANcAAAAAABcAAAAAAAEABHRlc3QAAnQxAAEDAAE= +dfLtTBcBAAAAIgAAAPkAAAAAABcAAAAAAAcAAf/+AQAAAA== +'; +SELECT * FROM t1; +c1 +1 +# Their values should be ON +SHOW SESSION VARIABLES LIKE "%_checks"; +Variable_name Value +foreign_key_checks ON +unique_checks ON + +SET @@SESSION.foreign_key_checks= OFF; +SET @@SESSION.unique_checks= OFF; +# INSERT INTO t1 VALUES(2) +# foreign_key_checks=1 and unique_checks=1 +BINLOG ' +dfLtTBMBAAAAKQAAAKsBAAAAABcAAAAAAAEABHRlc3QAAnQxAAEDAAE= +dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA== +'; +SELECT * FROM t1; +c1 +1 +2 +# Their values should be OFF +SHOW SESSION VARIABLES LIKE "%_checks"; +Variable_name Value +foreign_key_checks OFF +unique_checks OFF +# INSERT INTO t1 VALUES(2) +# foreign_key_checks=1 and unique_checks=1 +# It should not change current session's variables, even error happens +BINLOG ' +dfLtTBMBAAAAKQAAAKsBAAAAABcAAAAAAAEABHRlc3QAAnQxAAEDAAE= +dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA== +'; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +SELECT * FROM t1; +c1 +1 +2 +# Their values should be OFF +SHOW SESSION VARIABLES LIKE "%_checks"; +Variable_name Value +foreign_key_checks OFF +unique_checks OFF +DROP TABLE t1; diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index f5ba4524c61..872a93bef43 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -801,3 +801,62 @@ Log_name Pos Event_type Server_id End_log_pos Info # # Write_rows 1 # table_id: # flags: STMT_END_F # # Query 1 # COMMIT DROP TABLE t1; + +# BUG#54903 BINLOG statement toggles session variables +# ---------------------------------------------------------------------- +# This test verify that BINLOG statement doesn't change current session's +# variables foreign_key_checks and unique_checks. + +CREATE TABLE t1 (c1 INT KEY); +SET @@SESSION.foreign_key_checks= ON; +SET @@SESSION.unique_checks= ON; +# INSERT INTO t1 VALUES (1) +# foreign_key_checks=0 and unique_checks=0 +BINLOG ' +dfLtTBMBAAAAKQAAANcAAAAAABcAAAAAAAEABHRlc3QAAnQxAAEDAAE= +dfLtTBcBAAAAIgAAAPkAAAAAABcAAAAAAAcAAf/+AQAAAA== +'; +SELECT * FROM t1; +c1 +1 +# Their values should be ON +SHOW SESSION VARIABLES LIKE "%_checks"; +Variable_name Value +foreign_key_checks ON +unique_checks ON + +SET @@SESSION.foreign_key_checks= OFF; +SET @@SESSION.unique_checks= OFF; +# INSERT INTO t1 VALUES(2) +# foreign_key_checks=1 and unique_checks=1 +BINLOG ' +dfLtTBMBAAAAKQAAAKsBAAAAABcAAAAAAAEABHRlc3QAAnQxAAEDAAE= +dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA== +'; +SELECT * FROM t1; +c1 +1 +2 +# Their values should be OFF +SHOW SESSION VARIABLES LIKE "%_checks"; +Variable_name Value +foreign_key_checks OFF +unique_checks OFF +# INSERT INTO t1 VALUES(2) +# foreign_key_checks=1 and unique_checks=1 +# It should not change current session's variables, even error happens +BINLOG ' +dfLtTBMBAAAAKQAAAKsBAAAAABcAAAAAAAEABHRlc3QAAnQxAAEDAAE= +dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA== +'; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +SELECT * FROM t1; +c1 +1 +2 +# Their values should be OFF +SHOW SESSION VARIABLES LIKE "%_checks"; +Variable_name Value +foreign_key_checks OFF +unique_checks OFF +DROP TABLE t1; diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 82de6feb1a9..31fd2de3722 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -50,6 +50,13 @@ void mysql_client_binlog_statement(THD* thd) } size_t decoded_len= base64_needed_decoded_length(coded_len); + /* + thd->options will be changed when applying the event. But we don't expect + it be changed permanently after BINLOG statement, so backup it first. + It will be restored at the end of this function. + */ + ulonglong thd_options= thd->options; + /* Allocation */ @@ -236,6 +243,7 @@ void mysql_client_binlog_statement(THD* thd) my_ok(thd); end: + thd->options= thd_options; rli->clear_tables_to_lock(); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); DBUG_VOID_RETURN;