2012-06-12 13 views
15

tengo un disparador bastante simple:Postgres gatillo después de insertar el acceso a nuevos

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

mi mesa registros es la siguiente:

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

Después de insertar algo en dateien me sale el siguiente error:

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 

¿Por qué recibí este error? Miré en la documentación y parece que usan nuevas de la misma manera que yo.

Respuesta

33

Desde el 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.

Y desde 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.

Nota lo que dice acerca de los factores desencadenantes de nivel de fila y disparadores de nivel comunicado.

Usted tiene un trigger a nivel de declaración:

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

disparadores de nivel Declaración se activan una vez por sentencia y una declaración pueden aplicarse a varias filas por lo que la noción de afectada fila (que es lo NEW y OLD se trata) simplemente no se aplica.

Si desea utilizar NEW (o OLD) en un trigger a continuación, desea el gatillo a ejecutar para cada fila afectada y eso significa que quiere un disparador a nivel de fila:

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

simplemente he cambiado FOR EACH STATEMENT a FOR EACH ROW.


Su activación debe también 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.

por lo que debe RETURN NEW; o RETURN NULL; en su gatillo. Tienes un gatillo DESPUÉS, por lo que no importa qué RETORNO utilices, pero yo elegiría RETURN NEW;.

+2

¿Agregó también 'RETURN NEW;' al final de la función? – kgrittn

+0

@kgrittn: Ese sería el * siguiente * error, ¿no? Pero sí, ni siquiera vi eso y vale la pena mencionarlo mientras estamos aquí. –

+1

sí, he agregado la declaración 'RETURN' :) – soupdiver

Cuestiones relacionadas