4 * Generic trigger procedures for referential integrity constraint
7 * Note about memory management: the private hashtables kept here live
8 * across query and transaction boundaries, in fact they live as long as
9 * the backend does. This works because the hashtable structures
10 * themselves are allocated by dynahash.c in its permanent DynaHashCxt,
11 * and the SPI plans they point to are saved using SPI_keepplan().
12 * There is not currently any provision for throwing away a no-longer-needed
13 * plan --- consider improving this someday.
16 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
18 * src/backend/utils/adt/ri_triggers.c
27 * Add MATCH PARTIAL logic.
33 #include "access/htup_details.h"
34 #include "access/sysattr.h"
35 #include "access/xact.h"
36 #include "catalog/pg_collation.h"
37 #include "catalog/pg_constraint.h"
38 #include "catalog/pg_operator.h"
39 #include "catalog/pg_type.h"
40 #include "commands/trigger.h"
41 #include "executor/executor.h"
42 #include "executor/spi.h"
43 #include "parser/parse_coerce.h"
44 #include "parser/parse_relation.h"
45 #include "miscadmin.h"
46 #include "utils/builtins.h"
47 #include "utils/fmgroids.h"
48 #include "utils/guc.h"
49 #include "utils/inval.h"
50 #include "utils/lsyscache.h"
51 #include "utils/memutils.h"
52 #include "utils/rel.h"
53 #include "utils/snapmgr.h"
54 #include "utils/syscache.h"
55 #include "utils/tqual.h"
63 #define RI_MAX_NUMKEYS INDEX_MAX_KEYS
65 #define RI_INIT_CONSTRAINTHASHSIZE 64
66 #define RI_INIT_QUERYHASHSIZE (RI_INIT_CONSTRAINTHASHSIZE * 4)
68 #define RI_KEYS_ALL_NULL 0
69 #define RI_KEYS_SOME_NULL 1
70 #define RI_KEYS_NONE_NULL 2
72 /* RI query type codes */
73 /* these queries are executed against the PK (referenced) table: */
74 #define RI_PLAN_CHECK_LOOKUPPK 1
75 #define RI_PLAN_CHECK_LOOKUPPK_FROM_PK 2
76 #define RI_PLAN_LAST_ON_PK RI_PLAN_CHECK_LOOKUPPK_FROM_PK
77 /* these queries are executed against the FK (referencing) table: */
78 #define RI_PLAN_CASCADE_DEL_DODELETE 3
79 #define RI_PLAN_CASCADE_UPD_DOUPDATE 4
80 #define RI_PLAN_RESTRICT_DEL_CHECKREF 5
81 #define RI_PLAN_RESTRICT_UPD_CHECKREF 6
82 #define RI_PLAN_SETNULL_DEL_DOUPDATE 7
83 #define RI_PLAN_SETNULL_UPD_DOUPDATE 8
84 #define RI_PLAN_SETDEFAULT_DEL_DOUPDATE 9
85 #define RI_PLAN_SETDEFAULT_UPD_DOUPDATE 10
87 #define MAX_QUOTED_NAME_LEN (NAMEDATALEN*2+3)
88 #define MAX_QUOTED_REL_NAME_LEN (MAX_QUOTED_NAME_LEN*2)
90 #define RIAttName(rel, attnum) NameStr(*attnumAttName(rel, attnum))
91 #define RIAttType(rel, attnum) attnumTypeId(rel, attnum)
92 #define RIAttCollation(rel, attnum) attnumCollationId(rel, attnum)
94 #define RI_TRIGTYPE_INSERT 1
95 #define RI_TRIGTYPE_UPDATE 2
96 #define RI_TRIGTYPE_DELETE 3
102 * Information extracted from an FK pg_constraint entry. This is cached in
103 * ri_constraint_cache.
106 typedef struct RI_ConstraintInfo
108 Oid constraint_id; /* OID of pg_constraint entry (hash key) */
109 bool valid; /* successfully initialized? */
110 uint32 oidHashValue; /* hash value of pg_constraint OID */
111 NameData conname; /* name of the FK constraint */
112 Oid pk_relid; /* referenced relation */
113 Oid fk_relid; /* referencing relation */
114 char confupdtype; /* foreign key's ON UPDATE action */
115 char confdeltype; /* foreign key's ON DELETE action */
116 char confmatchtype; /* foreign key's match type */
117 int nkeys; /* number of key columns */
118 int16 pk_attnums[RI_MAX_NUMKEYS]; /* attnums of referenced cols */
119 int16 fk_attnums[RI_MAX_NUMKEYS]; /* attnums of referencing cols */
120 Oid pf_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (PK =
122 Oid pp_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (PK =
124 Oid ff_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (FK =
132 * The key identifying a prepared SPI plan in our query hashtable
135 typedef struct RI_QueryKey
137 Oid constr_id; /* OID of pg_constraint entry */
138 int32 constr_queryno; /* query type ID, see RI_PLAN_XXX above */
146 typedef struct RI_QueryHashEntry
156 * The key identifying an entry showing how to compare two values
159 typedef struct RI_CompareKey
161 Oid eq_opr; /* the equality operator to apply */
162 Oid typeid; /* the data type to apply it to */
167 * RI_CompareHashEntry
170 typedef struct RI_CompareHashEntry
173 bool valid; /* successfully initialized? */
174 FmgrInfo eq_opr_finfo; /* call info for equality fn */
175 FmgrInfo cast_func_finfo; /* in case we must coerce input */
176 } RI_CompareHashEntry;
183 static HTAB *ri_constraint_cache = NULL;
184 static HTAB *ri_query_cache = NULL;
185 static HTAB *ri_compare_cache = NULL;
189 * Local function prototypes
192 static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
194 const RI_ConstraintInfo *riinfo);
195 static Datum ri_restrict_del(TriggerData *trigdata, bool is_no_action);
196 static Datum ri_restrict_upd(TriggerData *trigdata, bool is_no_action);
197 static void quoteOneName(char *buffer, const char *name);
198 static void quoteRelationName(char *buffer, Relation rel);
199 static void ri_GenerateQual(StringInfo buf,
201 const char *leftop, Oid leftoptype,
203 const char *rightop, Oid rightoptype);
204 static void ri_add_cast_to(StringInfo buf, Oid typid);
205 static void ri_GenerateQualCollation(StringInfo buf, Oid collation);
206 static int ri_NullCheck(HeapTuple tup,
207 const RI_ConstraintInfo *riinfo, bool rel_is_pk);
208 static void ri_BuildQueryKey(RI_QueryKey *key,
209 const RI_ConstraintInfo *riinfo,
210 int32 constr_queryno);
211 static bool ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
212 const RI_ConstraintInfo *riinfo, bool rel_is_pk);
213 static bool ri_AttributesEqual(Oid eq_opr, Oid typeid,
214 Datum oldvalue, Datum newvalue);
216 static void ri_InitHashTables(void);
217 static void InvalidateConstraintCacheCallBack(Datum arg, int cacheid, uint32 hashvalue);
218 static SPIPlanPtr ri_FetchPreparedPlan(RI_QueryKey *key);
219 static void ri_HashPreparedPlan(RI_QueryKey *key, SPIPlanPtr plan);
220 static RI_CompareHashEntry *ri_HashCompareOp(Oid eq_opr, Oid typeid);
222 static void ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname,
224 static const RI_ConstraintInfo *ri_FetchConstraintInfo(Trigger *trigger,
225 Relation trig_rel, bool rel_is_pk);
226 static const RI_ConstraintInfo *ri_LoadConstraintInfo(Oid constraintOid);
227 static SPIPlanPtr ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
228 RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel,
230 static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo,
231 RI_QueryKey *qkey, SPIPlanPtr qplan,
232 Relation fk_rel, Relation pk_rel,
233 HeapTuple old_tuple, HeapTuple new_tuple,
234 bool detectNewRows, int expect_OK);
235 static void ri_ExtractValues(Relation rel, HeapTuple tup,
236 const RI_ConstraintInfo *riinfo, bool rel_is_pk,
237 Datum *vals, char *nulls);
238 static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
239 Relation pk_rel, Relation fk_rel,
240 HeapTuple violator, TupleDesc tupdesc,
241 int queryno, bool spi_err);
247 * Check foreign key existence (combined for INSERT and UPDATE).
251 RI_FKey_check(TriggerData *trigdata)
253 const RI_ConstraintInfo *riinfo;
265 riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
266 trigdata->tg_relation, false);
268 if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
270 new_row = trigdata->tg_newtuple;
271 new_row_buf = trigdata->tg_newtuplebuf;
275 new_row = trigdata->tg_trigtuple;
276 new_row_buf = trigdata->tg_trigtuplebuf;
280 * We should not even consider checking the row if it is no longer valid,
281 * since it was either deleted (so the deferred check should be skipped)
282 * or updated (in which case only the latest version of the row should be
283 * checked). Test its liveness according to SnapshotSelf.
285 * NOTE: The normal coding rule is that one must acquire the buffer
286 * content lock to call HeapTupleSatisfiesVisibility. We can skip that
287 * here because we know that AfterTriggerExecute just fetched the tuple
288 * successfully, so there cannot be a VACUUM compaction in progress on the
289 * page (either heap_fetch would have waited for the VACUUM, or the
290 * VACUUM's LockBufferForCleanup would be waiting for us to drop pin). And
291 * since this is a row inserted by our open transaction, no one else can
292 * be entitled to change its xmin/xmax.
294 Assert(new_row_buf != InvalidBuffer);
295 if (!HeapTupleSatisfiesVisibility(new_row, SnapshotSelf, new_row_buf))
296 return PointerGetDatum(NULL);
299 * Get the relation descriptors of the FK and PK tables.
301 * pk_rel is opened in RowShareLock mode since that's what our eventual
302 * SELECT FOR KEY SHARE will get on it.
304 fk_rel = trigdata->tg_relation;
305 pk_rel = heap_open(riinfo->pk_relid, RowShareLock);
307 if (riinfo->confmatchtype == FKCONSTR_MATCH_PARTIAL)
309 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
310 errmsg("MATCH PARTIAL not yet implemented")));
312 switch (ri_NullCheck(new_row, riinfo, false))
314 case RI_KEYS_ALL_NULL:
317 * No further check needed - an all-NULL key passes every type of
318 * foreign key constraint.
320 heap_close(pk_rel, RowShareLock);
321 return PointerGetDatum(NULL);
323 case RI_KEYS_SOME_NULL:
326 * This is the only case that differs between the three kinds of
329 switch (riinfo->confmatchtype)
331 case FKCONSTR_MATCH_FULL:
334 * Not allowed - MATCH FULL says either all or none of the
335 * attributes can be NULLs
338 (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
339 errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
340 RelationGetRelationName(fk_rel),
341 NameStr(riinfo->conname)),
342 errdetail("MATCH FULL does not allow mixing of null and nonnull key values."),
343 errtableconstraint(fk_rel,
344 NameStr(riinfo->conname))));
345 heap_close(pk_rel, RowShareLock);
346 return PointerGetDatum(NULL);
348 case FKCONSTR_MATCH_SIMPLE:
351 * MATCH SIMPLE - if ANY column is null, the key passes
354 heap_close(pk_rel, RowShareLock);
355 return PointerGetDatum(NULL);
357 case FKCONSTR_MATCH_PARTIAL:
360 * MATCH PARTIAL - all non-null columns must match. (not
361 * implemented, can be done by modifying the query below
362 * to only include non-null columns, or by writing a
363 * special version here)
366 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
367 errmsg("MATCH PARTIAL not yet implemented")));
368 heap_close(pk_rel, RowShareLock);
369 return PointerGetDatum(NULL);
372 elog(ERROR, "unrecognized confmatchtype: %d",
373 riinfo->confmatchtype);
377 case RI_KEYS_NONE_NULL:
380 * Have a full qualified key - continue below for all three kinds
386 if (SPI_connect() != SPI_OK_CONNECT)
387 elog(ERROR, "SPI_connect failed");
390 * Fetch or prepare a saved plan for the real check
392 ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CHECK_LOOKUPPK);
394 if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
396 StringInfoData querybuf;
397 char pkrelname[MAX_QUOTED_REL_NAME_LEN];
398 char attname[MAX_QUOTED_NAME_LEN];
400 const char *querysep;
401 Oid queryoids[RI_MAX_NUMKEYS];
404 * The query string built is
405 * SELECT 1 FROM ONLY <pktable> x WHERE pkatt1 = $1 [AND ...]
407 * The type id's for the $ parameters are those of the
408 * corresponding FK attributes.
411 initStringInfo(&querybuf);
412 quoteRelationName(pkrelname, pk_rel);
413 appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x", pkrelname);
415 for (i = 0; i < riinfo->nkeys; i++)
417 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
418 Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
420 quoteOneName(attname,
421 RIAttName(pk_rel, riinfo->pk_attnums[i]));
422 sprintf(paramname, "$%d", i + 1);
423 ri_GenerateQual(&querybuf, querysep,
425 riinfo->pf_eq_oprs[i],
428 queryoids[i] = fk_type;
430 appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
432 /* Prepare and save the plan */
433 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
434 &qkey, fk_rel, pk_rel, true);
438 * Now check that foreign key exists in PK table
440 ri_PerformCheck(riinfo, &qkey, qplan,
446 if (SPI_finish() != SPI_OK_FINISH)
447 elog(ERROR, "SPI_finish failed");
449 heap_close(pk_rel, RowShareLock);
451 return PointerGetDatum(NULL);
456 * RI_FKey_check_ins -
458 * Check foreign key existence at insert event on FK table.
462 RI_FKey_check_ins(PG_FUNCTION_ARGS)
465 * Check that this is a valid trigger call on the right time and event.
467 ri_CheckTrigger(fcinfo, "RI_FKey_check_ins", RI_TRIGTYPE_INSERT);
470 * Share code with UPDATE case.
472 return RI_FKey_check((TriggerData *) fcinfo->context);
477 * RI_FKey_check_upd -
479 * Check foreign key existence at update event on FK table.
483 RI_FKey_check_upd(PG_FUNCTION_ARGS)
486 * Check that this is a valid trigger call on the right time and event.
488 ri_CheckTrigger(fcinfo, "RI_FKey_check_upd", RI_TRIGTYPE_UPDATE);
491 * Share code with INSERT case.
493 return RI_FKey_check((TriggerData *) fcinfo->context);
500 * Check to see if another PK row has been created that provides the same
501 * key values as the "old_row" that's been modified or deleted in our trigger
502 * event. Returns true if a match is found in the PK table.
504 * We assume the caller checked that the old_row contains no NULL key values,
505 * since otherwise a match is impossible.
509 ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
511 const RI_ConstraintInfo *riinfo)
518 /* Only called for non-null rows */
519 Assert(ri_NullCheck(old_row, riinfo, true) == RI_KEYS_NONE_NULL);
521 if (SPI_connect() != SPI_OK_CONNECT)
522 elog(ERROR, "SPI_connect failed");
525 * Fetch or prepare a saved plan for checking PK table with values coming
528 ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CHECK_LOOKUPPK_FROM_PK);
530 if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
532 StringInfoData querybuf;
533 char pkrelname[MAX_QUOTED_REL_NAME_LEN];
534 char attname[MAX_QUOTED_NAME_LEN];
536 const char *querysep;
537 Oid queryoids[RI_MAX_NUMKEYS];
540 * The query string built is
541 * SELECT 1 FROM ONLY <pktable> x WHERE pkatt1 = $1 [AND ...]
543 * The type id's for the $ parameters are those of the
544 * PK attributes themselves.
547 initStringInfo(&querybuf);
548 quoteRelationName(pkrelname, pk_rel);
549 appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x", pkrelname);
551 for (i = 0; i < riinfo->nkeys; i++)
553 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
555 quoteOneName(attname,
556 RIAttName(pk_rel, riinfo->pk_attnums[i]));
557 sprintf(paramname, "$%d", i + 1);
558 ri_GenerateQual(&querybuf, querysep,
560 riinfo->pp_eq_oprs[i],
563 queryoids[i] = pk_type;
565 appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
567 /* Prepare and save the plan */
568 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
569 &qkey, fk_rel, pk_rel, true);
573 * We have a plan now. Run it.
575 result = ri_PerformCheck(riinfo, &qkey, qplan,
578 true, /* treat like update */
581 if (SPI_finish() != SPI_OK_FINISH)
582 elog(ERROR, "SPI_finish failed");
589 * RI_FKey_noaction_del -
591 * Give an error and roll back the current transaction if the
592 * delete has resulted in a violation of the given referential
593 * integrity constraint.
597 RI_FKey_noaction_del(PG_FUNCTION_ARGS)
600 * Check that this is a valid trigger call on the right time and event.
602 ri_CheckTrigger(fcinfo, "RI_FKey_noaction_del", RI_TRIGTYPE_DELETE);
605 * Share code with RESTRICT case.
607 return ri_restrict_del((TriggerData *) fcinfo->context, true);
611 * RI_FKey_restrict_del -
613 * Restrict delete from PK table to rows unreferenced by foreign key.
615 * The SQL standard intends that this referential action occur exactly when
616 * the delete is performed, rather than after. This appears to be
617 * the only difference between "NO ACTION" and "RESTRICT". In Postgres
618 * we still implement this as an AFTER trigger, but it's non-deferrable.
622 RI_FKey_restrict_del(PG_FUNCTION_ARGS)
625 * Check that this is a valid trigger call on the right time and event.
627 ri_CheckTrigger(fcinfo, "RI_FKey_restrict_del", RI_TRIGTYPE_DELETE);
630 * Share code with NO ACTION case.
632 return ri_restrict_del((TriggerData *) fcinfo->context, false);
638 * Common code for ON DELETE RESTRICT and ON DELETE NO ACTION.
642 ri_restrict_del(TriggerData *trigdata, bool is_no_action)
644 const RI_ConstraintInfo *riinfo;
655 riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
656 trigdata->tg_relation, true);
659 * Get the relation descriptors of the FK and PK tables and the old tuple.
661 * fk_rel is opened in RowShareLock mode since that's what our eventual
662 * SELECT FOR KEY SHARE will get on it.
664 fk_rel = heap_open(riinfo->fk_relid, RowShareLock);
665 pk_rel = trigdata->tg_relation;
666 old_row = trigdata->tg_trigtuple;
668 switch (riinfo->confmatchtype)
671 * SQL:2008 15.17 <Execution of referential actions>
672 * General rules 9) a) iv):
674 * ... ON DELETE RESTRICT
677 case FKCONSTR_MATCH_SIMPLE:
678 case FKCONSTR_MATCH_FULL:
679 switch (ri_NullCheck(old_row, riinfo, true))
681 case RI_KEYS_ALL_NULL:
682 case RI_KEYS_SOME_NULL:
685 * No check needed - there cannot be any reference to old
686 * key if it contains a NULL
688 heap_close(fk_rel, RowShareLock);
689 return PointerGetDatum(NULL);
691 case RI_KEYS_NONE_NULL:
694 * Have a full qualified key - continue below
700 * If another PK row now exists providing the old key values, we
701 * should not do anything. However, this check should only be
702 * made in the NO ACTION case; in RESTRICT cases we don't wish to
703 * allow another row to be substituted.
706 ri_Check_Pk_Match(pk_rel, fk_rel, old_row, riinfo))
708 heap_close(fk_rel, RowShareLock);
709 return PointerGetDatum(NULL);
712 if (SPI_connect() != SPI_OK_CONNECT)
713 elog(ERROR, "SPI_connect failed");
716 * Fetch or prepare a saved plan for the restrict delete lookup
718 ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_RESTRICT_DEL_CHECKREF);
720 if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
722 StringInfoData querybuf;
723 char fkrelname[MAX_QUOTED_REL_NAME_LEN];
724 char attname[MAX_QUOTED_NAME_LEN];
726 const char *querysep;
727 Oid queryoids[RI_MAX_NUMKEYS];
730 * The query string built is
731 * SELECT 1 FROM ONLY <fktable> x WHERE $1 = fkatt1 [AND ...]
733 * The type id's for the $ parameters are those of the
734 * corresponding PK attributes.
737 initStringInfo(&querybuf);
738 quoteRelationName(fkrelname, fk_rel);
739 appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x",
742 for (i = 0; i < riinfo->nkeys; i++)
744 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
745 Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
747 quoteOneName(attname,
748 RIAttName(fk_rel, riinfo->fk_attnums[i]));
749 sprintf(paramname, "$%d", i + 1);
750 ri_GenerateQual(&querybuf, querysep,
752 riinfo->pf_eq_oprs[i],
755 queryoids[i] = pk_type;
757 appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
759 /* Prepare and save the plan */
760 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
761 &qkey, fk_rel, pk_rel, true);
765 * We have a plan now. Run it to check for existing references.
767 ri_PerformCheck(riinfo, &qkey, qplan,
770 true, /* must detect new rows */
773 if (SPI_finish() != SPI_OK_FINISH)
774 elog(ERROR, "SPI_finish failed");
776 heap_close(fk_rel, RowShareLock);
778 return PointerGetDatum(NULL);
781 * Handle MATCH PARTIAL restrict delete.
783 case FKCONSTR_MATCH_PARTIAL:
785 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
786 errmsg("MATCH PARTIAL not yet implemented")));
787 return PointerGetDatum(NULL);
790 elog(ERROR, "unrecognized confmatchtype: %d",
791 riinfo->confmatchtype);
796 return PointerGetDatum(NULL);
801 * RI_FKey_noaction_upd -
803 * Give an error and roll back the current transaction if the
804 * update has resulted in a violation of the given referential
805 * integrity constraint.
809 RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
812 * Check that this is a valid trigger call on the right time and event.
814 ri_CheckTrigger(fcinfo, "RI_FKey_noaction_upd", RI_TRIGTYPE_UPDATE);
817 * Share code with RESTRICT case.
819 return ri_restrict_upd((TriggerData *) fcinfo->context, true);
823 * RI_FKey_restrict_upd -
825 * Restrict update of PK to rows unreferenced by foreign key.
827 * The SQL standard intends that this referential action occur exactly when
828 * the update is performed, rather than after. This appears to be
829 * the only difference between "NO ACTION" and "RESTRICT". In Postgres
830 * we still implement this as an AFTER trigger, but it's non-deferrable.
834 RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
837 * Check that this is a valid trigger call on the right time and event.
839 ri_CheckTrigger(fcinfo, "RI_FKey_restrict_upd", RI_TRIGTYPE_UPDATE);
842 * Share code with NO ACTION case.
844 return ri_restrict_upd((TriggerData *) fcinfo->context, false);
850 * Common code for ON UPDATE RESTRICT and ON UPDATE NO ACTION.
854 ri_restrict_upd(TriggerData *trigdata, bool is_no_action)
856 const RI_ConstraintInfo *riinfo;
868 riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
869 trigdata->tg_relation, true);
872 * Get the relation descriptors of the FK and PK tables and the new and
875 * fk_rel is opened in RowShareLock mode since that's what our eventual
876 * SELECT FOR KEY SHARE will get on it.
878 fk_rel = heap_open(riinfo->fk_relid, RowShareLock);
879 pk_rel = trigdata->tg_relation;
880 new_row = trigdata->tg_newtuple;
881 old_row = trigdata->tg_trigtuple;
883 switch (riinfo->confmatchtype)
886 * SQL:2008 15.17 <Execution of referential actions>
887 * General rules 10) a) iv):
889 * ... ON UPDATE RESTRICT
892 case FKCONSTR_MATCH_SIMPLE:
893 case FKCONSTR_MATCH_FULL:
894 switch (ri_NullCheck(old_row, riinfo, true))
896 case RI_KEYS_ALL_NULL:
897 case RI_KEYS_SOME_NULL:
900 * No check needed - there cannot be any reference to old
901 * key if it contains a NULL
903 heap_close(fk_rel, RowShareLock);
904 return PointerGetDatum(NULL);
906 case RI_KEYS_NONE_NULL:
909 * Have a full qualified key - continue below
915 * No need to check anything if old and new keys are equal
917 if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true))
919 heap_close(fk_rel, RowShareLock);
920 return PointerGetDatum(NULL);
924 * If another PK row now exists providing the old key values, we
925 * should not do anything. However, this check should only be
926 * made in the NO ACTION case; in RESTRICT cases we don't wish to
927 * allow another row to be substituted.
930 ri_Check_Pk_Match(pk_rel, fk_rel, old_row, riinfo))
932 heap_close(fk_rel, RowShareLock);
933 return PointerGetDatum(NULL);
936 if (SPI_connect() != SPI_OK_CONNECT)
937 elog(ERROR, "SPI_connect failed");
940 * Fetch or prepare a saved plan for the restrict update lookup
942 ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_RESTRICT_UPD_CHECKREF);
944 if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
946 StringInfoData querybuf;
947 char fkrelname[MAX_QUOTED_REL_NAME_LEN];
948 char attname[MAX_QUOTED_NAME_LEN];
950 const char *querysep;
951 Oid queryoids[RI_MAX_NUMKEYS];
954 * The query string built is
955 * SELECT 1 FROM ONLY <fktable> WHERE $1 = fkatt1 [AND ...]
956 * The type id's for the $ parameters are those of the
957 * corresponding PK attributes.
960 initStringInfo(&querybuf);
961 quoteRelationName(fkrelname, fk_rel);
962 appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x",
965 for (i = 0; i < riinfo->nkeys; i++)
967 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
968 Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
970 quoteOneName(attname,
971 RIAttName(fk_rel, riinfo->fk_attnums[i]));
972 sprintf(paramname, "$%d", i + 1);
973 ri_GenerateQual(&querybuf, querysep,
975 riinfo->pf_eq_oprs[i],
978 queryoids[i] = pk_type;
980 appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
982 /* Prepare and save the plan */
983 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
984 &qkey, fk_rel, pk_rel, true);
988 * We have a plan now. Run it to check for existing references.
990 ri_PerformCheck(riinfo, &qkey, qplan,
993 true, /* must detect new rows */
996 if (SPI_finish() != SPI_OK_FINISH)
997 elog(ERROR, "SPI_finish failed");
999 heap_close(fk_rel, RowShareLock);
1001 return PointerGetDatum(NULL);
1004 * Handle MATCH PARTIAL restrict update.
1006 case FKCONSTR_MATCH_PARTIAL:
1008 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1009 errmsg("MATCH PARTIAL not yet implemented")));
1010 return PointerGetDatum(NULL);
1013 elog(ERROR, "unrecognized confmatchtype: %d",
1014 riinfo->confmatchtype);
1019 return PointerGetDatum(NULL);
1024 * RI_FKey_cascade_del -
1026 * Cascaded delete foreign key references at delete event on PK table.
1030 RI_FKey_cascade_del(PG_FUNCTION_ARGS)
1032 TriggerData *trigdata = (TriggerData *) fcinfo->context;
1033 const RI_ConstraintInfo *riinfo;
1042 * Check that this is a valid trigger call on the right time and event.
1044 ri_CheckTrigger(fcinfo, "RI_FKey_cascade_del", RI_TRIGTYPE_DELETE);
1049 riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1050 trigdata->tg_relation, true);
1053 * Get the relation descriptors of the FK and PK tables and the old tuple.
1055 * fk_rel is opened in RowExclusiveLock mode since that's what our
1056 * eventual DELETE will get on it.
1058 fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock);
1059 pk_rel = trigdata->tg_relation;
1060 old_row = trigdata->tg_trigtuple;
1062 switch (riinfo->confmatchtype)
1065 * SQL:2008 15.17 <Execution of referential actions>
1066 * General rules 9) a) i):
1068 * ... ON DELETE CASCADE
1071 case FKCONSTR_MATCH_SIMPLE:
1072 case FKCONSTR_MATCH_FULL:
1073 switch (ri_NullCheck(old_row, riinfo, true))
1075 case RI_KEYS_ALL_NULL:
1076 case RI_KEYS_SOME_NULL:
1079 * No check needed - there cannot be any reference to old
1080 * key if it contains a NULL
1082 heap_close(fk_rel, RowExclusiveLock);
1083 return PointerGetDatum(NULL);
1085 case RI_KEYS_NONE_NULL:
1088 * Have a full qualified key - continue below
1093 if (SPI_connect() != SPI_OK_CONNECT)
1094 elog(ERROR, "SPI_connect failed");
1097 * Fetch or prepare a saved plan for the cascaded delete
1099 ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CASCADE_DEL_DODELETE);
1101 if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1103 StringInfoData querybuf;
1104 char fkrelname[MAX_QUOTED_REL_NAME_LEN];
1105 char attname[MAX_QUOTED_NAME_LEN];
1107 const char *querysep;
1108 Oid queryoids[RI_MAX_NUMKEYS];
1111 * The query string built is
1112 * DELETE FROM ONLY <fktable> WHERE $1 = fkatt1 [AND ...]
1113 * The type id's for the $ parameters are those of the
1114 * corresponding PK attributes.
1117 initStringInfo(&querybuf);
1118 quoteRelationName(fkrelname, fk_rel);
1119 appendStringInfo(&querybuf, "DELETE FROM ONLY %s", fkrelname);
1121 for (i = 0; i < riinfo->nkeys; i++)
1123 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1124 Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1126 quoteOneName(attname,
1127 RIAttName(fk_rel, riinfo->fk_attnums[i]));
1128 sprintf(paramname, "$%d", i + 1);
1129 ri_GenerateQual(&querybuf, querysep,
1131 riinfo->pf_eq_oprs[i],
1134 queryoids[i] = pk_type;
1137 /* Prepare and save the plan */
1138 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
1139 &qkey, fk_rel, pk_rel, true);
1143 * We have a plan now. Build up the arguments from the key values
1144 * in the deleted PK tuple and delete the referencing rows
1146 ri_PerformCheck(riinfo, &qkey, qplan,
1149 true, /* must detect new rows */
1152 if (SPI_finish() != SPI_OK_FINISH)
1153 elog(ERROR, "SPI_finish failed");
1155 heap_close(fk_rel, RowExclusiveLock);
1157 return PointerGetDatum(NULL);
1160 * Handle MATCH PARTIAL cascaded delete.
1162 case FKCONSTR_MATCH_PARTIAL:
1164 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1165 errmsg("MATCH PARTIAL not yet implemented")));
1166 return PointerGetDatum(NULL);
1169 elog(ERROR, "unrecognized confmatchtype: %d",
1170 riinfo->confmatchtype);
1175 return PointerGetDatum(NULL);
1180 * RI_FKey_cascade_upd -
1182 * Cascaded update foreign key references at update event on PK table.
1186 RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
1188 TriggerData *trigdata = (TriggerData *) fcinfo->context;
1189 const RI_ConstraintInfo *riinfo;
1200 * Check that this is a valid trigger call on the right time and event.
1202 ri_CheckTrigger(fcinfo, "RI_FKey_cascade_upd", RI_TRIGTYPE_UPDATE);
1207 riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1208 trigdata->tg_relation, true);
1211 * Get the relation descriptors of the FK and PK tables and the new and
1214 * fk_rel is opened in RowExclusiveLock mode since that's what our
1215 * eventual UPDATE will get on it.
1217 fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock);
1218 pk_rel = trigdata->tg_relation;
1219 new_row = trigdata->tg_newtuple;
1220 old_row = trigdata->tg_trigtuple;
1222 switch (riinfo->confmatchtype)
1225 * SQL:2008 15.17 <Execution of referential actions>
1226 * General rules 10) a) i):
1228 * ... ON UPDATE CASCADE
1231 case FKCONSTR_MATCH_SIMPLE:
1232 case FKCONSTR_MATCH_FULL:
1233 switch (ri_NullCheck(old_row, riinfo, true))
1235 case RI_KEYS_ALL_NULL:
1236 case RI_KEYS_SOME_NULL:
1239 * No check needed - there cannot be any reference to old
1240 * key if it contains a NULL
1242 heap_close(fk_rel, RowExclusiveLock);
1243 return PointerGetDatum(NULL);
1245 case RI_KEYS_NONE_NULL:
1248 * Have a full qualified key - continue below
1254 * No need to do anything if old and new keys are equal
1256 if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true))
1258 heap_close(fk_rel, RowExclusiveLock);
1259 return PointerGetDatum(NULL);
1262 if (SPI_connect() != SPI_OK_CONNECT)
1263 elog(ERROR, "SPI_connect failed");
1266 * Fetch or prepare a saved plan for the cascaded update
1268 ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CASCADE_UPD_DOUPDATE);
1270 if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1272 StringInfoData querybuf;
1273 StringInfoData qualbuf;
1274 char fkrelname[MAX_QUOTED_REL_NAME_LEN];
1275 char attname[MAX_QUOTED_NAME_LEN];
1277 const char *querysep;
1278 const char *qualsep;
1279 Oid queryoids[RI_MAX_NUMKEYS * 2];
1282 * The query string built is
1283 * UPDATE ONLY <fktable> SET fkatt1 = $1 [, ...]
1284 * WHERE $n = fkatt1 [AND ...]
1285 * The type id's for the $ parameters are those of the
1286 * corresponding PK attributes. Note that we are assuming
1287 * there is an assignment cast from the PK to the FK type;
1288 * else the parser will fail.
1291 initStringInfo(&querybuf);
1292 initStringInfo(&qualbuf);
1293 quoteRelationName(fkrelname, fk_rel);
1294 appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname);
1297 for (i = 0, j = riinfo->nkeys; i < riinfo->nkeys; i++, j++)
1299 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1300 Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1302 quoteOneName(attname,
1303 RIAttName(fk_rel, riinfo->fk_attnums[i]));
1304 appendStringInfo(&querybuf,
1306 querysep, attname, i + 1);
1307 sprintf(paramname, "$%d", j + 1);
1308 ri_GenerateQual(&qualbuf, qualsep,
1310 riinfo->pf_eq_oprs[i],
1314 queryoids[i] = pk_type;
1315 queryoids[j] = pk_type;
1317 appendStringInfoString(&querybuf, qualbuf.data);
1319 /* Prepare and save the plan */
1320 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys * 2, queryoids,
1321 &qkey, fk_rel, pk_rel, true);
1325 * We have a plan now. Run it to update the existing references.
1327 ri_PerformCheck(riinfo, &qkey, qplan,
1330 true, /* must detect new rows */
1333 if (SPI_finish() != SPI_OK_FINISH)
1334 elog(ERROR, "SPI_finish failed");
1336 heap_close(fk_rel, RowExclusiveLock);
1338 return PointerGetDatum(NULL);
1341 * Handle MATCH PARTIAL cascade update.
1343 case FKCONSTR_MATCH_PARTIAL:
1345 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1346 errmsg("MATCH PARTIAL not yet implemented")));
1347 return PointerGetDatum(NULL);
1350 elog(ERROR, "unrecognized confmatchtype: %d",
1351 riinfo->confmatchtype);
1356 return PointerGetDatum(NULL);
1361 * RI_FKey_setnull_del -
1363 * Set foreign key references to NULL values at delete event on PK table.
1367 RI_FKey_setnull_del(PG_FUNCTION_ARGS)
1369 TriggerData *trigdata = (TriggerData *) fcinfo->context;
1370 const RI_ConstraintInfo *riinfo;
1379 * Check that this is a valid trigger call on the right time and event.
1381 ri_CheckTrigger(fcinfo, "RI_FKey_setnull_del", RI_TRIGTYPE_DELETE);
1386 riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1387 trigdata->tg_relation, true);
1390 * Get the relation descriptors of the FK and PK tables and the old tuple.
1392 * fk_rel is opened in RowExclusiveLock mode since that's what our
1393 * eventual UPDATE will get on it.
1395 fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock);
1396 pk_rel = trigdata->tg_relation;
1397 old_row = trigdata->tg_trigtuple;
1399 switch (riinfo->confmatchtype)
1402 * SQL:2008 15.17 <Execution of referential actions>
1403 * General rules 9) a) ii):
1405 * ... ON DELETE SET NULL
1408 case FKCONSTR_MATCH_SIMPLE:
1409 case FKCONSTR_MATCH_FULL:
1410 switch (ri_NullCheck(old_row, riinfo, true))
1412 case RI_KEYS_ALL_NULL:
1413 case RI_KEYS_SOME_NULL:
1416 * No check needed - there cannot be any reference to old
1417 * key if it contains a NULL
1419 heap_close(fk_rel, RowExclusiveLock);
1420 return PointerGetDatum(NULL);
1422 case RI_KEYS_NONE_NULL:
1425 * Have a full qualified key - continue below
1430 if (SPI_connect() != SPI_OK_CONNECT)
1431 elog(ERROR, "SPI_connect failed");
1434 * Fetch or prepare a saved plan for the set null delete operation
1436 ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_SETNULL_DEL_DOUPDATE);
1438 if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1440 StringInfoData querybuf;
1441 StringInfoData qualbuf;
1442 char fkrelname[MAX_QUOTED_REL_NAME_LEN];
1443 char attname[MAX_QUOTED_NAME_LEN];
1445 const char *querysep;
1446 const char *qualsep;
1447 Oid queryoids[RI_MAX_NUMKEYS];
1450 * The query string built is
1451 * UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]
1452 * WHERE $1 = fkatt1 [AND ...]
1453 * The type id's for the $ parameters are those of the
1454 * corresponding PK attributes.
1457 initStringInfo(&querybuf);
1458 initStringInfo(&qualbuf);
1459 quoteRelationName(fkrelname, fk_rel);
1460 appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname);
1463 for (i = 0; i < riinfo->nkeys; i++)
1465 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1466 Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1468 quoteOneName(attname,
1469 RIAttName(fk_rel, riinfo->fk_attnums[i]));
1470 appendStringInfo(&querybuf,
1473 sprintf(paramname, "$%d", i + 1);
1474 ri_GenerateQual(&qualbuf, qualsep,
1476 riinfo->pf_eq_oprs[i],
1480 queryoids[i] = pk_type;
1482 appendStringInfoString(&querybuf, qualbuf.data);
1484 /* Prepare and save the plan */
1485 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
1486 &qkey, fk_rel, pk_rel, true);
1490 * We have a plan now. Run it to check for existing references.
1492 ri_PerformCheck(riinfo, &qkey, qplan,
1495 true, /* must detect new rows */
1498 if (SPI_finish() != SPI_OK_FINISH)
1499 elog(ERROR, "SPI_finish failed");
1501 heap_close(fk_rel, RowExclusiveLock);
1503 return PointerGetDatum(NULL);
1506 * Handle MATCH PARTIAL set null delete.
1508 case FKCONSTR_MATCH_PARTIAL:
1510 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1511 errmsg("MATCH PARTIAL not yet implemented")));
1512 return PointerGetDatum(NULL);
1515 elog(ERROR, "unrecognized confmatchtype: %d",
1516 riinfo->confmatchtype);
1521 return PointerGetDatum(NULL);
1526 * RI_FKey_setnull_upd -
1528 * Set foreign key references to NULL at update event on PK table.
1532 RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
1534 TriggerData *trigdata = (TriggerData *) fcinfo->context;
1535 const RI_ConstraintInfo *riinfo;
1545 * Check that this is a valid trigger call on the right time and event.
1547 ri_CheckTrigger(fcinfo, "RI_FKey_setnull_upd", RI_TRIGTYPE_UPDATE);
1552 riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1553 trigdata->tg_relation, true);
1556 * Get the relation descriptors of the FK and PK tables and the old tuple.
1558 * fk_rel is opened in RowExclusiveLock mode since that's what our
1559 * eventual UPDATE will get on it.
1561 fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock);
1562 pk_rel = trigdata->tg_relation;
1563 new_row = trigdata->tg_newtuple;
1564 old_row = trigdata->tg_trigtuple;
1566 switch (riinfo->confmatchtype)
1569 * SQL:2008 15.17 <Execution of referential actions>
1570 * General rules 10) a) ii):
1572 * ... ON UPDATE SET NULL
1575 case FKCONSTR_MATCH_SIMPLE:
1576 case FKCONSTR_MATCH_FULL:
1577 switch (ri_NullCheck(old_row, riinfo, true))
1579 case RI_KEYS_ALL_NULL:
1580 case RI_KEYS_SOME_NULL:
1583 * No check needed - there cannot be any reference to old
1584 * key if it contains a NULL
1586 heap_close(fk_rel, RowExclusiveLock);
1587 return PointerGetDatum(NULL);
1589 case RI_KEYS_NONE_NULL:
1592 * Have a full qualified key - continue below
1598 * No need to do anything if old and new keys are equal
1600 if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true))
1602 heap_close(fk_rel, RowExclusiveLock);
1603 return PointerGetDatum(NULL);
1606 if (SPI_connect() != SPI_OK_CONNECT)
1607 elog(ERROR, "SPI_connect failed");
1610 * Fetch or prepare a saved plan for the set null update operation
1612 ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_SETNULL_UPD_DOUPDATE);
1614 if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1616 StringInfoData querybuf;
1617 StringInfoData qualbuf;
1618 char fkrelname[MAX_QUOTED_REL_NAME_LEN];
1619 char attname[MAX_QUOTED_NAME_LEN];
1621 const char *querysep;
1622 const char *qualsep;
1623 Oid queryoids[RI_MAX_NUMKEYS];
1626 * The query string built is
1627 * UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]
1628 * WHERE $1 = fkatt1 [AND ...]
1629 * The type id's for the $ parameters are those of the
1630 * corresponding PK attributes.
1633 initStringInfo(&querybuf);
1634 initStringInfo(&qualbuf);
1635 quoteRelationName(fkrelname, fk_rel);
1636 appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname);
1639 for (i = 0; i < riinfo->nkeys; i++)
1641 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1642 Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1644 quoteOneName(attname,
1645 RIAttName(fk_rel, riinfo->fk_attnums[i]));
1646 appendStringInfo(&querybuf,
1649 sprintf(paramname, "$%d", i + 1);
1650 ri_GenerateQual(&qualbuf, qualsep,
1652 riinfo->pf_eq_oprs[i],
1656 queryoids[i] = pk_type;
1658 appendStringInfoString(&querybuf, qualbuf.data);
1660 /* Prepare and save the plan */
1661 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
1662 &qkey, fk_rel, pk_rel, true);
1666 * We have a plan now. Run it to update the existing references.
1668 ri_PerformCheck(riinfo, &qkey, qplan,
1671 true, /* must detect new rows */
1674 if (SPI_finish() != SPI_OK_FINISH)
1675 elog(ERROR, "SPI_finish failed");
1677 heap_close(fk_rel, RowExclusiveLock);
1679 return PointerGetDatum(NULL);
1682 * Handle MATCH PARTIAL set null update.
1684 case FKCONSTR_MATCH_PARTIAL:
1686 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1687 errmsg("MATCH PARTIAL not yet implemented")));
1688 return PointerGetDatum(NULL);
1691 elog(ERROR, "unrecognized confmatchtype: %d",
1692 riinfo->confmatchtype);
1697 return PointerGetDatum(NULL);
1702 * RI_FKey_setdefault_del -
1704 * Set foreign key references to defaults at delete event on PK table.
1708 RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
1710 TriggerData *trigdata = (TriggerData *) fcinfo->context;
1711 const RI_ConstraintInfo *riinfo;
1719 * Check that this is a valid trigger call on the right time and event.
1721 ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_del", RI_TRIGTYPE_DELETE);
1726 riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1727 trigdata->tg_relation, true);
1730 * Get the relation descriptors of the FK and PK tables and the old tuple.
1732 * fk_rel is opened in RowExclusiveLock mode since that's what our
1733 * eventual UPDATE will get on it.
1735 fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock);
1736 pk_rel = trigdata->tg_relation;
1737 old_row = trigdata->tg_trigtuple;
1739 switch (riinfo->confmatchtype)
1742 * SQL:2008 15.17 <Execution of referential actions>
1743 * General rules 9) a) iii):
1745 * ... ON DELETE SET DEFAULT
1748 case FKCONSTR_MATCH_SIMPLE:
1749 case FKCONSTR_MATCH_FULL:
1750 switch (ri_NullCheck(old_row, riinfo, true))
1752 case RI_KEYS_ALL_NULL:
1753 case RI_KEYS_SOME_NULL:
1756 * No check needed - there cannot be any reference to old
1757 * key if it contains a NULL
1759 heap_close(fk_rel, RowExclusiveLock);
1760 return PointerGetDatum(NULL);
1762 case RI_KEYS_NONE_NULL:
1765 * Have a full qualified key - continue below
1770 if (SPI_connect() != SPI_OK_CONNECT)
1771 elog(ERROR, "SPI_connect failed");
1774 * Fetch or prepare a saved plan for the set default delete
1777 ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_SETDEFAULT_DEL_DOUPDATE);
1779 if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1781 StringInfoData querybuf;
1782 StringInfoData qualbuf;
1783 char fkrelname[MAX_QUOTED_REL_NAME_LEN];
1784 char attname[MAX_QUOTED_NAME_LEN];
1786 const char *querysep;
1787 const char *qualsep;
1788 Oid queryoids[RI_MAX_NUMKEYS];
1792 * The query string built is
1793 * UPDATE ONLY <fktable> SET fkatt1 = DEFAULT [, ...]
1794 * WHERE $1 = fkatt1 [AND ...]
1795 * The type id's for the $ parameters are those of the
1796 * corresponding PK attributes.
1799 initStringInfo(&querybuf);
1800 initStringInfo(&qualbuf);
1801 quoteRelationName(fkrelname, fk_rel);
1802 appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname);
1805 for (i = 0; i < riinfo->nkeys; i++)
1807 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1808 Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1810 quoteOneName(attname,
1811 RIAttName(fk_rel, riinfo->fk_attnums[i]));
1812 appendStringInfo(&querybuf,
1815 sprintf(paramname, "$%d", i + 1);
1816 ri_GenerateQual(&qualbuf, qualsep,
1818 riinfo->pf_eq_oprs[i],
1822 queryoids[i] = pk_type;
1824 appendStringInfoString(&querybuf, qualbuf.data);
1826 /* Prepare and save the plan */
1827 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
1828 &qkey, fk_rel, pk_rel, true);
1832 * We have a plan now. Run it to update the existing references.
1834 ri_PerformCheck(riinfo, &qkey, qplan,
1837 true, /* must detect new rows */
1840 if (SPI_finish() != SPI_OK_FINISH)
1841 elog(ERROR, "SPI_finish failed");
1843 heap_close(fk_rel, RowExclusiveLock);
1846 * If we just deleted the PK row whose key was equal to the FK
1847 * columns' default values, and a referencing row exists in the FK
1848 * table, we would have updated that row to the same values it
1849 * already had --- and RI_FKey_fk_upd_check_required would hence
1850 * believe no check is necessary. So we need to do another lookup
1851 * now and in case a reference still exists, abort the operation.
1852 * That is already implemented in the NO ACTION trigger, so just
1853 * run it. (This recheck is only needed in the SET DEFAULT case,
1854 * since CASCADE would remove such rows, while SET NULL is certain
1855 * to result in rows that satisfy the FK constraint.)
1857 RI_FKey_noaction_del(fcinfo);
1859 return PointerGetDatum(NULL);
1862 * Handle MATCH PARTIAL set default delete.
1864 case FKCONSTR_MATCH_PARTIAL:
1866 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1867 errmsg("MATCH PARTIAL not yet implemented")));
1868 return PointerGetDatum(NULL);
1871 elog(ERROR, "unrecognized confmatchtype: %d",
1872 riinfo->confmatchtype);
1877 return PointerGetDatum(NULL);
1882 * RI_FKey_setdefault_upd -
1884 * Set foreign key references to defaults at update event on PK table.
1888 RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
1890 TriggerData *trigdata = (TriggerData *) fcinfo->context;
1891 const RI_ConstraintInfo *riinfo;
1900 * Check that this is a valid trigger call on the right time and event.
1902 ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_upd", RI_TRIGTYPE_UPDATE);
1907 riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1908 trigdata->tg_relation, true);
1911 * Get the relation descriptors of the FK and PK tables and the old tuple.
1913 * fk_rel is opened in RowExclusiveLock mode since that's what our
1914 * eventual UPDATE will get on it.
1916 fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock);
1917 pk_rel = trigdata->tg_relation;
1918 new_row = trigdata->tg_newtuple;
1919 old_row = trigdata->tg_trigtuple;
1921 switch (riinfo->confmatchtype)
1924 * SQL:2008 15.17 <Execution of referential actions>
1925 * General rules 10) a) iii):
1927 * ... ON UPDATE SET DEFAULT
1930 case FKCONSTR_MATCH_SIMPLE:
1931 case FKCONSTR_MATCH_FULL:
1932 switch (ri_NullCheck(old_row, riinfo, true))
1934 case RI_KEYS_ALL_NULL:
1935 case RI_KEYS_SOME_NULL:
1938 * No check needed - there cannot be any reference to old
1939 * key if it contains a NULL
1941 heap_close(fk_rel, RowExclusiveLock);
1942 return PointerGetDatum(NULL);
1944 case RI_KEYS_NONE_NULL:
1947 * Have a full qualified key - continue below
1953 * No need to do anything if old and new keys are equal
1955 if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true))
1957 heap_close(fk_rel, RowExclusiveLock);
1958 return PointerGetDatum(NULL);
1961 if (SPI_connect() != SPI_OK_CONNECT)
1962 elog(ERROR, "SPI_connect failed");
1965 * Fetch or prepare a saved plan for the set default update
1968 ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_SETDEFAULT_UPD_DOUPDATE);
1970 if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1972 StringInfoData querybuf;
1973 StringInfoData qualbuf;
1974 char fkrelname[MAX_QUOTED_REL_NAME_LEN];
1975 char attname[MAX_QUOTED_NAME_LEN];
1977 const char *querysep;
1978 const char *qualsep;
1979 Oid queryoids[RI_MAX_NUMKEYS];
1983 * The query string built is
1984 * UPDATE ONLY <fktable> SET fkatt1 = DEFAULT [, ...]
1985 * WHERE $1 = fkatt1 [AND ...]
1986 * The type id's for the $ parameters are those of the
1987 * corresponding PK attributes.
1990 initStringInfo(&querybuf);
1991 initStringInfo(&qualbuf);
1992 quoteRelationName(fkrelname, fk_rel);
1993 appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname);
1996 for (i = 0; i < riinfo->nkeys; i++)
1998 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1999 Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
2001 quoteOneName(attname,
2002 RIAttName(fk_rel, riinfo->fk_attnums[i]));
2003 appendStringInfo(&querybuf,
2006 sprintf(paramname, "$%d", i + 1);
2007 ri_GenerateQual(&qualbuf, qualsep,
2009 riinfo->pf_eq_oprs[i],
2013 queryoids[i] = pk_type;
2015 appendStringInfoString(&querybuf, qualbuf.data);
2017 /* Prepare and save the plan */
2018 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
2019 &qkey, fk_rel, pk_rel, true);
2023 * We have a plan now. Run it to update the existing references.
2025 ri_PerformCheck(riinfo, &qkey, qplan,
2028 true, /* must detect new rows */
2031 if (SPI_finish() != SPI_OK_FINISH)
2032 elog(ERROR, "SPI_finish failed");
2034 heap_close(fk_rel, RowExclusiveLock);
2037 * If we just updated the PK row whose key was equal to the FK
2038 * columns' default values, and a referencing row exists in the FK
2039 * table, we would have updated that row to the same values it
2040 * already had --- and RI_FKey_fk_upd_check_required would hence
2041 * believe no check is necessary. So we need to do another lookup
2042 * now and in case a reference still exists, abort the operation.
2043 * That is already implemented in the NO ACTION trigger, so just
2044 * run it. (This recheck is only needed in the SET DEFAULT case,
2045 * since CASCADE must change the FK key values, while SET NULL is
2046 * certain to result in rows that satisfy the FK constraint.)
2048 RI_FKey_noaction_upd(fcinfo);
2050 return PointerGetDatum(NULL);
2053 * Handle MATCH PARTIAL set default update.
2055 case FKCONSTR_MATCH_PARTIAL:
2057 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2058 errmsg("MATCH PARTIAL not yet implemented")));
2059 return PointerGetDatum(NULL);
2062 elog(ERROR, "unrecognized confmatchtype: %d",
2063 riinfo->confmatchtype);
2068 return PointerGetDatum(NULL);
2073 * RI_FKey_pk_upd_check_required -
2075 * Check if we really need to fire the RI trigger for an update to a PK
2076 * relation. This is called by the AFTER trigger queue manager to see if
2077 * it can skip queuing an instance of an RI trigger. Returns TRUE if the
2078 * trigger must be fired, FALSE if we can prove the constraint will still
2083 RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel,
2084 HeapTuple old_row, HeapTuple new_row)
2086 const RI_ConstraintInfo *riinfo;
2091 riinfo = ri_FetchConstraintInfo(trigger, pk_rel, true);
2093 switch (riinfo->confmatchtype)
2095 case FKCONSTR_MATCH_SIMPLE:
2096 case FKCONSTR_MATCH_FULL:
2099 * If any old key value is NULL, the row could not have been
2100 * referenced by an FK row, so no check is needed.
2102 if (ri_NullCheck(old_row, riinfo, true) != RI_KEYS_NONE_NULL)
2105 /* If all old and new key values are equal, no check is needed */
2106 if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true))
2109 /* Else we need to fire the trigger. */
2112 /* Handle MATCH PARTIAL check. */
2113 case FKCONSTR_MATCH_PARTIAL:
2115 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2116 errmsg("MATCH PARTIAL not yet implemented")));
2120 elog(ERROR, "unrecognized confmatchtype: %d",
2121 riinfo->confmatchtype);
2130 * RI_FKey_fk_upd_check_required -
2132 * Check if we really need to fire the RI trigger for an update to an FK
2133 * relation. This is called by the AFTER trigger queue manager to see if
2134 * it can skip queuing an instance of an RI trigger. Returns TRUE if the
2135 * trigger must be fired, FALSE if we can prove the constraint will still
2140 RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
2141 HeapTuple old_row, HeapTuple new_row)
2143 const RI_ConstraintInfo *riinfo;
2148 riinfo = ri_FetchConstraintInfo(trigger, fk_rel, false);
2150 switch (riinfo->confmatchtype)
2152 case FKCONSTR_MATCH_SIMPLE:
2155 * If any new key value is NULL, the row must satisfy the
2156 * constraint, so no check is needed.
2158 if (ri_NullCheck(new_row, riinfo, false) != RI_KEYS_NONE_NULL)
2162 * If the original row was inserted by our own transaction, we
2163 * must fire the trigger whether or not the keys are equal. This
2164 * is because our UPDATE will invalidate the INSERT so that the
2165 * INSERT RI trigger will not do anything; so we had better do the
2166 * UPDATE check. (We could skip this if we knew the INSERT
2167 * trigger already fired, but there is no easy way to know that.)
2169 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data)))
2172 /* If all old and new key values are equal, no check is needed */
2173 if (ri_KeysEqual(fk_rel, old_row, new_row, riinfo, false))
2176 /* Else we need to fire the trigger. */
2179 case FKCONSTR_MATCH_FULL:
2182 * If all new key values are NULL, the row must satisfy the
2183 * constraint, so no check is needed. On the other hand, if only
2184 * some of them are NULL, the row must fail the constraint. We
2185 * must not throw error here, because the row might get
2186 * invalidated before the constraint is to be checked, but we
2187 * should queue the event to apply the check later.
2189 switch (ri_NullCheck(new_row, riinfo, false))
2191 case RI_KEYS_ALL_NULL:
2193 case RI_KEYS_SOME_NULL:
2195 case RI_KEYS_NONE_NULL:
2196 break; /* continue with the check */
2200 * If the original row was inserted by our own transaction, we
2201 * must fire the trigger whether or not the keys are equal. This
2202 * is because our UPDATE will invalidate the INSERT so that the
2203 * INSERT RI trigger will not do anything; so we had better do the
2204 * UPDATE check. (We could skip this if we knew the INSERT
2205 * trigger already fired, but there is no easy way to know that.)
2207 if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data)))
2210 /* If all old and new key values are equal, no check is needed */
2211 if (ri_KeysEqual(fk_rel, old_row, new_row, riinfo, false))
2214 /* Else we need to fire the trigger. */
2217 /* Handle MATCH PARTIAL check. */
2218 case FKCONSTR_MATCH_PARTIAL:
2220 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2221 errmsg("MATCH PARTIAL not yet implemented")));
2225 elog(ERROR, "unrecognized confmatchtype: %d",
2226 riinfo->confmatchtype);
2235 * RI_Initial_Check -
2237 * Check an entire table for non-matching values using a single query.
2238 * This is not a trigger procedure, but is called during ALTER TABLE
2239 * ADD FOREIGN KEY to validate the initial table contents.
2241 * We expect that the caller has made provision to prevent any problems
2242 * caused by concurrent actions. This could be either by locking rel and
2243 * pkrel at ShareRowExclusiveLock or higher, or by otherwise ensuring
2244 * that triggers implementing the checks are already active.
2245 * Hence, we do not need to lock individual rows for the check.
2247 * If the check fails because the current user doesn't have permissions
2248 * to read both tables, return false to let our caller know that they will
2249 * need to do something else to check the constraint.
2253 RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
2255 const RI_ConstraintInfo *riinfo;
2256 StringInfoData querybuf;
2257 char pkrelname[MAX_QUOTED_REL_NAME_LEN];
2258 char fkrelname[MAX_QUOTED_REL_NAME_LEN];
2259 char pkattname[MAX_QUOTED_NAME_LEN + 3];
2260 char fkattname[MAX_QUOTED_NAME_LEN + 3];
2261 RangeTblEntry *pkrte;
2262 RangeTblEntry *fkrte;
2266 char workmembuf[32];
2270 /* Fetch constraint info. */
2271 riinfo = ri_FetchConstraintInfo(trigger, fk_rel, false);
2274 * Check to make sure current user has enough permissions to do the test
2275 * query. (If not, caller can fall back to the trigger method, which
2276 * works because it changes user IDs on the fly.)
2278 * XXX are there any other show-stopper conditions to check?
2280 pkrte = makeNode(RangeTblEntry);
2281 pkrte->rtekind = RTE_RELATION;
2282 pkrte->relid = RelationGetRelid(pk_rel);
2283 pkrte->relkind = pk_rel->rd_rel->relkind;
2284 pkrte->requiredPerms = ACL_SELECT;
2286 fkrte = makeNode(RangeTblEntry);
2287 fkrte->rtekind = RTE_RELATION;
2288 fkrte->relid = RelationGetRelid(fk_rel);
2289 fkrte->relkind = fk_rel->rd_rel->relkind;
2290 fkrte->requiredPerms = ACL_SELECT;
2292 for (i = 0; i < riinfo->nkeys; i++)
2296 attno = riinfo->pk_attnums[i] - FirstLowInvalidHeapAttributeNumber;
2297 pkrte->selectedCols = bms_add_member(pkrte->selectedCols, attno);
2299 attno = riinfo->fk_attnums[i] - FirstLowInvalidHeapAttributeNumber;
2300 fkrte->selectedCols = bms_add_member(fkrte->selectedCols, attno);
2303 if (!ExecCheckRTPerms(list_make2(fkrte, pkrte), false))
2307 * The query string built is:
2308 * SELECT fk.keycols FROM ONLY relname fk
2309 * LEFT OUTER JOIN ONLY pkrelname pk
2310 * ON (pk.pkkeycol1=fk.keycol1 [AND ...])
2311 * WHERE pk.pkkeycol1 IS NULL AND
2313 * (fk.keycol1 IS NOT NULL [AND ...])
2315 * (fk.keycol1 IS NOT NULL [OR ...])
2317 * We attach COLLATE clauses to the operators when comparing columns
2318 * that have different collations.
2321 initStringInfo(&querybuf);
2322 appendStringInfoString(&querybuf, "SELECT ");
2324 for (i = 0; i < riinfo->nkeys; i++)
2326 quoteOneName(fkattname,
2327 RIAttName(fk_rel, riinfo->fk_attnums[i]));
2328 appendStringInfo(&querybuf, "%sfk.%s", sep, fkattname);
2332 quoteRelationName(pkrelname, pk_rel);
2333 quoteRelationName(fkrelname, fk_rel);
2334 appendStringInfo(&querybuf,
2335 " FROM ONLY %s fk LEFT OUTER JOIN ONLY %s pk ON",
2336 fkrelname, pkrelname);
2338 strcpy(pkattname, "pk.");
2339 strcpy(fkattname, "fk.");
2341 for (i = 0; i < riinfo->nkeys; i++)
2343 Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
2344 Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
2345 Oid pk_coll = RIAttCollation(pk_rel, riinfo->pk_attnums[i]);
2346 Oid fk_coll = RIAttCollation(fk_rel, riinfo->fk_attnums[i]);
2348 quoteOneName(pkattname + 3,
2349 RIAttName(pk_rel, riinfo->pk_attnums[i]));
2350 quoteOneName(fkattname + 3,
2351 RIAttName(fk_rel, riinfo->fk_attnums[i]));
2352 ri_GenerateQual(&querybuf, sep,
2354 riinfo->pf_eq_oprs[i],
2355 fkattname, fk_type);
2356 if (pk_coll != fk_coll)
2357 ri_GenerateQualCollation(&querybuf, pk_coll);
2362 * It's sufficient to test any one pk attribute for null to detect a join
2365 quoteOneName(pkattname, RIAttName(pk_rel, riinfo->pk_attnums[0]));
2366 appendStringInfo(&querybuf, ") WHERE pk.%s IS NULL AND (", pkattname);
2369 for (i = 0; i < riinfo->nkeys; i++)
2371 quoteOneName(fkattname, RIAttName(fk_rel, riinfo->fk_attnums[i]));
2372 appendStringInfo(&querybuf,
2373 "%sfk.%s IS NOT NULL",
2375 switch (riinfo->confmatchtype)
2377 case FKCONSTR_MATCH_SIMPLE:
2380 case FKCONSTR_MATCH_FULL:
2383 case FKCONSTR_MATCH_PARTIAL:
2385 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2386 errmsg("MATCH PARTIAL not yet implemented")));
2389 elog(ERROR, "unrecognized confmatchtype: %d",
2390 riinfo->confmatchtype);
2394 appendStringInfoChar(&querybuf, ')');
2397 * Temporarily increase work_mem so that the check query can be executed
2398 * more efficiently. It seems okay to do this because the query is simple
2399 * enough to not use a multiple of work_mem, and one typically would not
2400 * have many large foreign-key validations happening concurrently. So
2401 * this seems to meet the criteria for being considered a "maintenance"
2402 * operation, and accordingly we use maintenance_work_mem.
2404 * We use the equivalent of a function SET option to allow the setting to
2405 * persist for exactly the duration of the check query. guc.c also takes
2406 * care of undoing the setting on error.
2408 save_nestlevel = NewGUCNestLevel();
2410 snprintf(workmembuf, sizeof(workmembuf), "%d", maintenance_work_mem);
2411 (void) set_config_option("work_mem", workmembuf,
2412 PGC_USERSET, PGC_S_SESSION,
2413 GUC_ACTION_SAVE, true, 0);
2415 if (SPI_connect() != SPI_OK_CONNECT)
2416 elog(ERROR, "SPI_connect failed");
2419 * Generate the plan. We don't need to cache it, and there are no
2420 * arguments to the plan.
2422 qplan = SPI_prepare(querybuf.data, 0, NULL);
2425 elog(ERROR, "SPI_prepare returned %d for %s",
2426 SPI_result, querybuf.data);
2429 * Run the plan. For safety we force a current snapshot to be used. (In
2430 * transaction-snapshot mode, this arguably violates transaction isolation
2431 * rules, but we really haven't got much choice.) We don't need to
2432 * register the snapshot, because SPI_execute_snapshot will see to it. We
2433 * need at most one tuple returned, so pass limit = 1.
2435 spi_result = SPI_execute_snapshot(qplan,
2437 GetLatestSnapshot(),
2442 if (spi_result != SPI_OK_SELECT)
2443 elog(ERROR, "SPI_execute_snapshot returned %d", spi_result);
2445 /* Did we find a tuple violating the constraint? */
2446 if (SPI_processed > 0)
2448 HeapTuple tuple = SPI_tuptable->vals[0];
2449 TupleDesc tupdesc = SPI_tuptable->tupdesc;
2450 RI_ConstraintInfo fake_riinfo;
2453 * The columns to look at in the result tuple are 1..N, not whatever
2454 * they are in the fk_rel. Hack up riinfo so that the subroutines
2455 * called here will behave properly.
2457 * In addition to this, we have to pass the correct tupdesc to
2458 * ri_ReportViolation, overriding its normal habit of using the pk_rel
2459 * or fk_rel's tupdesc.
2461 memcpy(&fake_riinfo, riinfo, sizeof(RI_ConstraintInfo));
2462 for (i = 0; i < fake_riinfo.nkeys; i++)
2463 fake_riinfo.fk_attnums[i] = i + 1;
2466 * If it's MATCH FULL, and there are any nulls in the FK keys,
2467 * complain about that rather than the lack of a match. MATCH FULL
2468 * disallows partially-null FK rows.
2470 if (fake_riinfo.confmatchtype == FKCONSTR_MATCH_FULL &&
2471 ri_NullCheck(tuple, &fake_riinfo, false) != RI_KEYS_NONE_NULL)
2473 (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
2474 errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
2475 RelationGetRelationName(fk_rel),
2476 NameStr(fake_riinfo.conname)),
2477 errdetail("MATCH FULL does not allow mixing of null and nonnull key values."),
2478 errtableconstraint(fk_rel,
2479 NameStr(fake_riinfo.conname))));
2482 * We tell ri_ReportViolation we were doing the RI_PLAN_CHECK_LOOKUPPK
2483 * query, which isn't true, but will cause it to use
2484 * fake_riinfo.fk_attnums as we need.
2486 ri_ReportViolation(&fake_riinfo,
2489 RI_PLAN_CHECK_LOOKUPPK, false);
2492 if (SPI_finish() != SPI_OK_FINISH)
2493 elog(ERROR, "SPI_finish failed");
2498 AtEOXact_GUC(true, save_nestlevel);
2505 * Local functions below
2511 * quoteOneName --- safely quote a single SQL name
2513 * buffer must be MAX_QUOTED_NAME_LEN long (includes room for \0)
2516 quoteOneName(char *buffer, const char *name)
2518 /* Rather than trying to be smart, just always quote it. */
2524 *buffer++ = *name++;
2531 * quoteRelationName --- safely quote a fully qualified relation name
2533 * buffer must be MAX_QUOTED_REL_NAME_LEN long (includes room for \0)
2536 quoteRelationName(char *buffer, Relation rel)
2538 quoteOneName(buffer, get_namespace_name(RelationGetNamespace(rel)));
2539 buffer += strlen(buffer);
2541 quoteOneName(buffer, RelationGetRelationName(rel));
2545 * ri_GenerateQual --- generate a WHERE clause equating two variables
2547 * The idea is to append " sep leftop op rightop" to buf. The complexity
2548 * comes from needing to be sure that the parser will select the desired
2549 * operator. We always name the operator using OPERATOR(schema.op) syntax
2550 * (readability isn't a big priority here), so as to avoid search-path
2551 * uncertainties. We have to emit casts too, if either input isn't already
2552 * the input type of the operator; else we are at the mercy of the parser's
2553 * heuristics for ambiguous-operator resolution.
2556 ri_GenerateQual(StringInfo buf,
2558 const char *leftop, Oid leftoptype,
2560 const char *rightop, Oid rightoptype)
2563 Form_pg_operator operform;
2567 opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(opoid));
2568 if (!HeapTupleIsValid(opertup))
2569 elog(ERROR, "cache lookup failed for operator %u", opoid);
2570 operform = (Form_pg_operator) GETSTRUCT(opertup);
2571 Assert(operform->oprkind == 'b');
2572 oprname = NameStr(operform->oprname);
2574 nspname = get_namespace_name(operform->oprnamespace);
2576 appendStringInfo(buf, " %s %s", sep, leftop);
2577 if (leftoptype != operform->oprleft)
2578 ri_add_cast_to(buf, operform->oprleft);
2579 appendStringInfo(buf, " OPERATOR(%s.", quote_identifier(nspname));
2580 appendStringInfoString(buf, oprname);
2581 appendStringInfo(buf, ") %s", rightop);
2582 if (rightoptype != operform->oprright)
2583 ri_add_cast_to(buf, operform->oprright);
2585 ReleaseSysCache(opertup);
2589 * Add a cast specification to buf. We spell out the type name the hard way,
2590 * intentionally not using format_type_be(). This is to avoid corner cases
2591 * for CHARACTER, BIT, and perhaps other types, where specifying the type
2592 * using SQL-standard syntax results in undesirable data truncation. By
2593 * doing it this way we can be certain that the cast will have default (-1)
2597 ri_add_cast_to(StringInfo buf, Oid typid)
2600 Form_pg_type typform;
2604 typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
2605 if (!HeapTupleIsValid(typetup))
2606 elog(ERROR, "cache lookup failed for type %u", typid);
2607 typform = (Form_pg_type) GETSTRUCT(typetup);
2609 typname = NameStr(typform->typname);
2610 nspname = get_namespace_name(typform->typnamespace);
2612 appendStringInfo(buf, "::%s.%s",
2613 quote_identifier(nspname), quote_identifier(typname));
2615 ReleaseSysCache(typetup);
2619 * ri_GenerateQualCollation --- add a COLLATE spec to a WHERE clause
2621 * At present, we intentionally do not use this function for RI queries that
2622 * compare a variable to a $n parameter. Since parameter symbols always have
2623 * default collation, the effect will be to use the variable's collation.
2624 * Now that is only strictly correct when testing the referenced column, since
2625 * the SQL standard specifies that RI comparisons should use the referenced
2626 * column's collation. However, so long as all collations have the same
2627 * notion of equality (which they do, because texteq reduces to bitwise
2628 * equality), there's no visible semantic impact from using the referencing
2629 * column's collation when testing it, and this is a good thing to do because
2630 * it lets us use a normal index on the referencing column. However, we do
2631 * have to use this function when directly comparing the referencing and
2632 * referenced columns, if they are of different collations; else the parser
2633 * will fail to resolve the collation to use.
2636 ri_GenerateQualCollation(StringInfo buf, Oid collation)
2639 Form_pg_collation colltup;
2641 char onename[MAX_QUOTED_NAME_LEN];
2643 /* Nothing to do if it's a noncollatable data type */
2644 if (!OidIsValid(collation))
2647 tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation));
2648 if (!HeapTupleIsValid(tp))
2649 elog(ERROR, "cache lookup failed for collation %u", collation);
2650 colltup = (Form_pg_collation) GETSTRUCT(tp);
2651 collname = NameStr(colltup->collname);
2654 * We qualify the name always, for simplicity and to ensure the query is
2655 * not search-path-dependent.
2657 quoteOneName(onename, get_namespace_name(colltup->collnamespace));
2658 appendStringInfo(buf, " COLLATE %s", onename);
2659 quoteOneName(onename, collname);
2660 appendStringInfo(buf, ".%s", onename);
2662 ReleaseSysCache(tp);
2666 * ri_BuildQueryKey -
2668 * Construct a hashtable key for a prepared SPI plan of an FK constraint.
2670 * key: output argument, *key is filled in based on the other arguments
2671 * riinfo: info from pg_constraint entry
2672 * constr_queryno: an internal number identifying the query type
2673 * (see RI_PLAN_XXX constants at head of file)
2677 ri_BuildQueryKey(RI_QueryKey *key, const RI_ConstraintInfo *riinfo,
2678 int32 constr_queryno)
2681 * We assume struct RI_QueryKey contains no padding bytes, else we'd need
2682 * to use memset to clear them.
2684 key->constr_id = riinfo->constraint_id;
2685 key->constr_queryno = constr_queryno;
2689 * Check that RI trigger function was called in expected context
2692 ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname, int tgkind)
2694 TriggerData *trigdata = (TriggerData *) fcinfo->context;
2696 if (!CALLED_AS_TRIGGER(fcinfo))
2698 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2699 errmsg("function \"%s\" was not called by trigger manager", funcname)));
2702 * Check proper event
2704 if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
2705 !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
2707 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2708 errmsg("function \"%s\" must be fired AFTER ROW", funcname)));
2712 case RI_TRIGTYPE_INSERT:
2713 if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
2715 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2716 errmsg("function \"%s\" must be fired for INSERT", funcname)));
2718 case RI_TRIGTYPE_UPDATE:
2719 if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
2721 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2722 errmsg("function \"%s\" must be fired for UPDATE", funcname)));
2724 case RI_TRIGTYPE_DELETE:
2725 if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
2727 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2728 errmsg("function \"%s\" must be fired for DELETE", funcname)));
2735 * Fetch the RI_ConstraintInfo struct for the trigger's FK constraint.
2737 static const RI_ConstraintInfo *
2738 ri_FetchConstraintInfo(Trigger *trigger, Relation trig_rel, bool rel_is_pk)
2740 Oid constraintOid = trigger->tgconstraint;
2741 const RI_ConstraintInfo *riinfo;
2744 * Check that the FK constraint's OID is available; it might not be if
2745 * we've been invoked via an ordinary trigger or an old-style "constraint
2748 if (!OidIsValid(constraintOid))
2750 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2751 errmsg("no pg_constraint entry for trigger \"%s\" on table \"%s\"",
2752 trigger->tgname, RelationGetRelationName(trig_rel)),
2753 errhint("Remove this referential integrity trigger and its mates, then do ALTER TABLE ADD CONSTRAINT.")));
2755 /* Find or create a hashtable entry for the constraint */
2756 riinfo = ri_LoadConstraintInfo(constraintOid);
2758 /* Do some easy cross-checks against the trigger call data */
2761 if (riinfo->fk_relid != trigger->tgconstrrelid ||
2762 riinfo->pk_relid != RelationGetRelid(trig_rel))
2763 elog(ERROR, "wrong pg_constraint entry for trigger \"%s\" on table \"%s\"",
2764 trigger->tgname, RelationGetRelationName(trig_rel));
2768 if (riinfo->fk_relid != RelationGetRelid(trig_rel) ||
2769 riinfo->pk_relid != trigger->tgconstrrelid)
2770 elog(ERROR, "wrong pg_constraint entry for trigger \"%s\" on table \"%s\"",
2771 trigger->tgname, RelationGetRelationName(trig_rel));
2778 * Fetch or create the RI_ConstraintInfo struct for an FK constraint.
2780 static const RI_ConstraintInfo *
2781 ri_LoadConstraintInfo(Oid constraintOid)
2783 RI_ConstraintInfo *riinfo;
2786 Form_pg_constraint conForm;
2793 * On the first call initialize the hashtable
2795 if (!ri_constraint_cache)
2796 ri_InitHashTables();
2799 * Find or create a hash entry. If we find a valid one, just return it.
2801 riinfo = (RI_ConstraintInfo *) hash_search(ri_constraint_cache,
2802 (void *) &constraintOid,
2803 HASH_ENTER, &found);
2805 riinfo->valid = false;
2806 else if (riinfo->valid)
2810 * Fetch the pg_constraint row so we can fill in the entry.
2812 tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
2813 if (!HeapTupleIsValid(tup)) /* should not happen */
2814 elog(ERROR, "cache lookup failed for constraint %u", constraintOid);
2815 conForm = (Form_pg_constraint) GETSTRUCT(tup);
2817 if (conForm->contype != CONSTRAINT_FOREIGN) /* should not happen */
2818 elog(ERROR, "constraint %u is not a foreign key constraint",
2821 /* And extract data */
2822 Assert(riinfo->constraint_id == constraintOid);
2823 riinfo->oidHashValue = GetSysCacheHashValue1(CONSTROID,
2824 ObjectIdGetDatum(constraintOid));
2825 memcpy(&riinfo->conname, &conForm->conname, sizeof(NameData));
2826 riinfo->pk_relid = conForm->confrelid;
2827 riinfo->fk_relid = conForm->conrelid;
2828 riinfo->confupdtype = conForm->confupdtype;
2829 riinfo->confdeltype = conForm->confdeltype;
2830 riinfo->confmatchtype = conForm->confmatchtype;
2833 * We expect the arrays to be 1-D arrays of the right types; verify that.
2834 * We don't need to use deconstruct_array() since the array data is just
2835 * going to look like a C array of values.
2837 adatum = SysCacheGetAttr(CONSTROID, tup,
2838 Anum_pg_constraint_conkey, &isNull);
2840 elog(ERROR, "null conkey for constraint %u", constraintOid);
2841 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
2842 if (ARR_NDIM(arr) != 1 ||
2844 ARR_ELEMTYPE(arr) != INT2OID)
2845 elog(ERROR, "conkey is not a 1-D smallint array");
2846 numkeys = ARR_DIMS(arr)[0];
2847 if (numkeys <= 0 || numkeys > RI_MAX_NUMKEYS)
2848 elog(ERROR, "foreign key constraint cannot have %d columns", numkeys);
2849 riinfo->nkeys = numkeys;
2850 memcpy(riinfo->fk_attnums, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
2851 if ((Pointer) arr != DatumGetPointer(adatum))
2852 pfree(arr); /* free de-toasted copy, if any */
2854 adatum = SysCacheGetAttr(CONSTROID, tup,
2855 Anum_pg_constraint_confkey, &isNull);
2857 elog(ERROR, "null confkey for constraint %u", constraintOid);
2858 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
2859 if (ARR_NDIM(arr) != 1 ||
2860 ARR_DIMS(arr)[0] != numkeys ||
2862 ARR_ELEMTYPE(arr) != INT2OID)
2863 elog(ERROR, "confkey is not a 1-D smallint array");
2864 memcpy(riinfo->pk_attnums, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
2865 if ((Pointer) arr != DatumGetPointer(adatum))
2866 pfree(arr); /* free de-toasted copy, if any */
2868 adatum = SysCacheGetAttr(CONSTROID, tup,
2869 Anum_pg_constraint_conpfeqop, &isNull);
2871 elog(ERROR, "null conpfeqop for constraint %u", constraintOid);
2872 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
2873 /* see TryReuseForeignKey if you change the test below */
2874 if (ARR_NDIM(arr) != 1 ||
2875 ARR_DIMS(arr)[0] != numkeys ||
2877 ARR_ELEMTYPE(arr) != OIDOID)
2878 elog(ERROR, "conpfeqop is not a 1-D Oid array");
2879 memcpy(riinfo->pf_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
2880 if ((Pointer) arr != DatumGetPointer(adatum))
2881 pfree(arr); /* free de-toasted copy, if any */
2883 adatum = SysCacheGetAttr(CONSTROID, tup,
2884 Anum_pg_constraint_conppeqop, &isNull);
2886 elog(ERROR, "null conppeqop for constraint %u", constraintOid);
2887 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
2888 if (ARR_NDIM(arr) != 1 ||
2889 ARR_DIMS(arr)[0] != numkeys ||
2891 ARR_ELEMTYPE(arr) != OIDOID)
2892 elog(ERROR, "conppeqop is not a 1-D Oid array");
2893 memcpy(riinfo->pp_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
2894 if ((Pointer) arr != DatumGetPointer(adatum))
2895 pfree(arr); /* free de-toasted copy, if any */
2897 adatum = SysCacheGetAttr(CONSTROID, tup,
2898 Anum_pg_constraint_conffeqop, &isNull);
2900 elog(ERROR, "null conffeqop for constraint %u", constraintOid);
2901 arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
2902 if (ARR_NDIM(arr) != 1 ||
2903 ARR_DIMS(arr)[0] != numkeys ||
2905 ARR_ELEMTYPE(arr) != OIDOID)
2906 elog(ERROR, "conffeqop is not a 1-D Oid array");
2907 memcpy(riinfo->ff_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
2908 if ((Pointer) arr != DatumGetPointer(adatum))
2909 pfree(arr); /* free de-toasted copy, if any */
2911 ReleaseSysCache(tup);
2913 riinfo->valid = true;
2919 * Callback for pg_constraint inval events
2921 * While most syscache callbacks just flush all their entries, pg_constraint
2922 * gets enough update traffic that it's probably worth being smarter.
2923 * Invalidate any ri_constraint_cache entry associated with the syscache
2924 * entry with the specified hash value, or all entries if hashvalue == 0.
2927 InvalidateConstraintCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
2929 HASH_SEQ_STATUS status;
2930 RI_ConstraintInfo *hentry;
2932 Assert(ri_constraint_cache != NULL);
2934 hash_seq_init(&status, ri_constraint_cache);
2935 while ((hentry = (RI_ConstraintInfo *) hash_seq_search(&status)) != NULL)
2937 if (hashvalue == 0 || hentry->oidHashValue == hashvalue)
2938 hentry->valid = false;
2944 * Prepare execution plan for a query to enforce an RI restriction
2946 * If cache_plan is true, the plan is saved into our plan hashtable
2947 * so that we don't need to plan it again.
2950 ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
2951 RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel,
2957 int save_sec_context;
2960 * Use the query type code to determine whether the query is run against
2961 * the PK or FK table; we'll do the check as that table's owner
2963 if (qkey->constr_queryno <= RI_PLAN_LAST_ON_PK)
2968 /* Switch to proper UID to perform check as */
2969 GetUserIdAndSecContext(&save_userid, &save_sec_context);
2970 SetUserIdAndSecContext(RelationGetForm(query_rel)->relowner,
2971 save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
2973 /* Create the plan */
2974 qplan = SPI_prepare(querystr, nargs, argtypes);
2977 elog(ERROR, "SPI_prepare returned %d for %s", SPI_result, querystr);
2979 /* Restore UID and security context */
2980 SetUserIdAndSecContext(save_userid, save_sec_context);
2982 /* Save the plan if requested */
2985 SPI_keepplan(qplan);
2986 ri_HashPreparedPlan(qkey, qplan);
2993 * Perform a query to enforce an RI restriction
2996 ri_PerformCheck(const RI_ConstraintInfo *riinfo,
2997 RI_QueryKey *qkey, SPIPlanPtr qplan,
2998 Relation fk_rel, Relation pk_rel,
2999 HeapTuple old_tuple, HeapTuple new_tuple,
3000 bool detectNewRows, int expect_OK)
3005 Snapshot test_snapshot;
3006 Snapshot crosscheck_snapshot;
3010 int save_sec_context;
3011 Datum vals[RI_MAX_NUMKEYS * 2];
3012 char nulls[RI_MAX_NUMKEYS * 2];
3015 * Use the query type code to determine whether the query is run against
3016 * the PK or FK table; we'll do the check as that table's owner
3018 if (qkey->constr_queryno <= RI_PLAN_LAST_ON_PK)
3024 * The values for the query are taken from the table on which the trigger
3025 * is called - it is normally the other one with respect to query_rel. An
3026 * exception is ri_Check_Pk_Match(), which uses the PK table for both (and
3027 * sets queryno to RI_PLAN_CHECK_LOOKUPPK_FROM_PK). We might eventually
3028 * need some less klugy way to determine this.
3030 if (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK)
3032 source_rel = fk_rel;
3033 source_is_pk = false;
3037 source_rel = pk_rel;
3038 source_is_pk = true;
3041 /* Extract the parameters to be passed into the query */
3044 ri_ExtractValues(source_rel, new_tuple, riinfo, source_is_pk,
3047 ri_ExtractValues(source_rel, old_tuple, riinfo, source_is_pk,
3048 vals + riinfo->nkeys, nulls + riinfo->nkeys);
3052 ri_ExtractValues(source_rel, old_tuple, riinfo, source_is_pk,
3057 * In READ COMMITTED mode, we just need to use an up-to-date regular
3058 * snapshot, and we will see all rows that could be interesting. But in
3059 * transaction-snapshot mode, we can't change the transaction snapshot. If
3060 * the caller passes detectNewRows == false then it's okay to do the query
3061 * with the transaction snapshot; otherwise we use a current snapshot, and
3062 * tell the executor to error out if it finds any rows under the current
3063 * snapshot that wouldn't be visible per the transaction snapshot. Note
3064 * that SPI_execute_snapshot will register the snapshots, so we don't need
3067 if (IsolationUsesXactSnapshot() && detectNewRows)
3069 CommandCounterIncrement(); /* be sure all my own work is visible */
3070 test_snapshot = GetLatestSnapshot();
3071 crosscheck_snapshot = GetTransactionSnapshot();
3075 /* the default SPI behavior is okay */
3076 test_snapshot = InvalidSnapshot;
3077 crosscheck_snapshot = InvalidSnapshot;
3081 * If this is a select query (e.g., for a 'no action' or 'restrict'
3082 * trigger), we only need to see if there is a single row in the table,
3083 * matching the key. Otherwise, limit = 0 - because we want the query to
3084 * affect ALL the matching rows.
3086 limit = (expect_OK == SPI_OK_SELECT) ? 1 : 0;
3088 /* Switch to proper UID to perform check as */
3089 GetUserIdAndSecContext(&save_userid, &save_sec_context);
3090 SetUserIdAndSecContext(RelationGetForm(query_rel)->relowner,
3091 save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
3093 /* Finally we can run the query. */
3094 spi_result = SPI_execute_snapshot(qplan,
3096 test_snapshot, crosscheck_snapshot,
3097 false, false, limit);
3099 /* Restore UID and security context */
3100 SetUserIdAndSecContext(save_userid, save_sec_context);
3104 elog(ERROR, "SPI_execute_snapshot returned %d", spi_result);
3106 if (expect_OK >= 0 && spi_result != expect_OK)
3107 ri_ReportViolation(riinfo,
3109 new_tuple ? new_tuple : old_tuple,
3111 qkey->constr_queryno, true);
3113 /* XXX wouldn't it be clearer to do this part at the caller? */
3114 if (qkey->constr_queryno != RI_PLAN_CHECK_LOOKUPPK_FROM_PK &&
3115 expect_OK == SPI_OK_SELECT &&
3116 (SPI_processed == 0) == (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK))
3117 ri_ReportViolation(riinfo,
3119 new_tuple ? new_tuple : old_tuple,
3121 qkey->constr_queryno, false);
3123 return SPI_processed != 0;
3127 * Extract fields from a tuple into Datum/nulls arrays
3130 ri_ExtractValues(Relation rel, HeapTuple tup,
3131 const RI_ConstraintInfo *riinfo, bool rel_is_pk,
3132 Datum *vals, char *nulls)
3134 TupleDesc tupdesc = rel->rd_att;
3135 const int16 *attnums;
3140 attnums = riinfo->pk_attnums;
3142 attnums = riinfo->fk_attnums;
3144 for (i = 0; i < riinfo->nkeys; i++)
3146 vals[i] = heap_getattr(tup, attnums[i], tupdesc,
3148 nulls[i] = isnull ? 'n' : ' ';
3153 * Produce an error report
3155 * If the failed constraint was on insert/update to the FK table,
3156 * we want the key names and values extracted from there, and the error
3157 * message to look like 'key blah is not present in PK'.
3158 * Otherwise, the attr names and values come from the PK table and the
3159 * message looks like 'key blah is still referenced from FK'.
3162 ri_ReportViolation(const RI_ConstraintInfo *riinfo,
3163 Relation pk_rel, Relation fk_rel,
3164 HeapTuple violator, TupleDesc tupdesc,
3165 int queryno, bool spi_err)
3167 StringInfoData key_names;
3168 StringInfoData key_values;
3170 const int16 *attnums;
3175 (errcode(ERRCODE_INTERNAL_ERROR),
3176 errmsg("referential integrity query on \"%s\" from constraint \"%s\" on \"%s\" gave unexpected result",
3177 RelationGetRelationName(pk_rel),
3178 NameStr(riinfo->conname),
3179 RelationGetRelationName(fk_rel)),
3180 errhint("This is most likely due to a rule having rewritten the query.")));
3183 * Determine which relation to complain about. If tupdesc wasn't passed
3184 * by caller, assume the violator tuple came from there.
3186 onfk = (queryno == RI_PLAN_CHECK_LOOKUPPK);
3189 attnums = riinfo->fk_attnums;
3190 if (tupdesc == NULL)
3191 tupdesc = fk_rel->rd_att;
3195 attnums = riinfo->pk_attnums;
3196 if (tupdesc == NULL)
3197 tupdesc = pk_rel->rd_att;
3200 /* Get printable versions of the keys involved */
3201 initStringInfo(&key_names);
3202 initStringInfo(&key_values);
3203 for (idx = 0; idx < riinfo->nkeys; idx++)
3205 int fnum = attnums[idx];
3209 name = SPI_fname(tupdesc, fnum);
3210 val = SPI_getvalue(violator, tupdesc, fnum);
3216 appendStringInfoString(&key_names, ", ");
3217 appendStringInfoString(&key_values, ", ");
3219 appendStringInfoString(&key_names, name);
3220 appendStringInfoString(&key_values, val);
3225 (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
3226 errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
3227 RelationGetRelationName(fk_rel),
3228 NameStr(riinfo->conname)),
3229 errdetail("Key (%s)=(%s) is not present in table \"%s\".",
3230 key_names.data, key_values.data,
3231 RelationGetRelationName(pk_rel)),
3232 errtableconstraint(fk_rel, NameStr(riinfo->conname))));
3235 (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
3236 errmsg("update or delete on table \"%s\" violates foreign key constraint \"%s\" on table \"%s\"",
3237 RelationGetRelationName(pk_rel),
3238 NameStr(riinfo->conname),
3239 RelationGetRelationName(fk_rel)),
3240 errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
3241 key_names.data, key_values.data,
3242 RelationGetRelationName(fk_rel)),
3243 errtableconstraint(fk_rel, NameStr(riinfo->conname))));
3250 * Determine the NULL state of all key values in a tuple
3252 * Returns one of RI_KEYS_ALL_NULL, RI_KEYS_NONE_NULL or RI_KEYS_SOME_NULL.
3256 ri_NullCheck(HeapTuple tup,
3257 const RI_ConstraintInfo *riinfo, bool rel_is_pk)
3259 const int16 *attnums;
3261 bool allnull = true;
3262 bool nonenull = true;
3265 attnums = riinfo->pk_attnums;
3267 attnums = riinfo->fk_attnums;
3269 for (i = 0; i < riinfo->nkeys; i++)
3271 if (heap_attisnull(tup, attnums[i]))
3278 return RI_KEYS_ALL_NULL;
3281 return RI_KEYS_NONE_NULL;
3283 return RI_KEYS_SOME_NULL;
3288 * ri_InitHashTables -
3290 * Initialize our internal hash tables.
3294 ri_InitHashTables(void)
3298 memset(&ctl, 0, sizeof(ctl));
3299 ctl.keysize = sizeof(Oid);
3300 ctl.entrysize = sizeof(RI_ConstraintInfo);
3301 ctl.hash = oid_hash;
3302 ri_constraint_cache = hash_create("RI constraint cache",
3303 RI_INIT_CONSTRAINTHASHSIZE,
3304 &ctl, HASH_ELEM | HASH_FUNCTION);
3306 /* Arrange to flush cache on pg_constraint changes */
3307 CacheRegisterSyscacheCallback(CONSTROID,
3308 InvalidateConstraintCacheCallBack,
3311 memset(&ctl, 0, sizeof(ctl));
3312 ctl.keysize = sizeof(RI_QueryKey);
3313 ctl.entrysize = sizeof(RI_QueryHashEntry);
3314 ctl.hash = tag_hash;
3315 ri_query_cache = hash_create("RI query cache",
3316 RI_INIT_QUERYHASHSIZE,
3317 &ctl, HASH_ELEM | HASH_FUNCTION);
3319 memset(&ctl, 0, sizeof(ctl));
3320 ctl.keysize = sizeof(RI_CompareKey);
3321 ctl.entrysize = sizeof(RI_CompareHashEntry);
3322 ctl.hash = tag_hash;
3323 ri_compare_cache = hash_create("RI compare cache",
3324 RI_INIT_QUERYHASHSIZE,
3325 &ctl, HASH_ELEM | HASH_FUNCTION);
3330 * ri_FetchPreparedPlan -
3332 * Lookup for a query key in our private hash table of prepared
3333 * and saved SPI execution plans. Return the plan if found or NULL.
3337 ri_FetchPreparedPlan(RI_QueryKey *key)
3339 RI_QueryHashEntry *entry;
3343 * On the first call initialize the hashtable
3345 if (!ri_query_cache)
3346 ri_InitHashTables();
3349 * Lookup for the key
3351 entry = (RI_QueryHashEntry *) hash_search(ri_query_cache,
3358 * Check whether the plan is still valid. If it isn't, we don't want to
3359 * simply rely on plancache.c to regenerate it; rather we should start
3360 * from scratch and rebuild the query text too. This is to cover cases
3361 * such as table/column renames. We depend on the plancache machinery to
3362 * detect possible invalidations, though.
3364 * CAUTION: this check is only trustworthy if the caller has already
3365 * locked both FK and PK rels.
3368 if (plan && SPI_plan_is_valid(plan))
3372 * Otherwise we might as well flush the cached plan now, to free a little
3373 * memory space before we make a new one.
3384 * ri_HashPreparedPlan -
3386 * Add another plan to our private SPI query plan hashtable.
3390 ri_HashPreparedPlan(RI_QueryKey *key, SPIPlanPtr plan)
3392 RI_QueryHashEntry *entry;
3396 * On the first call initialize the hashtable
3398 if (!ri_query_cache)
3399 ri_InitHashTables();
3402 * Add the new plan. We might be overwriting an entry previously found
3403 * invalid by ri_FetchPreparedPlan.
3405 entry = (RI_QueryHashEntry *) hash_search(ri_query_cache,
3407 HASH_ENTER, &found);
3408 Assert(!found || entry->plan == NULL);
3416 * Check if all key values in OLD and NEW are equal.
3418 * Note: at some point we might wish to redefine this as checking for
3419 * "IS NOT DISTINCT" rather than "=", that is, allow two nulls to be
3420 * considered equal. Currently there is no need since all callers have
3421 * previously found at least one of the rows to contain no nulls.
3425 ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
3426 const RI_ConstraintInfo *riinfo, bool rel_is_pk)
3428 TupleDesc tupdesc = RelationGetDescr(rel);
3429 const int16 *attnums;
3435 attnums = riinfo->pk_attnums;
3436 eq_oprs = riinfo->pp_eq_oprs;
3440 attnums = riinfo->fk_attnums;
3441 eq_oprs = riinfo->ff_eq_oprs;
3444 for (i = 0; i < riinfo->nkeys; i++)
3451 * Get one attribute's oldvalue. If it is NULL - they're not equal.
3453 oldvalue = heap_getattr(oldtup, attnums[i], tupdesc, &isnull);
3458 * Get one attribute's newvalue. If it is NULL - they're not equal.
3460 newvalue = heap_getattr(newtup, attnums[i], tupdesc, &isnull);
3465 * Compare them with the appropriate equality operator.
3467 if (!ri_AttributesEqual(eq_oprs[i], RIAttType(rel, attnums[i]),
3468 oldvalue, newvalue))
3477 * ri_AttributesEqual -
3479 * Call the appropriate equality comparison operator for two values.
3481 * NB: we have already checked that neither value is null.
3485 ri_AttributesEqual(Oid eq_opr, Oid typeid,
3486 Datum oldvalue, Datum newvalue)
3488 RI_CompareHashEntry *entry = ri_HashCompareOp(eq_opr, typeid);
3490 /* Do we need to cast the values? */
3491 if (OidIsValid(entry->cast_func_finfo.fn_oid))
3493 oldvalue = FunctionCall3(&entry->cast_func_finfo,
3495 Int32GetDatum(-1), /* typmod */
3496 BoolGetDatum(false)); /* implicit coercion */
3497 newvalue = FunctionCall3(&entry->cast_func_finfo,
3499 Int32GetDatum(-1), /* typmod */
3500 BoolGetDatum(false)); /* implicit coercion */
3504 * Apply the comparison operator. We assume it doesn't care about
3507 return DatumGetBool(FunctionCall2(&entry->eq_opr_finfo,
3508 oldvalue, newvalue));
3512 * ri_HashCompareOp -
3514 * See if we know how to compare two values, and create a new hash entry
3518 static RI_CompareHashEntry *
3519 ri_HashCompareOp(Oid eq_opr, Oid typeid)
3522 RI_CompareHashEntry *entry;
3526 * On the first call initialize the hashtable
3528 if (!ri_compare_cache)
3529 ri_InitHashTables();
3532 * Find or create a hash entry. Note we're assuming RI_CompareKey
3533 * contains no struct padding.
3535 key.eq_opr = eq_opr;
3536 key.typeid = typeid;
3537 entry = (RI_CompareHashEntry *) hash_search(ri_compare_cache,
3539 HASH_ENTER, &found);
3541 entry->valid = false;
3544 * If not already initialized, do so. Since we'll keep this hash entry
3545 * for the life of the backend, put any subsidiary info for the function
3546 * cache structs into TopMemoryContext.
3553 CoercionPathType pathtype;
3555 /* We always need to know how to call the equality operator */
3556 fmgr_info_cxt(get_opcode(eq_opr), &entry->eq_opr_finfo,
3560 * If we chose to use a cast from FK to PK type, we may have to apply
3561 * the cast function to get to the operator's input type.
3563 * XXX eventually it would be good to support array-coercion cases
3564 * here and in ri_AttributesEqual(). At the moment there is no point
3565 * because cases involving nonidentical array types will be rejected
3566 * at constraint creation time.
3568 * XXX perhaps also consider supporting CoerceViaIO? No need at the
3569 * moment since that will never be generated for implicit coercions.
3571 op_input_types(eq_opr, &lefttype, &righttype);
3572 Assert(lefttype == righttype);
3573 if (typeid == lefttype)
3574 castfunc = InvalidOid; /* simplest case */
3577 pathtype = find_coercion_pathway(lefttype, typeid,
3580 if (pathtype != COERCION_PATH_FUNC &&
3581 pathtype != COERCION_PATH_RELABELTYPE)
3584 * The declared input type of the eq_opr might be a
3585 * polymorphic type such as ANYARRAY or ANYENUM, or other
3586 * special cases such as RECORD; find_coercion_pathway
3587 * currently doesn't subsume these special cases.
3589 if (!IsBinaryCoercible(typeid, lefttype))
3590 elog(ERROR, "no conversion function from %s to %s",
3591 format_type_be(typeid),
3592 format_type_be(lefttype));
3595 if (OidIsValid(castfunc))
3596 fmgr_info_cxt(castfunc, &entry->cast_func_finfo,
3599 entry->cast_func_finfo.fn_oid = InvalidOid;
3600 entry->valid = true;
3608 * Given a trigger function OID, determine whether it is an RI trigger,
3609 * and if so whether it is attached to PK or FK relation.
3612 RI_FKey_trigger_type(Oid tgfoid)
3616 case F_RI_FKEY_CASCADE_DEL:
3617 case F_RI_FKEY_CASCADE_UPD:
3618 case F_RI_FKEY_RESTRICT_DEL:
3619 case F_RI_FKEY_RESTRICT_UPD:
3620 case F_RI_FKEY_SETNULL_DEL:
3621 case F_RI_FKEY_SETNULL_UPD:
3622 case F_RI_FKEY_SETDEFAULT_DEL:
3623 case F_RI_FKEY_SETDEFAULT_UPD:
3624 case F_RI_FKEY_NOACTION_DEL:
3625 case F_RI_FKEY_NOACTION_UPD:
3626 return RI_TRIGGER_PK;
3628 case F_RI_FKEY_CHECK_INS:
3629 case F_RI_FKEY_CHECK_UPD:
3630 return RI_TRIGGER_FK;
3633 return RI_TRIGGER_NONE;