Pho*_*ocs 4 database postgresql
是否可以在查询期间设置可由 TRIGGER 过程捕获的变量(仅对相关查询有效)?
例如,我想记录查询执行者的ID(current_user始终相同)。所以我会做这样的事情:
tbl_executor (
id PRIMARY KEY,
name VARCHAR
);
tbl_log (
executor REFERENCE tbl_executor(id),
op VARCHAR
);
tbl_other ...
CREATE TRIGGER t AFTER INSERT OR UPDATE OR DELETE ON tbl_executor
FOR EACH ROW
EXECUTE PROCEDURE (INSERT INTO tbl_log VALUES( ID_VAR_OF_THIS_QUERY ,TG_OP))
Run Code Online (Sandbox Code Playgroud)
现在,如果我运行如下查询:
INSERT INTO tbl_other
VALUES(.......) - and set ID_VAR_OF_THIS_QUERY='id of executor' -
Run Code Online (Sandbox Code Playgroud)
我得到以下结果:
tbl_log
-----------------------------
id | op |
-----------------------------
'id of executor' | 'INSERT'|
Run Code Online (Sandbox Code Playgroud)
我希望我已经提出了这个想法...而且我认为这几乎不可行...但是有人可以帮助我吗?
SET myvar.role_id = '123';
Run Code Online (Sandbox Code Playgroud)
但这需要一个字面值。还有这个功能set_config()。引用手册:
set_config(setting_name, new_value, is_local)...设置参数并返回新值
set_config将参数设置setting_name为new_value。如果is_local是true,则新值将仅适用于当前交易。
SHOW相应地,用或读取选项值current_setting()。有关的:
但是您的触发器位于错误的表 ( tbl_executor) 上,并且语法错误。看起来像Oracle代码,你可以直接提供代码CREATE TRIGGER。在 Postgres 中,你首先需要一个触发函数:
所以:
CREATE OR REPLACE FUNCTION trg_log_who()
RETURNS trigger AS
$func$
BEGIN
INSERT INTO tbl_log(executor, op)
VALUES(current_setting('myvar.role_id')::int, TG_OP); -- !
RETURN NULL; -- irrelevant for AFTER trigger
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
您的示例设置需要 a 类型转换::int。
然后:
CREATE TRIGGER trg_log_who
AFTER INSERT OR UPDATE OR DELETE ON tbl_other -- !
FOR EACH ROW EXECUTE PROCEDURE trg_log_who(); -- !
Run Code Online (Sandbox Code Playgroud)
最后,id从表中获取tbl_executor数据来设置变量:
BEGIN;
SELECT set_config('myvar.role_id', id::text, true) -- !
FROM tbl_executor
WHERE name = current_user;
INSERT INTO tbl_other VALUES( ... );
INSERT INTO tbl_other VALUES( ... );
-- more?
COMMIT;
Run Code Online (Sandbox Code Playgroud)
设置to的第三个参数 ( is_local)以使其按请求为会话本地。(相当于。)set_config()trueSET LOCAL
但为什么每行?按声明来写似乎更合理?
...
FOR EACH STATEMENT EXECUTE PROCEDURE trg_foo();Run Code Online (Sandbox Code Playgroud)
除此之外,我会考虑一种不同的方法:一个返回 aid列默认值的简单函数:
CREATE OR REPLACE FUNCTION f_current_role_id()
RETURNS int LANGUAGE sql STABLE AS
'SELECT id FROM tbl_executor WHERE name = current_user';
CREATE TABLE tbl_log (
executor int DEFAULT f_current_role_id() REFERENCES tbl_executor(id)
, op VARCHAR
);
Run Code Online (Sandbox Code Playgroud)
然后,在触发函数中,忽略该executor列;将自动填充:
...
INSERT INTO tbl_log(op) VALUES(TG_OP);
...
Run Code Online (Sandbox Code Playgroud)
current_user请注意和之间的区别session_user。看: