我有一个非常简单的触发器:
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
行。语句级触发器当前无法检查语句修改的单个行。
从触发程序:
NEW
数据类型RECORD
;变量保存新数据库行,用于行级触发器中的INSERT
/UPDATE
操作。此变量在语句级触发器和DELETE
操作中NULL
。
请注意它对行级触发器和语句级触发器的说明。
您有一个语句级触发器:
...
FOR EACH STATEMENT
EXECUTE PROCEDURE f_log_datei();
语句级触发器每个语句触发一次,一个语句可以应用于多行,因此受影响的行的概念(这就是NEW
和OLD
的内容)根本不适用。
如果要在触发器中使用NEW
(或OLD
),则希望触发器为每个受影响的行执行,这意味着您需要一个行级触发器:
CREATE TRIGGER log_datei AFTER INSERT OR UPDATE OR DELETE
ON dateien
FOR EACH ROW
EXECUTE PROCEDURE f_log_datei();
我只是FOR EACH STATEMENT
改为FOR EACH ROW
.
您的触发器还应该返回一些内容:
触发器函数必须返回
NULL
或记录/行值,该值与触发触发器的表的结构完全相同。
[...]
始终忽略AFTER
触发的行级触发器或BEFORE
或AFTER
触发的语句级触发器的返回值;它也可能是空的。但是,这些类型的触发器中的任何一个仍可能通过引发错误来中止整个操作。
因此,您应该在触发器中RETURN NEW;
或RETURN NULL;
。你有一个 AFTER 触发器,所以你使用哪个 RETURN 并不重要,但我会选择RETURN NEW;
.