Il ELSE
ramo può essere radicalmente semplificato. Ma un altro paio di cose sono inefficienti/imprecise/pericolose:
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;
-
In
ELSE
branch basta assegnare aNEW
direttamente. Non c'è bisogno di un SQL più dinamico, che attiverebbe di nuovo lo stesso trigger causando un ciclo infinito. Questo è l'errore principale. -
RETURN NEW;
al di fuori delIF
costrutto interromperebbe la tua funzione di attivazione perDELETE
, poichéNEW
non è assegnato ai DELETE. -
Una caratteristica fondamentale è l'uso di
hstore
e l'operatore hstore#=
per modificare dinamicamente due campi selezionati del tipo di riga noto - cioè sconosciuto al momento della scrittura del codice. In questo modo non manometterai ilOLD
originale valore, che potrebbe avere effetti collaterali sorprendenti se hai più trigger lungo la catena di eventi.OLD #= hstore('{mod_op, mod_datetime}'::text[] , ARRAY[left(TG_OP, 1), now()::text]);
Il modulo aggiuntivo
hstore
deve essere installato. Dettagli:- Come impostare il valore del campo della variabile composita utilizzando SQL dinamico
- Trasferimento dinamico dei nomi di colonna per una variabile record in PostgreSQL
Utilizzando
hstore(text[], text[])
variante qui per costruire unhstore
valore con più campi al volo. -
L'operatore di assegnazione in plpgsql è
:=
: -
Nota che ho usato il nome della colonna
mod_datetime
invece dell'ingannevolemod_date
, poiché la colonna è ovviamente untimestamp
e non unadate
.
Ho aggiunto un paio di altri miglioramenti mentre ci lavoravo. E il trigger stesso dovrebbe assomigliare a questo:
CREATE TRIGGER insupdel_bef
BEFORE INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();