aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ri_triggers.c
diff options
context:
space:
mode:
authorJan Wieck <JanWieck@Yahoo.com>2003-04-07 20:30:38 +0000
committerJan Wieck <JanWieck@Yahoo.com>2003-04-07 20:30:38 +0000
commitcd203f33958b99656e8486351be08197a9a73d76 (patch)
tree1b9ea0bc4c2b5b6910f051a9b41964e2d69c4f14 /src/backend/utils/adt/ri_triggers.c
parentafe1185cf082c4c1bb5cafcffa544e0f5d4fc97f (diff)
downloadpostgresql-cd203f33958b99656e8486351be08197a9a73d76.tar.gz
postgresql-cd203f33958b99656e8486351be08197a9a73d76.zip
Avoid primary key lookup (and lock) if foreign key does not change
on UPDATE. This get's rid of the long standing annoyance that updating a row that has foreign keys locks all the referenced rows even if the foreign key values do not change. The trick is to actually do a check identical to NO ACTION after an eventually done UPDATE in the SET DEFAULT case. Since a SET DEFAULT operation should have moved referencing rows to a new "home", a following NO ACTION check can only fail if the column defaults of the referencing table resulted in the key we actually deleted. Thanks to Stephan. Jan
Diffstat (limited to 'src/backend/utils/adt/ri_triggers.c')
-rw-r--r--src/backend/utils/adt/ri_triggers.c40
1 files changed, 33 insertions, 7 deletions
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index bc7c723ea25..2ebf92213be 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -17,7 +17,7 @@
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.48 2003/03/27 19:25:40 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.49 2003/04/07 20:30:38 wieck Exp $
*
* ----------
*/
@@ -395,13 +395,19 @@ RI_FKey_check(PG_FUNCTION_ARGS)
}
/*
- * Note: We cannot avoid the check on UPDATE, even if old and new key
- * are the same. Otherwise, someone could DELETE the PK that consists
- * of the DEFAULT values, and if there are any references, a ON DELETE
- * SET DEFAULT action would update the references to exactly these
- * values but we wouldn't see that weird case (this is the only place
- * to see it).
+ * No need to check anything if old and new references are the
+ * same on UPDATE.
*/
+ if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
+ {
+ if (ri_KeysEqual(fk_rel, old_row, new_row, &qkey,
+ RI_KEYPAIR_FK_IDX))
+ {
+ heap_close(pk_rel, RowShareLock);
+ return PointerGetDatum(NULL);
+ }
+ }
+
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect() failed in RI_FKey_check()");
@@ -2397,6 +2403,16 @@ RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
heap_close(fk_rel, RowExclusiveLock);
+ /*
+ * In the case we delete the row who's key is equal to the
+ * default values AND a referencing row in the foreign key
+ * table exists, we would just have updated it to the same
+ * values. We need to do another lookup now and in case a
+ * reference exists, abort the operation. That is already
+ * implemented in the NO ACTION trigger.
+ */
+ RI_FKey_noaction_del(fcinfo);
+
return PointerGetDatum(NULL);
/*
@@ -2635,6 +2651,16 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
heap_close(fk_rel, RowExclusiveLock);
+ /*
+ * In the case we updated the row who's key was equal to the
+ * default values AND a referencing row in the foreign key
+ * table exists, we would just have updated it to the same
+ * values. We need to do another lookup now and in case a
+ * reference exists, abort the operation. That is already
+ * implemented in the NO ACTION trigger.
+ */
+ RI_FKey_noaction_upd(fcinfo);
+
return PointerGetDatum(NULL);
/*