Commit 3300ff7a authored by Alfranio Correia's avatar Alfranio Correia

BUG#51277 SUPER_ACL should be checked unconditionally (binlog_format and binlog_direct)

SUPER_ACL should be checked unconditionally while verifying if the binlog_format
or the binlog_direct_non_transactional_updates might be changed.

Roughly speaking, both session values cannot be changed in the context of a
transaction or a stored function. Note that changing the global value does
not cause any effect until a new connection is created.

So, we fixed the problem by first checking the permissions and right after further
verifications are ignored if the global value is being updated. In this patch, we
also re-structure the test case to make it more readable.
parent 42747979
...@@ -5,9 +5,14 @@ create table t2 (a int) engine= innodb; ...@@ -5,9 +5,14 @@ create table t2 (a int) engine= innodb;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
@@session.binlog_format @@session.binlog_format
ROW ROW
SELECT @@session.binlog_direct_non_transactional_updates;
@@session.binlog_direct_non_transactional_updates
1
SET AUTOCOMMIT=1; SET AUTOCOMMIT=1;
# Test that the session variable 'binlog_format' # Test that the session variable 'binlog_format' and
# is writable outside a transaction. # 'binlog_direct_non_transactional_updates' are
# writable outside a transaction.
# Current session values are ROW and FALSE, 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;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
...@@ -17,15 +22,19 @@ SELECT @@session.binlog_direct_non_transactional_updates; ...@@ -17,15 +22,19 @@ SELECT @@session.binlog_direct_non_transactional_updates;
@@session.binlog_direct_non_transactional_updates @@session.binlog_direct_non_transactional_updates
1 1
begin; begin;
# Test that the session variable 'binlog_format' is read-only # Test that the session variable 'binlog_format' and
# inside a transaction with no preceding updates. # 'binlog_direct_non_transactional_updates' are
# read-only inside a transaction with no preceding updates.
# Current session values are STATEMENT and TRUE, 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
insert into t2 values (1); insert into t2 values (1);
# Test that the session variable 'binlog_format' is read-only # Test that the session variable 'binlog_format' and
# inside a transaction with preceding transactional updates. # 'binlog_direct_non_transactional_updates' are
# read-only inside a transaction with preceding transactional updates.
# Current session values are STATEMENT and TRUE, 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;
...@@ -33,15 +42,19 @@ ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates ins ...@@ -33,15 +42,19 @@ ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates ins
commit; commit;
begin; begin;
insert into t1 values (2); insert into t1 values (2);
# Test that the session variable 'binlog_format' is read-only # Test that the session variable 'binlog_format' and
# inside a transaction with preceding non-transactional updates. # 'binlog_direct_non_transactional_updates' are
set @@session.binlog_format= statement; # read-only inside a transaction with preceding non-transactional updates.
# Current session values are STATEMENT and TRUE, respectively.
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
commit; commit;
# Test that the session variable 'binlog_format' is writable # Test that the session variable 'binlog_format' and
# when AUTOCOMMIT=0, before a transaction has started. # 'binlog_direct_non_transactional_updates' are
# writable when AUTOCOMMIT=0, before a transaction has started.
# Current session values are STATEMENT and TRUE, 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;
...@@ -51,9 +64,12 @@ ROW ...@@ -51,9 +64,12 @@ 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
insert into t1 values (4); insert into t1 values (3);
# Test that the session variable 'binlog_format' is read-only inside an # Test that the session variable 'binlog_format' and
# AUTOCOMMIT=0 transaction with preceding non-transactional updates. # 'binlog_direct_non_transactional_updates' are
# read-only inside an AUTOCOMMIT=0 transaction
# with preceding non-transactional updates.
# Current session values are ROW and FALSE, 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;
...@@ -65,10 +81,13 @@ SELECT @@session.binlog_direct_non_transactional_updates; ...@@ -65,10 +81,13 @@ SELECT @@session.binlog_direct_non_transactional_updates;
@@session.binlog_direct_non_transactional_updates @@session.binlog_direct_non_transactional_updates
0 0
commit; commit;
insert into t2 values (5); insert into t2 values (4);
# Test that the session variable 'binlog_format' is read-only inside an # Test that the session variable 'binlog_format' and
# AUTOCOMMIT=0 transaction with preceding transactional updates. # 'binlog_direct_non_transactional_updates' are
set @@session.binlog_format= row; # read-only inside an AUTOCOMMIT=0 transaction with
# preceding transactional updates.
# Current session values are ROW and FALSE, respectively.
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
...@@ -80,9 +99,11 @@ SELECT @@session.binlog_direct_non_transactional_updates; ...@@ -80,9 +99,11 @@ SELECT @@session.binlog_direct_non_transactional_updates;
0 0
commit; commit;
begin; begin;
insert into t2 values (6); insert into t2 values (5);
# Test that the global variable 'binlog_format' is writable # Test that the global variable 'binlog_format' and
# inside a transaction. # 'binlog_direct_non_transactional_updates' are
# writable inside a transaction.
# Current session values are ROW and FALSE, respectively.
SELECT @@global.binlog_format; SELECT @@global.binlog_format;
@@global.binlog_format @@global.binlog_format
ROW ROW
...@@ -108,6 +129,7 @@ insert into t5(a) values(3); ...@@ -108,6 +129,7 @@ insert into t5(a) values(3);
end | end |
# Test that the session variable 'binlog_format' is read-only # Test that the session variable 'binlog_format' is read-only
# in sub-statements. # in sub-statements.
# Current session value is ROW.
insert into t3(a,b) values(1,1); insert into t3(a,b) values(1,1);
ERROR HY000: Cannot change the binary logging format inside a stored function or trigger ERROR HY000: Cannot change the binary logging format inside a stored function or trigger
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
...@@ -118,12 +140,14 @@ create table t7(a int) engine= innodb; ...@@ -118,12 +140,14 @@ create table t7(a int) engine= innodb;
create table t8(a int) engine= innodb; create table t8(a int) engine= innodb;
create trigger tr2 after insert on t6 for each row begin create trigger tr2 after insert on t6 for each row begin
insert into t7(a) values(1); insert into t7(a) values(1);
set @@global.binlog_direct_non_transactional_updates= FALSE; set @@session.binlog_direct_non_transactional_updates= TRUE;
insert into t7(a) values(2); insert into t7(a) values(2);
insert into t8(a) values(3); insert into t8(a) values(3);
end | end |
# Test that the session variable 'binlog_format' is read-only # Test that the session variable
# in sub-statements. # 'binlog_direct_non_transactional_updates' is
# read-only in sub-statements.
# Current session value is FALSE.
insert into t6(a,b) values(1,1); insert into t6(a,b) values(1,1);
ERROR HY000: Cannot change the binlog direct flag inside a stored function or trigger ERROR HY000: Cannot change the binlog direct flag inside a stored function or trigger
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
......
# #
# BUG#47863 # BUG#47863
# This test verifies if the session variable 'binlog_format' # This test verifies if the session variable 'binlog_format' and
# is read-only inside a transaction and in sub-statements. # 'binlog_direct_non_transactional_updates' are read-only inside
# a transaction and in sub-statements.
# #
source include/have_innodb.inc; source include/have_innodb.inc;
...@@ -13,25 +14,32 @@ create table t1 (a int) engine= myisam; ...@@ -13,25 +14,32 @@ 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;
SET AUTOCOMMIT=1; SET AUTOCOMMIT=1;
--echo # Test that the session variable 'binlog_format' --echo # Test that the session variable 'binlog_format' and
--echo # is writable outside a transaction. --echo # 'binlog_direct_non_transactional_updates' are
--echo # writable outside a transaction.
--echo # Current session values are ROW and FALSE, 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;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
begin; begin;
--echo # Test that the session variable 'binlog_format' is read-only --echo # Test that the session variable 'binlog_format' and
--echo # inside a transaction with no preceding updates. --echo # 'binlog_direct_non_transactional_updates' are
--echo # read-only inside a transaction with no preceding updates.
--echo # Current session values are STATEMENT and TRUE, 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;
insert into t2 values (1); insert into t2 values (1);
--echo # Test that the session variable 'binlog_format' is read-only --echo # Test that the session variable 'binlog_format' and
--echo # inside a transaction with preceding transactional updates. --echo # 'binlog_direct_non_transactional_updates' are
--echo # read-only inside a transaction with preceding transactional updates.
--echo # Current session values are STATEMENT and TRUE, 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
...@@ -40,25 +48,32 @@ commit; ...@@ -40,25 +48,32 @@ commit;
begin; begin;
insert into t1 values (2); insert into t1 values (2);
--echo # Test that the session variable 'binlog_format' is read-only --echo # Test that the session variable 'binlog_format' and
--echo # inside a transaction with preceding non-transactional updates. --echo # 'binlog_direct_non_transactional_updates' are
--echo # read-only inside a transaction with preceding non-transactional updates.
--echo # Current session values are STATEMENT and 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= 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;
commit; commit;
--echo # Test that the session variable 'binlog_format' is writable --echo # Test that the session variable 'binlog_format' and
--echo # when AUTOCOMMIT=0, before a transaction has started. --echo # 'binlog_direct_non_transactional_updates' are
--echo # writable when AUTOCOMMIT=0, before a transaction has started.
--echo # Current session values are STATEMENT and TRUE, 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;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
insert into t1 values (4); insert into t1 values (3);
--echo # Test that the session variable 'binlog_format' is read-only inside an --echo # Test that the session variable 'binlog_format' and
--echo # AUTOCOMMIT=0 transaction with preceding non-transactional updates. --echo # 'binlog_direct_non_transactional_updates' are
--echo # read-only inside an AUTOCOMMIT=0 transaction
--echo # with preceding non-transactional updates.
--echo # Current session values are ROW and FALSE, 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
...@@ -67,11 +82,14 @@ SELECT @@session.binlog_format; ...@@ -67,11 +82,14 @@ SELECT @@session.binlog_format;
SELECT @@session.binlog_direct_non_transactional_updates; SELECT @@session.binlog_direct_non_transactional_updates;
commit; commit;
insert into t2 values (5); insert into t2 values (4);
--echo # Test that the session variable 'binlog_format' is read-only inside an --echo # Test that the session variable 'binlog_format' and
--echo # AUTOCOMMIT=0 transaction with preceding transactional updates. --echo # 'binlog_direct_non_transactional_updates' are
--echo # read-only inside an AUTOCOMMIT=0 transaction with
--echo # preceding transactional updates.
--echo # Current session values are ROW 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= 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;
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
...@@ -79,9 +97,11 @@ SELECT @@session.binlog_direct_non_transactional_updates; ...@@ -79,9 +97,11 @@ SELECT @@session.binlog_direct_non_transactional_updates;
commit; commit;
begin; begin;
insert into t2 values (6); insert into t2 values (5);
--echo # Test that the global variable 'binlog_format' is writable --echo # Test that the global variable 'binlog_format' and
--echo # inside a transaction. --echo # 'binlog_direct_non_transactional_updates' are
--echo # writable inside a transaction.
--echo # Current session values are ROW and FALSE, 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;
...@@ -106,6 +126,7 @@ delimiter ;| ...@@ -106,6 +126,7 @@ delimiter ;|
--echo # Test that the session variable 'binlog_format' is read-only --echo # Test that the session variable 'binlog_format' is read-only
--echo # in sub-statements. --echo # in sub-statements.
--echo # Current session value is ROW.
--error ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT --error ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT
insert into t3(a,b) values(1,1); insert into t3(a,b) values(1,1);
SELECT @@session.binlog_format; SELECT @@session.binlog_format;
...@@ -116,14 +137,16 @@ create table t8(a int) engine= innodb; ...@@ -116,14 +137,16 @@ create table t8(a int) engine= innodb;
delimiter |; delimiter |;
eval create trigger tr2 after insert on t6 for each row begin eval create trigger tr2 after insert on t6 for each row begin
insert into t7(a) values(1); insert into t7(a) values(1);
set @@global.binlog_direct_non_transactional_updates= FALSE; set @@session.binlog_direct_non_transactional_updates= TRUE;
insert into t7(a) values(2); insert into t7(a) values(2);
insert into t8(a) values(3); insert into t8(a) values(3);
end | end |
delimiter ;| delimiter ;|
--echo # Test that the session variable 'binlog_format' is read-only --echo # Test that the session variable
--echo # in sub-statements. --echo # 'binlog_direct_non_transactional_updates' is
--echo # read-only in sub-statements.
--echo # Current session value is FALSE.
--error ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT --error ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT
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;
......
...@@ -240,6 +240,12 @@ static bool check_has_super(sys_var *self, THD *thd, set_var *var) ...@@ -240,6 +240,12 @@ static bool check_has_super(sys_var *self, THD *thd, set_var *var)
} }
static bool binlog_format_check(sys_var *self, THD *thd, set_var *var) static bool binlog_format_check(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 RBR and open temporary tables, their CREATE TABLE may not be in the 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. binlog, so we can't toggle to SBR in this connection.
...@@ -271,18 +277,12 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var) ...@@ -271,18 +277,12 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var)
/* /*
Make the session variable 'binlog_format' read-only inside a transaction. Make the session variable 'binlog_format' read-only inside a transaction.
*/ */
if (thd->active_transaction() && (var->type == OPT_SESSION)) if (thd->active_transaction())
{ {
my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0)); my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
return true; return true;
} }
if (check_has_super(self, thd, var))
return true;
if (var->type == OPT_GLOBAL ||
(thd->variables.binlog_format == var->save_result.ulonglong_value))
return false;
return false; return false;
} }
...@@ -311,31 +311,30 @@ static Sys_var_enum Sys_binlog_format( ...@@ -311,31 +311,30 @@ static Sys_var_enum Sys_binlog_format(
static bool binlog_direct_check(sys_var *self, THD *thd, set_var *var) static bool binlog_direct_check(sys_var *self, THD *thd, set_var *var)
{ {
if (check_has_super(self, thd, var))
return true;
if (var->type == OPT_GLOBAL)
return false;
/* /*
Makes the session variable 'binlog_direct_non_transactional_updates' Makes the session variable 'binlog_direct_non_transactional_updates'
read-only inside a transaction. read-only if within a procedure, trigger or function.
*/ */
if (thd->active_transaction() && (var->type == OPT_SESSION)) if (thd->in_sub_stmt)
{ {
my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0)); my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0));
return 1; return true;
} }
/* /*
Makes the session variable 'binlog_direct_non_transactional_updates' Makes the session variable 'binlog_direct_non_transactional_updates'
read-only if within a procedure, trigger or function. read-only inside a transaction.
*/ */
if (thd->in_sub_stmt) if (thd->active_transaction())
{ {
my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0)); my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0));
return 1;
}
if (check_has_super(self, thd, var))
return true; return true;
if (var->type == OPT_GLOBAL || }
(thd->variables.binlog_direct_non_trans_update ==
static_cast<my_bool>(var->save_result.ulonglong_value)))
return false;
return false; return false;
} }
......
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