Commit 4b615ca9 authored by unknown's avatar unknown

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.
parent 3283101f
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;
#
# 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;
......@@ -1244,6 +1244,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
......
......@@ -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"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment