El ELSE
La rama se puede simplificar radicalmente. Pero un par de cosas más son ineficientes/inexactas/peligrosas:
CREATE OR REPLACE FUNCTION sample_trigger_func()
RETURNS TRIGGER AS
$func$
BEGIN
IF TG_OP = 'DELETE' THEN
RAISE INFO 'OLD: %', OLD.name;
EXECUTE format('INSERT INTO %I SELECT ($1).*', TG_TABLE_NAME || '_deletes')
USING OLD #= hstore('{mod_op, mod_datetime}'::text[]
, ARRAY[left(TG_OP, 1), now()::text]);
RETURN OLD;
ELSE -- insert, update
NEW.mod_op := left(TG_OP, 1);
NEW.mod_datetime := now();
RETURN NEW;
END IF;
END
$func$ LANGUAGE plpgsql;
-
En el
ELSE
rama simplemente asigne aNEW
directamente. No es necesario un SQL más dinámico, que dispararía el mismo activador nuevamente y provocaría un bucle sin fin. Ese es el error principal. -
RETURN NEW;
fuera delIF
construir rompería su función de activación paraDELETE
, desdeNEW
no está asignado para DELETES. -
Una característica clave es el uso de
hstore
y el operador hstore#=
para cambiar dinámicamente dos campos seleccionados del tipo de fila conocido - eso es desconocido en el momento de escribir el código. De esta forma, no alterará elOLD
original. valor, que podría tener efectos secundarios sorprendentes si tiene más factores desencadenantes en la cadena de eventos.OLD #= hstore('{mod_op, mod_datetime}'::text[] , ARRAY[left(TG_OP, 1), now()::text]);
El módulo adicional
hstore
debe ser instalado. Detalles:- Cómo establecer el valor del campo variable compuesto usando SQL dinámico
- Pasar nombres de columnas dinámicamente para una variable de registro en PostgreSQL
Usando el
hstore(text[], text[])
variante aquí para construir unhstore
valor con múltiples campos sobre la marcha. -
El operador de asignación en plpgsql es
:=
: -
Tenga en cuenta que usé el nombre de columna
mod_datetime
en lugar del engañosomod_date
, ya que la columna es obviamente unatimestamp
y no unadate
.
Agregué un par de otras mejoras mientras estaba en eso. Y el activador en sí debería verse así:
CREATE TRIGGER insupdel_bef
BEFORE INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();