diff options
Diffstat (limited to 'src/test/regress/sql/triggers.sql')
-rw-r--r-- | src/test/regress/sql/triggers.sql | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql index f88cb81940e..78c5407560a 100644 --- a/src/test/regress/sql/triggers.sql +++ b/src/test/regress/sql/triggers.sql @@ -1025,3 +1025,158 @@ drop table depth_a, depth_b, depth_c; drop function depth_a_tf(); drop function depth_b_tf(); drop function depth_c_tf(); + +-- +-- Test updates to rows during firing of BEFORE ROW triggers. +-- As of 9.2, such cases should be rejected (see bug #6123). +-- + +create temp table parent ( + aid int not null primary key, + val1 text, + val2 text, + val3 text, + val4 text, + bcnt int not null default 0); +create temp table child ( + bid int not null primary key, + aid int not null, + val1 text); + +create function parent_upd_func() + returns trigger language plpgsql as +$$ +begin + if old.val1 <> new.val1 then + new.val2 = new.val1; + delete from child where child.aid = new.aid and child.val1 = new.val1; + end if; + return new; +end; +$$; +create trigger parent_upd_trig before update on parent + for each row execute procedure parent_upd_func(); + +create function parent_del_func() + returns trigger language plpgsql as +$$ +begin + delete from child where aid = old.aid; + return old; +end; +$$; +create trigger parent_del_trig before delete on parent + for each row execute procedure parent_del_func(); + +create function child_ins_func() + returns trigger language plpgsql as +$$ +begin + update parent set bcnt = bcnt + 1 where aid = new.aid; + return new; +end; +$$; +create trigger child_ins_trig after insert on child + for each row execute procedure child_ins_func(); + +create function child_del_func() + returns trigger language plpgsql as +$$ +begin + update parent set bcnt = bcnt - 1 where aid = old.aid; + return old; +end; +$$; +create trigger child_del_trig after delete on child + for each row execute procedure child_del_func(); + +insert into parent values (1, 'a', 'a', 'a', 'a', 0); +insert into child values (10, 1, 'b'); +select * from parent; select * from child; + +update parent set val1 = 'b' where aid = 1; -- should fail +select * from parent; select * from child; + +delete from parent where aid = 1; -- should fail +select * from parent; select * from child; + +-- replace the trigger function with one that restarts the deletion after +-- having modified a child +create or replace function parent_del_func() + returns trigger language plpgsql as +$$ +begin + delete from child where aid = old.aid; + if found then + delete from parent where aid = old.aid; + return null; -- cancel outer deletion + end if; + return old; +end; +$$; + +delete from parent where aid = 1; +select * from parent; select * from child; + +drop table parent, child; + +drop function parent_upd_func(); +drop function parent_del_func(); +drop function child_ins_func(); +drop function child_del_func(); + +-- similar case, but with a self-referencing FK so that parent and child +-- rows can be affected by a single operation + +create temp table self_ref_trigger ( + id int primary key, + parent int references self_ref_trigger, + data text, + nchildren int not null default 0 +); + +create function self_ref_trigger_ins_func() + returns trigger language plpgsql as +$$ +begin + if new.parent is not null then + update self_ref_trigger set nchildren = nchildren + 1 + where id = new.parent; + end if; + return new; +end; +$$; +create trigger self_ref_trigger_ins_trig before insert on self_ref_trigger + for each row execute procedure self_ref_trigger_ins_func(); + +create function self_ref_trigger_del_func() + returns trigger language plpgsql as +$$ +begin + if old.parent is not null then + update self_ref_trigger set nchildren = nchildren - 1 + where id = old.parent; + end if; + return old; +end; +$$; +create trigger self_ref_trigger_del_trig before delete on self_ref_trigger + for each row execute procedure self_ref_trigger_del_func(); + +insert into self_ref_trigger values (1, null, 'root'); +insert into self_ref_trigger values (2, 1, 'root child A'); +insert into self_ref_trigger values (3, 1, 'root child B'); +insert into self_ref_trigger values (4, 2, 'grandchild 1'); +insert into self_ref_trigger values (5, 3, 'grandchild 2'); + +update self_ref_trigger set data = 'root!' where id = 1; + +select * from self_ref_trigger; + +delete from self_ref_trigger; + +select * from self_ref_trigger; + +drop table self_ref_trigger; +drop function self_ref_trigger_ins_func(); +drop function self_ref_trigger_del_func(); |