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 */