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
ELSEgren bara tilldela tillNYdirekt. 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örIFkonstruktion skulle bryta din triggerfunktion förDELETE, eftersomNYär inte tilldelad för DELETEs. -
En nyckelfunktion är användningen av
hstoreoch 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 ursprungligaOLDvä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
hstoremå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 enhstorevärde med flera fält i farten. -
Tilldelningsoperatorn i plpgsql är
:=: -
Observera att jag använde kolumnnamnet
mod_datetimeistället för den missvisandemod_date, eftersom kolumnen uppenbarligen är entidsstämpeloch 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();