【问题标题】:Postgres trigger after insert accessing NEW插入访问 NEW 后 Postgres 触发
【发布时间】:2012-06-15 14:21:50
【问题描述】:

我有一个非常简单的触发器:

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 的方式与我相同。

【问题讨论】:

    标签: sql postgresql triggers plpgsql


    【解决方案1】:

    来自fine manual

    36.1。触发器行为概述
    [...]
    对于行级触发器,输入数据还包括用于INSERTUPDATE 触发器的NEW 行,和/或用于UPDATEDELETE 触发器的OLD 行。语句级触发器目前无法检查语句修改的各个行。

    来自Trigger Procedures

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

    注意它所说的行级触发器和语句级触发器。

    你有一个语句级触发器:

    ...
    FOR EACH STATEMENT
    EXECUTE PROCEDURE f_log_datei();
    

    每个语句触发一次语句级触发器,并且一个语句可以应用于多行,因此受影响的行的概念(这是 NEWOLD 的含义)根本不不适用。

    如果您想在触发器中使用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


    你的触发器也应该be returning something:

    触发器函数必须返回 NULL 或记录/行值,该值与触发触发器的表的结构完全相同。
    [...]
    触发AFTER 的行级触发器或触发BEFOREAFTER 的语句级触发器的返回值总是被忽略;它也可能为空。但是,这些类型的触发器中的任何一种仍可能通过引发错误来中止整个操作。

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

    【讨论】:

    • 函数末尾是否也加了RETURN NEW;
    • @kgrittn:那将是 next 错误,不是吗?但是,是的,我什至没有看到这一点,值得一提的是我们在这里。
    • 是的,我已经添加了RETURN 声明:)
    • 如果是在触发器之后,你应该使用RETURN NULLpostgresql.org/docs/current/plpgsql-trigger.html
    • 因为AFTER触发器没有效果。返回 NEW 充其量是误导。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    • 2013-12-06
    • 2016-10-13
    相关资源
    最近更新 更多