Commit 26aadd21 authored by unknown's avatar unknown

Bug#21975 Grant and revoke statements are non-transactional

Bug#21422 GRANT/REVOKE possible inside stored function, probably in a trigger
Bug#17244 GRANT gives strange error message when used in a stored function

GRANT/REVOKE statements are non-transactional (no explicit transaction
boundaries) in nature and hence are forbidden inside stored functions and
triggers, but they weren't being effectively forbidden. Furthermore, the
absence of implict commits makes changes made by GRANT/REVOKE statements to
not be rolled back.

The implemented fix is to issue a implicit commit with every GRANT/REVOKE
statement, effectively prohibiting these statements in stored functions
and triggers. The implicit commit also fixes the replication bug, and looks
like being in concert with the behavior of DDL and administrative statements.

Since this is a incompatible change, the following sentence should be
added to the Manual in the very end of the 3rd paragraph, subclause
13.4.3 "Statements That Cause an Implicit Commit": "Beginning with
MySQL 5.0.??, the GRANT and REVOKE statements cause an implicit commit."

Patch contributed by Vladimir Shebordaev


mysql-test/r/sp-error.result:
  Test case result for Bug#17244
mysql-test/t/sp-error.test:
  Test case for Bug#17244
sql/sp_head.cc:
  Set that a procedure with GRANT/REVOKE command has a (implicit or explicit)
  commit.
sql/sql_parse.cc:
  End active transaction in SQLCOM_GRANT and SQLCOM_REVOKE, and thus effectively
  prohibit these statements in stored functions and triggers. An implicit commit
  also fixes a bug in replication, when GRANT or REVOKE would disappear from the
  binary log in case of a subsequent ROLLBACK, since they were considered
  transactional statements.
mysql-test/suite/rpl/r/rpl_binlog_grant.result:
  Add test case result for Bug#21975
mysql-test/suite/rpl/t/rpl_binlog_grant.test:
  Add test case for Bug#21975
