2012-06-12 10 views
15

mam dość prosty spust:Postgres spust po wkładce dostępu 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(); 

Moje dzienniki tabeli jest następująca:

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

Po włożeniu czegoś w Dateien pojawia się następujący błąd:

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 

Dlaczego otrzymałem ten błąd? Zajrzałem do dokumentacji i wygląda na to, że używają nowych w taki sam sposób jak ja.

Odpowiedz

33

Z 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.

I od 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.

Uwaga to, co mówi o wyzwalacze poziomie wiersza i wyzwalaczy oświadczenie szczebla.

Masz spust oświadczenie-level:

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

komunikat szczebla wyzwalacze są uruchamiane raz na rachunku oraz oświadczenie może odnosić się do wielu wierszy więc pojęcie dotknięte wiersz (czego NEW i OLD są około) po prostu nie ma zastosowania.

Jeśli chcesz użyć NEW (lub OLD) w wyzwalacz następnie chcesz spust do wykonania dla każdego wiersza zagrożonym i oznacza, że ​​chcesz wyzwalacza poziomie wiersza:

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

Właśnie zmienił FOR EACH STATEMENT do FOR EACH ROW.


Twój spust powinien również 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.

Więc powinien RETURN NEW; lub RETURN NULL; w spuście. Masz wyzwalacz AFTER, więc nie ma znaczenia, którego RETURN używasz, ale wybrałbym numer RETURN NEW;.

+2

Czy dodałeś również "RETURN NEW;" na końcu funkcji? – kgrittn

+0

@kgrittn: To byłby * następny * błąd, nie? Ale tak, nawet tego nie zauważyłem i warto o tym wspomnieć, kiedy tu jesteśmy. –

+1

tak, dodałem wypowiedź 'RETURN' :) – soupdiver

Powiązane problemy