Sql 插入访问新文件后的Postgres触发器
我有一个非常简单的触发器:Sql 插入访问新文件后的Postgres触发器,sql,postgresql,triggers,plpgsql,Sql,Postgresql,Triggers,Plpgsql,我有一个非常简单的触发器: CREATE OR REPLACE FUNCTION f_log_datei() RETURNS TRIGGER AS $$ BEGIN INSERT INTO logs (aktion, tabelle, benutzer_id) VALUES(TG_OP, 'dateien', NEW.benutzer_id); END; $$ LANGUAGE 'plpgsql'; CREATE TRIGGER log_datei AFTER INSERT OR UPDA
CREATE OR REPLACE FUNCTION f_log_datei()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO logs (aktion, tabelle, benutzer_id) VALUES(TG_OP, 'dateien', NEW.benutzer_id);
END; $$ LANGUAGE 'plpgsql';
CREATE TRIGGER log_datei AFTER INSERT OR UPDATE OR DELETE
ON dateien
FOR EACH STATEMENT
EXECUTE PROCEDURE f_log_datei();
我的表日志如下所示:
CREATE TABLE logs(
id int PRIMARY KEY DEFAULT NEXTVAL('logs_id_seq'),
zeit timestamp DEFAULT now(),
aktion char(6),
tabelle varchar(32),
alt varchar(256),
neu varchar(256),
benutzer_id int references benutzer(id)
);
在dateien中插入某些内容后,出现以下错误:
ERROR: record "new" is not assigned yet
DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.
CONTEXT: SQL statement "INSERT INTO logs (aktion, tabelle, benutzer_id) VALUES(TG_OP, 'dateien', NEW.benutzer_id)"
PL/pgSQL function "f_log_datei" line 3 at SQL statement
为什么我会犯这个错误?我查看了文档,发现它们似乎以与我相同的方式使用了new。来自:
36.1。触发器行为概述[…]
对于行级触发器,输入数据还包括
INSERT
和UPDATE
触发器的NEW
行,和/或UPDATE
和DELETE
触发器的OLD
行。语句级触发器当前无法检查由语句修改的各行
和来自:
新建
数据类型
记录
;为行级触发器中的插入
/更新
操作保存新数据库行的变量。该变量在语句级触发器和DELETE
操作中为NULL
请注意它对行级触发器和语句级触发器的说明
您有一个语句级触发器:
...
FOR EACH STATEMENT
EXECUTE PROCEDURE f_log_datei();
CREATE TRIGGER log_datei AFTER INSERT OR UPDATE OR DELETE
ON dateien
FOR EACH ROW
EXECUTE PROCEDURE f_log_datei();
每个语句都会触发一次语句级触发器,并且一个语句可以应用于多行,因此受影响行的概念(即NEW
和OLD
的含义)根本不适用
如果要在触发器中使用NEW
(或OLD
),则需要为每个受影响的行执行触发器,这意味着您需要行级触发器:
...
FOR EACH STATEMENT
EXECUTE PROCEDURE f_log_datei();
CREATE TRIGGER log_datei AFTER INSERT OR UPDATE OR DELETE
ON dateien
FOR EACH ROW
EXECUTE PROCEDURE f_log_datei();
我刚刚将每条语句的更改为每行的
您的触发器还应:
触发器函数必须返回NULL
或一个记录/行值,该记录/行值必须与触发触发器的表的结构完全相同。
[…]
始终忽略在
之后触发的行级触发器或在
之前或之后触发的语句级触发器的返回值;它也可能是空的。但是,这些类型的触发器中的任何一种都可能通过引发错误而中止整个操作
所以你应该返回新的
或返回NULL代码>在触发器中。您有一个AFTER触发器,所以使用哪个返回并不重要,但我会选择returnnew代码>您是否也添加了返回新代码代码>到函数末尾?@kgrittn:那将是下一个bug,不是吗?但是,是的,我甚至没有看到,值得一提的是,我们在这里。是的,我添加了RETURN
语句:)如果是在触发器之后,您应该使用returnnull
。因为触发后没有效果。返回NEW
充其量只是误导。