aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/tablecmds.c28
-rw-r--r--src/test/regress/expected/foreign_key.out32
-rw-r--r--src/test/regress/sql/foreign_key.sql22
3 files changed, 75 insertions, 7 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 4d4d4069ee8..f679d619d7d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -6302,13 +6302,6 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
CommandCounterIncrement();
/*
- * Build and execute a CREATE CONSTRAINT TRIGGER statement for the CHECK
- * action for both INSERTs and UPDATEs on the referencing table.
- */
- CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, true);
- CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, false);
-
- /*
* Build and execute a CREATE CONSTRAINT TRIGGER statement for the ON
* DELETE action on the referenced table.
*/
@@ -6410,6 +6403,27 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint,
fk_trigger->args = NIL;
(void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true);
+
+ /* Make changes-so-far visible */
+ CommandCounterIncrement();
+
+ /*
+ * Build and execute CREATE CONSTRAINT TRIGGER statements for the CHECK
+ * action for both INSERTs and UPDATEs on the referencing table.
+ *
+ * Note: for a self-referential FK (referencing and referenced tables are
+ * the same), it is important that the ON UPDATE action fires before the
+ * CHECK action, since both triggers will fire on the same row during an
+ * UPDATE event; otherwise the CHECK trigger will be checking a non-final
+ * state of the row. Because triggers fire in name order, we are
+ * effectively relying on the OIDs of the triggers to sort correctly as
+ * text. This will work except when the OID counter wraps around or adds
+ * a digit, eg "99999" sorts after "100000". That is infrequent enough,
+ * and the use of self-referential FKs is rare enough, that we live with
+ * it for now. There will be a real fix in PG 9.2.
+ */
+ CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, true);
+ CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, false);
}
/*
diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out
index 87d573b6abf..65dfe024a99 100644
--- a/src/test/regress/expected/foreign_key.out
+++ b/src/test/regress/expected/foreign_key.out
@@ -1287,3 +1287,35 @@ SELECT * FROM tasks;
(3 rows)
COMMIT;
+--
+-- Test self-referential FK with CASCADE (bug #6268)
+--
+create temp table selfref (
+ a int primary key,
+ b int,
+ foreign key (b) references selfref (a)
+ on update cascade on delete cascade
+);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "selfref_pkey" for table "selfref"
+insert into selfref (a, b)
+values
+ (0, 0),
+ (1, 1);
+begin;
+ update selfref set a = 123 where a = 0;
+ select a, b from selfref;
+ a | b
+-----+-----
+ 1 | 1
+ 123 | 123
+(2 rows)
+
+ update selfref set a = 456 where a = 123;
+ select a, b from selfref;
+ a | b
+-----+-----
+ 1 | 1
+ 456 | 456
+(2 rows)
+
+commit;
diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql
index 6d7bdbe77a9..6bd9ddd1a5e 100644
--- a/src/test/regress/sql/foreign_key.sql
+++ b/src/test/regress/sql/foreign_key.sql
@@ -921,3 +921,25 @@ SELECT * FROM tasks;
DELETE FROM users WHERE id = 2;
SELECT * FROM tasks;
COMMIT;
+
+--
+-- Test self-referential FK with CASCADE (bug #6268)
+--
+create temp table selfref (
+ a int primary key,
+ b int,
+ foreign key (b) references selfref (a)
+ on update cascade on delete cascade
+);
+
+insert into selfref (a, b)
+values
+ (0, 0),
+ (1, 1);
+
+begin;
+ update selfref set a = 123 where a = 0;
+ select a, b from selfref;
+ update selfref set a = 456 where a = 123;
+ select a, b from selfref;
+commit;