插入访问NEW后触发Postgres

sou*_*ver 24 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 UPDATE OR DELETE
ON dateien
FOR EACH STATEMENT
EXECUTE PROCEDURE f_log_datei();
Run Code Online (Sandbox Code Playgroud)

我的表日志如下:

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)
);
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

为什么我会收到此错误?我查看了文档,似乎他们以与我相同的方式使用new.

mu *_*ort 43

精细手册:

36.1.触发器行为概述
[...]
对于行级触发器,输入数据还包括NEW行for INSERTUPDATE触发器,和/或OLD行for UPDATEDELETE触发器.语句级触发器当前没有任何方法可以检查由语句修改的各个行.

并从Trigger程序:

NEW
数据类型RECORD; 变量为行级触发器中的INSERT/ UPDATEoperations 保存新数据库行.此变量NULL位于语句级触发器和DELETE操作中.

请注意它对行级触发器和语句级触发器的说法.

你有一个语句级别的触发器:

...
FOR EACH STATEMENT
EXECUTE PROCEDURE f_log_datei();
Run Code Online (Sandbox Code Playgroud)

每个语句触发一次语句级触发器,并且语句可以应用于多行,因此受影响行的概念(即什么NEWOLD即将来临)根本不适用.

如果要在触发器中使用NEW(或OLD),则需要为每个受影响的行执行触发器,这意味着您需要行级触发器:

CREATE TRIGGER log_datei AFTER INSERT OR UPDATE OR DELETE
ON dateien
FOR EACH ROW
EXECUTE PROCEDURE f_log_datei();
Run Code Online (Sandbox Code Playgroud)

我刚换FOR EACH STATEMENTFOR EACH ROW.


你的触发器也应该返回一些东西:

触发器函数必须返回一个NULL或一个记录/行值,它具有触发器触发的表的结构.
[...]
触发行级触发器的返回值AFTER或触发BEFOREAFTER始终忽略语句级触发器; 它也可能是空的.但是,任何这些类型的触发器仍可能通过引发错误来中止整个操作.

所以你应该RETURN NEW;RETURN NULL;在触发器中.你有一个AFTER触发器,所以你使用哪个RETURN并不重要,但我会选择RETURN NEW;.

  • 您是否还在函数末尾添加了"RETURN NEW;"? (2认同)
  • 如果是 AFTER 触发器,则应该使用“RETURN NULL”。https://www.postgresql.org/docs/current/plpgsql-trigger.html (2认同)
  • 因为AFTER触发器没有效果。返回“NEW”充其量只是一种误导。 (2认同)