summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/trigger-grant.result287
-rw-r--r--mysql-test/t/trigger-grant.test513
-rw-r--r--sql/item.cc31
-rw-r--r--sql/item.h14
-rw-r--r--sql/sql_trigger.cc54
-rw-r--r--sql/sql_trigger.h11
-rw-r--r--sql/sql_yacc.yy7
7 files changed, 552 insertions, 365 deletions
diff --git a/mysql-test/r/trigger-grant.result b/mysql-test/r/trigger-grant.result
index 858cab7a04a..87e5e11d779 100644
--- a/mysql-test/r/trigger-grant.result
+++ b/mysql-test/r/trigger-grant.result
@@ -65,109 +65,6 @@ user_str
mysqltest_dfn@localhost
mysqltest_dfn@localhost
----> connection: default
-use mysqltest_db1;
-REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost;
-
----> connection: wl2818_definer_con
-use mysqltest_db1;
-DROP TRIGGER trg1;
-SET @new_sum = 0;
-SET @old_sum = 0;
----> INSERT INTO statement; BEFORE timing
-CREATE TRIGGER trg1 BEFORE INSERT ON t1
-FOR EACH ROW
-SET @new_sum = @new_sum + NEW.num_value;
-INSERT INTO t1 VALUES(4);
-ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
----> INSERT INTO statement; AFTER timing
-DROP TRIGGER trg1;
-CREATE TRIGGER trg1 AFTER INSERT ON t1
-FOR EACH ROW
-SET @new_sum = @new_sum + NEW.num_value;
-INSERT INTO t1 VALUES(5);
-ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
----> UPDATE statement; BEFORE timing
-DROP TRIGGER trg1;
-CREATE TRIGGER trg1 BEFORE UPDATE ON t1
-FOR EACH ROW
-SET @old_sum = @old_sum + OLD.num_value;
-UPDATE t1 SET num_value = 10;
-ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
----> UPDATE statement; AFTER timing
-DROP TRIGGER trg1;
-CREATE TRIGGER trg1 AFTER UPDATE ON t1
-FOR EACH ROW
-SET @new_sum = @new_sum + NEW.num_value;
-UPDATE t1 SET num_value = 20;
-ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
----> DELETE statement; BEFORE timing
-DROP TRIGGER trg1;
-CREATE TRIGGER trg1 BEFORE DELETE ON t1
-FOR EACH ROW
-SET @old_sum = @old_sum + OLD.num_value;
-DELETE FROM t1;
-ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
----> DELETE statement; AFTER timing
-DROP TRIGGER trg1;
-CREATE TRIGGER trg1 AFTER DELETE ON t1
-FOR EACH ROW
-SET @old_sum = @old_sum + OLD.num_value;
-DELETE FROM t1;
-ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
-
----> connection: default
-use mysqltest_db1;
-GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_dfn@localhost;
-REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost;
-
----> connection: wl2818_definer_con
-use mysqltest_db1;
-DROP TRIGGER trg1;
-SET @new_sum = 0;
-SET @old_sum = 0;
----> INSERT INTO statement; BEFORE timing
-CREATE TRIGGER trg1 BEFORE INSERT ON t1
-FOR EACH ROW
-SET @new_sum = @new_sum + NEW.num_value;
-INSERT INTO t1 VALUES(4);
-ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
----> INSERT INTO statement; AFTER timing
-DROP TRIGGER trg1;
-CREATE TRIGGER trg1 AFTER INSERT ON t1
-FOR EACH ROW
-SET @new_sum = @new_sum + NEW.num_value;
-INSERT INTO t1 VALUES(5);
-ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
----> UPDATE statement; BEFORE timing
-DROP TRIGGER trg1;
-CREATE TRIGGER trg1 BEFORE UPDATE ON t1
-FOR EACH ROW
-SET @old_sum = @old_sum + OLD.num_value;
-UPDATE t1 SET num_value = 10;
-ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
----> UPDATE statement; AFTER timing
-DROP TRIGGER trg1;
-CREATE TRIGGER trg1 AFTER UPDATE ON t1
-FOR EACH ROW
-SET @new_sum = @new_sum + NEW.num_value;
-UPDATE t1 SET num_value = 20;
-ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
----> DELETE statement; BEFORE timing
-DROP TRIGGER trg1;
-CREATE TRIGGER trg1 BEFORE DELETE ON t1
-FOR EACH ROW
-SET @old_sum = @old_sum + OLD.num_value;
-DELETE FROM t1;
-ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
----> DELETE statement; AFTER timing
-DROP TRIGGER trg1;
-CREATE TRIGGER trg1 AFTER DELETE ON t1
-FOR EACH ROW
-SET @old_sum = @old_sum + OLD.num_value;
-DELETE FROM t1;
-ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
-
---> connection: wl2818_definer_con
use mysqltest_db1;
DROP TRIGGER trg1;
@@ -229,3 +126,187 @@ DROP USER mysqltest_inv@localhost;
DROP DATABASE mysqltest_db1;
Warnings:
Warning 1454 No definer attribute for trigger 'mysqltest_db1'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
+DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%';
+DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%';
+DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%';
+DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%';
+FLUSH PRIVILEGES;
+DROP DATABASE IF EXISTS mysqltest_db1;
+CREATE DATABASE mysqltest_db1;
+use mysqltest_db1;
+CREATE TABLE t1(col CHAR(20));
+CREATE TABLE t2(col CHAR(20));
+CREATE TABLE t3(col CHAR(20));
+CREATE TABLE t4(col CHAR(20));
+CREATE USER mysqltest_u1@localhost;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_u1@localhost;
+GRANT SUPER ON *.* TO mysqltest_u1@localhost;
+GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
+SET @mysqltest_var = NULL;
+
+---> connection: default
+use mysqltest_db1;
+REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
+GRANT DELETE ON mysqltest_db1.* TO mysqltest_u1@localhost;
+SHOW GRANTS FOR mysqltest_u1@localhost;
+Grants for mysqltest_u1@localhost
+GRANT SUPER ON *.* TO 'mysqltest_u1'@'localhost'
+GRANT DELETE ON `mysqltest_db1`.* TO 'mysqltest_u1'@'localhost'
+
+---> connection: bug15166_u1_con
+use mysqltest_db1;
+CREATE TRIGGER t1_trg_after_delete AFTER DELETE ON t1
+FOR EACH ROW
+SET @mysqltest_var = 'Hello, world!';
+
+---> connection: default
+use mysqltest_db1;
+GRANT UPDATE ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
+GRANT UPDATE ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
+GRANT UPDATE(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost;
+GRANT UPDATE(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost;
+
+---> connection: bug15166_u1_con
+use mysqltest_db1;
+CREATE TRIGGER t1_trg_err_1 BEFORE INSERT ON t1
+FOR EACH ROW
+SET @mysqltest_var = NEW.col;
+DROP TRIGGER t1_trg_err_1;
+CREATE TRIGGER t1_trg_err_2 BEFORE DELETE ON t1
+FOR EACH ROW
+SET @mysqltest_var = OLD.col;
+DROP TRIGGER t1_trg_err_2;
+CREATE TRIGGER t2_trg_before_insert BEFORE INSERT ON t2
+FOR EACH ROW
+SET NEW.col = 't2_trg_before_insert';
+CREATE TRIGGER t3_trg_err_1 BEFORE INSERT ON t3
+FOR EACH ROW
+SET @mysqltest_var = NEW.col;
+DROP TRIGGER t3_trg_err_1;
+CREATE TRIGGER t3_trg_err_2 BEFORE DELETE ON t3
+FOR EACH ROW
+SET @mysqltest_var = OLD.col;
+DROP TRIGGER t3_trg_err_2;
+CREATE TRIGGER t4_trg_before_insert BEFORE INSERT ON t4
+FOR EACH ROW
+SET NEW.col = 't4_trg_before_insert';
+
+---> connection: default
+use mysqltest_db1;
+REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
+REVOKE UPDATE ON mysqltest_db1.t2 FROM mysqltest_u1@localhost;
+GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
+GRANT SELECT ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
+REVOKE UPDATE(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost;
+REVOKE UPDATE(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost;
+GRANT SELECT(col) on mysqltest_db1.t3 TO mysqltest_u1@localhost;
+GRANT SELECT(col) on mysqltest_db1.t4 TO mysqltest_u1@localhost;
+
+---> connection: bug15166_u1_con
+use mysqltest_db1;
+CREATE TRIGGER t1_trg_after_insert AFTER INSERT ON t1
+FOR EACH ROW
+SET @mysqltest_var = NEW.col;
+CREATE TRIGGER t1_trg_after_update AFTER UPDATE ON t1
+FOR EACH ROW
+SET @mysqltest_var = OLD.col;
+CREATE TRIGGER t2_trg_err_1 BEFORE UPDATE ON t2
+FOR EACH ROW
+SET NEW.col = 't2_trg_err_1';
+DROP TRIGGER t2_trg_err_1;
+CREATE TRIGGER t2_trg_err_2 BEFORE UPDATE ON t2
+FOR EACH ROW
+SET NEW.col = CONCAT(OLD.col, '(updated)');
+DROP TRIGGER t2_trg_err_2;
+CREATE TRIGGER t3_trg_after_insert AFTER INSERT ON t3
+FOR EACH ROW
+SET @mysqltest_var = NEW.col;
+CREATE TRIGGER t3_trg_after_update AFTER UPDATE ON t3
+FOR EACH ROW
+SET @mysqltest_var = OLD.col;
+CREATE TRIGGER t4_trg_err_1 BEFORE UPDATE ON t4
+FOR EACH ROW
+SET NEW.col = 't4_trg_err_1';
+DROP TRIGGER t4_trg_err_1;
+CREATE TRIGGER t4_trg_err_2 BEFORE UPDATE ON t4
+FOR EACH ROW
+SET NEW.col = CONCAT(OLD.col, '(updated)');
+DROP TRIGGER t4_trg_err_2;
+
+---> connection: default
+use mysqltest_db1;
+REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
+REVOKE SELECT ON mysqltest_db1.t2 FROM mysqltest_u1@localhost;
+GRANT UPDATE ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
+GRANT UPDATE ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
+REVOKE SELECT(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost;
+REVOKE SELECT(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost;
+GRANT UPDATE(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost;
+GRANT UPDATE(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost;
+INSERT INTO t1 VALUES('line1');
+ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't1'
+SELECT * FROM t1;
+col
+line1
+SELECT @mysqltest_var;
+@mysqltest_var
+NULL
+INSERT INTO t2 VALUES('line2');
+SELECT * FROM t2;
+col
+t2_trg_before_insert
+INSERT INTO t3 VALUES('t3_line1');
+ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't3'
+SELECT * FROM t3;
+col
+t3_line1
+SELECT @mysqltest_var;
+@mysqltest_var
+NULL
+INSERT INTO t4 VALUES('t4_line2');
+SELECT * FROM t4;
+col
+t4_trg_before_insert
+
+---> connection: default
+use mysqltest_db1;
+REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
+REVOKE UPDATE ON mysqltest_db1.t2 FROM mysqltest_u1@localhost;
+GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
+GRANT SELECT ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
+REVOKE UPDATE(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost;
+REVOKE UPDATE(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost;
+GRANT SELECT(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost;
+GRANT SELECT(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost;
+INSERT INTO t1 VALUES('line3');
+SELECT * FROM t1;
+col
+line1
+line3
+SELECT @mysqltest_var;
+@mysqltest_var
+line3
+INSERT INTO t2 VALUES('line4');
+ERROR 42000: UPDATE command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't2'
+SELECT * FROM t2;
+col
+t2_trg_before_insert
+INSERT INTO t3 VALUES('t3_line2');
+SELECT * FROM t3;
+col
+t3_line1
+t3_line2
+SELECT @mysqltest_var;
+@mysqltest_var
+t3_line2
+INSERT INTO t4 VALUES('t4_line2');
+ERROR 42000: UPDATE command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't4'
+SELECT * FROM t4;
+col
+t4_trg_before_insert
+DELETE FROM t1;
+SELECT @mysqltest_var;
+@mysqltest_var
+Hello, world!
+DROP USER mysqltest_u1@localhost;
+DROP DATABASE mysqltest_db1;
diff --git a/mysql-test/t/trigger-grant.test b/mysql-test/t/trigger-grant.test
index deeaeacbccc..e28bf44a2cc 100644
--- a/mysql-test/t/trigger-grant.test
+++ b/mysql-test/t/trigger-grant.test
@@ -8,8 +8,6 @@
#
# Tests for WL#2818:
# - Check that triggers are executed under the authorization of the definer.
-# - Check that if trigger contains NEW/OLD variables, the definer must have
-# SELECT privilege on the subject table.
# - Check DEFINER clause of CREATE TRIGGER statement;
# - Check that SUPER privilege required to create a trigger with different
# definer.
@@ -18,6 +16,8 @@
# - Check that the definer of a trigger does not exist, the trigger will
# not be activated.
# - Check that SHOW TRIGGERS statement provides "Definer" column.
+# - Check that if trigger contains NEW/OLD variables, the definer must have
+# SELECT privilege on the subject table (aka BUG#15166/BUG#15196).
#
# Let's also check that user name part of definer can contain '@' symbol (to
# check that triggers are not affected by BUG#13310 "incorrect user parsing
@@ -143,28 +143,28 @@ SELECT * FROM t1;
SELECT * FROM t2;
#
-# Check that if trigger contains NEW/OLD variables, the definer must have
-# SELECT/UPDATE privilege on the subject table:
-# - drop the trigger;
-# - create a new trigger, which will use NEW variable;
-# - create another new trigger, which will use OLD variable;
-# - revoke SELECT/UPDATE privilege on the first table from "definer";
-# - insert a row into the first table;
-# - analyze error code;
+# Check DEFINER clause of CREATE TRIGGER statement.
#
-
+# NOTE: there is no dedicated TRIGGER privilege for CREATE TRIGGER statement.
+# SUPER privilege is used instead. I.e., if one invokes CREATE TRIGGER, it should
+# have SUPER privilege, so this test is meaningless right now.
#
-# SELECT privilege.
+# - Check that SUPER privilege required to create a trigger with different
+# definer:
+# - try to create a trigger with DEFINER="definer@localhost" under
+# "invoker";
+# - analyze error code;
+# - Check that if the user specified as DEFINER does not exist, a warning is
+# emitted:
+# - create a trigger with DEFINER="non_existent_user@localhost" from
+# "definer";
+# - check that a warning emitted;
+# - Check that the definer of a trigger does not exist, the trigger will not
+# be activated:
+# - activate just created trigger;
+# - check error code;
#
---connection default
---echo
---echo ---> connection: default
-
-use mysqltest_db1;
-
-REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost;
-
--connection wl2818_definer_con
--echo
--echo ---> connection: wl2818_definer_con
@@ -173,95 +173,137 @@ use mysqltest_db1;
DROP TRIGGER trg1;
-SET @new_sum = 0;
-SET @old_sum = 0;
+# Check that SUPER is required to specify different DEFINER.
+# NOTE: meaningless at the moment
-# INSERT INTO statement; BEFORE timing
+CREATE DEFINER='mysqltest_inv'@'localhost'
+ TRIGGER trg1 BEFORE INSERT ON t1
+ FOR EACH ROW
+ SET @new_sum = 0;
---echo ---> INSERT INTO statement; BEFORE timing
+# Create with non-existent user.
-CREATE TRIGGER trg1 BEFORE INSERT ON t1
+CREATE DEFINER='mysqltest_nonexs'@'localhost'
+ TRIGGER trg2 AFTER INSERT ON t1
FOR EACH ROW
- SET @new_sum = @new_sum + NEW.num_value;
+ SET @new_sum = 0;
---error ER_TABLEACCESS_DENIED_ERROR
-INSERT INTO t1 VALUES(4);
+# Check that trg2 will not be activated.
-# INSERT INTO statement; AFTER timing
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO t1 VALUES(6);
---echo ---> INSERT INTO statement; AFTER timing
+#
+# Check that SHOW TRIGGERS statement provides "Definer" column.
+#
+
+SHOW TRIGGERS;
+
+#
+# Check that weird definer values do not break functionality. I.e. check the
+# following definer values:
+# - '';
+# - '@';
+# - '@abc@def@@';
+# - '@hostname';
+# - '@abc@def@@@hostname';
+#
DROP TRIGGER trg1;
+DROP TRIGGER trg2;
-CREATE TRIGGER trg1 AFTER INSERT ON t1
+CREATE TRIGGER trg1 BEFORE INSERT ON t1
FOR EACH ROW
- SET @new_sum = @new_sum + NEW.num_value;
-
---error ER_TABLEACCESS_DENIED_ERROR
-INSERT INTO t1 VALUES(5);
+ SET @a = 1;
-# UPDATE statement; BEFORE timing
+CREATE TRIGGER trg2 AFTER INSERT ON t1
+ FOR EACH ROW
+ SET @a = 2;
---echo ---> UPDATE statement; BEFORE timing
+CREATE TRIGGER trg3 BEFORE UPDATE ON t1
+ FOR EACH ROW
+ SET @a = 3;
-DROP TRIGGER trg1;
+CREATE TRIGGER trg4 AFTER UPDATE ON t1
+ FOR EACH ROW
+ SET @a = 4;
-CREATE TRIGGER trg1 BEFORE UPDATE ON t1
+CREATE TRIGGER trg5 BEFORE DELETE ON t1
FOR EACH ROW
- SET @old_sum = @old_sum + OLD.num_value;
+ SET @a = 5;
---error ER_TABLEACCESS_DENIED_ERROR
-UPDATE t1 SET num_value = 10;
+--exec egrep -v '^definers=' $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG > $MYSQL_TEST_DIR/var/tmp/t1.TRG
+--exec echo "definers='' '@' '@abc@def@@' '@hostname' '@abcdef@@@hostname'" >> $MYSQL_TEST_DIR/var/tmp/t1.TRG
+--exec mv $MYSQL_TEST_DIR/var/tmp/t1.TRG $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG
-# UPDATE statement; AFTER timing
+--echo
---echo ---> UPDATE statement; AFTER timing
+SELECT trigger_name, definer FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name;
-DROP TRIGGER trg1;
+--echo
-CREATE TRIGGER trg1 AFTER UPDATE ON t1
- FOR EACH ROW
- SET @new_sum = @new_sum + NEW.num_value;
+SELECT * FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name;
---error ER_TABLEACCESS_DENIED_ERROR
-UPDATE t1 SET num_value = 20;
+#
+# Cleanup
+#
-# DELETE statement; BEFORE timing
+--connection default
+--echo
+--echo ---> connection: default
---echo ---> DELETE statement; BEFORE timing
+DROP USER mysqltest_dfn@localhost;
+DROP USER mysqltest_inv@localhost;
-DROP TRIGGER trg1;
+DROP DATABASE mysqltest_db1;
-CREATE TRIGGER trg1 BEFORE DELETE ON t1
- FOR EACH ROW
- SET @old_sum = @old_sum + OLD.num_value;
+###########################################################################
+#
+# BUG#15166: Wrong update [was: select/update] permissions required to execute
+# triggers.
+#
+# BUG#15196: Wrong select permission required to execute triggers.
+#
+###########################################################################
---error ER_TABLEACCESS_DENIED_ERROR
-DELETE FROM t1;
+#
+# Prepare environment.
+#
-# DELETE statement; AFTER timing
+DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%';
+DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%';
+DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%';
+DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%';
+FLUSH PRIVILEGES;
---echo ---> DELETE statement; AFTER timing
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest_db1;
+--enable_warnings
-DROP TRIGGER trg1;
+CREATE DATABASE mysqltest_db1;
-CREATE TRIGGER trg1 AFTER DELETE ON t1
- FOR EACH ROW
- SET @old_sum = @old_sum + OLD.num_value;
+use mysqltest_db1;
---error ER_TABLEACCESS_DENIED_ERROR
-DELETE FROM t1;
+# Tables for tesing table-level privileges:
+CREATE TABLE t1(col CHAR(20)); # table for "read-value" trigger
+CREATE TABLE t2(col CHAR(20)); # table for "write-value" trigger
-#
-# UPDATE privilege
-#
-# NOTE: At the moment, UPDATE privilege is required if the trigger contains
-# NEW/OLD variables, whenever the trigger modifies them or not. Moreover,
-# UPDATE privilege is checked for whole table, not for individual columns.
-#
-# The following test cases should be changed when full support of UPDATE
-# privilege will be done.
-#
+# Tables for tesing column-level privileges:
+CREATE TABLE t3(col CHAR(20)); # table for "read-value" trigger
+CREATE TABLE t4(col CHAR(20)); # table for "write-value" trigger
+
+CREATE USER mysqltest_u1@localhost;
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_u1@localhost;
+GRANT SUPER ON *.* TO mysqltest_u1@localhost;
+GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost; # to allow connect
+
+SET @mysqltest_var = NULL;
+
+--connect (bug15166_u1_con,localhost,mysqltest_u1,,mysqltest_db1)
+
+# parsing (CREATE TRIGGER) time:
+# - check that nor SELECT either UPDATE is required to execute triggger w/o
+# NEW/OLD variables.
--connection default
--echo
@@ -269,207 +311,256 @@ DELETE FROM t1;
use mysqltest_db1;
-GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_dfn@localhost;
-REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost;
+REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
+GRANT DELETE ON mysqltest_db1.* TO mysqltest_u1@localhost;
+SHOW GRANTS FOR mysqltest_u1@localhost;
---connection wl2818_definer_con
+--connection bug15166_u1_con
--echo
---echo ---> connection: wl2818_definer_con
+--echo ---> connection: bug15166_u1_con
use mysqltest_db1;
-DROP TRIGGER trg1;
+CREATE TRIGGER t1_trg_after_delete AFTER DELETE ON t1
+ FOR EACH ROW
+ SET @mysqltest_var = 'Hello, world!';
-SET @new_sum = 0;
-SET @old_sum = 0;
+# parsing (CREATE TRIGGER) time:
+# - check that UPDATE is not enough to read the value;
+# - check that UPDATE is required to modify the value;
-# INSERT INTO statement; BEFORE timing
+--connection default
+--echo
+--echo ---> connection: default
---echo ---> INSERT INTO statement; BEFORE timing
+use mysqltest_db1;
-CREATE TRIGGER trg1 BEFORE INSERT ON t1
- FOR EACH ROW
- SET @new_sum = @new_sum + NEW.num_value;
+GRANT UPDATE ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
+GRANT UPDATE ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
---error ER_TABLEACCESS_DENIED_ERROR
-INSERT INTO t1 VALUES(4);
+GRANT UPDATE(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost;
+GRANT UPDATE(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost;
-# INSERT INTO statement; AFTER timing
+--connection bug15166_u1_con
+--echo
+--echo ---> connection: bug15166_u1_con
---echo ---> INSERT INTO statement; AFTER timing
+use mysqltest_db1;
-DROP TRIGGER trg1;
+# - table-level privileges
-CREATE TRIGGER trg1 AFTER INSERT ON t1
+# TODO: check privileges at CREATE TRIGGER time.
+# --error ER_COLUMNACCESS_DENIED_ERROR
+CREATE TRIGGER t1_trg_err_1 BEFORE INSERT ON t1
FOR EACH ROW
- SET @new_sum = @new_sum + NEW.num_value;
+ SET @mysqltest_var = NEW.col;
+DROP TRIGGER t1_trg_err_1;
---error ER_TABLEACCESS_DENIED_ERROR
-INSERT INTO t1 VALUES(5);
+# TODO: check privileges at CREATE TRIGGER time.
+# --error ER_COLUMNACCESS_DENIED_ERROR
+CREATE TRIGGER t1_trg_err_2 BEFORE DELETE ON t1
+ FOR EACH ROW
+ SET @mysqltest_var = OLD.col;
+DROP TRIGGER t1_trg_err_2;
-# UPDATE statement; BEFORE timing
+CREATE TRIGGER t2_trg_before_insert BEFORE INSERT ON t2
+ FOR EACH ROW
+ SET NEW.col = 't2_trg_before_insert';
---echo ---> UPDATE statement; BEFORE timing
+# - column-level privileges
-DROP TRIGGER trg1;
+# TODO: check privileges at CREATE TRIGGER time.
+# --error ER_COLUMNACCESS_DENIED_ERROR
+CREATE TRIGGER t3_trg_err_1 BEFORE INSERT ON t3
+ FOR EACH ROW
+ SET @mysqltest_var = NEW.col;
+DROP TRIGGER t3_trg_err_1;
-CREATE TRIGGER trg1 BEFORE UPDATE ON t1
+# TODO: check privileges at CREATE TRIGGER time.
+# --error ER_COLUMNACCESS_DENIED_ERROR
+CREATE TRIGGER t3_trg_err_2 BEFORE DELETE ON t3
FOR EACH ROW
- SET @old_sum = @old_sum + OLD.num_value;
+ SET @mysqltest_var = OLD.col;
+DROP TRIGGER t3_trg_err_2;
---error ER_TABLEACCESS_DENIED_ERROR
-UPDATE t1 SET num_value = 10;
+CREATE TRIGGER t4_trg_before_insert BEFORE INSERT ON t4
+ FOR EACH ROW
+ SET NEW.col = 't4_trg_before_insert';
-# UPDATE statement; AFTER timing
+# parsing (CREATE TRIGGER) time:
+# - check that SELECT is required to read the value;
+# - check that SELECT is not enough to modify the value;
---echo ---> UPDATE statement; AFTER timing
+--connection default
+--echo
+--echo ---> connection: default
-DROP TRIGGER trg1;
+use mysqltest_db1;
-CREATE TRIGGER trg1 AFTER UPDATE ON t1
- FOR EACH ROW
- SET @new_sum = @new_sum + NEW.num_value;
+REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
+REVOKE UPDATE ON mysqltest_db1.t2 FROM mysqltest_u1@localhost;
+GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
+GRANT SELECT ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
---error ER_TABLEACCESS_DENIED_ERROR
-UPDATE t1 SET num_value = 20;
+REVOKE UPDATE(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost;
+REVOKE UPDATE(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost;
+GRANT SELECT(col) on mysqltest_db1.t3 TO mysqltest_u1@localhost;
+GRANT SELECT(col) on mysqltest_db1.t4 TO mysqltest_u1@localhost;
-# DELETE statement; BEFORE timing
+--connection bug15166_u1_con
+--echo
+--echo ---> connection: bug15166_u1_con
---echo ---> DELETE statement; BEFORE timing
+use mysqltest_db1;
-DROP TRIGGER trg1;
+# - table-level privileges
-CREATE TRIGGER trg1 BEFORE DELETE ON t1
- FOR EACH ROW
- SET @old_sum = @old_sum + OLD.num_value;
+CREATE TRIGGER t1_trg_after_insert AFTER INSERT ON t1
+ FOR EACH ROW
+ SET @mysqltest_var = NEW.col;
---error ER_TABLEACCESS_DENIED_ERROR
-DELETE FROM t1;
+CREATE TRIGGER t1_trg_after_update AFTER UPDATE ON t1
+ FOR EACH ROW
+ SET @mysqltest_var = OLD.col;
-# DELETE statement; AFTER timing
+# TODO: check privileges at CREATE TRIGGER time.
+# --error ER_COLUMNACCESS_DENIED_ERROR
+CREATE TRIGGER t2_trg_err_1 BEFORE UPDATE ON t2
+ FOR EACH ROW
+ SET NEW.col = 't2_trg_err_1';
+DROP TRIGGER t2_trg_err_1;
---echo ---> DELETE statement; AFTER timing
+# TODO: check privileges at CREATE TRIGGER time.
+# --error ER_COLUMNACCESS_DENIED_ERROR
+CREATE TRIGGER t2_trg_err_2 BEFORE UPDATE ON t2
+ FOR EACH ROW
+ SET NEW.col = CONCAT(OLD.col, '(updated)');
+DROP TRIGGER t2_trg_err_2;
-DROP TRIGGER trg1;
+# - column-level privileges
-CREATE TRIGGER trg1 AFTER DELETE ON t1
+CREATE TRIGGER t3_trg_after_insert AFTER INSERT ON t3
FOR EACH ROW
- SET @old_sum = @old_sum + OLD.num_value;
-
---error ER_TABLEACCESS_DENIED_ERROR
-DELETE FROM t1;
+ SET @mysqltest_var = NEW.col;
-#
-# Check DEFINER clause of CREATE TRIGGER statement.
-#
-# NOTE: there is no dedicated TRIGGER privilege for CREATE TRIGGER statement.
-# SUPER privilege is used instead. I.e., if one invokes CREATE TRIGGER, it should
-# have SUPER privilege, so this test is meaningless right now.
-#
-# - Check that SUPER privilege required to create a trigger with different
-# definer:
-# - try to create a trigger with DEFINER="definer@localhost" under
-# "invoker";
-# - analyze error code;
-# - Check that if the user specified as DEFINER does not exist, a warning is
-# emitted:
-# - create a trigger with DEFINER="non_existent_user@localhost" from
-# "definer";
-# - check that a warning emitted;
-# - Check that the definer of a trigger does not exist, the trigger will not
-# be activated:
-# - activate just created trigger;
-# - check error code;
-#
+CREATE TRIGGER t3_trg_after_update AFTER UPDATE ON t3
+ FOR EACH ROW
+ SET @mysqltest_var = OLD.col;
+
+# TODO: check privileges at CREATE TRIGGER time.
+# --error ER_COLUMNACCESS_DENIED_ERROR
+CREATE TRIGGER t4_trg_err_1 BEFORE UPDATE ON t4
+ FOR EACH ROW
+ SET NEW.col = 't4_trg_err_1';
+DROP TRIGGER t4_trg_err_1;
+
+# TODO: check privileges at CREATE TRIGGER time.
+# --error ER_COLUMNACCESS_DENIED_ERROR
+CREATE TRIGGER t4_trg_err_2 BEFORE UPDATE ON t4
+ FOR EACH ROW
+ SET NEW.col = CONCAT(OLD.col, '(updated)');
+DROP TRIGGER t4_trg_err_2;
+
+# execution time:
+# - check that UPDATE is not enough to read the value;
+# - check that UPDATE is required to modify the value;
---connection wl2818_definer_con
+--connection default
--echo
---echo ---> connection: wl2818_definer_con
+--echo ---> connection: default
use mysqltest_db1;
-DROP TRIGGER trg1;
+REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
+REVOKE SELECT ON mysqltest_db1.t2 FROM mysqltest_u1@localhost;
+GRANT UPDATE ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
+GRANT UPDATE ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
-# Check that SUPER is required to specify different DEFINER.
-# NOTE: meaningless at the moment
+REVOKE SELECT(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost;
+REVOKE SELECT(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost;
+GRANT UPDATE(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost;
+GRANT UPDATE(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost;
-CREATE DEFINER='mysqltest_inv'@'localhost'
- TRIGGER trg1 BEFORE INSERT ON t1
- FOR EACH ROW
- SET @new_sum = 0;
+# - table-level privileges
-# Create with non-existent user.
+--error ER_COLUMNACCESS_DENIED_ERROR
+INSERT INTO t1 VALUES('line1');
-CREATE DEFINER='mysqltest_nonexs'@'localhost'
- TRIGGER trg2 AFTER INSERT ON t1
- FOR EACH ROW
- SET @new_sum = 0;
+SELECT * FROM t1;
+SELECT @mysqltest_var;
-# Check that trg2 will not be activated.
+INSERT INTO t2 VALUES('line2');
---error ER_SPECIFIC_ACCESS_DENIED_ERROR
-INSERT INTO t1 VALUES(6);
+SELECT * FROM t2;
-#
-# Check that SHOW TRIGGERS statement provides "Definer" column.
-#
+# - column-level privileges
-SHOW TRIGGERS;
+--error ER_COLUMNACCESS_DENIED_ERROR
+INSERT INTO t3 VALUES('t3_line1');
-#
-# Check that weird definer values do not break functionality. I.e. check the
-# following definer values:
-# - '';
-# - '@';
-# - '@abc@def@@';
-# - '@hostname';
-# - '@abc@def@@@hostname';
-#
+SELECT * FROM t3;
+SELECT @mysqltest_var;
-DROP TRIGGER trg1;
-DROP TRIGGER trg2;
+INSERT INTO t4 VALUES('t4_line2');
-CREATE TRIGGER trg1 BEFORE INSERT ON t1
- FOR EACH ROW
- SET @a = 1;
+SELECT * FROM t4;
-CREATE TRIGGER trg2 AFTER INSERT ON t1
- FOR EACH ROW
- SET @a = 2;
+# execution time:
+# - check that SELECT is required to read the value;
+# - check that SELECT is not enough to modify the value;
-CREATE TRIGGER trg3 BEFORE UPDATE ON t1
- FOR EACH ROW
- SET @a = 3;
+--connection default
+--echo
+--echo ---> connection: default
-CREATE TRIGGER trg4 AFTER UPDATE ON t1
- FOR EACH ROW
- SET @a = 4;
+use mysqltest_db1;
-CREATE TRIGGER trg5 BEFORE DELETE ON t1
- FOR EACH ROW
- SET @a = 5;
+REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
+REVOKE UPDATE ON mysqltest_db1.t2 FROM mysqltest_u1@localhost;
+GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
+GRANT SELECT ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
---exec egrep -v '^definers=' $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG > $MYSQL_TEST_DIR/var/tmp/t1.TRG
---exec echo "definers='' '@' '@abc@def@@' '@hostname' '@abcdef@@@hostname'" >> $MYSQL_TEST_DIR/var/tmp/t1.TRG
---exec mv $MYSQL_TEST_DIR/var/tmp/t1.TRG $MYSQL_TEST_DIR/var/master-data/mysqltest_db1/t1.TRG
+REVOKE UPDATE(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost;
+REVOKE UPDATE(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost;
+GRANT SELECT(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost;
+GRANT SELECT(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost;
---echo
+# - table-level privileges
-SELECT trigger_name, definer FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name;
+INSERT INTO t1 VALUES('line3');
---echo
+SELECT * FROM t1;
+SELECT @mysqltest_var;
-SELECT * FROM INFORMATION_SCHEMA.TRIGGERS ORDER BY trigger_name;
+--error ER_COLUMNACCESS_DENIED_ERROR
+INSERT INTO t2 VALUES('line4');
+
+SELECT * FROM t2;
+
+# - column-level privileges
+
+INSERT INTO t3 VALUES('t3_line2');
+
+SELECT * FROM t3;
+SELECT @mysqltest_var;
+
+--error ER_COLUMNACCESS_DENIED_ERROR
+INSERT INTO t4 VALUES('t4_line2');
+
+SELECT * FROM t4;
+
+# execution time:
+# - check that nor SELECT either UPDATE is required to execute triggger w/o
+# NEW/OLD variables.
+
+DELETE FROM t1;
+
+SELECT @mysqltest_var;
#
-# Cleanup
+# Cleanup.
#
---connection default
---echo
---echo ---> connection: default
-
-DROP USER mysqltest_dfn@localhost;
-DROP USER mysqltest_inv@localhost;
+DROP USER mysqltest_u1@localhost;
DROP DATABASE mysqltest_db1;
diff --git a/sql/item.cc b/sql/item.cc
index 45a23322ef2..70fea63ba7e 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -5215,6 +5215,7 @@ void Item_insert_value::print(String *str)
setup_field()
thd - current thread context
table - table of trigger (and where we looking for fields)
+ table_grant_info - GRANT_INFO of the subject table
NOTE
This function does almost the same as fix_fields() for Item_field
@@ -5228,7 +5229,8 @@ void Item_insert_value::print(String *str)
table of trigger which uses this item.
*/
-void Item_trigger_field::setup_field(THD *thd, TABLE *table)
+void Item_trigger_field::setup_field(THD *thd, TABLE *table,
+ GRANT_INFO *table_grant_info)
{
bool save_set_query_id= thd->set_query_id;
@@ -5242,6 +5244,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table)
0, &field_idx);
thd->set_query_id= save_set_query_id;
triggers= table->triggers;
+ table_grants= table_grant_info;
}
@@ -5260,22 +5263,42 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items)
Since trigger is object tightly associated with TABLE object most
of its set up can be performed during trigger loading i.e. trigger
parsing! So we have little to do in fix_fields. :)
- FIXME may be we still should bother about permissions here.
*/
+
DBUG_ASSERT(fixed == 0);
+ /* Set field. */
+
if (field_idx != (uint)-1)
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ Check access privileges for the subject table. We check privileges only
+ in runtime.
+ */
+
+ if (table_grants)
+ {
+ table_grants->want_privilege=
+ access_type == AT_READ ? SELECT_ACL : UPDATE_ACL;
+
+ if (check_grant_column(thd, table_grants, triggers->table->s->db,
+ triggers->table->s->table_name, field_name,
+ strlen(field_name), thd->security_ctx))
+ return TRUE;
+ }
+#endif // NO_EMBEDDED_ACCESS_CHECKS
+
field= (row_version == OLD_ROW) ? triggers->old_field[field_idx] :
triggers->new_field[field_idx];
set_field(field);
fixed= 1;
- return 0;
+ return FALSE;
}
my_error(ER_BAD_FIELD_ERROR, MYF(0), field_name,
(row_version == NEW_ROW) ? "NEW" : "OLD");
- return 1;
+ return TRUE;
}
diff --git a/sql/item.h b/sql/item.h
index eee9bc5b284..af42ce38b9b 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -2126,6 +2126,8 @@ public:
/* Is this item represents row from NEW or OLD row ? */
enum row_version_type {OLD_ROW, NEW_ROW};
row_version_type row_version;
+ /* Is this item used for reading or updating the value? */
+ enum access_types { AT_READ = 0x1, AT_UPDATE = 0x2 };
/* Next in list of all Item_trigger_field's in trigger */
Item_trigger_field *next_trg_field;
/* Index of the field in the TABLE::field array */
@@ -2135,18 +2137,24 @@ public:
Item_trigger_field(Name_resolution_context *context_arg,
row_version_type row_ver_arg,
- const char *field_name_arg)
+ const char *field_name_arg,
+ access_types access_type_arg)
:Item_field(context_arg,
(const char *)NULL, (const char *)NULL, field_name_arg),
- row_version(row_ver_arg), field_idx((uint)-1)
+ row_version(row_ver_arg), field_idx((uint)-1),
+ access_type(access_type_arg), table_grants(NULL)
{}
- void setup_field(THD *thd, TABLE *table);
+ void setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info);
enum Type type() const { return TRIGGER_FIELD_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, Item **);
void print(String *str);
table_map used_tables() const { return (table_map)0L; }
void cleanup();
+
+private:
+ access_types access_type;
+ GRANT_INFO *table_grants;
};
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index c70914edc31..53743314782 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -381,7 +381,12 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
for (trg_field= (Item_trigger_field *)(lex->trg_table_fields.first);
trg_field; trg_field= trg_field->next_trg_field)
{
- trg_field->setup_field(thd, table);
+ /*
+ NOTE: now we do not check privileges at CREATE TRIGGER time. This will
+ be changed in the future.
+ */
+ trg_field->setup_field(thd, table, NULL);
+
if (!trg_field->fixed &&
trg_field->fix_fields(thd, (Item **)0))
return 1;
@@ -828,8 +833,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
char *trg_name_buff;
List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
- List_iterator_fast<LEX_STRING> it_definer(triggers->
- definers_list);
+ List_iterator_fast<LEX_STRING> it_definer(triggers->definers_list);
LEX *old_lex= thd->lex, lex;
sp_rcontext *save_spcont= thd->spcont;
ulong save_sql_mode= thd->variables.sql_mode;
@@ -844,6 +848,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
{
trg_sql_mode= itm++;
LEX_STRING *trg_definer= it_definer++;
+
thd->variables.sql_mode= (ulong)*trg_sql_mode;
lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length);
@@ -917,11 +922,11 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
(Item_trigger_field *)(lex.trg_table_fields.first);
trg_field;
trg_field= trg_field->next_trg_field)
- trg_field->setup_field(thd, table);
-
- triggers->m_spec_var_used[lex.trg_chistics.event]
- [lex.trg_chistics.action_time]=
- lex.trg_table_fields.first ? TRUE : FALSE;
+ {
+ trg_field->setup_field(thd, table,
+ &triggers->subject_table_grants[lex.trg_chistics.event]
+ [lex.trg_chistics.action_time]);
+ }
lex_end(&lex);
}
@@ -1172,33 +1177,14 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
}
/*
- If the trigger uses special variables (NEW/OLD), check that we have
- SELECT and UPDATE privileges on the subject table.
+ Fetch information about table-level privileges to GRANT_INFO structure for
+ subject table. Check of privileges that will use it and information about
+ column-level privileges will happen in Item_trigger_field::fix_fields().
*/
-
- if (is_special_var_used(event, time_type))
- {
- TABLE_LIST table_list, **save_query_tables_own_last;
- bzero((char *) &table_list, sizeof (table_list));
- table_list.db= (char *) table->s->db;
- table_list.db_length= strlen(table_list.db);
- table_list.table_name= (char *) table->s->table_name;
- table_list.table_name_length= strlen(table_list.table_name);
- table_list.alias= (char *) table->alias;
- table_list.table= table;
- save_query_tables_own_last= thd->lex->query_tables_own_last;
- thd->lex->query_tables_own_last= 0;
-
- err_status= check_table_access(thd, SELECT_ACL | UPDATE_ACL,
- &table_list, 0);
- thd->lex->query_tables_own_last= save_query_tables_own_last;
- if (err_status)
- {
- sp_restore_security_context(thd, save_ctx);
- return TRUE;
- }
- }
-
+
+ fill_effective_table_privileges(thd,
+ &subject_table_grants[event][time_type],
+ table->s->db, table->s->table_name);
#endif // NO_EMBEDDED_ACCESS_CHECKS
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 51002683897..8992de63b37 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -56,10 +56,9 @@ class Table_triggers_list: public Sql_alloc
LEX_STRING sroutines_key;
/*
- is_special_var_used specifies whether trigger body contains special
- variables (NEW/OLD).
+ Grant information for each trigger (pair: subject table, trigger definer).
*/
- bool m_spec_var_used[TRG_EVENT_MAX][TRG_ACTION_MAX];
+ GRANT_INFO subject_table_grants[TRG_EVENT_MAX][TRG_ACTION_MAX];
public:
/*
@@ -78,6 +77,7 @@ public:
record1_field(0), table(table_arg)
{
bzero((char *)bodies, sizeof(bodies));
+ bzero((char *)&subject_table_grants, sizeof(subject_table_grants));
}
~Table_triggers_list();
@@ -109,11 +109,6 @@ public:
return test(bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]);
}
- inline bool is_special_var_used(int event, int action_time) const
- {
- return m_spec_var_used[event][action_time];
- }
-
void set_table(TABLE *new_table);
friend class Item_trigger_field;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 41552100264..0ef389950fc 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -7303,7 +7303,8 @@ simple_ident_q:
new_row ?
Item_trigger_field::NEW_ROW:
Item_trigger_field::OLD_ROW,
- $3.str)))
+ $3.str,
+ Item_trigger_field::AT_READ)))
YYABORT;
/*
@@ -7929,7 +7930,9 @@ sys_option_value:
if (!(trg_fld= new Item_trigger_field(Lex->current_context(),
Item_trigger_field::NEW_ROW,
- $2.base_name.str)) ||
+ $2.base_name.str,
+ Item_trigger_field::AT_UPDATE)
+ ) ||
!(sp_fld= new sp_instr_set_trigger_field(lex->sphead->
instructions(),
lex->spcont,