ELSE
větev lze radikálně zjednodušit. Ale pár dalších věcí je neefektivních / nepřesných / nebezpečných:
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;
-
V
ELSE
větev stačí přiřadit kNEW
přímo. Není třeba dynamičtějšího SQL - což by znovu spustilo stejný spouštěč a způsobilo by nekonečnou smyčku. To je hlavní chyba. -
VRÁTIT NOVÝ;
mimoIF
konstrukt by přerušil vaši spouštěcí funkci proDELETE
, protožeNOVINKA
není přiřazeno pro DELETE. -
Klíčovou funkcí je použití
hstore
a operátor hstore#=
pro dynamickou změnu dvou vybraných polí dobře známého typu řádku - to je neznámé v době psaní kódu. Tímto způsobem nezasahujete do původníhoSTARÉHO
hodnotu, což může mít překvapivý vedlejší účinek, pokud máte v řetězci událostí více spouštěčů.OLD #= hstore('{mod_op, mod_datetime}'::text[] , ARRAY[left(TG_OP, 1), now()::text]);
Doplňkový modul
hstore
musí být nainstalován. Podrobnosti:- Jak nastavit hodnotu pole složené proměnné pomocí dynamického SQL
- Dynamické předávání názvů sloupců pro proměnnou záznamu v PostgreSQL
Pomocí
hstore(text[], text[])
zde vytvořítehstore
hodnotu s více poli za běhu. -
Operátor přiřazení v plpgsql je
:=
: -
Všimněte si, že jsem použil název sloupce
mod_datetime
místo zavádějícíhomod_date
, protože sloupec je zjevněčasové razítko
a nikolidatum
.
Během toho jsem přidal několik dalších vylepšení. A samotná spoušť by měla vypadat takto:
CREATE TRIGGER insupdel_bef
BEFORE INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();