お題
- トリガーってどの権限で動くんだっけ? 定義したユーザの権限? トリガーを引いたユーザの権限?
- プロシージャと違って、SQL SECURITY の指定がない
TLDR;
- トリガーはDEFINERに指定したユーザで動作する
- DEFINERをナシにすることはできない、省略した場合はCREATE TRIGGERを実行したユーザがDEFINERに入る
- SQL SECURITYは指定できない。トリガーを引いたユーザで、トリガーを実行することはできない。DEFINERで指定したユーザで必ず実行される
- SUPERを持っているのに、read_onlyのDBに書き込めない場合は、トリガーを疑うべし
試します
適当にテーブルを作ります。
-- トリガーを仕掛けるテーブル mysql> CREATE TABLE tbl_p (pk SERIAL PRIMARY KEY, var1 VARCHAR(100), updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP); Query OK, 0 rows affected (0.02 sec) -- トリガーによって更新するテーブル mysql> CREATE TABLE tbl_c (pk SERIAL PRIMARY KEY, triggered_by VARCHAR(100), updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP); Query OK, 0 rows affected (0.02 sec)
tbl_p に行をINSERTすると、tbl_c に行をINSERTするトリガーを作ります。
このときに、triggered_by カラムにどのユーザで実行されたかを INSERT INTO tbl_c (triggered_by) VALUES(CURRENT_USER()) のようにして、記録しておきます。
delimiter //
CREATE TRIGGER trg_t BEFORE INSERT ON tbl_p
FOR EACH ROW
BEGIN
INSERT INTO tbl_c (triggered_by) VALUES(CURRENT_USER());
END; //
delimiter ;
mysql> SHOW CREATE TRIGGER t.trg_t \G
*************************** 1. row ***************************
Trigger: trg_t
sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
SQL Original Statement: CREATE DEFINER=`user1`@`%` TRIGGER `trg_t` BEFORE INSERT ON `tbl_p` FOR EACH ROW BEGIN
INSERT INTO tbl_c (triggered_by) VALUES(CURRENT_USER());
END
character_set_client: utf8mb4
collation_connection: utf8mb4_0900_ai_ci
Database Collation: utf8mb4_general_ci
Created: 2020-03-06 16:16:50.90
1 row in set (0.00 sec)
DEFINERを省略すると、CREATE TRIGGERを実行したユーザがDEFINERとなりますね。 DEFINERを省略するということはできないようです。
トリガーの動作確認。トリガーがDEFINERの user1 で動作することが確認できました。
mysql> INSERT INTO tbl_p (var1) VALUES('test');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tbl_c;
+----+--------------+---------------------+
| pk | triggered_by | updated_at |
+----+--------------+---------------------+
| 1 | user1@% | 2020-03-06 16:18:53 |
+----+--------------+---------------------+
1 row in set (0.00 sec)
念の為、root でトリガーを引いてみます。 root でトリガーを引いても、user1の権限で tbl_c に INSERTが行われたことが分かりました。
mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
mysql> INSERT INTO tbl_p (var1) VALUES('test');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM tbl_c;
+----+--------------+---------------------+
| pk | triggered_by | updated_at |
+----+--------------+---------------------+
| 1 | user1@% | 2020-03-06 16:18:53 |
| 2 | user1@% | 2020-03-06 16:19:27 |
+----+--------------+---------------------+
2 rows in set (0.00 sec)
read only のときの挙動
read_only でも SUPER 権限があれば書き込むことができます。 しかし、上述のようにTRIGGERはDEFINERの権限で動作するため、read_only状態でトリガーのある書き込もうとすると、エラーとなります。
mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
-- トリガーのないテーブルには書き込める
mysql> INSERT INTO tx1 VALUES(1);
Query OK, 1 row affected (0.01 sec)
-- superを持たないユーザが作ったトリガーがあると書き込めない
mysql> INSERT INTO tbl_p (var1) VALUES('I am super');
ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement