ANELSE
gren kan förenklas radikalt. Men ett par saker till är ineffektiva / felaktiga / farliga:
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;
-
I
ELSE
gren bara tilldela tillNY
direkt. Inget behov av mer dynamisk SQL - vilket skulle utlösa samma trigger igen och orsaka en oändlig loop. Det är det primära felet. -
TILLBAKA NYTT;
utanförIF
konstruktion skulle bryta din triggerfunktion förDELETE
, eftersomNY
är inte tilldelad för DELETEs. -
En nyckelfunktion är användningen av
hstore
och hstore-operatören#=
för att dynamiskt ändra två valda fält av den välkända radtypen - det är okänt när koden skrevs. På så sätt manipulerar du inte den ursprungligaOLD
värde, vilket kan ha en överraskande bieffekt om du har fler triggers i händelsekedjan.OLD #= hstore('{mod_op, mod_datetime}'::text[] , ARRAY[left(TG_OP, 1), now()::text]);
Tilläggsmodulen
hstore
måste installeras. Detaljer:- Hur man ställer in värdet på det sammansatta variabelfältet med hjälp av dynamisk SQL
- Att skicka kolumnnamn dynamiskt för en postvariabel i PostgreSQL
Använda
hstore(text[], text[])
variant här för att konstruera enhstore
värde med flera fält i farten. -
Tilldelningsoperatorn i plpgsql är
:=
: -
Observera att jag använde kolumnnamnet
mod_datetime
istället för den missvisandemod_date
, eftersom kolumnen uppenbarligen är entidsstämpel
och inte ettdatum
.
Jag har lagt till ett par andra förbättringar medan jag håller på. Och själva utlösaren ska se ut så här:
CREATE TRIGGER insupdel_bef
BEFORE INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();