aboutsummaryrefslogtreecommitdiff
path: root/src/test/regress/sql/triggers.sql
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/regress/sql/triggers.sql')
-rw-r--r--src/test/regress/sql/triggers.sql155
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();