diff options
author | unknown <Dao-Gang.Qu@sun.com> | 2009-12-23 18:43:45 +0800 |
---|---|---|
committer | unknown <Dao-Gang.Qu@sun.com> | 2009-12-23 18:43:45 +0800 |
commit | f87816b450055e9815ced19d47a224bc58e9bfcc (patch) | |
tree | b5f1b15e2d418254319f1d6862d4fc4e085a0666 | |
parent | 03324f6a0a177d5e31f58533ab773970f2b2f747 (diff) | |
download | mariadb-git-f87816b450055e9815ced19d47a224bc58e9bfcc.tar.gz |
Bug #47863 binlog_format should be writable only at transaction boundaries
When @@session.binlog_format is modified inside a transaction,
it can cause slave to go out of sync.
To fix the problem, make the session variable 'binlog_format'
read-only inside a transaction.
mysql-test/suite/binlog/r/binlog_format_switch_inside_trans.result:
Test result for bug#47863.
mysql-test/suite/binlog/t/binlog_format_switch_inside_trans.test:
Added test file to verify if the session variable 'binlog_format'
is read-only inside a transaction and in sub-statements.
sql/set_var.cc:
Added code to make the session variable 'binlog_format'
read-only inside a transaction.
-rw-r--r-- | mysql-test/suite/binlog/r/binlog_format_switch_inside_trans.result | 90 | ||||
-rw-r--r-- | mysql-test/suite/binlog/t/binlog_format_switch_inside_trans.test | 98 | ||||
-rw-r--r-- | sql/set_var.cc | 8 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 2 |
4 files changed, 198 insertions, 0 deletions
diff --git a/mysql-test/suite/binlog/r/binlog_format_switch_inside_trans.result b/mysql-test/suite/binlog/r/binlog_format_switch_inside_trans.result new file mode 100644 index 00000000000..c1e900053e4 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_format_switch_inside_trans.result @@ -0,0 +1,90 @@ +set @save_binlog_format= @@global.binlog_format; +create table t1 (a int) engine= myisam; +create table t2 (a int) engine= innodb; +SELECT @@session.binlog_format; +@@session.binlog_format +ROW +SET AUTOCOMMIT=1; +# Test that the session variable 'binlog_format' +# is writable outside a transaction. +set @@session.binlog_format= statement; +SELECT @@session.binlog_format; +@@session.binlog_format +STATEMENT +begin; +# Test that the session variable 'binlog_format' is read-only +# inside a transaction with no preceding updates. +set @@session.binlog_format= mixed; +ERROR HY000: Cannot modify @@session.binlog_format inside a transaction +insert into t2 values (1); +# Test that the session variable 'binlog_format' is read-only +# inside a transaction with preceding transactional updates. +set @@session.binlog_format= row; +ERROR HY000: Cannot modify @@session.binlog_format inside a transaction +commit; +begin; +insert into t1 values (2); +# Test that the session variable 'binlog_format' is read-only +# inside a transaction with preceding non-transactional updates. +set @@session.binlog_format= statement; +ERROR HY000: Cannot modify @@session.binlog_format inside a transaction +commit; +# Test that the session variable 'binlog_format' is writable +# when AUTOCOMMIT=0, before a transaction has started. +set AUTOCOMMIT=0; +set @@session.binlog_format= row; +SELECT @@session.binlog_format; +@@session.binlog_format +ROW +insert into t1 values (4); +# Test that the session variable 'binlog_format' is read-only inside an +# AUTOCOMMIT=0 transaction with preceding non-transactional updates. +set @@session.binlog_format= statement; +ERROR HY000: Cannot modify @@session.binlog_format inside a transaction +SELECT @@session.binlog_format; +@@session.binlog_format +ROW +commit; +insert into t2 values (5); +# Test that the session variable 'binlog_format' is read-only inside an +# AUTOCOMMIT=0 transaction with preceding transactional updates. +set @@session.binlog_format= row; +ERROR HY000: Cannot modify @@session.binlog_format inside a transaction +SELECT @@session.binlog_format; +@@session.binlog_format +ROW +commit; +begin; +insert into t2 values (6); +# Test that the global variable 'binlog_format' is writable +# inside a transaction. +SELECT @@global.binlog_format; +@@global.binlog_format +ROW +set @@global.binlog_format= statement; +SELECT @@global.binlog_format; +@@global.binlog_format +STATEMENT +commit; +set @@global.binlog_format= @save_binlog_format; +create table t3(a int, b int) engine= innodb; +create table t4(a int) engine= innodb; +create table t5(a int) engine= innodb; +create trigger tr2 after insert on t3 for each row begin +insert into t4(a) values(1); +set @@session.binlog_format= statement; +insert into t4(a) values(2); +insert into t5(a) values(3); +end | +# Test that the session variable 'binlog_format' is read-only +# in sub-statements. +insert into t3(a,b) values(1,1); +ERROR HY000: Cannot change the binary logging format inside a stored function or trigger +SELECT @@session.binlog_format; +@@session.binlog_format +ROW +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; diff --git a/mysql-test/suite/binlog/t/binlog_format_switch_inside_trans.test b/mysql-test/suite/binlog/t/binlog_format_switch_inside_trans.test new file mode 100644 index 00000000000..8ae87d13a12 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_format_switch_inside_trans.test @@ -0,0 +1,98 @@ +# +# BUG#47863 +# This test verifies if the session variable 'binlog_format' +# is read-only inside a transaction and in sub-statements. +# + +source include/have_innodb.inc; +source include/have_binlog_format_row.inc; + +set @save_binlog_format= @@global.binlog_format; +create table t1 (a int) engine= myisam; +create table t2 (a int) engine= innodb; + +SELECT @@session.binlog_format; +SET AUTOCOMMIT=1; +--echo # Test that the session variable 'binlog_format' +--echo # is writable outside a transaction. +set @@session.binlog_format= statement; +SELECT @@session.binlog_format; + +begin; +--echo # Test that the session variable 'binlog_format' is read-only +--echo # inside a transaction with no preceding updates. +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT + set @@session.binlog_format= mixed; + + insert into t2 values (1); +--echo # Test that the session variable 'binlog_format' is read-only +--echo # inside a transaction with preceding transactional updates. +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT + set @@session.binlog_format= row; +commit; + +begin; + insert into t1 values (2); +--echo # Test that the session variable 'binlog_format' is read-only +--echo # inside a transaction with preceding non-transactional updates. +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT + set @@session.binlog_format= statement; +commit; + +--echo # Test that the session variable 'binlog_format' is writable +--echo # when AUTOCOMMIT=0, before a transaction has started. +set AUTOCOMMIT=0; +set @@session.binlog_format= row; +SELECT @@session.binlog_format; + +insert into t1 values (4); +--echo # Test that the session variable 'binlog_format' is read-only inside an +--echo # AUTOCOMMIT=0 transaction with preceding non-transactional updates. +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT +set @@session.binlog_format= statement; +SELECT @@session.binlog_format; +commit; + +insert into t2 values (5); +--echo # Test that the session variable 'binlog_format' is read-only inside an +--echo # AUTOCOMMIT=0 transaction with preceding transactional updates. +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT +set @@session.binlog_format= row; +SELECT @@session.binlog_format; +commit; + +begin; + insert into t2 values (6); +--echo # Test that the global variable 'binlog_format' is writable +--echo # inside a transaction. + SELECT @@global.binlog_format; + set @@global.binlog_format= statement; + SELECT @@global.binlog_format; +commit; + +set @@global.binlog_format= @save_binlog_format; + +create table t3(a int, b int) engine= innodb; +create table t4(a int) engine= innodb; +create table t5(a int) engine= innodb; +delimiter |; +eval create trigger tr2 after insert on t3 for each row begin + insert into t4(a) values(1); + set @@session.binlog_format= statement; + insert into t4(a) values(2); + insert into t5(a) values(3); +end | +delimiter ;| + +--echo # Test that the session variable 'binlog_format' is read-only +--echo # in sub-statements. +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT +insert into t3(a,b) values(1,1); +SELECT @@session.binlog_format; + +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; + diff --git a/sql/set_var.cc b/sql/set_var.cc index 16772fee3c3..b1d1c89cfe6 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1245,6 +1245,14 @@ void fix_slave_exec_mode(enum_var_type type) bool sys_var_thd_binlog_format::check(THD *thd, set_var *var) { /* + Make the session variable 'binlog_format' read-only inside a transaction. + */ + if (thd->active_transaction() && (var->type == OPT_SESSION)) + { + my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0)); + return 1; + } + /* All variables that affect writing to binary log (either format or turning logging on and off) use the same checking. We call the superclass ::check function to assign the variable correctly, and diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 4262aa82cfa..1ce306bb35e 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6249,3 +6249,5 @@ ER_DEBUG_SYNC_TIMEOUT ER_DEBUG_SYNC_HIT_LIMIT eng "debug sync point hit limit reached" ger "Debug Sync Point Hit Limit erreicht" +ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT + eng "Cannot modify @@session.binlog_format inside a transaction" |