插入访问NEW后触发Postgres

时间:2012-06-12 16:49:40

标签: 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();

我的表日志如下:

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。

1 个答案:

答案 0 :(得分:41)

来自fine manual

  

<强> 36.1。触发行为概述
  [...]
  对于行级触发器,输入数据还包括NEWINSERT触发器的UPDATE行和/或OLD的{​​{1}}行和UPDATE触发器。语句级触发器目前无法检查由语句修改的各行。

来自Trigger Procedures

  

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

注意它所说的关于行级触发器和语句级触发器的内容。

你有一个语句级触发器:

DELETE

每个语句触发一次语句级触发器,并且语句可以应用于多行,因此受影响的行的概念(... 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


您的触发器也应该be returning something

  

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

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