parent 0ecee6df
...@@ -969,6 +969,18 @@ CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create user 'mysqltest ...@@ -969,6 +969,18 @@ CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create user 'mysqltest
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
CREATE FUNCTION bug_13627_f() returns int BEGIN create user 'mysqltest_1'; return 1; END | CREATE FUNCTION bug_13627_f() returns int BEGIN create user 'mysqltest_1'; return 1; END |
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN grant select on t1 to 'mysqltest_1'; END |
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
CREATE FUNCTION bug21975() returns int BEGIN grant select on t1 to 'mysqltest_1'; return 1; END |
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN revoke select on t1 from 'mysqltest_1'; END |
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
CREATE FUNCTION bug21975() returns int BEGIN revoke select on t1 from 'mysqltest_1'; return 1; END |
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN revoke all privileges on *.* from 'mysqltest_1'; END |
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
CREATE FUNCTION bug21975() returns int BEGIN revoke all privileges on *.* from 'mysqltest_1'; return 1; END |
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop user 'mysqltest_1'; END | CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop user 'mysqltest_1'; END |
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
CREATE FUNCTION bug_13627_f() returns int BEGIN drop user 'mysqltest_1'; return 1; END | CREATE FUNCTION bug_13627_f() returns int BEGIN drop user 'mysqltest_1'; return 1; END |
......
drop database if exists d1;
create database d1;
use d1;
create table t (s1 int) engine=innodb;
set @@autocommit=0;
start transaction;
insert into t values (1);
grant select on t to x@y;
rollback;
show grants for x@y;
Grants for x@y
GRANT USAGE ON *.* TO 'x'@'y'
GRANT SELECT ON `d1`.`t` TO 'x'@'y'
show binlog events;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server ver: VERSION, Binlog ver: 4
master-bin.000001 106 Query 1 193 drop database if exists d1
master-bin.000001 193 Query 1 272 create database d1
master-bin.000001 272 Query 1 370 use `d1`; create table t (s1 int) engine=innodb
master-bin.000001 370 Query 1 436 use `d1`; BEGIN
master-bin.000001 436 Query 1 521 use `d1`; insert into t values (1)
master-bin.000001 521 Xid 1 548 COMMIT /* xid=12 */
master-bin.000001 548 Query 1 633 use `d1`; grant select on t to x@y
start transaction;
insert into t values (2);
revoke select on t from x@y;
commit;
select * from t;
s1
1
2
show grants for x@y;
Grants for x@y
GRANT USAGE ON *.* TO 'x'@'y'
show binlog events;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server ver: VERSION, Binlog ver: 4
master-bin.000001 106 Query 1 193 drop database if exists d1
master-bin.000001 193 Query 1 272 create database d1
master-bin.000001 272 Query 1 370 use `d1`; create table t (s1 int) engine=innodb
master-bin.000001 370 Query 1 436 use `d1`; BEGIN
master-bin.000001 436 Query 1 521 use `d1`; insert into t values (1)
master-bin.000001 521 Xid 1 548 COMMIT /* xid=12 */
master-bin.000001 548 Query 1 633 use `d1`; grant select on t to x@y
master-bin.000001 633 Query 1 699 use `d1`; BEGIN
master-bin.000001 699 Query 1 784 use `d1`; insert into t values (2)
master-bin.000001 784 Xid 1 811 COMMIT /* xid=18 */
master-bin.000001 811 Query 1 899 use `d1`; revoke select on t from x@y
drop user x@y;
drop database d1;
-- source include/have_innodb.inc
-- source include/not_embedded.inc
-- source include/have_binlog_format_mixed_or_statement.inc
let $VERSION=`select version()`;
# Bug #21975: grant/revoke statements in transaction
# used to disappear from binlog upon rallback.
# Now GRANT/REVOKE do implicitly commit
# transaction
--disable_warnings
drop database if exists d1;
--enable_warnings
create database d1;
use d1;
create table t (s1 int) engine=innodb;
set @@autocommit=0;
start transaction;
insert into t values (1);
grant select on t to x@y;
#
# There is no active transaction here
#
rollback;
show grants for x@y;
--replace_result $VERSION VERSION
show binlog events;
start transaction;
insert into t values (2);
revoke select on t from x@y;
#
# There is no active transaction here
#
commit;
select * from t;
show grants for x@y;
--replace_result $VERSION VERSION
show binlog events;
drop user x@y;
drop database d1;
...@@ -1386,6 +1386,21 @@ CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create user 'mysqltest ...@@ -1386,6 +1386,21 @@ CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create user 'mysqltest
-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG -- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
CREATE FUNCTION bug_13627_f() returns int BEGIN create user 'mysqltest_1'; return 1; END | CREATE FUNCTION bug_13627_f() returns int BEGIN create user 'mysqltest_1'; return 1; END |
-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN grant select on t1 to 'mysqltest_1'; END |
-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
CREATE FUNCTION bug21975() returns int BEGIN grant select on t1 to 'mysqltest_1'; return 1; END |
-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN revoke select on t1 from 'mysqltest_1'; END |
-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
CREATE FUNCTION bug21975() returns int BEGIN revoke select on t1 from 'mysqltest_1'; return 1; END |
-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
CREATE TRIGGER bug21975 BEFORE INSERT ON t1 FOR EACH ROW BEGIN revoke all privileges on *.* from 'mysqltest_1'; END |
-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
CREATE FUNCTION bug21975() returns int BEGIN revoke all privileges on *.* from 'mysqltest_1'; return 1; END |
-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG -- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop user 'mysqltest_1'; END | CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop user 'mysqltest_1'; END |
-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG -- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
......
...@@ -247,11 +247,14 @@ sp_get_flags_for_command(LEX *lex) ...@@ -247,11 +247,14 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_CREATE_TRIGGER: case SQLCOM_CREATE_TRIGGER:
case SQLCOM_CREATE_USER: case SQLCOM_CREATE_USER:
case SQLCOM_ALTER_TABLE: case SQLCOM_ALTER_TABLE:
case SQLCOM_GRANT:
case SQLCOM_REVOKE:
case SQLCOM_BEGIN: case SQLCOM_BEGIN:
case SQLCOM_RENAME_TABLE: case SQLCOM_RENAME_TABLE:
case SQLCOM_RENAME_USER: case SQLCOM_RENAME_USER:
case SQLCOM_DROP_INDEX: case SQLCOM_DROP_INDEX:
case SQLCOM_DROP_DB: case SQLCOM_DROP_DB:
case SQLCOM_REVOKE_ALL:
case SQLCOM_DROP_USER: case SQLCOM_DROP_USER:
case SQLCOM_DROP_VIEW: case SQLCOM_DROP_VIEW:
case SQLCOM_DROP_TRIGGER: case SQLCOM_DROP_TRIGGER:
......
...@@ -3381,6 +3381,8 @@ end_with_restore_list: ...@@ -3381,6 +3381,8 @@ end_with_restore_list:
} }
case SQLCOM_REVOKE_ALL: case SQLCOM_REVOKE_ALL:
{ {
if (end_active_trans(thd))
goto error;
if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) && if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL)) check_global_access(thd,CREATE_USER_ACL))
break; break;
...@@ -3392,6 +3394,9 @@ end_with_restore_list: ...@@ -3392,6 +3394,9 @@ end_with_restore_list:
case SQLCOM_REVOKE: case SQLCOM_REVOKE:
case SQLCOM_GRANT: case SQLCOM_GRANT:
{ {
if (end_active_trans(thd))
goto error;
if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL, if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
first_table ? first_table->db : select_lex->db, first_table ? first_table->db : select_lex->db,
first_table ? &first_table->grant.privilege : 0, first_table ? &first_table->grant.privilege : 0,
......
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