在 Informix 中跳过特定用户的触发器
Skip a Trigger for a Specific User in Informix
当特定数据库用户通过 运行 脚本进行更改时是否可以绕过触发器?
在 Informix 触发器的 when 子句中,我们可以这样做吗:
CREATE TRIGGER trigger_name
update on table_name
referencing old as olddata new as newdata
for each row when(USER <> 'a specific database user')
(…triggered actions…)
关于 Informix 12.10 的文档 CREATE TRIGGER eventually leads to the WHEN condition 描述。
只要您可以预测何时创建触发器,哪些用户不应触发该操作,您就应该能够编写类似 WHEN (USER != 'exempt')
的内容,但要让它发挥作用会更难动态地。您可能能够在 WHEN 条件中调用存储过程,以评估当前用户当前是否免于触发操作。除了在 WHEN 条件下或作为触发操作使用存储过程之外,它可能无法有意义地完成。
概念验证
架构和触发器
DROP TABLE IF EXISTS trigger_test;
CREATE TABLE trigger_test
(
s SERIAL NOT NULL PRIMARY KEY,
t DATETIME YEAR TO SECOND NOT NULL DEFAULT CURRENT YEAR TO SECOND,
v VARCHAR(64) NOT NULL
);
DROP TABLE IF EXISTS trigger_log;
CREATE TABLE trigger_log
(
log_id SERIAL NOT NULL PRIMARY KEY,
old_s INTEGER NOT NULL,
old_t DATETIME YEAR TO SECOND NOT NULL,
new_t DATETIME YEAR TO SECOND NOT NULL,
old_v VARCHAR(64) NOT NULL,
new_v VARCHAR(64) NOT NULL,
log_t DATETIME YEAR TO SECOND NOT NULL DEFAULT CURRENT YEAR TO SECOND,
log_u VARCHAR(32) NOT NULL DEFAULT USER
);
CREATE TRIGGER skip_user
UPDATE ON trigger_test
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW WHEN(USER != 'informix')
(INSERT INTO trigger_log(old_s, old_t, new_t, old_v, new_v)
VALUES(old.s, old.t, new.t, old.v, new.v)
)
;
作为非 informix 用户的操作顺序
我正在使用我的 sqlcmd
程序(可从 ESQL 部分的 IIUG Software Archive 获得 — 它与 Microsoft 的同名 johnny-come-lately 程序截然不同)和自定义工具a6
切换为使用 informix
凭据(实际上类似于 su informix
或 sudo informix
)。
$ sqlcmd -d stores -xHTf user-action.sql
+ INSERT INTO trigger_test(v) VALUES("Hello");
+ SELECT * FROM trigger_test;
s|t|v
SERIAL|DATETIME YEAR TO SECOND|VARCHAR(64)
1|2019-12-19 17:04:04|Hello
+ SELECT * FROM trigger_log;
log_id|old_s|old_t|new_t|old_v|new_v|log_t|log_u
SERIAL|INTEGER|DATETIME YEAR TO SECOND|DATETIME YEAR TO SECOND|VARCHAR(64)|VARCHAR(64)|DATETIME YEAR TO SECOND|VARCHAR(32)
+ UPDATE trigger_test SET t = '2019-12-31 23:59:59', v = 'Farewell to 2019';
+ SELECT * FROM trigger_test;
s|t|v
SERIAL|DATETIME YEAR TO SECOND|VARCHAR(64)
1|2019-12-31 23:59:59|Farewell to 2019
+ SELECT * FROM trigger_log;
log_id|old_s|old_t|new_t|old_v|new_v|log_t|log_u
SERIAL|INTEGER|DATETIME YEAR TO SECOND|DATETIME YEAR TO SECOND|VARCHAR(64)|VARCHAR(64)|DATETIME YEAR TO SECOND|VARCHAR(32)
1|1|2019-12-19 17:04:04|2019-12-31 23:59:59|Hello|Farewell to 2019|2019-12-19 17:04:04|jonathanleffler
+ UPDATE trigger_test SET t = '2038-01-19 03:14:07', v = 'Farewell to 32-bit Unix time';
+ SELECT * FROM trigger_test;
s|t|v
SERIAL|DATETIME YEAR TO SECOND|VARCHAR(64)
1|2038-01-19 03:14:07|Farewell to 32-bit Unix time
+ SELECT * FROM trigger_log;
log_id|old_s|old_t|new_t|old_v|new_v|log_t|log_u
SERIAL|INTEGER|DATETIME YEAR TO SECOND|DATETIME YEAR TO SECOND|VARCHAR(64)|VARCHAR(64)|DATETIME YEAR TO SECOND|VARCHAR(32)
1|1|2019-12-19 17:04:04|2019-12-31 23:59:59|Hello|Farewell to 2019|2019-12-19 17:04:04|jonathanleffler
2|1|2019-12-31 23:59:59|2038-01-19 03:14:07|Farewell to 2019|Farewell to 32-bit Unix time|2019-12-19 17:04:04|jonathanleffler
$
如您所见,我执行的操作记录在 trigger_log
table.
作为用户 informix 的操作顺序
$ a6 sqlcmd -d stores -xHTf ifmx-action.sql
+ UPDATE trigger_test SET t = '2019-01-01 00:00:00', v = 'Welcome to the New Year 2019';
+ SELECT * FROM trigger_test;
s|t|v
SERIAL|DATETIME YEAR TO SECOND|VARCHAR(64)
1|2019-01-01 00:00:00|Welcome to the New Year 2019
+ SELECT * FROM trigger_log;
log_id|old_s|old_t|new_t|old_v|new_v|log_t|log_u
SERIAL|INTEGER|DATETIME YEAR TO SECOND|DATETIME YEAR TO SECOND|VARCHAR(64)|VARCHAR(64)|DATETIME YEAR TO SECOND|VARCHAR(32)
1|1|2019-12-19 17:04:04|2019-12-31 23:59:59|Hello|Farewell to 2019|2019-12-19 17:04:04|jonathanleffler
2|1|2019-12-31 23:59:59|2038-01-19 03:14:07|Farewell to 2019|Farewell to 32-bit Unix time|2019-12-19 17:04:04|jonathanleffler
$
可以看到,更新生效了,但是结果没有记录在trigger_log
table.
正如您可能还观察到的,使用的 UPDATE 语句很草率;他们更新所有行。最好也使用 DATETIME YEAR TO FRACTION(5)。我的数据库服务器 运行 的时区设置为 UTC — 因此插入时间也以 UTC 记录。
当特定数据库用户通过 运行 脚本进行更改时是否可以绕过触发器?
在 Informix 触发器的 when 子句中,我们可以这样做吗:
CREATE TRIGGER trigger_name
update on table_name
referencing old as olddata new as newdata
for each row when(USER <> 'a specific database user')
(…triggered actions…)
关于 Informix 12.10 的文档 CREATE TRIGGER eventually leads to the WHEN condition 描述。
只要您可以预测何时创建触发器,哪些用户不应触发该操作,您就应该能够编写类似 WHEN (USER != 'exempt')
的内容,但要让它发挥作用会更难动态地。您可能能够在 WHEN 条件中调用存储过程,以评估当前用户当前是否免于触发操作。除了在 WHEN 条件下或作为触发操作使用存储过程之外,它可能无法有意义地完成。
概念验证
架构和触发器
DROP TABLE IF EXISTS trigger_test;
CREATE TABLE trigger_test
(
s SERIAL NOT NULL PRIMARY KEY,
t DATETIME YEAR TO SECOND NOT NULL DEFAULT CURRENT YEAR TO SECOND,
v VARCHAR(64) NOT NULL
);
DROP TABLE IF EXISTS trigger_log;
CREATE TABLE trigger_log
(
log_id SERIAL NOT NULL PRIMARY KEY,
old_s INTEGER NOT NULL,
old_t DATETIME YEAR TO SECOND NOT NULL,
new_t DATETIME YEAR TO SECOND NOT NULL,
old_v VARCHAR(64) NOT NULL,
new_v VARCHAR(64) NOT NULL,
log_t DATETIME YEAR TO SECOND NOT NULL DEFAULT CURRENT YEAR TO SECOND,
log_u VARCHAR(32) NOT NULL DEFAULT USER
);
CREATE TRIGGER skip_user
UPDATE ON trigger_test
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW WHEN(USER != 'informix')
(INSERT INTO trigger_log(old_s, old_t, new_t, old_v, new_v)
VALUES(old.s, old.t, new.t, old.v, new.v)
)
;
作为非 informix 用户的操作顺序
我正在使用我的 sqlcmd
程序(可从 ESQL 部分的 IIUG Software Archive 获得 — 它与 Microsoft 的同名 johnny-come-lately 程序截然不同)和自定义工具a6
切换为使用 informix
凭据(实际上类似于 su informix
或 sudo informix
)。
$ sqlcmd -d stores -xHTf user-action.sql
+ INSERT INTO trigger_test(v) VALUES("Hello");
+ SELECT * FROM trigger_test;
s|t|v
SERIAL|DATETIME YEAR TO SECOND|VARCHAR(64)
1|2019-12-19 17:04:04|Hello
+ SELECT * FROM trigger_log;
log_id|old_s|old_t|new_t|old_v|new_v|log_t|log_u
SERIAL|INTEGER|DATETIME YEAR TO SECOND|DATETIME YEAR TO SECOND|VARCHAR(64)|VARCHAR(64)|DATETIME YEAR TO SECOND|VARCHAR(32)
+ UPDATE trigger_test SET t = '2019-12-31 23:59:59', v = 'Farewell to 2019';
+ SELECT * FROM trigger_test;
s|t|v
SERIAL|DATETIME YEAR TO SECOND|VARCHAR(64)
1|2019-12-31 23:59:59|Farewell to 2019
+ SELECT * FROM trigger_log;
log_id|old_s|old_t|new_t|old_v|new_v|log_t|log_u
SERIAL|INTEGER|DATETIME YEAR TO SECOND|DATETIME YEAR TO SECOND|VARCHAR(64)|VARCHAR(64)|DATETIME YEAR TO SECOND|VARCHAR(32)
1|1|2019-12-19 17:04:04|2019-12-31 23:59:59|Hello|Farewell to 2019|2019-12-19 17:04:04|jonathanleffler
+ UPDATE trigger_test SET t = '2038-01-19 03:14:07', v = 'Farewell to 32-bit Unix time';
+ SELECT * FROM trigger_test;
s|t|v
SERIAL|DATETIME YEAR TO SECOND|VARCHAR(64)
1|2038-01-19 03:14:07|Farewell to 32-bit Unix time
+ SELECT * FROM trigger_log;
log_id|old_s|old_t|new_t|old_v|new_v|log_t|log_u
SERIAL|INTEGER|DATETIME YEAR TO SECOND|DATETIME YEAR TO SECOND|VARCHAR(64)|VARCHAR(64)|DATETIME YEAR TO SECOND|VARCHAR(32)
1|1|2019-12-19 17:04:04|2019-12-31 23:59:59|Hello|Farewell to 2019|2019-12-19 17:04:04|jonathanleffler
2|1|2019-12-31 23:59:59|2038-01-19 03:14:07|Farewell to 2019|Farewell to 32-bit Unix time|2019-12-19 17:04:04|jonathanleffler
$
如您所见,我执行的操作记录在 trigger_log
table.
作为用户 informix 的操作顺序
$ a6 sqlcmd -d stores -xHTf ifmx-action.sql
+ UPDATE trigger_test SET t = '2019-01-01 00:00:00', v = 'Welcome to the New Year 2019';
+ SELECT * FROM trigger_test;
s|t|v
SERIAL|DATETIME YEAR TO SECOND|VARCHAR(64)
1|2019-01-01 00:00:00|Welcome to the New Year 2019
+ SELECT * FROM trigger_log;
log_id|old_s|old_t|new_t|old_v|new_v|log_t|log_u
SERIAL|INTEGER|DATETIME YEAR TO SECOND|DATETIME YEAR TO SECOND|VARCHAR(64)|VARCHAR(64)|DATETIME YEAR TO SECOND|VARCHAR(32)
1|1|2019-12-19 17:04:04|2019-12-31 23:59:59|Hello|Farewell to 2019|2019-12-19 17:04:04|jonathanleffler
2|1|2019-12-31 23:59:59|2038-01-19 03:14:07|Farewell to 2019|Farewell to 32-bit Unix time|2019-12-19 17:04:04|jonathanleffler
$
可以看到,更新生效了,但是结果没有记录在trigger_log
table.
正如您可能还观察到的,使用的 UPDATE 语句很草率;他们更新所有行。最好也使用 DATETIME YEAR TO FRACTION(5)。我的数据库服务器 运行 的时区设置为 UTC — 因此插入时间也以 UTC 记录。