]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/ri_triggers.c
Silence compiler warnings about possibly unset variables.
[postgresql] / src / backend / utils / adt / ri_triggers.c
1 /* ----------
2  * ri_triggers.c
3  *
4  *      Generic trigger procedures for referential integrity constraint
5  *      checks.
6  *
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.
14  *
15  *
16  * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
17  *
18  * src/backend/utils/adt/ri_triggers.c
19  *
20  * ----------
21  */
22
23
24 /* ----------
25  * Internal TODO:
26  *
27  *              Add MATCH PARTIAL logic.
28  * ----------
29  */
30
31 #include "postgres.h"
32
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"
56
57
58 /* ----------
59  * Local definitions
60  * ----------
61  */
62
63 #define RI_MAX_NUMKEYS                                  INDEX_MAX_KEYS
64
65 #define RI_INIT_CONSTRAINTHASHSIZE              64
66 #define RI_INIT_QUERYHASHSIZE                   (RI_INIT_CONSTRAINTHASHSIZE * 4)
67
68 #define RI_KEYS_ALL_NULL                                0
69 #define RI_KEYS_SOME_NULL                               1
70 #define RI_KEYS_NONE_NULL                               2
71
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
86
87 #define MAX_QUOTED_NAME_LEN  (NAMEDATALEN*2+3)
88 #define MAX_QUOTED_REL_NAME_LEN  (MAX_QUOTED_NAME_LEN*2)
89
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)
93
94 #define RI_TRIGTYPE_INSERT 1
95 #define RI_TRIGTYPE_UPDATE 2
96 #define RI_TRIGTYPE_DELETE 3
97
98
99 /* ----------
100  * RI_ConstraintInfo
101  *
102  *      Information extracted from an FK pg_constraint entry.  This is cached in
103  *      ri_constraint_cache.
104  * ----------
105  */
106 typedef struct RI_ConstraintInfo
107 {
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 =
121                                                                                                  * FK) */
122         Oid                     pp_eq_oprs[RI_MAX_NUMKEYS];             /* equality operators (PK =
123                                                                                                  * PK) */
124         Oid                     ff_eq_oprs[RI_MAX_NUMKEYS];             /* equality operators (FK =
125                                                                                                  * FK) */
126 } RI_ConstraintInfo;
127
128
129 /* ----------
130  * RI_QueryKey
131  *
132  *      The key identifying a prepared SPI plan in our query hashtable
133  * ----------
134  */
135 typedef struct RI_QueryKey
136 {
137         Oid                     constr_id;              /* OID of pg_constraint entry */
138         int32           constr_queryno; /* query type ID, see RI_PLAN_XXX above */
139 } RI_QueryKey;
140
141
142 /* ----------
143  * RI_QueryHashEntry
144  * ----------
145  */
146 typedef struct RI_QueryHashEntry
147 {
148         RI_QueryKey key;
149         SPIPlanPtr      plan;
150 } RI_QueryHashEntry;
151
152
153 /* ----------
154  * RI_CompareKey
155  *
156  *      The key identifying an entry showing how to compare two values
157  * ----------
158  */
159 typedef struct RI_CompareKey
160 {
161         Oid                     eq_opr;                 /* the equality operator to apply */
162         Oid                     typeid;                 /* the data type to apply it to */
163 } RI_CompareKey;
164
165
166 /* ----------
167  * RI_CompareHashEntry
168  * ----------
169  */
170 typedef struct RI_CompareHashEntry
171 {
172         RI_CompareKey key;
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;
177
178
179 /* ----------
180  * Local data
181  * ----------
182  */
183 static HTAB *ri_constraint_cache = NULL;
184 static HTAB *ri_query_cache = NULL;
185 static HTAB *ri_compare_cache = NULL;
186
187
188 /* ----------
189  * Local function prototypes
190  * ----------
191  */
192 static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
193                                   HeapTuple old_row,
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,
200                                 const char *sep,
201                                 const char *leftop, Oid leftoptype,
202                                 Oid opoid,
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);
215
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);
221
222 static void ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname,
223                                 int tgkind);
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,
229                          bool cache_plan);
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);
242
243
244 /* ----------
245  * RI_FKey_check -
246  *
247  *      Check foreign key existence (combined for INSERT and UPDATE).
248  * ----------
249  */
250 static Datum
251 RI_FKey_check(TriggerData *trigdata)
252 {
253         const RI_ConstraintInfo *riinfo;
254         Relation        fk_rel;
255         Relation        pk_rel;
256         HeapTuple       new_row;
257         Buffer          new_row_buf;
258         RI_QueryKey qkey;
259         SPIPlanPtr      qplan;
260         int                     i;
261
262         /*
263          * Get arguments.
264          */
265         riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
266                                                                         trigdata->tg_relation, false);
267
268         if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
269         {
270                 new_row = trigdata->tg_newtuple;
271                 new_row_buf = trigdata->tg_newtuplebuf;
272         }
273         else
274         {
275                 new_row = trigdata->tg_trigtuple;
276                 new_row_buf = trigdata->tg_trigtuplebuf;
277         }
278
279         /*
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.
284          *
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.
293          */
294         Assert(new_row_buf != InvalidBuffer);
295         if (!HeapTupleSatisfiesVisibility(new_row, SnapshotSelf, new_row_buf))
296                 return PointerGetDatum(NULL);
297
298         /*
299          * Get the relation descriptors of the FK and PK tables.
300          *
301          * pk_rel is opened in RowShareLock mode since that's what our eventual
302          * SELECT FOR KEY SHARE will get on it.
303          */
304         fk_rel = trigdata->tg_relation;
305         pk_rel = heap_open(riinfo->pk_relid, RowShareLock);
306
307         if (riinfo->confmatchtype == FKCONSTR_MATCH_PARTIAL)
308                 ereport(ERROR,
309                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
310                                  errmsg("MATCH PARTIAL not yet implemented")));
311
312         switch (ri_NullCheck(new_row, riinfo, false))
313         {
314                 case RI_KEYS_ALL_NULL:
315
316                         /*
317                          * No further check needed - an all-NULL key passes every type of
318                          * foreign key constraint.
319                          */
320                         heap_close(pk_rel, RowShareLock);
321                         return PointerGetDatum(NULL);
322
323                 case RI_KEYS_SOME_NULL:
324
325                         /*
326                          * This is the only case that differs between the three kinds of
327                          * MATCH.
328                          */
329                         switch (riinfo->confmatchtype)
330                         {
331                                 case FKCONSTR_MATCH_FULL:
332
333                                         /*
334                                          * Not allowed - MATCH FULL says either all or none of the
335                                          * attributes can be NULLs
336                                          */
337                                         ereport(ERROR,
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);
347
348                                 case FKCONSTR_MATCH_SIMPLE:
349
350                                         /*
351                                          * MATCH SIMPLE - if ANY column is null, the key passes
352                                          * the constraint.
353                                          */
354                                         heap_close(pk_rel, RowShareLock);
355                                         return PointerGetDatum(NULL);
356
357                                 case FKCONSTR_MATCH_PARTIAL:
358
359                                         /*
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)
364                                          */
365                                         ereport(ERROR,
366                                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
367                                                          errmsg("MATCH PARTIAL not yet implemented")));
368                                         heap_close(pk_rel, RowShareLock);
369                                         return PointerGetDatum(NULL);
370
371                                 default:
372                                         elog(ERROR, "unrecognized confmatchtype: %d",
373                                                  riinfo->confmatchtype);
374                                         break;
375                         }
376
377                 case RI_KEYS_NONE_NULL:
378
379                         /*
380                          * Have a full qualified key - continue below for all three kinds
381                          * of MATCH.
382                          */
383                         break;
384         }
385
386         if (SPI_connect() != SPI_OK_CONNECT)
387                 elog(ERROR, "SPI_connect failed");
388
389         /*
390          * Fetch or prepare a saved plan for the real check
391          */
392         ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CHECK_LOOKUPPK);
393
394         if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
395         {
396                 StringInfoData querybuf;
397                 char            pkrelname[MAX_QUOTED_REL_NAME_LEN];
398                 char            attname[MAX_QUOTED_NAME_LEN];
399                 char            paramname[16];
400                 const char *querysep;
401                 Oid                     queryoids[RI_MAX_NUMKEYS];
402
403                 /* ----------
404                  * The query string built is
405                  *      SELECT 1 FROM ONLY <pktable> x WHERE pkatt1 = $1 [AND ...]
406                  *                 FOR KEY SHARE OF x
407                  * The type id's for the $ parameters are those of the
408                  * corresponding FK attributes.
409                  * ----------
410                  */
411                 initStringInfo(&querybuf);
412                 quoteRelationName(pkrelname, pk_rel);
413                 appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x", pkrelname);
414                 querysep = "WHERE";
415                 for (i = 0; i < riinfo->nkeys; i++)
416                 {
417                         Oid                     pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
418                         Oid                     fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
419
420                         quoteOneName(attname,
421                                                  RIAttName(pk_rel, riinfo->pk_attnums[i]));
422                         sprintf(paramname, "$%d", i + 1);
423                         ri_GenerateQual(&querybuf, querysep,
424                                                         attname, pk_type,
425                                                         riinfo->pf_eq_oprs[i],
426                                                         paramname, fk_type);
427                         querysep = "AND";
428                         queryoids[i] = fk_type;
429                 }
430                 appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
431
432                 /* Prepare and save the plan */
433                 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
434                                                          &qkey, fk_rel, pk_rel, true);
435         }
436
437         /*
438          * Now check that foreign key exists in PK table
439          */
440         ri_PerformCheck(riinfo, &qkey, qplan,
441                                         fk_rel, pk_rel,
442                                         NULL, new_row,
443                                         false,
444                                         SPI_OK_SELECT);
445
446         if (SPI_finish() != SPI_OK_FINISH)
447                 elog(ERROR, "SPI_finish failed");
448
449         heap_close(pk_rel, RowShareLock);
450
451         return PointerGetDatum(NULL);
452 }
453
454
455 /* ----------
456  * RI_FKey_check_ins -
457  *
458  *      Check foreign key existence at insert event on FK table.
459  * ----------
460  */
461 Datum
462 RI_FKey_check_ins(PG_FUNCTION_ARGS)
463 {
464         /*
465          * Check that this is a valid trigger call on the right time and event.
466          */
467         ri_CheckTrigger(fcinfo, "RI_FKey_check_ins", RI_TRIGTYPE_INSERT);
468
469         /*
470          * Share code with UPDATE case.
471          */
472         return RI_FKey_check((TriggerData *) fcinfo->context);
473 }
474
475
476 /* ----------
477  * RI_FKey_check_upd -
478  *
479  *      Check foreign key existence at update event on FK table.
480  * ----------
481  */
482 Datum
483 RI_FKey_check_upd(PG_FUNCTION_ARGS)
484 {
485         /*
486          * Check that this is a valid trigger call on the right time and event.
487          */
488         ri_CheckTrigger(fcinfo, "RI_FKey_check_upd", RI_TRIGTYPE_UPDATE);
489
490         /*
491          * Share code with INSERT case.
492          */
493         return RI_FKey_check((TriggerData *) fcinfo->context);
494 }
495
496
497 /* ----------
498  * ri_Check_Pk_Match
499  *
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.
503  *
504  * We assume the caller checked that the old_row contains no NULL key values,
505  * since otherwise a match is impossible.
506  * ----------
507  */
508 static bool
509 ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
510                                   HeapTuple old_row,
511                                   const RI_ConstraintInfo *riinfo)
512 {
513         SPIPlanPtr      qplan;
514         RI_QueryKey qkey;
515         int                     i;
516         bool            result;
517
518         /* Only called for non-null rows */
519         Assert(ri_NullCheck(old_row, riinfo, true) == RI_KEYS_NONE_NULL);
520
521         if (SPI_connect() != SPI_OK_CONNECT)
522                 elog(ERROR, "SPI_connect failed");
523
524         /*
525          * Fetch or prepare a saved plan for checking PK table with values coming
526          * from a PK row
527          */
528         ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CHECK_LOOKUPPK_FROM_PK);
529
530         if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
531         {
532                 StringInfoData querybuf;
533                 char            pkrelname[MAX_QUOTED_REL_NAME_LEN];
534                 char            attname[MAX_QUOTED_NAME_LEN];
535                 char            paramname[16];
536                 const char *querysep;
537                 Oid                     queryoids[RI_MAX_NUMKEYS];
538
539                 /* ----------
540                  * The query string built is
541                  *      SELECT 1 FROM ONLY <pktable> x WHERE pkatt1 = $1 [AND ...]
542                  *                 FOR KEY SHARE OF x
543                  * The type id's for the $ parameters are those of the
544                  * PK attributes themselves.
545                  * ----------
546                  */
547                 initStringInfo(&querybuf);
548                 quoteRelationName(pkrelname, pk_rel);
549                 appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x", pkrelname);
550                 querysep = "WHERE";
551                 for (i = 0; i < riinfo->nkeys; i++)
552                 {
553                         Oid                     pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
554
555                         quoteOneName(attname,
556                                                  RIAttName(pk_rel, riinfo->pk_attnums[i]));
557                         sprintf(paramname, "$%d", i + 1);
558                         ri_GenerateQual(&querybuf, querysep,
559                                                         attname, pk_type,
560                                                         riinfo->pp_eq_oprs[i],
561                                                         paramname, pk_type);
562                         querysep = "AND";
563                         queryoids[i] = pk_type;
564                 }
565                 appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
566
567                 /* Prepare and save the plan */
568                 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
569                                                          &qkey, fk_rel, pk_rel, true);
570         }
571
572         /*
573          * We have a plan now. Run it.
574          */
575         result = ri_PerformCheck(riinfo, &qkey, qplan,
576                                                          fk_rel, pk_rel,
577                                                          old_row, NULL,
578                                                          true,          /* treat like update */
579                                                          SPI_OK_SELECT);
580
581         if (SPI_finish() != SPI_OK_FINISH)
582                 elog(ERROR, "SPI_finish failed");
583
584         return result;
585 }
586
587
588 /* ----------
589  * RI_FKey_noaction_del -
590  *
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.
594  * ----------
595  */
596 Datum
597 RI_FKey_noaction_del(PG_FUNCTION_ARGS)
598 {
599         /*
600          * Check that this is a valid trigger call on the right time and event.
601          */
602         ri_CheckTrigger(fcinfo, "RI_FKey_noaction_del", RI_TRIGTYPE_DELETE);
603
604         /*
605          * Share code with RESTRICT case.
606          */
607         return ri_restrict_del((TriggerData *) fcinfo->context, true);
608 }
609
610 /* ----------
611  * RI_FKey_restrict_del -
612  *
613  *      Restrict delete from PK table to rows unreferenced by foreign key.
614  *
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.
619  * ----------
620  */
621 Datum
622 RI_FKey_restrict_del(PG_FUNCTION_ARGS)
623 {
624         /*
625          * Check that this is a valid trigger call on the right time and event.
626          */
627         ri_CheckTrigger(fcinfo, "RI_FKey_restrict_del", RI_TRIGTYPE_DELETE);
628
629         /*
630          * Share code with NO ACTION case.
631          */
632         return ri_restrict_del((TriggerData *) fcinfo->context, false);
633 }
634
635 /* ----------
636  * ri_restrict_del -
637  *
638  *      Common code for ON DELETE RESTRICT and ON DELETE NO ACTION.
639  * ----------
640  */
641 static Datum
642 ri_restrict_del(TriggerData *trigdata, bool is_no_action)
643 {
644         const RI_ConstraintInfo *riinfo;
645         Relation        fk_rel;
646         Relation        pk_rel;
647         HeapTuple       old_row;
648         RI_QueryKey qkey;
649         SPIPlanPtr      qplan;
650         int                     i;
651
652         /*
653          * Get arguments.
654          */
655         riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
656                                                                         trigdata->tg_relation, true);
657
658         /*
659          * Get the relation descriptors of the FK and PK tables and the old tuple.
660          *
661          * fk_rel is opened in RowShareLock mode since that's what our eventual
662          * SELECT FOR KEY SHARE will get on it.
663          */
664         fk_rel = heap_open(riinfo->fk_relid, RowShareLock);
665         pk_rel = trigdata->tg_relation;
666         old_row = trigdata->tg_trigtuple;
667
668         switch (riinfo->confmatchtype)
669         {
670                         /* ----------
671                          * SQL:2008 15.17 <Execution of referential actions>
672                          *      General rules 9) a) iv):
673                          *              MATCH SIMPLE/FULL
674                          *                      ... ON DELETE RESTRICT
675                          * ----------
676                          */
677                 case FKCONSTR_MATCH_SIMPLE:
678                 case FKCONSTR_MATCH_FULL:
679                         switch (ri_NullCheck(old_row, riinfo, true))
680                         {
681                                 case RI_KEYS_ALL_NULL:
682                                 case RI_KEYS_SOME_NULL:
683
684                                         /*
685                                          * No check needed - there cannot be any reference to old
686                                          * key if it contains a NULL
687                                          */
688                                         heap_close(fk_rel, RowShareLock);
689                                         return PointerGetDatum(NULL);
690
691                                 case RI_KEYS_NONE_NULL:
692
693                                         /*
694                                          * Have a full qualified key - continue below
695                                          */
696                                         break;
697                         }
698
699                         /*
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.
704                          */
705                         if (is_no_action &&
706                                 ri_Check_Pk_Match(pk_rel, fk_rel, old_row, riinfo))
707                         {
708                                 heap_close(fk_rel, RowShareLock);
709                                 return PointerGetDatum(NULL);
710                         }
711
712                         if (SPI_connect() != SPI_OK_CONNECT)
713                                 elog(ERROR, "SPI_connect failed");
714
715                         /*
716                          * Fetch or prepare a saved plan for the restrict delete lookup
717                          */
718                         ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_RESTRICT_DEL_CHECKREF);
719
720                         if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
721                         {
722                                 StringInfoData querybuf;
723                                 char            fkrelname[MAX_QUOTED_REL_NAME_LEN];
724                                 char            attname[MAX_QUOTED_NAME_LEN];
725                                 char            paramname[16];
726                                 const char *querysep;
727                                 Oid                     queryoids[RI_MAX_NUMKEYS];
728
729                                 /* ----------
730                                  * The query string built is
731                                  *      SELECT 1 FROM ONLY <fktable> x WHERE $1 = fkatt1 [AND ...]
732                                  *                 FOR KEY SHARE OF x
733                                  * The type id's for the $ parameters are those of the
734                                  * corresponding PK attributes.
735                                  * ----------
736                                  */
737                                 initStringInfo(&querybuf);
738                                 quoteRelationName(fkrelname, fk_rel);
739                                 appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x",
740                                                                  fkrelname);
741                                 querysep = "WHERE";
742                                 for (i = 0; i < riinfo->nkeys; i++)
743                                 {
744                                         Oid                     pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
745                                         Oid                     fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
746
747                                         quoteOneName(attname,
748                                                                  RIAttName(fk_rel, riinfo->fk_attnums[i]));
749                                         sprintf(paramname, "$%d", i + 1);
750                                         ri_GenerateQual(&querybuf, querysep,
751                                                                         paramname, pk_type,
752                                                                         riinfo->pf_eq_oprs[i],
753                                                                         attname, fk_type);
754                                         querysep = "AND";
755                                         queryoids[i] = pk_type;
756                                 }
757                                 appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
758
759                                 /* Prepare and save the plan */
760                                 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
761                                                                          &qkey, fk_rel, pk_rel, true);
762                         }
763
764                         /*
765                          * We have a plan now. Run it to check for existing references.
766                          */
767                         ri_PerformCheck(riinfo, &qkey, qplan,
768                                                         fk_rel, pk_rel,
769                                                         old_row, NULL,
770                                                         true,           /* must detect new rows */
771                                                         SPI_OK_SELECT);
772
773                         if (SPI_finish() != SPI_OK_FINISH)
774                                 elog(ERROR, "SPI_finish failed");
775
776                         heap_close(fk_rel, RowShareLock);
777
778                         return PointerGetDatum(NULL);
779
780                         /*
781                          * Handle MATCH PARTIAL restrict delete.
782                          */
783                 case FKCONSTR_MATCH_PARTIAL:
784                         ereport(ERROR,
785                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
786                                          errmsg("MATCH PARTIAL not yet implemented")));
787                         return PointerGetDatum(NULL);
788
789                 default:
790                         elog(ERROR, "unrecognized confmatchtype: %d",
791                                  riinfo->confmatchtype);
792                         break;
793         }
794
795         /* Never reached */
796         return PointerGetDatum(NULL);
797 }
798
799
800 /* ----------
801  * RI_FKey_noaction_upd -
802  *
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.
806  * ----------
807  */
808 Datum
809 RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
810 {
811         /*
812          * Check that this is a valid trigger call on the right time and event.
813          */
814         ri_CheckTrigger(fcinfo, "RI_FKey_noaction_upd", RI_TRIGTYPE_UPDATE);
815
816         /*
817          * Share code with RESTRICT case.
818          */
819         return ri_restrict_upd((TriggerData *) fcinfo->context, true);
820 }
821
822 /* ----------
823  * RI_FKey_restrict_upd -
824  *
825  *      Restrict update of PK to rows unreferenced by foreign key.
826  *
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.
831  * ----------
832  */
833 Datum
834 RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
835 {
836         /*
837          * Check that this is a valid trigger call on the right time and event.
838          */
839         ri_CheckTrigger(fcinfo, "RI_FKey_restrict_upd", RI_TRIGTYPE_UPDATE);
840
841         /*
842          * Share code with NO ACTION case.
843          */
844         return ri_restrict_upd((TriggerData *) fcinfo->context, false);
845 }
846
847 /* ----------
848  * ri_restrict_upd -
849  *
850  *      Common code for ON UPDATE RESTRICT and ON UPDATE NO ACTION.
851  * ----------
852  */
853 static Datum
854 ri_restrict_upd(TriggerData *trigdata, bool is_no_action)
855 {
856         const RI_ConstraintInfo *riinfo;
857         Relation        fk_rel;
858         Relation        pk_rel;
859         HeapTuple       new_row;
860         HeapTuple       old_row;
861         RI_QueryKey qkey;
862         SPIPlanPtr      qplan;
863         int                     i;
864
865         /*
866          * Get arguments.
867          */
868         riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
869                                                                         trigdata->tg_relation, true);
870
871         /*
872          * Get the relation descriptors of the FK and PK tables and the new and
873          * old tuple.
874          *
875          * fk_rel is opened in RowShareLock mode since that's what our eventual
876          * SELECT FOR KEY SHARE will get on it.
877          */
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;
882
883         switch (riinfo->confmatchtype)
884         {
885                         /* ----------
886                          * SQL:2008 15.17 <Execution of referential actions>
887                          *      General rules 10) a) iv):
888                          *              MATCH SIMPLE/FULL
889                          *                      ... ON UPDATE RESTRICT
890                          * ----------
891                          */
892                 case FKCONSTR_MATCH_SIMPLE:
893                 case FKCONSTR_MATCH_FULL:
894                         switch (ri_NullCheck(old_row, riinfo, true))
895                         {
896                                 case RI_KEYS_ALL_NULL:
897                                 case RI_KEYS_SOME_NULL:
898
899                                         /*
900                                          * No check needed - there cannot be any reference to old
901                                          * key if it contains a NULL
902                                          */
903                                         heap_close(fk_rel, RowShareLock);
904                                         return PointerGetDatum(NULL);
905
906                                 case RI_KEYS_NONE_NULL:
907
908                                         /*
909                                          * Have a full qualified key - continue below
910                                          */
911                                         break;
912                         }
913
914                         /*
915                          * No need to check anything if old and new keys are equal
916                          */
917                         if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true))
918                         {
919                                 heap_close(fk_rel, RowShareLock);
920                                 return PointerGetDatum(NULL);
921                         }
922
923                         /*
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.
928                          */
929                         if (is_no_action &&
930                                 ri_Check_Pk_Match(pk_rel, fk_rel, old_row, riinfo))
931                         {
932                                 heap_close(fk_rel, RowShareLock);
933                                 return PointerGetDatum(NULL);
934                         }
935
936                         if (SPI_connect() != SPI_OK_CONNECT)
937                                 elog(ERROR, "SPI_connect failed");
938
939                         /*
940                          * Fetch or prepare a saved plan for the restrict update lookup
941                          */
942                         ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_RESTRICT_UPD_CHECKREF);
943
944                         if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
945                         {
946                                 StringInfoData querybuf;
947                                 char            fkrelname[MAX_QUOTED_REL_NAME_LEN];
948                                 char            attname[MAX_QUOTED_NAME_LEN];
949                                 char            paramname[16];
950                                 const char *querysep;
951                                 Oid                     queryoids[RI_MAX_NUMKEYS];
952
953                                 /* ----------
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.
958                                  * ----------
959                                  */
960                                 initStringInfo(&querybuf);
961                                 quoteRelationName(fkrelname, fk_rel);
962                                 appendStringInfo(&querybuf, "SELECT 1 FROM ONLY %s x",
963                                                                  fkrelname);
964                                 querysep = "WHERE";
965                                 for (i = 0; i < riinfo->nkeys; i++)
966                                 {
967                                         Oid                     pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
968                                         Oid                     fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
969
970                                         quoteOneName(attname,
971                                                                  RIAttName(fk_rel, riinfo->fk_attnums[i]));
972                                         sprintf(paramname, "$%d", i + 1);
973                                         ri_GenerateQual(&querybuf, querysep,
974                                                                         paramname, pk_type,
975                                                                         riinfo->pf_eq_oprs[i],
976                                                                         attname, fk_type);
977                                         querysep = "AND";
978                                         queryoids[i] = pk_type;
979                                 }
980                                 appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
981
982                                 /* Prepare and save the plan */
983                                 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
984                                                                          &qkey, fk_rel, pk_rel, true);
985                         }
986
987                         /*
988                          * We have a plan now. Run it to check for existing references.
989                          */
990                         ri_PerformCheck(riinfo, &qkey, qplan,
991                                                         fk_rel, pk_rel,
992                                                         old_row, NULL,
993                                                         true,           /* must detect new rows */
994                                                         SPI_OK_SELECT);
995
996                         if (SPI_finish() != SPI_OK_FINISH)
997                                 elog(ERROR, "SPI_finish failed");
998
999                         heap_close(fk_rel, RowShareLock);
1000
1001                         return PointerGetDatum(NULL);
1002
1003                         /*
1004                          * Handle MATCH PARTIAL restrict update.
1005                          */
1006                 case FKCONSTR_MATCH_PARTIAL:
1007                         ereport(ERROR,
1008                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1009                                          errmsg("MATCH PARTIAL not yet implemented")));
1010                         return PointerGetDatum(NULL);
1011
1012                 default:
1013                         elog(ERROR, "unrecognized confmatchtype: %d",
1014                                  riinfo->confmatchtype);
1015                         break;
1016         }
1017
1018         /* Never reached */
1019         return PointerGetDatum(NULL);
1020 }
1021
1022
1023 /* ----------
1024  * RI_FKey_cascade_del -
1025  *
1026  *      Cascaded delete foreign key references at delete event on PK table.
1027  * ----------
1028  */
1029 Datum
1030 RI_FKey_cascade_del(PG_FUNCTION_ARGS)
1031 {
1032         TriggerData *trigdata = (TriggerData *) fcinfo->context;
1033         const RI_ConstraintInfo *riinfo;
1034         Relation        fk_rel;
1035         Relation        pk_rel;
1036         HeapTuple       old_row;
1037         RI_QueryKey qkey;
1038         SPIPlanPtr      qplan;
1039         int                     i;
1040
1041         /*
1042          * Check that this is a valid trigger call on the right time and event.
1043          */
1044         ri_CheckTrigger(fcinfo, "RI_FKey_cascade_del", RI_TRIGTYPE_DELETE);
1045
1046         /*
1047          * Get arguments.
1048          */
1049         riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1050                                                                         trigdata->tg_relation, true);
1051
1052         /*
1053          * Get the relation descriptors of the FK and PK tables and the old tuple.
1054          *
1055          * fk_rel is opened in RowExclusiveLock mode since that's what our
1056          * eventual DELETE will get on it.
1057          */
1058         fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock);
1059         pk_rel = trigdata->tg_relation;
1060         old_row = trigdata->tg_trigtuple;
1061
1062         switch (riinfo->confmatchtype)
1063         {
1064                         /* ----------
1065                          * SQL:2008 15.17 <Execution of referential actions>
1066                          *      General rules 9) a) i):
1067                          *              MATCH SIMPLE/FULL
1068                          *                      ... ON DELETE CASCADE
1069                          * ----------
1070                          */
1071                 case FKCONSTR_MATCH_SIMPLE:
1072                 case FKCONSTR_MATCH_FULL:
1073                         switch (ri_NullCheck(old_row, riinfo, true))
1074                         {
1075                                 case RI_KEYS_ALL_NULL:
1076                                 case RI_KEYS_SOME_NULL:
1077
1078                                         /*
1079                                          * No check needed - there cannot be any reference to old
1080                                          * key if it contains a NULL
1081                                          */
1082                                         heap_close(fk_rel, RowExclusiveLock);
1083                                         return PointerGetDatum(NULL);
1084
1085                                 case RI_KEYS_NONE_NULL:
1086
1087                                         /*
1088                                          * Have a full qualified key - continue below
1089                                          */
1090                                         break;
1091                         }
1092
1093                         if (SPI_connect() != SPI_OK_CONNECT)
1094                                 elog(ERROR, "SPI_connect failed");
1095
1096                         /*
1097                          * Fetch or prepare a saved plan for the cascaded delete
1098                          */
1099                         ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CASCADE_DEL_DODELETE);
1100
1101                         if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1102                         {
1103                                 StringInfoData querybuf;
1104                                 char            fkrelname[MAX_QUOTED_REL_NAME_LEN];
1105                                 char            attname[MAX_QUOTED_NAME_LEN];
1106                                 char            paramname[16];
1107                                 const char *querysep;
1108                                 Oid                     queryoids[RI_MAX_NUMKEYS];
1109
1110                                 /* ----------
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.
1115                                  * ----------
1116                                  */
1117                                 initStringInfo(&querybuf);
1118                                 quoteRelationName(fkrelname, fk_rel);
1119                                 appendStringInfo(&querybuf, "DELETE FROM ONLY %s", fkrelname);
1120                                 querysep = "WHERE";
1121                                 for (i = 0; i < riinfo->nkeys; i++)
1122                                 {
1123                                         Oid                     pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1124                                         Oid                     fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1125
1126                                         quoteOneName(attname,
1127                                                                  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1128                                         sprintf(paramname, "$%d", i + 1);
1129                                         ri_GenerateQual(&querybuf, querysep,
1130                                                                         paramname, pk_type,
1131                                                                         riinfo->pf_eq_oprs[i],
1132                                                                         attname, fk_type);
1133                                         querysep = "AND";
1134                                         queryoids[i] = pk_type;
1135                                 }
1136
1137                                 /* Prepare and save the plan */
1138                                 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
1139                                                                          &qkey, fk_rel, pk_rel, true);
1140                         }
1141
1142                         /*
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
1145                          */
1146                         ri_PerformCheck(riinfo, &qkey, qplan,
1147                                                         fk_rel, pk_rel,
1148                                                         old_row, NULL,
1149                                                         true,           /* must detect new rows */
1150                                                         SPI_OK_DELETE);
1151
1152                         if (SPI_finish() != SPI_OK_FINISH)
1153                                 elog(ERROR, "SPI_finish failed");
1154
1155                         heap_close(fk_rel, RowExclusiveLock);
1156
1157                         return PointerGetDatum(NULL);
1158
1159                         /*
1160                          * Handle MATCH PARTIAL cascaded delete.
1161                          */
1162                 case FKCONSTR_MATCH_PARTIAL:
1163                         ereport(ERROR,
1164                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1165                                          errmsg("MATCH PARTIAL not yet implemented")));
1166                         return PointerGetDatum(NULL);
1167
1168                 default:
1169                         elog(ERROR, "unrecognized confmatchtype: %d",
1170                                  riinfo->confmatchtype);
1171                         break;
1172         }
1173
1174         /* Never reached */
1175         return PointerGetDatum(NULL);
1176 }
1177
1178
1179 /* ----------
1180  * RI_FKey_cascade_upd -
1181  *
1182  *      Cascaded update foreign key references at update event on PK table.
1183  * ----------
1184  */
1185 Datum
1186 RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
1187 {
1188         TriggerData *trigdata = (TriggerData *) fcinfo->context;
1189         const RI_ConstraintInfo *riinfo;
1190         Relation        fk_rel;
1191         Relation        pk_rel;
1192         HeapTuple       new_row;
1193         HeapTuple       old_row;
1194         RI_QueryKey qkey;
1195         SPIPlanPtr      qplan;
1196         int                     i;
1197         int                     j;
1198
1199         /*
1200          * Check that this is a valid trigger call on the right time and event.
1201          */
1202         ri_CheckTrigger(fcinfo, "RI_FKey_cascade_upd", RI_TRIGTYPE_UPDATE);
1203
1204         /*
1205          * Get arguments.
1206          */
1207         riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1208                                                                         trigdata->tg_relation, true);
1209
1210         /*
1211          * Get the relation descriptors of the FK and PK tables and the new and
1212          * old tuple.
1213          *
1214          * fk_rel is opened in RowExclusiveLock mode since that's what our
1215          * eventual UPDATE will get on it.
1216          */
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;
1221
1222         switch (riinfo->confmatchtype)
1223         {
1224                         /* ----------
1225                          * SQL:2008 15.17 <Execution of referential actions>
1226                          *      General rules 10) a) i):
1227                          *              MATCH SIMPLE/FULL
1228                          *                      ... ON UPDATE CASCADE
1229                          * ----------
1230                          */
1231                 case FKCONSTR_MATCH_SIMPLE:
1232                 case FKCONSTR_MATCH_FULL:
1233                         switch (ri_NullCheck(old_row, riinfo, true))
1234                         {
1235                                 case RI_KEYS_ALL_NULL:
1236                                 case RI_KEYS_SOME_NULL:
1237
1238                                         /*
1239                                          * No check needed - there cannot be any reference to old
1240                                          * key if it contains a NULL
1241                                          */
1242                                         heap_close(fk_rel, RowExclusiveLock);
1243                                         return PointerGetDatum(NULL);
1244
1245                                 case RI_KEYS_NONE_NULL:
1246
1247                                         /*
1248                                          * Have a full qualified key - continue below
1249                                          */
1250                                         break;
1251                         }
1252
1253                         /*
1254                          * No need to do anything if old and new keys are equal
1255                          */
1256                         if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true))
1257                         {
1258                                 heap_close(fk_rel, RowExclusiveLock);
1259                                 return PointerGetDatum(NULL);
1260                         }
1261
1262                         if (SPI_connect() != SPI_OK_CONNECT)
1263                                 elog(ERROR, "SPI_connect failed");
1264
1265                         /*
1266                          * Fetch or prepare a saved plan for the cascaded update
1267                          */
1268                         ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_CASCADE_UPD_DOUPDATE);
1269
1270                         if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1271                         {
1272                                 StringInfoData querybuf;
1273                                 StringInfoData qualbuf;
1274                                 char            fkrelname[MAX_QUOTED_REL_NAME_LEN];
1275                                 char            attname[MAX_QUOTED_NAME_LEN];
1276                                 char            paramname[16];
1277                                 const char *querysep;
1278                                 const char *qualsep;
1279                                 Oid                     queryoids[RI_MAX_NUMKEYS * 2];
1280
1281                                 /* ----------
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.
1289                                  * ----------
1290                                  */
1291                                 initStringInfo(&querybuf);
1292                                 initStringInfo(&qualbuf);
1293                                 quoteRelationName(fkrelname, fk_rel);
1294                                 appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname);
1295                                 querysep = "";
1296                                 qualsep = "WHERE";
1297                                 for (i = 0, j = riinfo->nkeys; i < riinfo->nkeys; i++, j++)
1298                                 {
1299                                         Oid                     pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1300                                         Oid                     fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1301
1302                                         quoteOneName(attname,
1303                                                                  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1304                                         appendStringInfo(&querybuf,
1305                                                                          "%s %s = $%d",
1306                                                                          querysep, attname, i + 1);
1307                                         sprintf(paramname, "$%d", j + 1);
1308                                         ri_GenerateQual(&qualbuf, qualsep,
1309                                                                         paramname, pk_type,
1310                                                                         riinfo->pf_eq_oprs[i],
1311                                                                         attname, fk_type);
1312                                         querysep = ",";
1313                                         qualsep = "AND";
1314                                         queryoids[i] = pk_type;
1315                                         queryoids[j] = pk_type;
1316                                 }
1317                                 appendStringInfoString(&querybuf, qualbuf.data);
1318
1319                                 /* Prepare and save the plan */
1320                                 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys * 2, queryoids,
1321                                                                          &qkey, fk_rel, pk_rel, true);
1322                         }
1323
1324                         /*
1325                          * We have a plan now. Run it to update the existing references.
1326                          */
1327                         ri_PerformCheck(riinfo, &qkey, qplan,
1328                                                         fk_rel, pk_rel,
1329                                                         old_row, new_row,
1330                                                         true,           /* must detect new rows */
1331                                                         SPI_OK_UPDATE);
1332
1333                         if (SPI_finish() != SPI_OK_FINISH)
1334                                 elog(ERROR, "SPI_finish failed");
1335
1336                         heap_close(fk_rel, RowExclusiveLock);
1337
1338                         return PointerGetDatum(NULL);
1339
1340                         /*
1341                          * Handle MATCH PARTIAL cascade update.
1342                          */
1343                 case FKCONSTR_MATCH_PARTIAL:
1344                         ereport(ERROR,
1345                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1346                                          errmsg("MATCH PARTIAL not yet implemented")));
1347                         return PointerGetDatum(NULL);
1348
1349                 default:
1350                         elog(ERROR, "unrecognized confmatchtype: %d",
1351                                  riinfo->confmatchtype);
1352                         break;
1353         }
1354
1355         /* Never reached */
1356         return PointerGetDatum(NULL);
1357 }
1358
1359
1360 /* ----------
1361  * RI_FKey_setnull_del -
1362  *
1363  *      Set foreign key references to NULL values at delete event on PK table.
1364  * ----------
1365  */
1366 Datum
1367 RI_FKey_setnull_del(PG_FUNCTION_ARGS)
1368 {
1369         TriggerData *trigdata = (TriggerData *) fcinfo->context;
1370         const RI_ConstraintInfo *riinfo;
1371         Relation        fk_rel;
1372         Relation        pk_rel;
1373         HeapTuple       old_row;
1374         RI_QueryKey qkey;
1375         SPIPlanPtr      qplan;
1376         int                     i;
1377
1378         /*
1379          * Check that this is a valid trigger call on the right time and event.
1380          */
1381         ri_CheckTrigger(fcinfo, "RI_FKey_setnull_del", RI_TRIGTYPE_DELETE);
1382
1383         /*
1384          * Get arguments.
1385          */
1386         riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1387                                                                         trigdata->tg_relation, true);
1388
1389         /*
1390          * Get the relation descriptors of the FK and PK tables and the old tuple.
1391          *
1392          * fk_rel is opened in RowExclusiveLock mode since that's what our
1393          * eventual UPDATE will get on it.
1394          */
1395         fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock);
1396         pk_rel = trigdata->tg_relation;
1397         old_row = trigdata->tg_trigtuple;
1398
1399         switch (riinfo->confmatchtype)
1400         {
1401                         /* ----------
1402                          * SQL:2008 15.17 <Execution of referential actions>
1403                          *      General rules 9) a) ii):
1404                          *              MATCH SIMPLE/FULL
1405                          *                      ... ON DELETE SET NULL
1406                          * ----------
1407                          */
1408                 case FKCONSTR_MATCH_SIMPLE:
1409                 case FKCONSTR_MATCH_FULL:
1410                         switch (ri_NullCheck(old_row, riinfo, true))
1411                         {
1412                                 case RI_KEYS_ALL_NULL:
1413                                 case RI_KEYS_SOME_NULL:
1414
1415                                         /*
1416                                          * No check needed - there cannot be any reference to old
1417                                          * key if it contains a NULL
1418                                          */
1419                                         heap_close(fk_rel, RowExclusiveLock);
1420                                         return PointerGetDatum(NULL);
1421
1422                                 case RI_KEYS_NONE_NULL:
1423
1424                                         /*
1425                                          * Have a full qualified key - continue below
1426                                          */
1427                                         break;
1428                         }
1429
1430                         if (SPI_connect() != SPI_OK_CONNECT)
1431                                 elog(ERROR, "SPI_connect failed");
1432
1433                         /*
1434                          * Fetch or prepare a saved plan for the set null delete operation
1435                          */
1436                         ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_SETNULL_DEL_DOUPDATE);
1437
1438                         if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1439                         {
1440                                 StringInfoData querybuf;
1441                                 StringInfoData qualbuf;
1442                                 char            fkrelname[MAX_QUOTED_REL_NAME_LEN];
1443                                 char            attname[MAX_QUOTED_NAME_LEN];
1444                                 char            paramname[16];
1445                                 const char *querysep;
1446                                 const char *qualsep;
1447                                 Oid                     queryoids[RI_MAX_NUMKEYS];
1448
1449                                 /* ----------
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.
1455                                  * ----------
1456                                  */
1457                                 initStringInfo(&querybuf);
1458                                 initStringInfo(&qualbuf);
1459                                 quoteRelationName(fkrelname, fk_rel);
1460                                 appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname);
1461                                 querysep = "";
1462                                 qualsep = "WHERE";
1463                                 for (i = 0; i < riinfo->nkeys; i++)
1464                                 {
1465                                         Oid                     pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1466                                         Oid                     fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1467
1468                                         quoteOneName(attname,
1469                                                                  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1470                                         appendStringInfo(&querybuf,
1471                                                                          "%s %s = NULL",
1472                                                                          querysep, attname);
1473                                         sprintf(paramname, "$%d", i + 1);
1474                                         ri_GenerateQual(&qualbuf, qualsep,
1475                                                                         paramname, pk_type,
1476                                                                         riinfo->pf_eq_oprs[i],
1477                                                                         attname, fk_type);
1478                                         querysep = ",";
1479                                         qualsep = "AND";
1480                                         queryoids[i] = pk_type;
1481                                 }
1482                                 appendStringInfoString(&querybuf, qualbuf.data);
1483
1484                                 /* Prepare and save the plan */
1485                                 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
1486                                                                          &qkey, fk_rel, pk_rel, true);
1487                         }
1488
1489                         /*
1490                          * We have a plan now. Run it to check for existing references.
1491                          */
1492                         ri_PerformCheck(riinfo, &qkey, qplan,
1493                                                         fk_rel, pk_rel,
1494                                                         old_row, NULL,
1495                                                         true,           /* must detect new rows */
1496                                                         SPI_OK_UPDATE);
1497
1498                         if (SPI_finish() != SPI_OK_FINISH)
1499                                 elog(ERROR, "SPI_finish failed");
1500
1501                         heap_close(fk_rel, RowExclusiveLock);
1502
1503                         return PointerGetDatum(NULL);
1504
1505                         /*
1506                          * Handle MATCH PARTIAL set null delete.
1507                          */
1508                 case FKCONSTR_MATCH_PARTIAL:
1509                         ereport(ERROR,
1510                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1511                                          errmsg("MATCH PARTIAL not yet implemented")));
1512                         return PointerGetDatum(NULL);
1513
1514                 default:
1515                         elog(ERROR, "unrecognized confmatchtype: %d",
1516                                  riinfo->confmatchtype);
1517                         break;
1518         }
1519
1520         /* Never reached */
1521         return PointerGetDatum(NULL);
1522 }
1523
1524
1525 /* ----------
1526  * RI_FKey_setnull_upd -
1527  *
1528  *      Set foreign key references to NULL at update event on PK table.
1529  * ----------
1530  */
1531 Datum
1532 RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
1533 {
1534         TriggerData *trigdata = (TriggerData *) fcinfo->context;
1535         const RI_ConstraintInfo *riinfo;
1536         Relation        fk_rel;
1537         Relation        pk_rel;
1538         HeapTuple       new_row;
1539         HeapTuple       old_row;
1540         RI_QueryKey qkey;
1541         SPIPlanPtr      qplan;
1542         int                     i;
1543
1544         /*
1545          * Check that this is a valid trigger call on the right time and event.
1546          */
1547         ri_CheckTrigger(fcinfo, "RI_FKey_setnull_upd", RI_TRIGTYPE_UPDATE);
1548
1549         /*
1550          * Get arguments.
1551          */
1552         riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1553                                                                         trigdata->tg_relation, true);
1554
1555         /*
1556          * Get the relation descriptors of the FK and PK tables and the old tuple.
1557          *
1558          * fk_rel is opened in RowExclusiveLock mode since that's what our
1559          * eventual UPDATE will get on it.
1560          */
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;
1565
1566         switch (riinfo->confmatchtype)
1567         {
1568                         /* ----------
1569                          * SQL:2008 15.17 <Execution of referential actions>
1570                          *      General rules 10) a) ii):
1571                          *              MATCH SIMPLE/FULL
1572                          *                      ... ON UPDATE SET NULL
1573                          * ----------
1574                          */
1575                 case FKCONSTR_MATCH_SIMPLE:
1576                 case FKCONSTR_MATCH_FULL:
1577                         switch (ri_NullCheck(old_row, riinfo, true))
1578                         {
1579                                 case RI_KEYS_ALL_NULL:
1580                                 case RI_KEYS_SOME_NULL:
1581
1582                                         /*
1583                                          * No check needed - there cannot be any reference to old
1584                                          * key if it contains a NULL
1585                                          */
1586                                         heap_close(fk_rel, RowExclusiveLock);
1587                                         return PointerGetDatum(NULL);
1588
1589                                 case RI_KEYS_NONE_NULL:
1590
1591                                         /*
1592                                          * Have a full qualified key - continue below
1593                                          */
1594                                         break;
1595                         }
1596
1597                         /*
1598                          * No need to do anything if old and new keys are equal
1599                          */
1600                         if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true))
1601                         {
1602                                 heap_close(fk_rel, RowExclusiveLock);
1603                                 return PointerGetDatum(NULL);
1604                         }
1605
1606                         if (SPI_connect() != SPI_OK_CONNECT)
1607                                 elog(ERROR, "SPI_connect failed");
1608
1609                         /*
1610                          * Fetch or prepare a saved plan for the set null update operation
1611                          */
1612                         ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_SETNULL_UPD_DOUPDATE);
1613
1614                         if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1615                         {
1616                                 StringInfoData querybuf;
1617                                 StringInfoData qualbuf;
1618                                 char            fkrelname[MAX_QUOTED_REL_NAME_LEN];
1619                                 char            attname[MAX_QUOTED_NAME_LEN];
1620                                 char            paramname[16];
1621                                 const char *querysep;
1622                                 const char *qualsep;
1623                                 Oid                     queryoids[RI_MAX_NUMKEYS];
1624
1625                                 /* ----------
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.
1631                                  * ----------
1632                                  */
1633                                 initStringInfo(&querybuf);
1634                                 initStringInfo(&qualbuf);
1635                                 quoteRelationName(fkrelname, fk_rel);
1636                                 appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname);
1637                                 querysep = "";
1638                                 qualsep = "WHERE";
1639                                 for (i = 0; i < riinfo->nkeys; i++)
1640                                 {
1641                                         Oid                     pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1642                                         Oid                     fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1643
1644                                         quoteOneName(attname,
1645                                                                  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1646                                         appendStringInfo(&querybuf,
1647                                                                          "%s %s = NULL",
1648                                                                          querysep, attname);
1649                                         sprintf(paramname, "$%d", i + 1);
1650                                         ri_GenerateQual(&qualbuf, qualsep,
1651                                                                         paramname, pk_type,
1652                                                                         riinfo->pf_eq_oprs[i],
1653                                                                         attname, fk_type);
1654                                         querysep = ",";
1655                                         qualsep = "AND";
1656                                         queryoids[i] = pk_type;
1657                                 }
1658                                 appendStringInfoString(&querybuf, qualbuf.data);
1659
1660                                 /* Prepare and save the plan */
1661                                 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
1662                                                                          &qkey, fk_rel, pk_rel, true);
1663                         }
1664
1665                         /*
1666                          * We have a plan now. Run it to update the existing references.
1667                          */
1668                         ri_PerformCheck(riinfo, &qkey, qplan,
1669                                                         fk_rel, pk_rel,
1670                                                         old_row, NULL,
1671                                                         true,           /* must detect new rows */
1672                                                         SPI_OK_UPDATE);
1673
1674                         if (SPI_finish() != SPI_OK_FINISH)
1675                                 elog(ERROR, "SPI_finish failed");
1676
1677                         heap_close(fk_rel, RowExclusiveLock);
1678
1679                         return PointerGetDatum(NULL);
1680
1681                         /*
1682                          * Handle MATCH PARTIAL set null update.
1683                          */
1684                 case FKCONSTR_MATCH_PARTIAL:
1685                         ereport(ERROR,
1686                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1687                                          errmsg("MATCH PARTIAL not yet implemented")));
1688                         return PointerGetDatum(NULL);
1689
1690                 default:
1691                         elog(ERROR, "unrecognized confmatchtype: %d",
1692                                  riinfo->confmatchtype);
1693                         break;
1694         }
1695
1696         /* Never reached */
1697         return PointerGetDatum(NULL);
1698 }
1699
1700
1701 /* ----------
1702  * RI_FKey_setdefault_del -
1703  *
1704  *      Set foreign key references to defaults at delete event on PK table.
1705  * ----------
1706  */
1707 Datum
1708 RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
1709 {
1710         TriggerData *trigdata = (TriggerData *) fcinfo->context;
1711         const RI_ConstraintInfo *riinfo;
1712         Relation        fk_rel;
1713         Relation        pk_rel;
1714         HeapTuple       old_row;
1715         RI_QueryKey qkey;
1716         SPIPlanPtr      qplan;
1717
1718         /*
1719          * Check that this is a valid trigger call on the right time and event.
1720          */
1721         ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_del", RI_TRIGTYPE_DELETE);
1722
1723         /*
1724          * Get arguments.
1725          */
1726         riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1727                                                                         trigdata->tg_relation, true);
1728
1729         /*
1730          * Get the relation descriptors of the FK and PK tables and the old tuple.
1731          *
1732          * fk_rel is opened in RowExclusiveLock mode since that's what our
1733          * eventual UPDATE will get on it.
1734          */
1735         fk_rel = heap_open(riinfo->fk_relid, RowExclusiveLock);
1736         pk_rel = trigdata->tg_relation;
1737         old_row = trigdata->tg_trigtuple;
1738
1739         switch (riinfo->confmatchtype)
1740         {
1741                         /* ----------
1742                          * SQL:2008 15.17 <Execution of referential actions>
1743                          *      General rules 9) a) iii):
1744                          *              MATCH SIMPLE/FULL
1745                          *                      ... ON DELETE SET DEFAULT
1746                          * ----------
1747                          */
1748                 case FKCONSTR_MATCH_SIMPLE:
1749                 case FKCONSTR_MATCH_FULL:
1750                         switch (ri_NullCheck(old_row, riinfo, true))
1751                         {
1752                                 case RI_KEYS_ALL_NULL:
1753                                 case RI_KEYS_SOME_NULL:
1754
1755                                         /*
1756                                          * No check needed - there cannot be any reference to old
1757                                          * key if it contains a NULL
1758                                          */
1759                                         heap_close(fk_rel, RowExclusiveLock);
1760                                         return PointerGetDatum(NULL);
1761
1762                                 case RI_KEYS_NONE_NULL:
1763
1764                                         /*
1765                                          * Have a full qualified key - continue below
1766                                          */
1767                                         break;
1768                         }
1769
1770                         if (SPI_connect() != SPI_OK_CONNECT)
1771                                 elog(ERROR, "SPI_connect failed");
1772
1773                         /*
1774                          * Fetch or prepare a saved plan for the set default delete
1775                          * operation
1776                          */
1777                         ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_SETDEFAULT_DEL_DOUPDATE);
1778
1779                         if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1780                         {
1781                                 StringInfoData querybuf;
1782                                 StringInfoData qualbuf;
1783                                 char            fkrelname[MAX_QUOTED_REL_NAME_LEN];
1784                                 char            attname[MAX_QUOTED_NAME_LEN];
1785                                 char            paramname[16];
1786                                 const char *querysep;
1787                                 const char *qualsep;
1788                                 Oid                     queryoids[RI_MAX_NUMKEYS];
1789                                 int                     i;
1790
1791                                 /* ----------
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.
1797                                  * ----------
1798                                  */
1799                                 initStringInfo(&querybuf);
1800                                 initStringInfo(&qualbuf);
1801                                 quoteRelationName(fkrelname, fk_rel);
1802                                 appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname);
1803                                 querysep = "";
1804                                 qualsep = "WHERE";
1805                                 for (i = 0; i < riinfo->nkeys; i++)
1806                                 {
1807                                         Oid                     pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1808                                         Oid                     fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1809
1810                                         quoteOneName(attname,
1811                                                                  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1812                                         appendStringInfo(&querybuf,
1813                                                                          "%s %s = DEFAULT",
1814                                                                          querysep, attname);
1815                                         sprintf(paramname, "$%d", i + 1);
1816                                         ri_GenerateQual(&qualbuf, qualsep,
1817                                                                         paramname, pk_type,
1818                                                                         riinfo->pf_eq_oprs[i],
1819                                                                         attname, fk_type);
1820                                         querysep = ",";
1821                                         qualsep = "AND";
1822                                         queryoids[i] = pk_type;
1823                                 }
1824                                 appendStringInfoString(&querybuf, qualbuf.data);
1825
1826                                 /* Prepare and save the plan */
1827                                 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
1828                                                                          &qkey, fk_rel, pk_rel, true);
1829                         }
1830
1831                         /*
1832                          * We have a plan now. Run it to update the existing references.
1833                          */
1834                         ri_PerformCheck(riinfo, &qkey, qplan,
1835                                                         fk_rel, pk_rel,
1836                                                         old_row, NULL,
1837                                                         true,           /* must detect new rows */
1838                                                         SPI_OK_UPDATE);
1839
1840                         if (SPI_finish() != SPI_OK_FINISH)
1841                                 elog(ERROR, "SPI_finish failed");
1842
1843                         heap_close(fk_rel, RowExclusiveLock);
1844
1845                         /*
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.)
1856                          */
1857                         RI_FKey_noaction_del(fcinfo);
1858
1859                         return PointerGetDatum(NULL);
1860
1861                         /*
1862                          * Handle MATCH PARTIAL set default delete.
1863                          */
1864                 case FKCONSTR_MATCH_PARTIAL:
1865                         ereport(ERROR,
1866                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1867                                          errmsg("MATCH PARTIAL not yet implemented")));
1868                         return PointerGetDatum(NULL);
1869
1870                 default:
1871                         elog(ERROR, "unrecognized confmatchtype: %d",
1872                                  riinfo->confmatchtype);
1873                         break;
1874         }
1875
1876         /* Never reached */
1877         return PointerGetDatum(NULL);
1878 }
1879
1880
1881 /* ----------
1882  * RI_FKey_setdefault_upd -
1883  *
1884  *      Set foreign key references to defaults at update event on PK table.
1885  * ----------
1886  */
1887 Datum
1888 RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
1889 {
1890         TriggerData *trigdata = (TriggerData *) fcinfo->context;
1891         const RI_ConstraintInfo *riinfo;
1892         Relation        fk_rel;
1893         Relation        pk_rel;
1894         HeapTuple       new_row;
1895         HeapTuple       old_row;
1896         RI_QueryKey qkey;
1897         SPIPlanPtr      qplan;
1898
1899         /*
1900          * Check that this is a valid trigger call on the right time and event.
1901          */
1902         ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_upd", RI_TRIGTYPE_UPDATE);
1903
1904         /*
1905          * Get arguments.
1906          */
1907         riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1908                                                                         trigdata->tg_relation, true);
1909
1910         /*
1911          * Get the relation descriptors of the FK and PK tables and the old tuple.
1912          *
1913          * fk_rel is opened in RowExclusiveLock mode since that's what our
1914          * eventual UPDATE will get on it.
1915          */
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;
1920
1921         switch (riinfo->confmatchtype)
1922         {
1923                         /* ----------
1924                          * SQL:2008 15.17 <Execution of referential actions>
1925                          *      General rules 10) a) iii):
1926                          *              MATCH SIMPLE/FULL
1927                          *                      ... ON UPDATE SET DEFAULT
1928                          * ----------
1929                          */
1930                 case FKCONSTR_MATCH_SIMPLE:
1931                 case FKCONSTR_MATCH_FULL:
1932                         switch (ri_NullCheck(old_row, riinfo, true))
1933                         {
1934                                 case RI_KEYS_ALL_NULL:
1935                                 case RI_KEYS_SOME_NULL:
1936
1937                                         /*
1938                                          * No check needed - there cannot be any reference to old
1939                                          * key if it contains a NULL
1940                                          */
1941                                         heap_close(fk_rel, RowExclusiveLock);
1942                                         return PointerGetDatum(NULL);
1943
1944                                 case RI_KEYS_NONE_NULL:
1945
1946                                         /*
1947                                          * Have a full qualified key - continue below
1948                                          */
1949                                         break;
1950                         }
1951
1952                         /*
1953                          * No need to do anything if old and new keys are equal
1954                          */
1955                         if (ri_KeysEqual(pk_rel, old_row, new_row, riinfo, true))
1956                         {
1957                                 heap_close(fk_rel, RowExclusiveLock);
1958                                 return PointerGetDatum(NULL);
1959                         }
1960
1961                         if (SPI_connect() != SPI_OK_CONNECT)
1962                                 elog(ERROR, "SPI_connect failed");
1963
1964                         /*
1965                          * Fetch or prepare a saved plan for the set default update
1966                          * operation
1967                          */
1968                         ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_SETDEFAULT_UPD_DOUPDATE);
1969
1970                         if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1971                         {
1972                                 StringInfoData querybuf;
1973                                 StringInfoData qualbuf;
1974                                 char            fkrelname[MAX_QUOTED_REL_NAME_LEN];
1975                                 char            attname[MAX_QUOTED_NAME_LEN];
1976                                 char            paramname[16];
1977                                 const char *querysep;
1978                                 const char *qualsep;
1979                                 Oid                     queryoids[RI_MAX_NUMKEYS];
1980                                 int                     i;
1981
1982                                 /* ----------
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.
1988                                  * ----------
1989                                  */
1990                                 initStringInfo(&querybuf);
1991                                 initStringInfo(&qualbuf);
1992                                 quoteRelationName(fkrelname, fk_rel);
1993                                 appendStringInfo(&querybuf, "UPDATE ONLY %s SET", fkrelname);
1994                                 querysep = "";
1995                                 qualsep = "WHERE";
1996                                 for (i = 0; i < riinfo->nkeys; i++)
1997                                 {
1998                                         Oid                     pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1999                                         Oid                     fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
2000
2001                                         quoteOneName(attname,
2002                                                                  RIAttName(fk_rel, riinfo->fk_attnums[i]));
2003                                         appendStringInfo(&querybuf,
2004                                                                          "%s %s = DEFAULT",
2005                                                                          querysep, attname);
2006                                         sprintf(paramname, "$%d", i + 1);
2007                                         ri_GenerateQual(&qualbuf, qualsep,
2008                                                                         paramname, pk_type,
2009                                                                         riinfo->pf_eq_oprs[i],
2010                                                                         attname, fk_type);
2011                                         querysep = ",";
2012                                         qualsep = "AND";
2013                                         queryoids[i] = pk_type;
2014                                 }
2015                                 appendStringInfoString(&querybuf, qualbuf.data);
2016
2017                                 /* Prepare and save the plan */
2018                                 qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
2019                                                                          &qkey, fk_rel, pk_rel, true);
2020                         }
2021
2022                         /*
2023                          * We have a plan now. Run it to update the existing references.
2024                          */
2025                         ri_PerformCheck(riinfo, &qkey, qplan,
2026                                                         fk_rel, pk_rel,
2027                                                         old_row, NULL,
2028                                                         true,           /* must detect new rows */
2029                                                         SPI_OK_UPDATE);
2030
2031                         if (SPI_finish() != SPI_OK_FINISH)
2032                                 elog(ERROR, "SPI_finish failed");
2033
2034                         heap_close(fk_rel, RowExclusiveLock);
2035
2036                         /*
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.)
2047                          */
2048                         RI_FKey_noaction_upd(fcinfo);
2049
2050                         return PointerGetDatum(NULL);
2051
2052                         /*
2053                          * Handle MATCH PARTIAL set default update.
2054                          */
2055                 case FKCONSTR_MATCH_PARTIAL:
2056                         ereport(ERROR,
2057                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2058                                          errmsg("MATCH PARTIAL not yet implemented")));
2059                         return PointerGetDatum(NULL);
2060
2061                 default:
2062                         elog(ERROR, "unrecognized confmatchtype: %d",
2063                                  riinfo->confmatchtype);
2064                         break;
2065         }
2066
2067         /* Never reached */
2068         return PointerGetDatum(NULL);
2069 }
2070
2071
2072 /* ----------
2073  * RI_FKey_pk_upd_check_required -
2074  *
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
2079  *      be satisfied.
2080  * ----------
2081  */
2082 bool
2083 RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel,
2084                                                           HeapTuple old_row, HeapTuple new_row)
2085 {
2086         const RI_ConstraintInfo *riinfo;
2087
2088         /*
2089          * Get arguments.
2090          */
2091         riinfo = ri_FetchConstraintInfo(trigger, pk_rel, true);
2092
2093         switch (riinfo->confmatchtype)
2094         {
2095                 case FKCONSTR_MATCH_SIMPLE:
2096                 case FKCONSTR_MATCH_FULL:
2097
2098                         /*
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.
2101                          */
2102                         if (ri_NullCheck(old_row, riinfo, true) != RI_KEYS_NONE_NULL)
2103                                 return false;
2104
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))
2107                                 return false;
2108
2109                         /* Else we need to fire the trigger. */
2110                         return true;
2111
2112                         /* Handle MATCH PARTIAL check. */
2113                 case FKCONSTR_MATCH_PARTIAL:
2114                         ereport(ERROR,
2115                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2116                                          errmsg("MATCH PARTIAL not yet implemented")));
2117                         break;
2118
2119                 default:
2120                         elog(ERROR, "unrecognized confmatchtype: %d",
2121                                  riinfo->confmatchtype);
2122                         break;
2123         }
2124
2125         /* Never reached */
2126         return false;
2127 }
2128
2129 /* ----------
2130  * RI_FKey_fk_upd_check_required -
2131  *
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
2136  *      be satisfied.
2137  * ----------
2138  */
2139 bool
2140 RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
2141                                                           HeapTuple old_row, HeapTuple new_row)
2142 {
2143         const RI_ConstraintInfo *riinfo;
2144
2145         /*
2146          * Get arguments.
2147          */
2148         riinfo = ri_FetchConstraintInfo(trigger, fk_rel, false);
2149
2150         switch (riinfo->confmatchtype)
2151         {
2152                 case FKCONSTR_MATCH_SIMPLE:
2153
2154                         /*
2155                          * If any new key value is NULL, the row must satisfy the
2156                          * constraint, so no check is needed.
2157                          */
2158                         if (ri_NullCheck(new_row, riinfo, false) != RI_KEYS_NONE_NULL)
2159                                 return false;
2160
2161                         /*
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.)
2168                          */
2169                         if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data)))
2170                                 return true;
2171
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))
2174                                 return false;
2175
2176                         /* Else we need to fire the trigger. */
2177                         return true;
2178
2179                 case FKCONSTR_MATCH_FULL:
2180
2181                         /*
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.
2188                          */
2189                         switch (ri_NullCheck(new_row, riinfo, false))
2190                         {
2191                                 case RI_KEYS_ALL_NULL:
2192                                         return false;
2193                                 case RI_KEYS_SOME_NULL:
2194                                         return true;
2195                                 case RI_KEYS_NONE_NULL:
2196                                         break;          /* continue with the check */
2197                         }
2198
2199                         /*
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.)
2206                          */
2207                         if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(old_row->t_data)))
2208                                 return true;
2209
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))
2212                                 return false;
2213
2214                         /* Else we need to fire the trigger. */
2215                         return true;
2216
2217                         /* Handle MATCH PARTIAL check. */
2218                 case FKCONSTR_MATCH_PARTIAL:
2219                         ereport(ERROR,
2220                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2221                                          errmsg("MATCH PARTIAL not yet implemented")));
2222                         break;
2223
2224                 default:
2225                         elog(ERROR, "unrecognized confmatchtype: %d",
2226                                  riinfo->confmatchtype);
2227                         break;
2228         }
2229
2230         /* Never reached */
2231         return false;
2232 }
2233
2234 /* ----------
2235  * RI_Initial_Check -
2236  *
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.
2240  *
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.
2246  *
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.
2250  * ----------
2251  */
2252 bool
2253 RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
2254 {
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;
2263         const char *sep;
2264         int                     i;
2265         int                     save_nestlevel;
2266         char            workmembuf[32];
2267         int                     spi_result;
2268         SPIPlanPtr      qplan;
2269
2270         /* Fetch constraint info. */
2271         riinfo = ri_FetchConstraintInfo(trigger, fk_rel, false);
2272
2273         /*
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.)
2277          *
2278          * XXX are there any other show-stopper conditions to check?
2279          */
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;
2285
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;
2291
2292         for (i = 0; i < riinfo->nkeys; i++)
2293         {
2294                 int                     attno;
2295
2296                 attno = riinfo->pk_attnums[i] - FirstLowInvalidHeapAttributeNumber;
2297                 pkrte->selectedCols = bms_add_member(pkrte->selectedCols, attno);
2298
2299                 attno = riinfo->fk_attnums[i] - FirstLowInvalidHeapAttributeNumber;
2300                 fkrte->selectedCols = bms_add_member(fkrte->selectedCols, attno);
2301         }
2302
2303         if (!ExecCheckRTPerms(list_make2(fkrte, pkrte), false))
2304                 return false;
2305
2306         /*----------
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
2312          * For MATCH SIMPLE:
2313          *       (fk.keycol1 IS NOT NULL [AND ...])
2314          * For MATCH FULL:
2315          *       (fk.keycol1 IS NOT NULL [OR ...])
2316          *
2317          * We attach COLLATE clauses to the operators when comparing columns
2318          * that have different collations.
2319          *----------
2320          */
2321         initStringInfo(&querybuf);
2322         appendStringInfoString(&querybuf, "SELECT ");
2323         sep = "";
2324         for (i = 0; i < riinfo->nkeys; i++)
2325         {
2326                 quoteOneName(fkattname,
2327                                          RIAttName(fk_rel, riinfo->fk_attnums[i]));
2328                 appendStringInfo(&querybuf, "%sfk.%s", sep, fkattname);
2329                 sep = ", ";
2330         }
2331
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);
2337
2338         strcpy(pkattname, "pk.");
2339         strcpy(fkattname, "fk.");
2340         sep = "(";
2341         for (i = 0; i < riinfo->nkeys; i++)
2342         {
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]);
2347
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,
2353                                                 pkattname, pk_type,
2354                                                 riinfo->pf_eq_oprs[i],
2355                                                 fkattname, fk_type);
2356                 if (pk_coll != fk_coll)
2357                         ri_GenerateQualCollation(&querybuf, pk_coll);
2358                 sep = "AND";
2359         }
2360
2361         /*
2362          * It's sufficient to test any one pk attribute for null to detect a join
2363          * failure.
2364          */
2365         quoteOneName(pkattname, RIAttName(pk_rel, riinfo->pk_attnums[0]));
2366         appendStringInfo(&querybuf, ") WHERE pk.%s IS NULL AND (", pkattname);
2367
2368         sep = "";
2369         for (i = 0; i < riinfo->nkeys; i++)
2370         {
2371                 quoteOneName(fkattname, RIAttName(fk_rel, riinfo->fk_attnums[i]));
2372                 appendStringInfo(&querybuf,
2373                                                  "%sfk.%s IS NOT NULL",
2374                                                  sep, fkattname);
2375                 switch (riinfo->confmatchtype)
2376                 {
2377                         case FKCONSTR_MATCH_SIMPLE:
2378                                 sep = " AND ";
2379                                 break;
2380                         case FKCONSTR_MATCH_FULL:
2381                                 sep = " OR ";
2382                                 break;
2383                         case FKCONSTR_MATCH_PARTIAL:
2384                                 ereport(ERROR,
2385                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2386                                                  errmsg("MATCH PARTIAL not yet implemented")));
2387                                 break;
2388                         default:
2389                                 elog(ERROR, "unrecognized confmatchtype: %d",
2390                                          riinfo->confmatchtype);
2391                                 break;
2392                 }
2393         }
2394         appendStringInfoChar(&querybuf, ')');
2395
2396         /*
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.
2403          *
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.
2407          */
2408         save_nestlevel = NewGUCNestLevel();
2409
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);
2414
2415         if (SPI_connect() != SPI_OK_CONNECT)
2416                 elog(ERROR, "SPI_connect failed");
2417
2418         /*
2419          * Generate the plan.  We don't need to cache it, and there are no
2420          * arguments to the plan.
2421          */
2422         qplan = SPI_prepare(querybuf.data, 0, NULL);
2423
2424         if (qplan == NULL)
2425                 elog(ERROR, "SPI_prepare returned %d for %s",
2426                          SPI_result, querybuf.data);
2427
2428         /*
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.
2434          */
2435         spi_result = SPI_execute_snapshot(qplan,
2436                                                                           NULL, NULL,
2437                                                                           GetLatestSnapshot(),
2438                                                                           InvalidSnapshot,
2439                                                                           true, false, 1);
2440
2441         /* Check result */
2442         if (spi_result != SPI_OK_SELECT)
2443                 elog(ERROR, "SPI_execute_snapshot returned %d", spi_result);
2444
2445         /* Did we find a tuple violating the constraint? */
2446         if (SPI_processed > 0)
2447         {
2448                 HeapTuple       tuple = SPI_tuptable->vals[0];
2449                 TupleDesc       tupdesc = SPI_tuptable->tupdesc;
2450                 RI_ConstraintInfo fake_riinfo;
2451
2452                 /*
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.
2456                  *
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.
2460                  */
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;
2464
2465                 /*
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.
2469                  */
2470                 if (fake_riinfo.confmatchtype == FKCONSTR_MATCH_FULL &&
2471                         ri_NullCheck(tuple, &fake_riinfo, false) != RI_KEYS_NONE_NULL)
2472                         ereport(ERROR,
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))));
2480
2481                 /*
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.
2485                  */
2486                 ri_ReportViolation(&fake_riinfo,
2487                                                    pk_rel, fk_rel,
2488                                                    tuple, tupdesc,
2489                                                    RI_PLAN_CHECK_LOOKUPPK, false);
2490         }
2491
2492         if (SPI_finish() != SPI_OK_FINISH)
2493                 elog(ERROR, "SPI_finish failed");
2494
2495         /*
2496          * Restore work_mem.
2497          */
2498         AtEOXact_GUC(true, save_nestlevel);
2499
2500         return true;
2501 }
2502
2503
2504 /* ----------
2505  * Local functions below
2506  * ----------
2507  */
2508
2509
2510 /*
2511  * quoteOneName --- safely quote a single SQL name
2512  *
2513  * buffer must be MAX_QUOTED_NAME_LEN long (includes room for \0)
2514  */
2515 static void
2516 quoteOneName(char *buffer, const char *name)
2517 {
2518         /* Rather than trying to be smart, just always quote it. */
2519         *buffer++ = '"';
2520         while (*name)
2521         {
2522                 if (*name == '"')
2523                         *buffer++ = '"';
2524                 *buffer++ = *name++;
2525         }
2526         *buffer++ = '"';
2527         *buffer = '\0';
2528 }
2529
2530 /*
2531  * quoteRelationName --- safely quote a fully qualified relation name
2532  *
2533  * buffer must be MAX_QUOTED_REL_NAME_LEN long (includes room for \0)
2534  */
2535 static void
2536 quoteRelationName(char *buffer, Relation rel)
2537 {
2538         quoteOneName(buffer, get_namespace_name(RelationGetNamespace(rel)));
2539         buffer += strlen(buffer);
2540         *buffer++ = '.';
2541         quoteOneName(buffer, RelationGetRelationName(rel));
2542 }
2543
2544 /*
2545  * ri_GenerateQual --- generate a WHERE clause equating two variables
2546  *
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.
2554  */
2555 static void
2556 ri_GenerateQual(StringInfo buf,
2557                                 const char *sep,
2558                                 const char *leftop, Oid leftoptype,
2559                                 Oid opoid,
2560                                 const char *rightop, Oid rightoptype)
2561 {
2562         HeapTuple       opertup;
2563         Form_pg_operator operform;
2564         char       *oprname;
2565         char       *nspname;
2566
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);
2573
2574         nspname = get_namespace_name(operform->oprnamespace);
2575
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);
2584
2585         ReleaseSysCache(opertup);
2586 }
2587
2588 /*
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)
2594  * target typmod.
2595  */
2596 static void
2597 ri_add_cast_to(StringInfo buf, Oid typid)
2598 {
2599         HeapTuple       typetup;
2600         Form_pg_type typform;
2601         char       *typname;
2602         char       *nspname;
2603
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);
2608
2609         typname = NameStr(typform->typname);
2610         nspname = get_namespace_name(typform->typnamespace);
2611
2612         appendStringInfo(buf, "::%s.%s",
2613                                          quote_identifier(nspname), quote_identifier(typname));
2614
2615         ReleaseSysCache(typetup);
2616 }
2617
2618 /*
2619  * ri_GenerateQualCollation --- add a COLLATE spec to a WHERE clause
2620  *
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.
2634  */
2635 static void
2636 ri_GenerateQualCollation(StringInfo buf, Oid collation)
2637 {
2638         HeapTuple       tp;
2639         Form_pg_collation colltup;
2640         char       *collname;
2641         char            onename[MAX_QUOTED_NAME_LEN];
2642
2643         /* Nothing to do if it's a noncollatable data type */
2644         if (!OidIsValid(collation))
2645                 return;
2646
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);
2652
2653         /*
2654          * We qualify the name always, for simplicity and to ensure the query is
2655          * not search-path-dependent.
2656          */
2657         quoteOneName(onename, get_namespace_name(colltup->collnamespace));
2658         appendStringInfo(buf, " COLLATE %s", onename);
2659         quoteOneName(onename, collname);
2660         appendStringInfo(buf, ".%s", onename);
2661
2662         ReleaseSysCache(tp);
2663 }
2664
2665 /* ----------
2666  * ri_BuildQueryKey -
2667  *
2668  *      Construct a hashtable key for a prepared SPI plan of an FK constraint.
2669  *
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)
2674  * ----------
2675  */
2676 static void
2677 ri_BuildQueryKey(RI_QueryKey *key, const RI_ConstraintInfo *riinfo,
2678                                  int32 constr_queryno)
2679 {
2680         /*
2681          * We assume struct RI_QueryKey contains no padding bytes, else we'd need
2682          * to use memset to clear them.
2683          */
2684         key->constr_id = riinfo->constraint_id;
2685         key->constr_queryno = constr_queryno;
2686 }
2687
2688 /*
2689  * Check that RI trigger function was called in expected context
2690  */
2691 static void
2692 ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname, int tgkind)
2693 {
2694         TriggerData *trigdata = (TriggerData *) fcinfo->context;
2695
2696         if (!CALLED_AS_TRIGGER(fcinfo))
2697                 ereport(ERROR,
2698                                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2699                                  errmsg("function \"%s\" was not called by trigger manager", funcname)));
2700
2701         /*
2702          * Check proper event
2703          */
2704         if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
2705                 !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
2706                 ereport(ERROR,
2707                                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2708                            errmsg("function \"%s\" must be fired AFTER ROW", funcname)));
2709
2710         switch (tgkind)
2711         {
2712                 case RI_TRIGTYPE_INSERT:
2713                         if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
2714                                 ereport(ERROR,
2715                                                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2716                                                  errmsg("function \"%s\" must be fired for INSERT", funcname)));
2717                         break;
2718                 case RI_TRIGTYPE_UPDATE:
2719                         if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
2720                                 ereport(ERROR,
2721                                                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2722                                                  errmsg("function \"%s\" must be fired for UPDATE", funcname)));
2723                         break;
2724                 case RI_TRIGTYPE_DELETE:
2725                         if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
2726                                 ereport(ERROR,
2727                                                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2728                                                  errmsg("function \"%s\" must be fired for DELETE", funcname)));
2729                         break;
2730         }
2731 }
2732
2733
2734 /*
2735  * Fetch the RI_ConstraintInfo struct for the trigger's FK constraint.
2736  */
2737 static const RI_ConstraintInfo *
2738 ri_FetchConstraintInfo(Trigger *trigger, Relation trig_rel, bool rel_is_pk)
2739 {
2740         Oid                     constraintOid = trigger->tgconstraint;
2741         const RI_ConstraintInfo *riinfo;
2742
2743         /*
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
2746          * trigger".
2747          */
2748         if (!OidIsValid(constraintOid))
2749                 ereport(ERROR,
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.")));
2754
2755         /* Find or create a hashtable entry for the constraint */
2756         riinfo = ri_LoadConstraintInfo(constraintOid);
2757
2758         /* Do some easy cross-checks against the trigger call data */
2759         if (rel_is_pk)
2760         {
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));
2765         }
2766         else
2767         {
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));
2772         }
2773
2774         return riinfo;
2775 }
2776
2777 /*
2778  * Fetch or create the RI_ConstraintInfo struct for an FK constraint.
2779  */
2780 static const RI_ConstraintInfo *
2781 ri_LoadConstraintInfo(Oid constraintOid)
2782 {
2783         RI_ConstraintInfo *riinfo;
2784         bool            found;
2785         HeapTuple       tup;
2786         Form_pg_constraint conForm;
2787         Datum           adatum;
2788         bool            isNull;
2789         ArrayType  *arr;
2790         int                     numkeys;
2791
2792         /*
2793          * On the first call initialize the hashtable
2794          */
2795         if (!ri_constraint_cache)
2796                 ri_InitHashTables();
2797
2798         /*
2799          * Find or create a hash entry.  If we find a valid one, just return it.
2800          */
2801         riinfo = (RI_ConstraintInfo *) hash_search(ri_constraint_cache,
2802                                                                                            (void *) &constraintOid,
2803                                                                                            HASH_ENTER, &found);
2804         if (!found)
2805                 riinfo->valid = false;
2806         else if (riinfo->valid)
2807                 return riinfo;
2808
2809         /*
2810          * Fetch the pg_constraint row so we can fill in the entry.
2811          */
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);
2816
2817         if (conForm->contype != CONSTRAINT_FOREIGN) /* should not happen */
2818                 elog(ERROR, "constraint %u is not a foreign key constraint",
2819                          constraintOid);
2820
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;
2831
2832         /*
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.
2836          */
2837         adatum = SysCacheGetAttr(CONSTROID, tup,
2838                                                          Anum_pg_constraint_conkey, &isNull);
2839         if (isNull)
2840                 elog(ERROR, "null conkey for constraint %u", constraintOid);
2841         arr = DatumGetArrayTypeP(adatum);       /* ensure not toasted */
2842         if (ARR_NDIM(arr) != 1 ||
2843                 ARR_HASNULL(arr) ||
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 */
2853
2854         adatum = SysCacheGetAttr(CONSTROID, tup,
2855                                                          Anum_pg_constraint_confkey, &isNull);
2856         if (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 ||
2861                 ARR_HASNULL(arr) ||
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 */
2867
2868         adatum = SysCacheGetAttr(CONSTROID, tup,
2869                                                          Anum_pg_constraint_conpfeqop, &isNull);
2870         if (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 ||
2876                 ARR_HASNULL(arr) ||
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 */
2882
2883         adatum = SysCacheGetAttr(CONSTROID, tup,
2884                                                          Anum_pg_constraint_conppeqop, &isNull);
2885         if (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 ||
2890                 ARR_HASNULL(arr) ||
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 */
2896
2897         adatum = SysCacheGetAttr(CONSTROID, tup,
2898                                                          Anum_pg_constraint_conffeqop, &isNull);
2899         if (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 ||
2904                 ARR_HASNULL(arr) ||
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 */
2910
2911         ReleaseSysCache(tup);
2912
2913         riinfo->valid = true;
2914
2915         return riinfo;
2916 }
2917
2918 /*
2919  * Callback for pg_constraint inval events
2920  *
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.
2925  */
2926 static void
2927 InvalidateConstraintCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
2928 {
2929         HASH_SEQ_STATUS status;
2930         RI_ConstraintInfo *hentry;
2931
2932         Assert(ri_constraint_cache != NULL);
2933
2934         hash_seq_init(&status, ri_constraint_cache);
2935         while ((hentry = (RI_ConstraintInfo *) hash_seq_search(&status)) != NULL)
2936         {
2937                 if (hashvalue == 0 || hentry->oidHashValue == hashvalue)
2938                         hentry->valid = false;
2939         }
2940 }
2941
2942
2943 /*
2944  * Prepare execution plan for a query to enforce an RI restriction
2945  *
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.
2948  */
2949 static SPIPlanPtr
2950 ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
2951                          RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel,
2952                          bool cache_plan)
2953 {
2954         SPIPlanPtr      qplan;
2955         Relation        query_rel;
2956         Oid                     save_userid;
2957         int                     save_sec_context;
2958
2959         /*
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
2962          */
2963         if (qkey->constr_queryno <= RI_PLAN_LAST_ON_PK)
2964                 query_rel = pk_rel;
2965         else
2966                 query_rel = fk_rel;
2967
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);
2972
2973         /* Create the plan */
2974         qplan = SPI_prepare(querystr, nargs, argtypes);
2975
2976         if (qplan == NULL)
2977                 elog(ERROR, "SPI_prepare returned %d for %s", SPI_result, querystr);
2978
2979         /* Restore UID and security context */
2980         SetUserIdAndSecContext(save_userid, save_sec_context);
2981
2982         /* Save the plan if requested */
2983         if (cache_plan)
2984         {
2985                 SPI_keepplan(qplan);
2986                 ri_HashPreparedPlan(qkey, qplan);
2987         }
2988
2989         return qplan;
2990 }
2991
2992 /*
2993  * Perform a query to enforce an RI restriction
2994  */
2995 static bool
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)
3001 {
3002         Relation        query_rel,
3003                                 source_rel;
3004         bool            source_is_pk;
3005         Snapshot        test_snapshot;
3006         Snapshot        crosscheck_snapshot;
3007         int                     limit;
3008         int                     spi_result;
3009         Oid                     save_userid;
3010         int                     save_sec_context;
3011         Datum           vals[RI_MAX_NUMKEYS * 2];
3012         char            nulls[RI_MAX_NUMKEYS * 2];
3013
3014         /*
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
3017          */
3018         if (qkey->constr_queryno <= RI_PLAN_LAST_ON_PK)
3019                 query_rel = pk_rel;
3020         else
3021                 query_rel = fk_rel;
3022
3023         /*
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.
3029          */
3030         if (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK)
3031         {
3032                 source_rel = fk_rel;
3033                 source_is_pk = false;
3034         }
3035         else
3036         {
3037                 source_rel = pk_rel;
3038                 source_is_pk = true;
3039         }
3040
3041         /* Extract the parameters to be passed into the query */
3042         if (new_tuple)
3043         {
3044                 ri_ExtractValues(source_rel, new_tuple, riinfo, source_is_pk,
3045                                                  vals, nulls);
3046                 if (old_tuple)
3047                         ri_ExtractValues(source_rel, old_tuple, riinfo, source_is_pk,
3048                                                          vals + riinfo->nkeys, nulls + riinfo->nkeys);
3049         }
3050         else
3051         {
3052                 ri_ExtractValues(source_rel, old_tuple, riinfo, source_is_pk,
3053                                                  vals, nulls);
3054         }
3055
3056         /*
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
3065          * to bother here.
3066          */
3067         if (IsolationUsesXactSnapshot() && detectNewRows)
3068         {
3069                 CommandCounterIncrement();              /* be sure all my own work is visible */
3070                 test_snapshot = GetLatestSnapshot();
3071                 crosscheck_snapshot = GetTransactionSnapshot();
3072         }
3073         else
3074         {
3075                 /* the default SPI behavior is okay */
3076                 test_snapshot = InvalidSnapshot;
3077                 crosscheck_snapshot = InvalidSnapshot;
3078         }
3079
3080         /*
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.
3085          */
3086         limit = (expect_OK == SPI_OK_SELECT) ? 1 : 0;
3087
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);
3092
3093         /* Finally we can run the query. */
3094         spi_result = SPI_execute_snapshot(qplan,
3095                                                                           vals, nulls,
3096                                                                           test_snapshot, crosscheck_snapshot,
3097                                                                           false, false, limit);
3098
3099         /* Restore UID and security context */
3100         SetUserIdAndSecContext(save_userid, save_sec_context);
3101
3102         /* Check result */
3103         if (spi_result < 0)
3104                 elog(ERROR, "SPI_execute_snapshot returned %d", spi_result);
3105
3106         if (expect_OK >= 0 && spi_result != expect_OK)
3107                 ri_ReportViolation(riinfo,
3108                                                    pk_rel, fk_rel,
3109                                                    new_tuple ? new_tuple : old_tuple,
3110                                                    NULL,
3111                                                    qkey->constr_queryno, true);
3112
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,
3118                                                    pk_rel, fk_rel,
3119                                                    new_tuple ? new_tuple : old_tuple,
3120                                                    NULL,
3121                                                    qkey->constr_queryno, false);
3122
3123         return SPI_processed != 0;
3124 }
3125
3126 /*
3127  * Extract fields from a tuple into Datum/nulls arrays
3128  */
3129 static void
3130 ri_ExtractValues(Relation rel, HeapTuple tup,
3131                                  const RI_ConstraintInfo *riinfo, bool rel_is_pk,
3132                                  Datum *vals, char *nulls)
3133 {
3134         TupleDesc       tupdesc = rel->rd_att;
3135         const int16 *attnums;
3136         int                     i;
3137         bool            isnull;
3138
3139         if (rel_is_pk)
3140                 attnums = riinfo->pk_attnums;
3141         else
3142                 attnums = riinfo->fk_attnums;
3143
3144         for (i = 0; i < riinfo->nkeys; i++)
3145         {
3146                 vals[i] = heap_getattr(tup, attnums[i], tupdesc,
3147                                                            &isnull);
3148                 nulls[i] = isnull ? 'n' : ' ';
3149         }
3150 }
3151
3152 /*
3153  * Produce an error report
3154  *
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'.
3160  */
3161 static void
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)
3166 {
3167         StringInfoData key_names;
3168         StringInfoData key_values;
3169         bool            onfk;
3170         const int16 *attnums;
3171         int                     idx;
3172
3173         if (spi_err)
3174                 ereport(ERROR,
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.")));
3181
3182         /*
3183          * Determine which relation to complain about.  If tupdesc wasn't passed
3184          * by caller, assume the violator tuple came from there.
3185          */
3186         onfk = (queryno == RI_PLAN_CHECK_LOOKUPPK);
3187         if (onfk)
3188         {
3189                 attnums = riinfo->fk_attnums;
3190                 if (tupdesc == NULL)
3191                         tupdesc = fk_rel->rd_att;
3192         }
3193         else
3194         {
3195                 attnums = riinfo->pk_attnums;
3196                 if (tupdesc == NULL)
3197                         tupdesc = pk_rel->rd_att;
3198         }
3199
3200         /* Get printable versions of the keys involved */
3201         initStringInfo(&key_names);
3202         initStringInfo(&key_values);
3203         for (idx = 0; idx < riinfo->nkeys; idx++)
3204         {
3205                 int                     fnum = attnums[idx];
3206                 char       *name,
3207                                    *val;
3208
3209                 name = SPI_fname(tupdesc, fnum);
3210                 val = SPI_getvalue(violator, tupdesc, fnum);
3211                 if (!val)
3212                         val = "null";
3213
3214                 if (idx > 0)
3215                 {
3216                         appendStringInfoString(&key_names, ", ");
3217                         appendStringInfoString(&key_values, ", ");
3218                 }
3219                 appendStringInfoString(&key_names, name);
3220                 appendStringInfoString(&key_values, val);
3221         }
3222
3223         if (onfk)
3224                 ereport(ERROR,
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))));
3233         else
3234                 ereport(ERROR,
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))));
3244 }
3245
3246
3247 /* ----------
3248  * ri_NullCheck -
3249  *
3250  *      Determine the NULL state of all key values in a tuple
3251  *
3252  *      Returns one of RI_KEYS_ALL_NULL, RI_KEYS_NONE_NULL or RI_KEYS_SOME_NULL.
3253  * ----------
3254  */
3255 static int
3256 ri_NullCheck(HeapTuple tup,
3257                          const RI_ConstraintInfo *riinfo, bool rel_is_pk)
3258 {
3259         const int16 *attnums;
3260         int                     i;
3261         bool            allnull = true;
3262         bool            nonenull = true;
3263
3264         if (rel_is_pk)
3265                 attnums = riinfo->pk_attnums;
3266         else
3267                 attnums = riinfo->fk_attnums;
3268
3269         for (i = 0; i < riinfo->nkeys; i++)
3270         {
3271                 if (heap_attisnull(tup, attnums[i]))
3272                         nonenull = false;
3273                 else
3274                         allnull = false;
3275         }
3276
3277         if (allnull)
3278                 return RI_KEYS_ALL_NULL;
3279
3280         if (nonenull)
3281                 return RI_KEYS_NONE_NULL;
3282
3283         return RI_KEYS_SOME_NULL;
3284 }
3285
3286
3287 /* ----------
3288  * ri_InitHashTables -
3289  *
3290  *      Initialize our internal hash tables.
3291  * ----------
3292  */
3293 static void
3294 ri_InitHashTables(void)
3295 {
3296         HASHCTL         ctl;
3297
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);
3305
3306         /* Arrange to flush cache on pg_constraint changes */
3307         CacheRegisterSyscacheCallback(CONSTROID,
3308                                                                   InvalidateConstraintCacheCallBack,
3309                                                                   (Datum) 0);
3310
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);
3318
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);
3326 }
3327
3328
3329 /* ----------
3330  * ri_FetchPreparedPlan -
3331  *
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.
3334  * ----------
3335  */
3336 static SPIPlanPtr
3337 ri_FetchPreparedPlan(RI_QueryKey *key)
3338 {
3339         RI_QueryHashEntry *entry;
3340         SPIPlanPtr      plan;
3341
3342         /*
3343          * On the first call initialize the hashtable
3344          */
3345         if (!ri_query_cache)
3346                 ri_InitHashTables();
3347
3348         /*
3349          * Lookup for the key
3350          */
3351         entry = (RI_QueryHashEntry *) hash_search(ri_query_cache,
3352                                                                                           (void *) key,
3353                                                                                           HASH_FIND, NULL);
3354         if (entry == NULL)
3355                 return NULL;
3356
3357         /*
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.
3363          *
3364          * CAUTION: this check is only trustworthy if the caller has already
3365          * locked both FK and PK rels.
3366          */
3367         plan = entry->plan;
3368         if (plan && SPI_plan_is_valid(plan))
3369                 return plan;
3370
3371         /*
3372          * Otherwise we might as well flush the cached plan now, to free a little
3373          * memory space before we make a new one.
3374          */
3375         entry->plan = NULL;
3376         if (plan)
3377                 SPI_freeplan(plan);
3378
3379         return NULL;
3380 }
3381
3382
3383 /* ----------
3384  * ri_HashPreparedPlan -
3385  *
3386  *      Add another plan to our private SPI query plan hashtable.
3387  * ----------
3388  */
3389 static void
3390 ri_HashPreparedPlan(RI_QueryKey *key, SPIPlanPtr plan)
3391 {
3392         RI_QueryHashEntry *entry;
3393         bool            found;
3394
3395         /*
3396          * On the first call initialize the hashtable
3397          */
3398         if (!ri_query_cache)
3399                 ri_InitHashTables();
3400
3401         /*
3402          * Add the new plan.  We might be overwriting an entry previously found
3403          * invalid by ri_FetchPreparedPlan.
3404          */
3405         entry = (RI_QueryHashEntry *) hash_search(ri_query_cache,
3406                                                                                           (void *) key,
3407                                                                                           HASH_ENTER, &found);
3408         Assert(!found || entry->plan == NULL);
3409         entry->plan = plan;
3410 }
3411
3412
3413 /* ----------
3414  * ri_KeysEqual -
3415  *
3416  *      Check if all key values in OLD and NEW are equal.
3417  *
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.
3422  * ----------
3423  */
3424 static bool
3425 ri_KeysEqual(Relation rel, HeapTuple oldtup, HeapTuple newtup,
3426                          const RI_ConstraintInfo *riinfo, bool rel_is_pk)
3427 {
3428         TupleDesc       tupdesc = RelationGetDescr(rel);
3429         const int16 *attnums;
3430         const Oid  *eq_oprs;
3431         int                     i;
3432
3433         if (rel_is_pk)
3434         {
3435                 attnums = riinfo->pk_attnums;
3436                 eq_oprs = riinfo->pp_eq_oprs;
3437         }
3438         else
3439         {
3440                 attnums = riinfo->fk_attnums;
3441                 eq_oprs = riinfo->ff_eq_oprs;
3442         }
3443
3444         for (i = 0; i < riinfo->nkeys; i++)
3445         {
3446                 Datum           oldvalue;
3447                 Datum           newvalue;
3448                 bool            isnull;
3449
3450                 /*
3451                  * Get one attribute's oldvalue. If it is NULL - they're not equal.
3452                  */
3453                 oldvalue = heap_getattr(oldtup, attnums[i], tupdesc, &isnull);
3454                 if (isnull)
3455                         return false;
3456
3457                 /*
3458                  * Get one attribute's newvalue. If it is NULL - they're not equal.
3459                  */
3460                 newvalue = heap_getattr(newtup, attnums[i], tupdesc, &isnull);
3461                 if (isnull)
3462                         return false;
3463
3464                 /*
3465                  * Compare them with the appropriate equality operator.
3466                  */
3467                 if (!ri_AttributesEqual(eq_oprs[i], RIAttType(rel, attnums[i]),
3468                                                                 oldvalue, newvalue))
3469                         return false;
3470         }
3471
3472         return true;
3473 }
3474
3475
3476 /* ----------
3477  * ri_AttributesEqual -
3478  *
3479  *      Call the appropriate equality comparison operator for two values.
3480  *
3481  *      NB: we have already checked that neither value is null.
3482  * ----------
3483  */
3484 static bool
3485 ri_AttributesEqual(Oid eq_opr, Oid typeid,
3486                                    Datum oldvalue, Datum newvalue)
3487 {
3488         RI_CompareHashEntry *entry = ri_HashCompareOp(eq_opr, typeid);
3489
3490         /* Do we need to cast the values? */
3491         if (OidIsValid(entry->cast_func_finfo.fn_oid))
3492         {
3493                 oldvalue = FunctionCall3(&entry->cast_func_finfo,
3494                                                                  oldvalue,
3495                                                                  Int32GetDatum(-1),             /* typmod */
3496                                                                  BoolGetDatum(false));  /* implicit coercion */
3497                 newvalue = FunctionCall3(&entry->cast_func_finfo,
3498                                                                  newvalue,
3499                                                                  Int32GetDatum(-1),             /* typmod */
3500                                                                  BoolGetDatum(false));  /* implicit coercion */
3501         }
3502
3503         /*
3504          * Apply the comparison operator.  We assume it doesn't care about
3505          * collations.
3506          */
3507         return DatumGetBool(FunctionCall2(&entry->eq_opr_finfo,
3508                                                                           oldvalue, newvalue));
3509 }
3510
3511 /* ----------
3512  * ri_HashCompareOp -
3513  *
3514  *      See if we know how to compare two values, and create a new hash entry
3515  *      if not.
3516  * ----------
3517  */
3518 static RI_CompareHashEntry *
3519 ri_HashCompareOp(Oid eq_opr, Oid typeid)
3520 {
3521         RI_CompareKey key;
3522         RI_CompareHashEntry *entry;
3523         bool            found;
3524
3525         /*
3526          * On the first call initialize the hashtable
3527          */
3528         if (!ri_compare_cache)
3529                 ri_InitHashTables();
3530
3531         /*
3532          * Find or create a hash entry.  Note we're assuming RI_CompareKey
3533          * contains no struct padding.
3534          */
3535         key.eq_opr = eq_opr;
3536         key.typeid = typeid;
3537         entry = (RI_CompareHashEntry *) hash_search(ri_compare_cache,
3538                                                                                                 (void *) &key,
3539                                                                                                 HASH_ENTER, &found);
3540         if (!found)
3541                 entry->valid = false;
3542
3543         /*
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.
3547          */
3548         if (!entry->valid)
3549         {
3550                 Oid                     lefttype,
3551                                         righttype,
3552                                         castfunc;
3553                 CoercionPathType pathtype;
3554
3555                 /* We always need to know how to call the equality operator */
3556                 fmgr_info_cxt(get_opcode(eq_opr), &entry->eq_opr_finfo,
3557                                           TopMemoryContext);
3558
3559                 /*
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.
3562                  *
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.
3567                  *
3568                  * XXX perhaps also consider supporting CoerceViaIO?  No need at the
3569                  * moment since that will never be generated for implicit coercions.
3570                  */
3571                 op_input_types(eq_opr, &lefttype, &righttype);
3572                 Assert(lefttype == righttype);
3573                 if (typeid == lefttype)
3574                         castfunc = InvalidOid;          /* simplest case */
3575                 else
3576                 {
3577                         pathtype = find_coercion_pathway(lefttype, typeid,
3578                                                                                          COERCION_IMPLICIT,
3579                                                                                          &castfunc);
3580                         if (pathtype != COERCION_PATH_FUNC &&
3581                                 pathtype != COERCION_PATH_RELABELTYPE)
3582                         {
3583                                 /*
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.
3588                                  */
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));
3593                         }
3594                 }
3595                 if (OidIsValid(castfunc))
3596                         fmgr_info_cxt(castfunc, &entry->cast_func_finfo,
3597                                                   TopMemoryContext);
3598                 else
3599                         entry->cast_func_finfo.fn_oid = InvalidOid;
3600                 entry->valid = true;
3601         }
3602
3603         return entry;
3604 }
3605
3606
3607 /*
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.
3610  */
3611 int
3612 RI_FKey_trigger_type(Oid tgfoid)
3613 {
3614         switch (tgfoid)
3615         {
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;
3627
3628                 case F_RI_FKEY_CHECK_INS:
3629                 case F_RI_FKEY_CHECK_UPD:
3630                         return RI_TRIGGER_FK;
3631         }
3632
3633         return RI_TRIGGER_NONE;
3634 }