summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorTom Lane2004-09-10 18:40:09 +0000
committerTom Lane2004-09-10 18:40:09 +0000
commitb339d1fff6c2f14776af29a35c8550b222ca70b2 (patch)
treebe0ed19fa78e35cdde627d1c6bc4c4be9f7cb44e /src/test
parent856d1faac1024717b7c37665c46fd635dc52b1b4 (diff)
Fire non-deferred AFTER triggers immediately upon query completion,
rather than when returning to the idle loop. This makes no particular difference for interactively-issued queries, but it makes a big difference for queries issued within functions: trigger execution now occurs before the calling function is allowed to proceed. This responds to numerous complaints about nonintuitive behavior of foreign key checking, such as http://archives.postgresql.org/pgsql-bugs/2004-09/msg00020.php, and appears to be required by the SQL99 spec. Also take the opportunity to simplify the data structures used for the pending-trigger list, rename them for more clarity, and squeeze out a bit of space.
Diffstat (limited to 'src/test')
-rw-r--r--src/test/regress/expected/foreign_key.out1
-rw-r--r--src/test/regress/expected/plpgsql.out71
-rw-r--r--src/test/regress/sql/plpgsql.sql51
3 files changed, 123 insertions, 0 deletions
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index b291000add1..e954a232f1b 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -646,6 +646,7 @@ SELECT * from FKTABLE;
UPDATE PKTABLE set ptest2=5 where ptest2=2;
ERROR: insert or update on table "fktable" violates foreign key constraint "constrname3"
DETAIL: Key (ftest1,ftest2,ftest3)=(1,-1,3) is not present in table "pktable".
+CONTEXT: SQL query "UPDATE ONLY "public"."fktable" SET "ftest2" = DEFAULT WHERE "ftest1" = $1 AND "ftest2" = $2 AND "ftest3" = $3"
-- Try to update something that will set default
UPDATE PKTABLE set ptest1=0, ptest2=5, ptest3=10 where ptest2=2;
UPDATE PKTABLE set ptest2=10 where ptest2=4;
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 73962dbb37a..50d72830fb4 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -1935,3 +1935,74 @@ select * from foo;
20
(2 rows)
+--
+-- test foreign key error trapping
+--
+create temp table master(f1 int primary key);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "master_pkey" for table "master"
+create temp table slave(f1 int references master deferrable);
+insert into master values(1);
+insert into slave values(1);
+insert into slave values(2); -- fails
+ERROR: insert or update on table "slave" violates foreign key constraint "slave_f1_fkey"
+DETAIL: Key (f1)=(2) is not present in table "master".
+create function trap_foreign_key(int) returns int as $$
+begin
+ begin -- start a subtransaction
+ insert into slave values($1);
+ exception
+ when foreign_key_violation then
+ raise notice 'caught foreign_key_violation';
+ return 0;
+ end;
+ return 1;
+end$$ language plpgsql;
+create function trap_foreign_key_2() returns int as $$
+begin
+ begin -- start a subtransaction
+ set constraints all immediate;
+ exception
+ when foreign_key_violation then
+ raise notice 'caught foreign_key_violation';
+ return 0;
+ end;
+ return 1;
+end$$ language plpgsql;
+select trap_foreign_key(1);
+ trap_foreign_key
+------------------
+ 1
+(1 row)
+
+select trap_foreign_key(2); -- detects FK violation
+NOTICE: caught foreign_key_violation
+ trap_foreign_key
+------------------
+ 0
+(1 row)
+
+begin;
+ set constraints all deferred;
+ select trap_foreign_key(2); -- should not detect FK violation
+ trap_foreign_key
+------------------
+ 1
+(1 row)
+
+ savepoint x;
+ set constraints all immediate; -- fails
+ERROR: insert or update on table "slave" violates foreign key constraint "slave_f1_fkey"
+DETAIL: Key (f1)=(2) is not present in table "master".
+ rollback to x;
+ select trap_foreign_key_2(); -- detects FK violation
+NOTICE: caught foreign_key_violation
+ trap_foreign_key_2
+--------------------
+ 0
+(1 row)
+
+commit; -- still fails
+ERROR: insert or update on table "slave" violates foreign key constraint "slave_f1_fkey"
+DETAIL: Key (f1)=(2) is not present in table "master".
+drop function trap_foreign_key(int);
+drop function trap_foreign_key_2();
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 948a02ac0e2..a8951cd6efa 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -1699,3 +1699,54 @@ select blockme();
reset statement_timeout;
select * from foo;
+
+--
+-- test foreign key error trapping
+--
+
+create temp table master(f1 int primary key);
+
+create temp table slave(f1 int references master deferrable);
+
+insert into master values(1);
+insert into slave values(1);
+insert into slave values(2); -- fails
+
+create function trap_foreign_key(int) returns int as $$
+begin
+ begin -- start a subtransaction
+ insert into slave values($1);
+ exception
+ when foreign_key_violation then
+ raise notice 'caught foreign_key_violation';
+ return 0;
+ end;
+ return 1;
+end$$ language plpgsql;
+
+create function trap_foreign_key_2() returns int as $$
+begin
+ begin -- start a subtransaction
+ set constraints all immediate;
+ exception
+ when foreign_key_violation then
+ raise notice 'caught foreign_key_violation';
+ return 0;
+ end;
+ return 1;
+end$$ language plpgsql;
+
+select trap_foreign_key(1);
+select trap_foreign_key(2); -- detects FK violation
+
+begin;
+ set constraints all deferred;
+ select trap_foreign_key(2); -- should not detect FK violation
+ savepoint x;
+ set constraints all immediate; -- fails
+ rollback to x;
+ select trap_foreign_key_2(); -- detects FK violation
+commit; -- still fails
+
+drop function trap_foreign_key(int);
+drop function trap_foreign_key_2();