aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ri_triggers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/ri_triggers.c')
-rw-r--r--src/backend/utils/adt/ri_triggers.c196
1 files changed, 131 insertions, 65 deletions
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 0dc12410124..a0d561f1f0f 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-2005, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.78 2005/05/29 04:23:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.79 2005/05/30 07:20:58 neilc Exp $
*
* ----------
*/
@@ -38,10 +38,11 @@
#include "optimizer/planmain.h"
#include "parser/parse_oper.h"
#include "rewrite/rewriteHandler.h"
-#include "utils/lsyscache.h"
-#include "utils/typcache.h"
#include "utils/acl.h"
+#include "utils/fmgroids.h"
#include "utils/guc.h"
+#include "utils/lsyscache.h"
+#include "utils/typcache.h"
#include "miscadmin.h"
@@ -375,22 +376,6 @@ RI_FKey_check(PG_FUNCTION_ARGS)
break;
}
- /*
- * No need to check anything if old and new references are the same on
- * UPDATE.
- */
- if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
- {
- if (HeapTupleHeaderGetXmin(old_row->t_data) !=
- GetCurrentTransactionId() &&
- 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");
@@ -2005,8 +1990,8 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
* corresponding to changed columns in pk_rel's key
*/
if (match_type == RI_MATCH_TYPE_FULL ||
- !ri_OneKeyEqual(pk_rel, i, old_row, new_row, &qkey,
- RI_KEYPAIR_PK_IDX))
+ !ri_OneKeyEqual(pk_rel, i, old_row, new_row, &qkey,
+ RI_KEYPAIR_PK_IDX))
{
snprintf(querystr + strlen(querystr), sizeof(querystr) - strlen(querystr), "%s %s = NULL",
querysep, attname);
@@ -2016,7 +2001,7 @@ RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
qualsep, attname, i + 1);
qualsep = "AND";
queryoids[i] = SPI_gettypeid(pk_rel->rd_att,
- qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
+ qkey.keypair[i][RI_KEYPAIR_PK_IDX]);
}
strcat(querystr, qualstr);
@@ -2451,30 +2436,27 @@ RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
/* ----------
- * RI_FKey_keyequal_upd -
- *
- * Check if we have a key change on update.
+ * RI_FKey_keyequal_upd_pk -
*
- * This is not a real trigger procedure. It is used by the AFTER
- * trigger queue manager to detect "triggered data change violation".
+ * Check if we have a key change on an update to a PK relation. This is
+ * used by the AFTER trigger queue manager to detect "triggered data
+ * change violation".
* ----------
*/
bool
-RI_FKey_keyequal_upd(TriggerData *trigdata)
+RI_FKey_keyequal_upd_pk(Trigger *trigger, Relation pk_rel,
+ HeapTuple old_row, HeapTuple new_row)
{
int tgnargs;
char **tgargs;
Relation fk_rel;
- Relation pk_rel;
- HeapTuple new_row;
- HeapTuple old_row;
RI_QueryKey qkey;
/*
* Check for the correct # of call arguments
*/
- tgnargs = trigdata->tg_trigger->tgnargs;
- tgargs = trigdata->tg_trigger->tgargs;
+ tgnargs = trigger->tgnargs;
+ tgargs = trigger->tgargs;
if (tgnargs < 4 ||
tgnargs > RI_MAX_ARGUMENTS ||
(tgnargs % 2) != 0)
@@ -2489,48 +2471,32 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
if (tgnargs == 4)
return true;
- /*
- * Get the relation descriptors of the FK and PK tables and the new
- * and old tuple.
- *
- * Use minimal locking for fk_rel here.
- */
- if (!OidIsValid(trigdata->tg_trigger->tgconstrrelid))
+ if (!OidIsValid(trigger->tgconstrrelid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("no target table given for trigger \"%s\" on table \"%s\"",
- trigdata->tg_trigger->tgname,
- RelationGetRelationName(trigdata->tg_relation)),
- errhint("Remove this referential integrity trigger and its mates, then do ALTER TABLE ADD CONSTRAINT.")));
+ errmsg("no target table given for trigger \"%s\" on table \"%s\"",
+ trigger->tgname,
+ RelationGetRelationName(pk_rel)),
+ errhint("Remove this referential integrity trigger and its mates, "
+ "then do ALTER TABLE ADD CONSTRAINT.")));
- fk_rel = heap_open(trigdata->tg_trigger->tgconstrrelid, AccessShareLock);
- pk_rel = trigdata->tg_relation;
- new_row = trigdata->tg_newtuple;
- old_row = trigdata->tg_trigtuple;
+ fk_rel = heap_open(trigger->tgconstrrelid, AccessShareLock);
switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]))
{
- /*
- * MATCH <UNSPECIFIED>
- */
case RI_MATCH_TYPE_UNSPECIFIED:
case RI_MATCH_TYPE_FULL:
- ri_BuildQueryKeyFull(&qkey, trigdata->tg_trigger->tgoid,
+ ri_BuildQueryKeyFull(&qkey, trigger->tgoid,
RI_PLAN_KEYEQUAL_UPD,
fk_rel, pk_rel,
tgnargs, tgargs);
-
heap_close(fk_rel, AccessShareLock);
- /*
- * Return if key's are equal
- */
+ /* Return if key's are equal */
return ri_KeysEqual(pk_rel, old_row, new_row, &qkey,
RI_KEYPAIR_PK_IDX);
- /*
- * Handle MATCH PARTIAL set null delete.
- */
+ /* Handle MATCH PARTIAL set null delete. */
case RI_MATCH_TYPE_PARTIAL:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -2538,14 +2504,85 @@ RI_FKey_keyequal_upd(TriggerData *trigdata)
break;
}
+ /* Never reached */
+ elog(ERROR, "invalid match_type");
+ return false;
+}
+
+/* ----------
+ * RI_FKey_keyequal_upd_fk -
+ *
+ * Check if we have a key change on an update to an FK relation. This is
+ * used by the AFTER trigger queue manager to detect "triggered data
+ * change violation".
+ * ----------
+ */
+bool
+RI_FKey_keyequal_upd_fk(Trigger *trigger, Relation fk_rel,
+ HeapTuple old_row, HeapTuple new_row)
+{
+ int tgnargs;
+ char **tgargs;
+ Relation pk_rel;
+ RI_QueryKey qkey;
+
/*
- * Never reached
+ * Check for the correct # of call arguments
*/
+ tgnargs = trigger->tgnargs;
+ tgargs = trigger->tgargs;
+ if (tgnargs < 4 ||
+ tgnargs > RI_MAX_ARGUMENTS ||
+ (tgnargs % 2) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
+ errmsg("function \"%s\" called with wrong number of trigger arguments",
+ "RI_FKey_keyequal_upd")));
+
+ /*
+ * Nothing to do if no column names to compare given
+ */
+ if (tgnargs == 4)
+ return true;
+
+ if (!OidIsValid(trigger->tgconstrrelid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("no target table given for trigger \"%s\" on table \"%s\"",
+ trigger->tgname,
+ RelationGetRelationName(fk_rel)),
+ errhint("Remove this referential integrity trigger and its mates, "
+ "then do ALTER TABLE ADD CONSTRAINT.")));
+
+ pk_rel = heap_open(trigger->tgconstrrelid, AccessShareLock);
+
+ switch (ri_DetermineMatchType(tgargs[RI_MATCH_TYPE_ARGNO]))
+ {
+ case RI_MATCH_TYPE_UNSPECIFIED:
+ case RI_MATCH_TYPE_FULL:
+ ri_BuildQueryKeyFull(&qkey, trigger->tgoid,
+ RI_PLAN_KEYEQUAL_UPD,
+ fk_rel, pk_rel,
+ tgnargs, tgargs);
+ heap_close(pk_rel, AccessShareLock);
+
+ /* Return if key's are equal */
+ return ri_KeysEqual(fk_rel, old_row, new_row, &qkey,
+ RI_KEYPAIR_FK_IDX);
+
+ /* Handle MATCH PARTIAL set null delete. */
+ case RI_MATCH_TYPE_PARTIAL:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("MATCH PARTIAL not yet implemented")));
+ break;
+ }
+
+ /* Never reached */
elog(ERROR, "invalid match_type");
return false;
}
-
/* ----------
* RI_Initial_Check -
*
@@ -2871,7 +2908,7 @@ ri_BuildQueryKeyFull(RI_QueryKey *key, Oid constr_id, int32 constr_queryno,
/*
* Initialize the key and fill in type, oid's and number of keypairs
*/
- memset((void *) key, 0, sizeof(RI_QueryKey));
+ memset(key, 0, sizeof(RI_QueryKey));
key->constr_type = RI_MATCH_TYPE_FULL;
key->constr_id = constr_id;
key->constr_queryno = constr_queryno;
@@ -3489,7 +3526,7 @@ ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
for (i = 0; i < key->nkeypairs; i++)
{
/*
- * Get one attributes oldvalue. If it is NULL - they're not equal.
+ * Get one attribute's oldvalue. If it is NULL - they're not equal.
*/
oldvalue = SPI_getbinval(oldtup, rel->rd_att,
key->keypair[i][pairidx], &isnull);
@@ -3497,7 +3534,7 @@ ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
return false;
/*
- * Get one attributes oldvalue. If it is NULL - they're not equal.
+ * Get one attribute's oldvalue. If it is NULL - they're not equal.
*/
newvalue = SPI_getbinval(newtup, rel->rd_att,
key->keypair[i][pairidx], &isnull);
@@ -3505,7 +3542,7 @@ ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
return false;
/*
- * Get the attributes type OID and call the '=' operator to
+ * Get the attribute's type OID and call the '=' operator to
* compare the values.
*/
typeid = SPI_gettypeid(rel->rd_att, key->keypair[i][pairidx]);
@@ -3644,3 +3681,32 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
return DatumGetBool(FunctionCall2(&(typentry->eq_opr_finfo),
oldvalue, newvalue));
}
+
+/*
+ * Given a trigger function OID, determine whether it is an RI trigger,
+ * and if so whether it is attached to PK or FK relation.
+ */
+int
+RI_FKey_trigger_type(Oid tgfoid)
+{
+ switch (tgfoid)
+ {
+ case F_RI_FKEY_CASCADE_DEL:
+ case F_RI_FKEY_CASCADE_UPD:
+ case F_RI_FKEY_RESTRICT_DEL:
+ case F_RI_FKEY_RESTRICT_UPD:
+ case F_RI_FKEY_SETNULL_DEL:
+ case F_RI_FKEY_SETNULL_UPD:
+ case F_RI_FKEY_SETDEFAULT_DEL:
+ case F_RI_FKEY_SETDEFAULT_UPD:
+ case F_RI_FKEY_NOACTION_DEL:
+ case F_RI_FKEY_NOACTION_UPD:
+ return RI_TRIGGER_PK;
+
+ case F_RI_FKEY_CHECK_INS:
+ case F_RI_FKEY_CHECK_UPD:
+ return RI_TRIGGER_FK;
+ }
+
+ return RI_TRIGGER_NONE;
+}