Skip to content

Commit 8e1d1e4

Browse files
authored andcommitted
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.
1 parent 261a1e2 commit 8e1d1e4

File tree

4 files changed

+198
-0
lines changed

4 files changed

+198
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
set @save_binlog_format= @@global.binlog_format;
2+
create table t1 (a int) engine= myisam;
3+
create table t2 (a int) engine= innodb;
4+
SELECT @@session.binlog_format;
5+
@@session.binlog_format
6+
ROW
7+
SET AUTOCOMMIT=1;
8+
# Test that the session variable 'binlog_format'
9+
# is writable outside a transaction.
10+
set @@session.binlog_format= statement;
11+
SELECT @@session.binlog_format;
12+
@@session.binlog_format
13+
STATEMENT
14+
begin;
15+
# Test that the session variable 'binlog_format' is read-only
16+
# inside a transaction with no preceding updates.
17+
set @@session.binlog_format= mixed;
18+
ERROR HY000: Cannot modify @@session.binlog_format inside a transaction
19+
insert into t2 values (1);
20+
# Test that the session variable 'binlog_format' is read-only
21+
# inside a transaction with preceding transactional updates.
22+
set @@session.binlog_format= row;
23+
ERROR HY000: Cannot modify @@session.binlog_format inside a transaction
24+
commit;
25+
begin;
26+
insert into t1 values (2);
27+
# Test that the session variable 'binlog_format' is read-only
28+
# inside a transaction with preceding non-transactional updates.
29+
set @@session.binlog_format= statement;
30+
ERROR HY000: Cannot modify @@session.binlog_format inside a transaction
31+
commit;
32+
# Test that the session variable 'binlog_format' is writable
33+
# when AUTOCOMMIT=0, before a transaction has started.
34+
set AUTOCOMMIT=0;
35+
set @@session.binlog_format= row;
36+
SELECT @@session.binlog_format;
37+
@@session.binlog_format
38+
ROW
39+
insert into t1 values (4);
40+
# Test that the session variable 'binlog_format' is read-only inside an
41+
# AUTOCOMMIT=0 transaction with preceding non-transactional updates.
42+
set @@session.binlog_format= statement;
43+
ERROR HY000: Cannot modify @@session.binlog_format inside a transaction
44+
SELECT @@session.binlog_format;
45+
@@session.binlog_format
46+
ROW
47+
commit;
48+
insert into t2 values (5);
49+
# Test that the session variable 'binlog_format' is read-only inside an
50+
# AUTOCOMMIT=0 transaction with preceding transactional updates.
51+
set @@session.binlog_format= row;
52+
ERROR HY000: Cannot modify @@session.binlog_format inside a transaction
53+
SELECT @@session.binlog_format;
54+
@@session.binlog_format
55+
ROW
56+
commit;
57+
begin;
58+
insert into t2 values (6);
59+
# Test that the global variable 'binlog_format' is writable
60+
# inside a transaction.
61+
SELECT @@global.binlog_format;
62+
@@global.binlog_format
63+
ROW
64+
set @@global.binlog_format= statement;
65+
SELECT @@global.binlog_format;
66+
@@global.binlog_format
67+
STATEMENT
68+
commit;
69+
set @@global.binlog_format= @save_binlog_format;
70+
create table t3(a int, b int) engine= innodb;
71+
create table t4(a int) engine= innodb;
72+
create table t5(a int) engine= innodb;
73+
create trigger tr2 after insert on t3 for each row begin
74+
insert into t4(a) values(1);
75+
set @@session.binlog_format= statement;
76+
insert into t4(a) values(2);
77+
insert into t5(a) values(3);
78+
end |
79+
# Test that the session variable 'binlog_format' is read-only
80+
# in sub-statements.
81+
insert into t3(a,b) values(1,1);
82+
ERROR HY000: Cannot change the binary logging format inside a stored function or trigger
83+
SELECT @@session.binlog_format;
84+
@@session.binlog_format
85+
ROW
86+
drop table t1;
87+
drop table t2;
88+
drop table t3;
89+
drop table t4;
90+
drop table t5;
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#
2+
# BUG#47863
3+
# This test verifies if the session variable 'binlog_format'
4+
# is read-only inside a transaction and in sub-statements.
5+
#
6+
7+
source include/have_innodb.inc;
8+
source include/have_binlog_format_row.inc;
9+
10+
set @save_binlog_format= @@global.binlog_format;
11+
create table t1 (a int) engine= myisam;
12+
create table t2 (a int) engine= innodb;
13+
14+
SELECT @@session.binlog_format;
15+
SET AUTOCOMMIT=1;
16+
--echo # Test that the session variable 'binlog_format'
17+
--echo # is writable outside a transaction.
18+
set @@session.binlog_format= statement;
19+
SELECT @@session.binlog_format;
20+
21+
begin;
22+
--echo # Test that the session variable 'binlog_format' is read-only
23+
--echo # inside a transaction with no preceding updates.
24+
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
25+
set @@session.binlog_format= mixed;
26+
27+
insert into t2 values (1);
28+
--echo # Test that the session variable 'binlog_format' is read-only
29+
--echo # inside a transaction with preceding transactional updates.
30+
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
31+
set @@session.binlog_format= row;
32+
commit;
33+
34+
begin;
35+
insert into t1 values (2);
36+
--echo # Test that the session variable 'binlog_format' is read-only
37+
--echo # inside a transaction with preceding non-transactional updates.
38+
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
39+
set @@session.binlog_format= statement;
40+
commit;
41+
42+
--echo # Test that the session variable 'binlog_format' is writable
43+
--echo # when AUTOCOMMIT=0, before a transaction has started.
44+
set AUTOCOMMIT=0;
45+
set @@session.binlog_format= row;
46+
SELECT @@session.binlog_format;
47+
48+
insert into t1 values (4);
49+
--echo # Test that the session variable 'binlog_format' is read-only inside an
50+
--echo # AUTOCOMMIT=0 transaction with preceding non-transactional updates.
51+
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
52+
set @@session.binlog_format= statement;
53+
SELECT @@session.binlog_format;
54+
commit;
55+
56+
insert into t2 values (5);
57+
--echo # Test that the session variable 'binlog_format' is read-only inside an
58+
--echo # AUTOCOMMIT=0 transaction with preceding transactional updates.
59+
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
60+
set @@session.binlog_format= row;
61+
SELECT @@session.binlog_format;
62+
commit;
63+
64+
begin;
65+
insert into t2 values (6);
66+
--echo # Test that the global variable 'binlog_format' is writable
67+
--echo # inside a transaction.
68+
SELECT @@global.binlog_format;
69+
set @@global.binlog_format= statement;
70+
SELECT @@global.binlog_format;
71+
commit;
72+
73+
set @@global.binlog_format= @save_binlog_format;
74+
75+
create table t3(a int, b int) engine= innodb;
76+
create table t4(a int) engine= innodb;
77+
create table t5(a int) engine= innodb;
78+
delimiter |;
79+
eval create trigger tr2 after insert on t3 for each row begin
80+
insert into t4(a) values(1);
81+
set @@session.binlog_format= statement;
82+
insert into t4(a) values(2);
83+
insert into t5(a) values(3);
84+
end |
85+
delimiter ;|
86+
87+
--echo # Test that the session variable 'binlog_format' is read-only
88+
--echo # in sub-statements.
89+
--error ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT
90+
insert into t3(a,b) values(1,1);
91+
SELECT @@session.binlog_format;
92+
93+
drop table t1;
94+
drop table t2;
95+
drop table t3;
96+
drop table t4;
97+
drop table t5;
98+

sql/set_var.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,14 @@ void fix_slave_exec_mode(enum_var_type type)
12441244

12451245

12461246
bool sys_var_thd_binlog_format::check(THD *thd, set_var *var) {
1247+
/*
1248+
Make the session variable 'binlog_format' read-only inside a transaction.
1249+
*/
1250+
if (thd->active_transaction() && (var->type == OPT_SESSION))
1251+
{
1252+
my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
1253+
return 1;
1254+
}
12471255
/*
12481256
All variables that affect writing to binary log (either format or
12491257
turning logging on and off) use the same checking. We call the

sql/share/errmsg.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6249,3 +6249,5 @@ ER_DEBUG_SYNC_TIMEOUT
62496249
ER_DEBUG_SYNC_HIT_LIMIT
62506250
eng "debug sync point hit limit reached"
62516251
ger "Debug Sync Point Hit Limit erreicht"
6252+
ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
6253+
eng "Cannot modify @@session.binlog_format inside a transaction"

0 commit comments

Comments
 (0)