ELSE
клонът може да бъде радикално опростен. Но още няколко неща са неефективни/неточни/опасни:
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;
-
В
ELSE
клон просто присвоете наНОВ
директно. Няма нужда от по-динамичен SQL - който би задействал отново същия тригер, причинявайки безкраен цикъл. Това е основната грешка. -
ВРЪЩАНЕ НА НОВ;
извънIF
конструкцията ще наруши вашата тригерна функция заDELETE
, отНОВО
не се присвоява за ИЗТРИВАНЕ. -
Ключова функция е използването на
hstore
и оператора hstore#=
за динамична промяна на две избрани полета от добре познатия тип ред - това е неизвестно в момента на писане на кода. По този начин не подправяте оригиналнияOLD
стойност, която може да има изненадващ страничен ефект, ако имате повече задействания по веригата от събития.OLD #= hstore('{mod_op, mod_datetime}'::text[] , ARRAY[left(TG_OP, 1), now()::text]);
Допълнителният модул
hstore
трябва да се инсталира. Подробности:- Как да зададете стойност на полето на съставна променлива с помощта на динамичен SQL
- Динамично подаване на имена на колони за записваща променлива в PostgreSQL
Използване на
hstore(text[], text[])код>
вариант тук, за да създадетеhstore
стойност с множество полета в движение. -
Операторът за присвояване в plpgsql е
:=
: -
Имайте предвид, че използвах името на колоната
mod_datetime
вместо подвеждащияmod_date
, тъй като колоната очевидно еtimestamp
а недата
.
Добавих няколко други подобрения, докато го правех. А самият тригер трябва да изглежда така:
CREATE TRIGGER insupdel_bef
BEFORE INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();