Commit 9fbf4b72 authored by Alfranio Correia's avatar Alfranio Correia

BUG#53437 @@session.sql_bin_log support in substatements is incorrect

      
The thd->variables.option_bits & OPTION_BIN_LOG is currently abused: 
it's both a system variable and an implementation switch. The current
approach to this option bit breaks the session variable encapsulation. 
      
Besides it is allowed to change @@session.sql_bin_log within a
transaction what may lead to not correctly logging a transaction.
      
To fix the problems,  we created a thd->variables variable to represent
the "sql_log_bin" and prohibited its update inside a transaction or
sub-statement.
parent b3259e93
...@@ -67,11 +67,8 @@ Note 1592 Unsafe statement written to the binary log using statement format sinc ...@@ -67,11 +67,8 @@ Note 1592 Unsafe statement written to the binary log using statement format sinc
SELECT sf_bug50192(); SELECT sf_bug50192();
sf_bug50192() sf_bug50192()
1 1
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly.
SHOW WARNINGS; SHOW WARNINGS;
Level Code Message Level Code Message
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly.
DROP FUNCTION sf_bug50192; DROP FUNCTION sf_bug50192;
DROP TRIGGER tr_bug50192; DROP TRIGGER tr_bug50192;
DROP TABLE t1, t2; DROP TABLE t1, t2;
set @save_binlog_format= @@global.binlog_format; set @save_binlog_format= @@global.binlog_format;
set @save_binlog_dirct= @@global.binlog_direct_non_transactional_updates; set @save_binlog_dirct= @@global.binlog_direct_non_transactional_updates;
set @save_sql_log_bin= @@global.sql_log_bin;
create table t1 (a int) engine= myisam; create table t1 (a int) engine= myisam;
create table t2 (a int) engine= innodb; create table t2 (a int) engine= innodb;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
...@@ -8,116 +9,148 @@ ROW ...@@ -8,116 +9,148 @@ ROW
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
@@session.binlog_direct_non_transactional_updates @@session.binlog_direct_non_transactional_updates
1 1
SELECT @@session.sql_log_bin;
@@session.sql_log_bin
1
SET AUTOCOMMIT=1; SET AUTOCOMMIT=1;
# Test that the session variable 'binlog_format' and # Test that the session variable 'binlog_format',
# 'binlog_direct_non_transactional_updates' are # 'binlog_direct_non_transactional_updates' and 'sql_log_bin'
# writable outside a transaction. # are writable outside a transaction.
# Current session values are ROW and FALSE, respectively. # Current session values are ROW, FALSE, TRUE, respectively.
set @@session.binlog_format= statement; set @@session.binlog_format= statement;
set @@session.binlog_direct_non_transactional_updates= TRUE; set @@session.binlog_direct_non_transactional_updates= TRUE;
set @@session.sql_log_bin= FALSE;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
@@session.binlog_format @@session.binlog_format
STATEMENT STATEMENT
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
@@session.binlog_direct_non_transactional_updates @@session.binlog_direct_non_transactional_updates
1 1
SELECT @@session.sql_log_bin;
@@session.sql_log_bin
0
begin; begin;
# Test that the session variable 'binlog_format' and # Test that the session variable 'binlog_format',
# 'binlog_direct_non_transactional_updates' are # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
# read-only inside a transaction with no preceding updates. # read-only inside a transaction with no preceding updates.
# Current session values are STATEMENT and TRUE, respectively. # Current session values are STATEMENT, TRUE, FALSE, respectively.
set @@session.binlog_format= mixed; set @@session.binlog_format= mixed;
ERROR HY000: Cannot modify @@session.binlog_format inside a transaction ERROR HY000: Cannot modify @@session.binlog_format inside a transaction
set @@session.binlog_direct_non_transactional_updates= FALSE; set @@session.binlog_direct_non_transactional_updates= FALSE;
ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction
set @@session.sql_log_bin= FALSE;
ERROR HY000: Cannot modify @@session.sql_log_bin inside a transaction
insert into t2 values (1); insert into t2 values (1);
# Test that the session variable 'binlog_format' and # Test that the session variable 'binlog_format',
# 'binlog_direct_non_transactional_updates' are # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
# read-only inside a transaction with preceding transactional updates. # read-only inside a transaction with preceding transactional updates.
# Current session values are STATEMENT and TRUE, respectively. # Current session values are STATEMENT, TRUE and FALSE, respectively.
set @@session.binlog_format= row; set @@session.binlog_format= row;
ERROR HY000: Cannot modify @@session.binlog_format inside a transaction ERROR HY000: Cannot modify @@session.binlog_format inside a transaction
set @@session.binlog_direct_non_transactional_updates= FALSE; set @@session.binlog_direct_non_transactional_updates= FALSE;
ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction
set @@session.sql_log_bin= FALSE;
ERROR HY000: Cannot modify @@session.sql_log_bin inside a transaction
commit; commit;
begin; begin;
insert into t1 values (2); insert into t1 values (2);
# Test that the session variable 'binlog_format' and # Test that the session variable 'binlog_format'
# 'binlog_direct_non_transactional_updates' are # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
# read-only inside a transaction with preceding non-transactional updates. # read-only inside a transaction with preceding non-transactional updates.
# Current session values are STATEMENT and TRUE, respectively. # Current session values are STATEMENT, TRUE, FALSE, respectively.
set @@session.binlog_format= mixed; set @@session.binlog_format= mixed;
ERROR HY000: Cannot modify @@session.binlog_format inside a transaction ERROR HY000: Cannot modify @@session.binlog_format inside a transaction
set @@session.binlog_direct_non_transactional_updates= FALSE; set @@session.binlog_direct_non_transactional_updates= FALSE;
ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction
set @@session.sql_log_bin= FALSE;
ERROR HY000: Cannot modify @@session.sql_log_bin inside a transaction
commit; commit;
# Test that the session variable 'binlog_format' and # Test that the session variable 'binlog_format',
# 'binlog_direct_non_transactional_updates' are # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
# writable when AUTOCOMMIT=0, before a transaction has started. # writable when AUTOCOMMIT=0, before a transaction has started.
# Current session values are STATEMENT and TRUE, respectively. # Current session values are STATEMENT, TRUE, FALSE, respectively.
set AUTOCOMMIT=0; set AUTOCOMMIT=0;
set @@session.binlog_format= row; set @@session.binlog_format= row;
set @@session.binlog_direct_non_transactional_updates= FALSE; set @@session.binlog_direct_non_transactional_updates= FALSE;
set @@session.sql_log_bin= TRUE;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
@@session.binlog_format @@session.binlog_format
ROW ROW
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
@@session.binlog_direct_non_transactional_updates @@session.binlog_direct_non_transactional_updates
0 0
SELECT @@session.sql_log_bin;
@@session.sql_log_bin
1
insert into t1 values (3); insert into t1 values (3);
# Test that the session variable 'binlog_format' and # Test that the session variable 'binlog_format',
# 'binlog_direct_non_transactional_updates' are # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
# read-only inside an AUTOCOMMIT=0 transaction # read-only inside an AUTOCOMMIT=0 transaction
# with preceding non-transactional updates. # with preceding non-transactional updates.
# Current session values are ROW and FALSE, respectively. # Current session values are ROW, FALSE, TRUE, respectively.
set @@session.binlog_format= statement; set @@session.binlog_format= statement;
ERROR HY000: Cannot modify @@session.binlog_format inside a transaction ERROR HY000: Cannot modify @@session.binlog_format inside a transaction
set @@session.binlog_direct_non_transactional_updates= TRUE; set @@session.binlog_direct_non_transactional_updates= TRUE;
ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction
set @@session.sql_log_bin= FALSE;
ERROR HY000: Cannot modify @@session.sql_log_bin inside a transaction
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
@@session.binlog_format @@session.binlog_format
ROW ROW
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
@@session.binlog_direct_non_transactional_updates @@session.binlog_direct_non_transactional_updates
0 0
SELECT @@session.sql_log_bin;
@@session.sql_log_bin
1
commit; commit;
insert into t2 values (4); insert into t2 values (4);
# Test that the session variable 'binlog_format' and # Test that the session variable 'binlog_format',
# 'binlog_direct_non_transactional_updates' are # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
# read-only inside an AUTOCOMMIT=0 transaction with # read-only inside an AUTOCOMMIT=0 transaction with
# preceding transactional updates. # preceding transactional updates.
# Current session values are ROW and FALSE, respectively. # Current session values are ROW, FALSE, TRUE, respectively.
set @@session.binlog_format= statement; set @@session.binlog_format= statement;
ERROR HY000: Cannot modify @@session.binlog_format inside a transaction ERROR HY000: Cannot modify @@session.binlog_format inside a transaction
set @@session.binlog_direct_non_transactional_updates= TRUE; set @@session.binlog_direct_non_transactional_updates= TRUE;
ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction
set @@session.sql_log_bin= FALSE;
ERROR HY000: Cannot modify @@session.sql_log_bin inside a transaction
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
@@session.binlog_format @@session.binlog_format
ROW ROW
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
@@session.binlog_direct_non_transactional_updates @@session.binlog_direct_non_transactional_updates
0 0
SELECT @@session.sql_log_bin;
@@session.sql_log_bin
1
commit; commit;
begin; begin;
insert into t2 values (5); insert into t2 values (5);
# Test that the global variable 'binlog_format' and # Test that the global variable 'binlog_format' and
# 'binlog_direct_non_transactional_updates' are # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
# writable inside a transaction. # writable inside a transaction.
# Current session values are ROW and FALSE, respectively. # Current session values are ROW, FALSE, TRUE respectively.
SELECT @@global.binlog_format; SELECT @@global.binlog_format;
@@global.binlog_format @@global.binlog_format
ROW ROW
set @@global.binlog_format= statement; set @@global.binlog_format= statement;
set @@global.binlog_direct_non_transactional_updates= TRUE; set @@global.binlog_direct_non_transactional_updates= TRUE;
set @@global.sql_log_bin= FALSE;
SELECT @@global.binlog_format; SELECT @@global.binlog_format;
@@global.binlog_format @@global.binlog_format
STATEMENT STATEMENT
SELECT @@global.binlog_direct_non_transactional_updates; SELECT @@global.binlog_direct_non_transactional_updates;
@@global.binlog_direct_non_transactional_updates @@global.binlog_direct_non_transactional_updates
1 1
SELECT @@global.sql_log_bin;
@@global.sql_log_bin
0
commit; commit;
set @@global.binlog_format= @save_binlog_format; set @@global.binlog_format= @save_binlog_format;
set @@global.binlog_direct_non_transactional_updates= @save_binlog_dirct; set @@global.binlog_direct_non_transactional_updates= @save_binlog_dirct;
set @@global.sql_log_bin= @save_sql_log_bin;
create table t3(a int, b int) engine= innodb; create table t3(a int, b int) engine= innodb;
create table t4(a int) engine= innodb; create table t4(a int) engine= innodb;
create table t5(a int) engine= innodb; create table t5(a int) engine= innodb;
...@@ -153,6 +186,23 @@ ERROR HY000: Cannot change the binlog direct flag inside a stored function or tr ...@@ -153,6 +186,23 @@ ERROR HY000: Cannot change the binlog direct flag inside a stored function or tr
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
@@session.binlog_direct_non_transactional_updates @@session.binlog_direct_non_transactional_updates
0 0
create table t9(a int, b int) engine= innodb;
create table t10(a int) engine= innodb;
create table t11(a int) engine= innodb;
create trigger tr3 after insert on t9 for each row begin
insert into t10(a) values(1);
set @@session.sql_log_bin= TRUE;
insert into t10(a) values(2);
insert into t11(a) values(3);
end |
# Test that the session variable 'sql_log_bin' is
# read-only in sub-statements.
# Current session value is FALSE.
insert into t9(a,b) values(1,1);
ERROR HY000: Cannot change the sql_log_bin inside a stored function or trigger
SELECT @@session.sql_log_bin;
@@session.sql_log_bin
1
drop table t1; drop table t1;
drop table t2; drop table t2;
drop table t3; drop table t3;
...@@ -161,3 +211,6 @@ drop table t5; ...@@ -161,3 +211,6 @@ drop table t5;
drop table t6; drop table t6;
drop table t7; drop table t7;
drop table t8; drop table t8;
drop table t9;
drop table t10;
drop table t11;
...@@ -10,107 +10,128 @@ source include/have_binlog_format_row.inc; ...@@ -10,107 +10,128 @@ source include/have_binlog_format_row.inc;
set @save_binlog_format= @@global.binlog_format; set @save_binlog_format= @@global.binlog_format;
set @save_binlog_dirct= @@global.binlog_direct_non_transactional_updates; set @save_binlog_dirct= @@global.binlog_direct_non_transactional_updates;
set @save_sql_log_bin= @@global.sql_log_bin;
create table t1 (a int) engine= myisam; create table t1 (a int) engine= myisam;
create table t2 (a int) engine= innodb; create table t2 (a int) engine= innodb;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
SELECT @@session.sql_log_bin;
SET AUTOCOMMIT=1; SET AUTOCOMMIT=1;
--echo # Test that the session variable 'binlog_format' and --echo # Test that the session variable 'binlog_format',
--echo # 'binlog_direct_non_transactional_updates' are --echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin'
--echo # writable outside a transaction. --echo # are writable outside a transaction.
--echo # Current session values are ROW and FALSE, respectively. --echo # Current session values are ROW, FALSE, TRUE, respectively.
set @@session.binlog_format= statement; set @@session.binlog_format= statement;
set @@session.binlog_direct_non_transactional_updates= TRUE; set @@session.binlog_direct_non_transactional_updates= TRUE;
set @@session.sql_log_bin= FALSE;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
SELECT @@session.sql_log_bin;
begin; begin;
--echo # Test that the session variable 'binlog_format' and --echo # Test that the session variable 'binlog_format',
--echo # 'binlog_direct_non_transactional_updates' are --echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
--echo # read-only inside a transaction with no preceding updates. --echo # read-only inside a transaction with no preceding updates.
--echo # Current session values are STATEMENT and TRUE, respectively. --echo # Current session values are STATEMENT, TRUE, FALSE, respectively.
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
set @@session.binlog_format= mixed; set @@session.binlog_format= mixed;
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT
set @@session.binlog_direct_non_transactional_updates= FALSE; set @@session.binlog_direct_non_transactional_updates= FALSE;
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN
set @@session.sql_log_bin= FALSE;
insert into t2 values (1); insert into t2 values (1);
--echo # Test that the session variable 'binlog_format' and --echo # Test that the session variable 'binlog_format',
--echo # 'binlog_direct_non_transactional_updates' are --echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
--echo # read-only inside a transaction with preceding transactional updates. --echo # read-only inside a transaction with preceding transactional updates.
--echo # Current session values are STATEMENT and TRUE, respectively. --echo # Current session values are STATEMENT, TRUE and FALSE, respectively.
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
set @@session.binlog_format= row; set @@session.binlog_format= row;
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT
set @@session.binlog_direct_non_transactional_updates= FALSE; set @@session.binlog_direct_non_transactional_updates= FALSE;
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN
set @@session.sql_log_bin= FALSE;
commit; commit;
begin; begin;
insert into t1 values (2); insert into t1 values (2);
--echo # Test that the session variable 'binlog_format' and --echo # Test that the session variable 'binlog_format'
--echo # 'binlog_direct_non_transactional_updates' are --echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
--echo # read-only inside a transaction with preceding non-transactional updates. --echo # read-only inside a transaction with preceding non-transactional updates.
--echo # Current session values are STATEMENT and TRUE, respectively. --echo # Current session values are STATEMENT, TRUE, FALSE, respectively.
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
set @@session.binlog_format= mixed; set @@session.binlog_format= mixed;
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT
set @@session.binlog_direct_non_transactional_updates= FALSE; set @@session.binlog_direct_non_transactional_updates= FALSE;
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN
set @@session.sql_log_bin= FALSE;
commit; commit;
--echo # Test that the session variable 'binlog_format' and --echo # Test that the session variable 'binlog_format',
--echo # 'binlog_direct_non_transactional_updates' are --echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
--echo # writable when AUTOCOMMIT=0, before a transaction has started. --echo # writable when AUTOCOMMIT=0, before a transaction has started.
--echo # Current session values are STATEMENT and TRUE, respectively. --echo # Current session values are STATEMENT, TRUE, FALSE, respectively.
set AUTOCOMMIT=0; set AUTOCOMMIT=0;
set @@session.binlog_format= row; set @@session.binlog_format= row;
set @@session.binlog_direct_non_transactional_updates= FALSE; set @@session.binlog_direct_non_transactional_updates= FALSE;
set @@session.sql_log_bin= TRUE;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
SELECT @@session.sql_log_bin;
insert into t1 values (3); insert into t1 values (3);
--echo # Test that the session variable 'binlog_format' and --echo # Test that the session variable 'binlog_format',
--echo # 'binlog_direct_non_transactional_updates' are --echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
--echo # read-only inside an AUTOCOMMIT=0 transaction --echo # read-only inside an AUTOCOMMIT=0 transaction
--echo # with preceding non-transactional updates. --echo # with preceding non-transactional updates.
--echo # Current session values are ROW and FALSE, respectively. --echo # Current session values are ROW, FALSE, TRUE, respectively.
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
set @@session.binlog_format= statement; set @@session.binlog_format= statement;
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT
set @@session.binlog_direct_non_transactional_updates= TRUE; set @@session.binlog_direct_non_transactional_updates= TRUE;
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN
set @@session.sql_log_bin= FALSE;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
SELECT @@session.sql_log_bin;
commit; commit;
insert into t2 values (4); insert into t2 values (4);
--echo # Test that the session variable 'binlog_format' and --echo # Test that the session variable 'binlog_format',
--echo # 'binlog_direct_non_transactional_updates' are --echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
--echo # read-only inside an AUTOCOMMIT=0 transaction with --echo # read-only inside an AUTOCOMMIT=0 transaction with
--echo # preceding transactional updates. --echo # preceding transactional updates.
--echo # Current session values are ROW and FALSE, respectively. --echo # Current session values are ROW, FALSE, TRUE, respectively.
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT
set @@session.binlog_format= statement; set @@session.binlog_format= statement;
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT
set @@session.binlog_direct_non_transactional_updates= TRUE; set @@session.binlog_direct_non_transactional_updates= TRUE;
--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN
set @@session.sql_log_bin= FALSE;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
SELECT @@session.sql_log_bin;
commit; commit;
begin; begin;
insert into t2 values (5); insert into t2 values (5);
--echo # Test that the global variable 'binlog_format' and --echo # Test that the global variable 'binlog_format' and
--echo # 'binlog_direct_non_transactional_updates' are --echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are
--echo # writable inside a transaction. --echo # writable inside a transaction.
--echo # Current session values are ROW and FALSE, respectively. --echo # Current session values are ROW, FALSE, TRUE respectively.
SELECT @@global.binlog_format; SELECT @@global.binlog_format;
set @@global.binlog_format= statement; set @@global.binlog_format= statement;
set @@global.binlog_direct_non_transactional_updates= TRUE; set @@global.binlog_direct_non_transactional_updates= TRUE;
set @@global.sql_log_bin= FALSE;
SELECT @@global.binlog_format; SELECT @@global.binlog_format;
SELECT @@global.binlog_direct_non_transactional_updates; SELECT @@global.binlog_direct_non_transactional_updates;
SELECT @@global.sql_log_bin;
commit; commit;
set @@global.binlog_format= @save_binlog_format; set @@global.binlog_format= @save_binlog_format;
set @@global.binlog_direct_non_transactional_updates= @save_binlog_dirct; set @@global.binlog_direct_non_transactional_updates= @save_binlog_dirct;
set @@global.sql_log_bin= @save_sql_log_bin;
create table t3(a int, b int) engine= innodb; create table t3(a int, b int) engine= innodb;
create table t4(a int) engine= innodb; create table t4(a int) engine= innodb;
...@@ -151,6 +172,25 @@ delimiter ;| ...@@ -151,6 +172,25 @@ delimiter ;|
insert into t6(a,b) values(1,1); insert into t6(a,b) values(1,1);
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
create table t9(a int, b int) engine= innodb;
create table t10(a int) engine= innodb;
create table t11(a int) engine= innodb;
delimiter |;
eval create trigger tr3 after insert on t9 for each row begin
insert into t10(a) values(1);
set @@session.sql_log_bin= TRUE;
insert into t10(a) values(2);
insert into t11(a) values(3);
end |
delimiter ;|
--echo # Test that the session variable 'sql_log_bin' is
--echo # read-only in sub-statements.
--echo # Current session value is FALSE.
--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN
insert into t9(a,b) values(1,1);
SELECT @@session.sql_log_bin;
drop table t1; drop table t1;
drop table t2; drop table t2;
drop table t3; drop table t3;
...@@ -159,3 +199,6 @@ drop table t5; ...@@ -159,3 +199,6 @@ drop table t5;
drop table t6; drop table t6;
drop table t7; drop table t7;
drop table t8; drop table t8;
drop table t9;
drop table t10;
drop table t11;
...@@ -6336,3 +6336,11 @@ ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE ...@@ -6336,3 +6336,11 @@ ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE
ER_BINLOG_UNSAFE_MIXED_STATEMENT ER_BINLOG_UNSAFE_MIXED_STATEMENT
eng "Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe." eng "Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe."
ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN
eng "Cannot modify @@session.sql_log_bin inside a transaction"
ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN
eng "Cannot change the sql_log_bin inside a stored function or trigger"
...@@ -4001,9 +4001,9 @@ thr_lock_type read_lock_type_for_table(THD *thd, ...@@ -4001,9 +4001,9 @@ thr_lock_type read_lock_type_for_table(THD *thd,
prelocked mode we can't rely on OPTION_BIN_LOG flag in THD::options prelocked mode we can't rely on OPTION_BIN_LOG flag in THD::options
bitmap to determine that binary logging is turned on as this bit can bitmap to determine that binary logging is turned on as this bit can
be cleared before executing sub-statement. So instead we have to look be cleared before executing sub-statement. So instead we have to look
at THD::sql_log_bin_toplevel member. at THD::variables::sql_log_bin member.
*/ */
bool log_on= mysql_bin_log.is_open() && thd->sql_log_bin_toplevel; bool log_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin;
ulong binlog_format= thd->variables.binlog_format; ulong binlog_format= thd->variables.binlog_format;
if ((log_on == FALSE) || (binlog_format == BINLOG_FORMAT_ROW) || if ((log_on == FALSE) || (binlog_format == BINLOG_FORMAT_ROW) ||
(table_list->table->s->table_category == TABLE_CATEGORY_LOG) || (table_list->table->s->table_category == TABLE_CATEGORY_LOG) ||
......
...@@ -460,7 +460,6 @@ THD::THD() ...@@ -460,7 +460,6 @@ THD::THD()
rli_fake(0), rli_fake(0),
lock_id(&main_lock_id), lock_id(&main_lock_id),
user_time(0), in_sub_stmt(0), user_time(0), in_sub_stmt(0),
sql_log_bin_toplevel(false),
binlog_unsafe_warning_flags(0), binlog_table_maps(0), binlog_unsafe_warning_flags(0), binlog_table_maps(0),
table_map_for_update(0), table_map_for_update(0),
arg_of_last_insert_id_function(FALSE), arg_of_last_insert_id_function(FALSE),
...@@ -929,7 +928,11 @@ void THD::init(void) ...@@ -929,7 +928,11 @@ void THD::init(void)
update_charset(); update_charset();
reset_current_stmt_binlog_format_row(); reset_current_stmt_binlog_format_row();
bzero((char *) &status_var, sizeof(status_var)); bzero((char *) &status_var, sizeof(status_var));
sql_log_bin_toplevel= variables.option_bits & OPTION_BIN_LOG;
if (variables.sql_log_bin)
variables.option_bits|= OPTION_BIN_LOG;
else
variables.option_bits&= ~OPTION_BIN_LOG;
#if defined(ENABLED_DEBUG_SYNC) #if defined(ENABLED_DEBUG_SYNC)
/* Initialize the Debug Sync Facility. See debug_sync.cc. */ /* Initialize the Debug Sync Facility. See debug_sync.cc. */
...@@ -4554,8 +4557,13 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, ...@@ -4554,8 +4557,13 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
because the warnings should be printed only if the statement is because the warnings should be printed only if the statement is
actually logged. When executing decide_logging_format(), we cannot actually logged. When executing decide_logging_format(), we cannot
know for sure if the statement will be logged. know for sure if the statement will be logged.
Besides, we should not try to print these warnings if it is not
possible to write statements to the binary log as it happens when
the execution is inside a function, or generaly speaking, when
the variables.option_bits & OPTION_BIN_LOG is false.
*/ */
if (sql_log_bin_toplevel) if (variables.option_bits & OPTION_BIN_LOG)
issue_unsafe_warnings(); issue_unsafe_warnings();
switch (qtype) { switch (qtype) {
......
...@@ -428,6 +428,7 @@ typedef struct system_variables ...@@ -428,6 +428,7 @@ typedef struct system_variables
uint binlog_format; ///< binlog format for this thd (see enum_binlog_format) uint binlog_format; ///< binlog format for this thd (see enum_binlog_format)
my_bool binlog_direct_non_trans_update; my_bool binlog_direct_non_trans_update;
my_bool sql_log_bin;
uint completion_type; uint completion_type;
uint query_cache_type; uint query_cache_type;
uint tx_isolation; uint tx_isolation;
...@@ -1667,8 +1668,6 @@ class THD :public Statement, ...@@ -1667,8 +1668,6 @@ class THD :public Statement,
/* <> 0 if we are inside of trigger or stored function. */ /* <> 0 if we are inside of trigger or stored function. */
uint in_sub_stmt; uint in_sub_stmt;
/* TRUE when the current top has SQL_LOG_BIN ON */
bool sql_log_bin_toplevel;
/* container for handler's private per-connection data */ /* container for handler's private per-connection data */
Ha_data ha_data[MAX_HA]; Ha_data ha_data[MAX_HA];
......
...@@ -2236,17 +2236,69 @@ static Sys_var_bit Sys_log_off( ...@@ -2236,17 +2236,69 @@ static Sys_var_bit Sys_log_off(
SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_LOG_OFF, SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_LOG_OFF,
DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super)); DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super));
static bool fix_sql_log_bin(sys_var *self, THD *thd, enum_var_type type) /**
This function sets the session variable thd->variables.sql_log_bin
to reflect changes to @@session.sql_log_bin.
@param[IN] self A pointer to the sys_var, i.e. Sys_log_binlog.
@param[IN] type The type either session or global.
@return @c FALSE.
*/
static bool fix_sql_log_bin_after_update(sys_var *self, THD *thd,
enum_var_type type)
{ {
if (type != OPT_GLOBAL && !thd->in_sub_stmt) if (type == OPT_SESSION)
thd->sql_log_bin_toplevel= thd->variables.option_bits & OPTION_BIN_LOG; {
return false; if (thd->variables.sql_log_bin)
thd->variables.option_bits |= OPTION_BIN_LOG;
else
thd->variables.option_bits &= ~OPTION_BIN_LOG;
}
return FALSE;
} }
static Sys_var_bit Sys_log_binlog(
/**
This function checks if the sql_log_bin can be changed,
what is possible if:
- the user is a super user;
- the set is not called from within a function/trigger;
- there is no on-going transaction.
@param[IN] self A pointer to the sys_var, i.e. Sys_log_binlog.
@param[IN] var A pointer to the set_var created by the parser.
@return @c FALSE if the change is allowed, otherwise @c TRUE.
*/
static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var)
{
if (check_has_super(self, thd, var))
return TRUE;
if (var->type == OPT_GLOBAL)
return FALSE;
/* If in a stored function/trigger, it's too late to change sql_log_bin. */
if (thd->in_sub_stmt)
{
my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN, MYF(0));
return TRUE;
}
/* Make the session variable 'sql_log_bin' read-only inside a transaction. */
if (thd->in_active_multi_stmt_transaction())
{
my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN, MYF(0));
return TRUE;
}
return FALSE;
}
static Sys_var_mybool Sys_log_binlog(
"sql_log_bin", "sql_log_bin", "sql_log_bin", "sql_log_bin",
SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_BIN_LOG, SESSION_VAR(sql_log_bin), NO_CMD_LINE,
DEFAULT(TRUE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super), DEFAULT(TRUE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_sql_log_bin),
ON_UPDATE(fix_sql_log_bin)); ON_UPDATE(fix_sql_log_bin_after_update));
static Sys_var_bit Sys_sql_warnings( static Sys_var_bit Sys_sql_warnings(
"sql_warnings", "sql_warnings", "sql_warnings", "sql_warnings",
......
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