2012-06-12 6 views
15

Ich habe einen ziemlich einfachen Trigger:Postgres Trigger nach Einsatz Zugriff NEW

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(); 

Meine Tabellenprotokolle ist die folgenden:

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) 
); 

Nach etwas in dateien Einsetzen bekomme ich folgende Fehlermeldung:

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 

Warum habe ich diesen Fehler erhalten? Ich habe mir die Dokumentation angesehen und es scheint, dass sie auf die gleiche Weise wie ich neue verwenden.

Antwort

33

Vom fine manual:

36.1. Overview of Trigger Behavior
[...]
For a row-level trigger, the input data also includes the NEW row for INSERT and UPDATE triggers, and/or the OLD row for UPDATE and DELETE triggers. Statement-level triggers do not currently have any way to examine the individual row(s) modified by the statement.

Und von Trigger Procedures:

NEW
Data type RECORD ; variable holding the new database row for INSERT/UPDATE operations in row-level triggers. This variable is NULL in statement-level triggers and for DELETE operations.

Hinweis, was es sagt über Trigger auf Zeilenebene und auf Anweisungsebene Trigger.

Sie haben einen Trigger auf Anweisungsebene:

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

Statement-Level-Trigger werden einmal ausgelöst pro Anweisung und eine Anweisung kann auf mehrere Zeilen gelten, so die Vorstellung von Reihe betroffen (das ist, was NEW und OLD sind ungefähr) trifft einfach nicht zu.

Wenn Sie NEW (oder OLD) in einem Trigger verwenden, dann mögen Sie den Auslöser für jede betroffene Zeile auszuführen, und das bedeutet, dass Sie einen Trigger auf Zeilenebene wollen:

CREATE TRIGGER log_datei AFTER INSERT OR UPDATE OR DELETE 
ON dateien 
FOR EACH ROW 
EXECUTE PROCEDURE f_log_datei(); 

ich gerade geändert FOR EACH STATEMENT zu FOR EACH ROW.


Ihre Trigger sollte auch be returning something:

A trigger function must return either NULL or a record/row value having exactly the structure of the table the trigger was fired for.
[...]
The return value of a row-level trigger fired AFTER or a statement-level trigger fired BEFORE or AFTER is always ignored; it might as well be null. However, any of these types of triggers might still abort the entire operation by raising an error.

So sollten Sie RETURN NEW; oder RETURN NULL; in Ihrem Trigger. Sie haben einen AFTER-Trigger, so dass es egal ist, welche RETURN Sie verwenden, aber ich würde mit RETURN NEW; gehen.

+2

Haben Sie am Ende der Funktion auch 'RETURN NEW;' hinzugefügt? – kgrittn

+0

@kgrittn: Das wäre der * nächste * Fehler, nein? Aber ja, das habe ich nicht einmal gesehen und es ist erwähnenswert, während wir hier sind. –

+1

yeah Ich habe die Anweisung 'RETURN' hinzugefügt :) – soupdiver

Verwandte Themen