From 32b6e904551e0aaff66b71d66dde7fbca288ddac Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Jan 2010 17:41:15 +0800 Subject: [PATCH] Bug #45855 row events in binlog after switch from binlog_fmt=mix to stmt with open tmp tbl Bug #45856 can't switch from binlog_format=row to mix with open tmp tbl If binlog_format=MIXED, there are open temporary tables, an unsafe statement is executed, and the user issues 'SET @@session.binlog_format = STATEMENT', then subsequent DML statements will be written in row format despite binlog_format=STATEMENT. Because the binlog format can't be reset to statement based by 'reset_current_stmt_binlog_row_based' function. If binlog_format=ROW, there are open temporary tables, and an unsafe statement is executed, then the statement 'SET @@session.binlog_format = MIXED' generates the error: "Cannot switch out of the row-based binary log format when the session has open temporary tables" However, it is safe to switch to MIXED mode because events in row format are allowed. To fix the above two problems, generate ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR and forbid switching from MIXED or ROW to STATEMENT when there are open temp tables and we are logging in row format. There is no error in any other case. mysql-test/suite/binlog/r/binlog_format_switch_in_tmp_table.result: Test result for bug#45855 and bug#45856. mysql-test/suite/binlog/t/binlog_format_switch_in_tmp_table.test: Added test file to verify if the program will generate ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR error and forbid switching from MIXED or ROW to STATEMENT when there are open temp tables and we are logging in row format. There is no error in any other case. --- .../binlog_format_switch_in_tmp_table.result | 78 +++++++++++++++++++ .../t/binlog_format_switch_in_tmp_table.test | 76 ++++++++++++++++++ sql/set_var.cc | 36 +++++---- 3 files changed, 173 insertions(+), 17 deletions(-) create mode 100644 mysql-test/suite/binlog/r/binlog_format_switch_in_tmp_table.result create mode 100644 mysql-test/suite/binlog/t/binlog_format_switch_in_tmp_table.test diff --git a/mysql-test/suite/binlog/r/binlog_format_switch_in_tmp_table.result b/mysql-test/suite/binlog/r/binlog_format_switch_in_tmp_table.result new file mode 100644 index 00000000000..f886ccb134d --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_format_switch_in_tmp_table.result @@ -0,0 +1,78 @@ +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +MIXED +CREATE TABLE t1 (a VARCHAR(100)); +CREATE TEMPORARY TABLE t2 (a VARCHAR(100)); +# Test allow switching @@SESSION.binlog_format from MIXED to STATEMENT +# when there are open temp tables and we are logging in statement based format. +SET SESSION binlog_format = STATEMENT; +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +STATEMENT +# Test allow switching @@SESSION.binlog_format from STATEMENT to +# STATEMENT when there are open temp tables. +SET SESSION binlog_format = STATEMENT; +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +STATEMENT +INSERT INTO t1 VALUES ('statement based'); +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +STATEMENT +# Test allow switching @@SESSION.binlog_format from STATEMENT to +# MIXED when there are open temp tables. +SET SESSION binlog_format = MIXED; +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +MIXED +# Test allow switching @@SESSION.binlog_format from MIXED to MIXED +# when there are open temp tables. +SET SESSION binlog_format = MIXED; +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +MIXED +INSERT INTO t2 VALUES (UUID()); +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +MIXED +# Test forbit switching @@SESSION.binlog_format from MIXED to STATEMENT +# when there are open temp tables and we are logging in row based format. +SET SESSION binlog_format = STATEMENT; +ERROR HY000: Cannot switch out of the row-based binary log format when the session has open temporary tables +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +MIXED +SET SESSION binlog_format = ROW; +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +ROW +INSERT INTO t1 VALUES ('row based'); +# Test allow switching @@SESSION.binlog_format from ROW to MIXED +# when there are open temp tables. +SET SESSION binlog_format = MIXED; +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +MIXED +INSERT INTO t1 VALUES ('row based'); +# Test allow switching @@SESSION.binlog_format from MIXED to ROW +# when there are open temp tables. +SET SESSION binlog_format = ROW; +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +ROW +# Test allow switching @@SESSION.binlog_format from ROW to ROW +# when there are open temp tables. +SET SESSION binlog_format = ROW; +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +ROW +INSERT INTO t1 VALUES ('row based'); +# Test forbit switching @@SESSION.binlog_format from ROW to STATEMENT +# when there are open temp tables. +SET SESSION binlog_format = STATEMENT; +ERROR HY000: Cannot switch out of the row-based binary log format when the session has open temporary tables +SELECT @@SESSION.binlog_format; +@@SESSION.binlog_format +ROW +DROP TEMPORARY TABLE t2; +DROP TABLE t1; diff --git a/mysql-test/suite/binlog/t/binlog_format_switch_in_tmp_table.test b/mysql-test/suite/binlog/t/binlog_format_switch_in_tmp_table.test new file mode 100644 index 00000000000..6868506008c --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_format_switch_in_tmp_table.test @@ -0,0 +1,76 @@ +# +# Bug #45855 row events in binlog after switch from binlog_fmt=mix to stmt with open tmp tbl +# Bug #45856 can't switch from binlog_format=row to mix with open tmp tbl +# This test verfies if the program will generate ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR +# error and forbid switching @@SESSION.binlog_format from MIXED or ROW to +# STATEMENT when there are open temp tables and we are logging in row format. +# There is no error in any other case. +# + +source include/have_binlog_format_mixed.inc; + +SELECT @@SESSION.binlog_format; +CREATE TABLE t1 (a VARCHAR(100)); +CREATE TEMPORARY TABLE t2 (a VARCHAR(100)); + +--echo # Test allow switching @@SESSION.binlog_format from MIXED to STATEMENT +--echo # when there are open temp tables and we are logging in statement based format. +SET SESSION binlog_format = STATEMENT; +SELECT @@SESSION.binlog_format; + +--echo # Test allow switching @@SESSION.binlog_format from STATEMENT to +--echo # STATEMENT when there are open temp tables. +SET SESSION binlog_format = STATEMENT; +SELECT @@SESSION.binlog_format; + +INSERT INTO t1 VALUES ('statement based'); +SELECT @@SESSION.binlog_format; +--echo # Test allow switching @@SESSION.binlog_format from STATEMENT to +--echo # MIXED when there are open temp tables. +SET SESSION binlog_format = MIXED; +SELECT @@SESSION.binlog_format; + +--echo # Test allow switching @@SESSION.binlog_format from MIXED to MIXED +--echo # when there are open temp tables. +SET SESSION binlog_format = MIXED; +SELECT @@SESSION.binlog_format; + +INSERT INTO t2 VALUES (UUID()); +SELECT @@SESSION.binlog_format; + +--echo # Test forbit switching @@SESSION.binlog_format from MIXED to STATEMENT +--echo # when there are open temp tables and we are logging in row based format. +--ERROR ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR +SET SESSION binlog_format = STATEMENT; +SELECT @@SESSION.binlog_format; + +SET SESSION binlog_format = ROW; +SELECT @@SESSION.binlog_format; + +INSERT INTO t1 VALUES ('row based'); +--echo # Test allow switching @@SESSION.binlog_format from ROW to MIXED +--echo # when there are open temp tables. +SET SESSION binlog_format = MIXED; +SELECT @@SESSION.binlog_format; + +INSERT INTO t1 VALUES ('row based'); +--echo # Test allow switching @@SESSION.binlog_format from MIXED to ROW +--echo # when there are open temp tables. +SET SESSION binlog_format = ROW; +SELECT @@SESSION.binlog_format; + +--echo # Test allow switching @@SESSION.binlog_format from ROW to ROW +--echo # when there are open temp tables. +SET SESSION binlog_format = ROW; +SELECT @@SESSION.binlog_format; + +INSERT INTO t1 VALUES ('row based'); +--echo # Test forbit switching @@SESSION.binlog_format from ROW to STATEMENT +--echo # when there are open temp tables. +--ERROR ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR +SET SESSION binlog_format = STATEMENT; +SELECT @@SESSION.binlog_format; + +DROP TEMPORARY TABLE t2; +DROP TABLE t1; + diff --git a/sql/set_var.cc b/sql/set_var.cc index d9bd14564bf..9dfbf2c7a6c 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1294,6 +1294,25 @@ bool sys_var_thd_binlog_format::check(THD *thd, set_var *var) { bool result= sys_var_thd_enum::check(thd, var); if (!result) result= check_log_update(thd, var); + /* + If RBR and open temporary tables, their CREATE TABLE may not be in the + binlog, so we can't toggle to SBR in this connection. + + If binlog_format=MIXED, there are open temporary tables, and an unsafe + statement is executed, then subsequent statements are logged in row + format and hence changes to temporary tables may be lost. So we forbid + switching @@SESSION.binlog_format from MIXED to STATEMENT when there are + open temp tables and we are logging in row format. + */ + if (thd->temporary_tables && var->type == OPT_SESSION && + var->save_result.ulong_value == BINLOG_FORMAT_STMT && + ((thd->variables.binlog_format == BINLOG_FORMAT_MIXED && + thd->is_current_stmt_binlog_format_row()) || + thd->variables.binlog_format == BINLOG_FORMAT_ROW)) + { + my_error(ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR, MYF(0)); + return 1; + } return result; } @@ -1303,23 +1322,6 @@ bool sys_var_thd_binlog_format::is_readonly() const Under certain circumstances, the variable is read-only (unchangeable): */ THD *thd= current_thd; - /* - If RBR and open temporary tables, their CREATE TABLE may not be in the - binlog, so we can't toggle to SBR in this connection. - The test below will also prevent SET GLOBAL, well it was not easy to test - if global or not here. - And this test will also prevent switching from RBR to RBR (a no-op which - should not happen too often). - - If we don't have row-based replication compiled in, the variable - is always read-only. - */ - if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW) && - thd->temporary_tables) - { - my_error(ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR, MYF(0)); - return 1; - } /* if in a stored function/trigger, it's too late to change mode */