PostgreSQL Source Code  git master
ri_triggers.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * ri_triggers.c
4  *
5  * Generic trigger procedures for referential integrity constraint
6  * checks.
7  *
8  * Note about memory management: the private hashtables kept here live
9  * across query and transaction boundaries, in fact they live as long as
10  * the backend does. This works because the hashtable structures
11  * themselves are allocated by dynahash.c in its permanent DynaHashCxt,
12  * and the SPI plans they point to are saved using SPI_keepplan().
13  * There is not currently any provision for throwing away a no-longer-needed
14  * plan --- consider improving this someday.
15  *
16  *
17  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
18  *
19  * src/backend/utils/adt/ri_triggers.c
20  *
21  *-------------------------------------------------------------------------
22  */
23 
24 #include "postgres.h"
25 
26 #include "access/htup_details.h"
27 #include "access/sysattr.h"
28 #include "access/table.h"
29 #include "access/tableam.h"
30 #include "access/xact.h"
31 #include "catalog/pg_collation.h"
32 #include "catalog/pg_constraint.h"
33 #include "catalog/pg_proc.h"
34 #include "commands/trigger.h"
35 #include "executor/executor.h"
36 #include "executor/spi.h"
37 #include "lib/ilist.h"
38 #include "miscadmin.h"
39 #include "parser/parse_coerce.h"
40 #include "parser/parse_relation.h"
41 #include "utils/acl.h"
42 #include "utils/builtins.h"
43 #include "utils/datum.h"
44 #include "utils/fmgroids.h"
45 #include "utils/guc.h"
46 #include "utils/inval.h"
47 #include "utils/lsyscache.h"
48 #include "utils/memutils.h"
49 #include "utils/rangetypes.h"
50 #include "utils/rel.h"
51 #include "utils/rls.h"
52 #include "utils/ruleutils.h"
53 #include "utils/snapmgr.h"
54 #include "utils/syscache.h"
55 
56 /*
57  * Local definitions
58  */
59 
60 #define RI_MAX_NUMKEYS INDEX_MAX_KEYS
61 
62 #define RI_INIT_CONSTRAINTHASHSIZE 64
63 #define RI_INIT_QUERYHASHSIZE (RI_INIT_CONSTRAINTHASHSIZE * 4)
64 
65 #define RI_KEYS_ALL_NULL 0
66 #define RI_KEYS_SOME_NULL 1
67 #define RI_KEYS_NONE_NULL 2
68 
69 /* RI query type codes */
70 /* these queries are executed against the PK (referenced) table: */
71 #define RI_PLAN_CHECK_LOOKUPPK 1
72 #define RI_PLAN_CHECK_LOOKUPPK_FROM_PK 2
73 #define RI_PLAN_LAST_ON_PK RI_PLAN_CHECK_LOOKUPPK_FROM_PK
74 /* these queries are executed against the FK (referencing) table: */
75 #define RI_PLAN_CASCADE_ONDELETE 3
76 #define RI_PLAN_CASCADE_ONUPDATE 4
77 /* For RESTRICT, the same plan can be used for both ON DELETE and ON UPDATE triggers. */
78 #define RI_PLAN_RESTRICT 5
79 #define RI_PLAN_SETNULL_ONDELETE 6
80 #define RI_PLAN_SETNULL_ONUPDATE 7
81 #define RI_PLAN_SETDEFAULT_ONDELETE 8
82 #define RI_PLAN_SETDEFAULT_ONUPDATE 9
83 
84 #define MAX_QUOTED_NAME_LEN (NAMEDATALEN*2+3)
85 #define MAX_QUOTED_REL_NAME_LEN (MAX_QUOTED_NAME_LEN*2)
86 
87 #define RIAttName(rel, attnum) NameStr(*attnumAttName(rel, attnum))
88 #define RIAttType(rel, attnum) attnumTypeId(rel, attnum)
89 #define RIAttCollation(rel, attnum) attnumCollationId(rel, attnum)
90 
91 #define RI_TRIGTYPE_INSERT 1
92 #define RI_TRIGTYPE_UPDATE 2
93 #define RI_TRIGTYPE_DELETE 3
94 
95 
96 /*
97  * RI_ConstraintInfo
98  *
99  * Information extracted from an FK pg_constraint entry. This is cached in
100  * ri_constraint_cache.
101  *
102  * Note that pf/pp/ff_eq_oprs may hold the overlaps operator instead of equals
103  * for the PERIOD part of a temporal foreign key.
104  */
105 typedef struct RI_ConstraintInfo
106 {
107  Oid constraint_id; /* OID of pg_constraint entry (hash key) */
108  bool valid; /* successfully initialized? */
109  Oid constraint_root_id; /* OID of topmost ancestor constraint;
110  * same as constraint_id if not inherited */
111  uint32 oidHashValue; /* hash value of constraint_id */
112  uint32 rootHashValue; /* hash value of constraint_root_id */
113  NameData conname; /* name of the FK constraint */
114  Oid pk_relid; /* referenced relation */
115  Oid fk_relid; /* referencing relation */
116  char confupdtype; /* foreign key's ON UPDATE action */
117  char confdeltype; /* foreign key's ON DELETE action */
118  int ndelsetcols; /* number of columns referenced in ON DELETE
119  * SET clause */
120  int16 confdelsetcols[RI_MAX_NUMKEYS]; /* attnums of cols to set on
121  * delete */
122  char confmatchtype; /* foreign key's match type */
123  bool hasperiod; /* if the foreign key uses PERIOD */
124  int nkeys; /* number of key columns */
125  int16 pk_attnums[RI_MAX_NUMKEYS]; /* attnums of referenced cols */
126  int16 fk_attnums[RI_MAX_NUMKEYS]; /* attnums of referencing cols */
127  Oid pf_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (PK = FK) */
128  Oid pp_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (PK = PK) */
129  Oid ff_eq_oprs[RI_MAX_NUMKEYS]; /* equality operators (FK = FK) */
130  Oid period_contained_by_oper; /* anyrange <@ anyrange */
131  Oid agged_period_contained_by_oper; /* fkattr <@ range_agg(pkattr) */
132  dlist_node valid_link; /* Link in list of valid entries */
134 
135 /*
136  * RI_QueryKey
137  *
138  * The key identifying a prepared SPI plan in our query hashtable
139  */
140 typedef struct RI_QueryKey
141 {
142  Oid constr_id; /* OID of pg_constraint entry */
143  int32 constr_queryno; /* query type ID, see RI_PLAN_XXX above */
145 
146 /*
147  * RI_QueryHashEntry
148  */
149 typedef struct RI_QueryHashEntry
150 {
154 
155 /*
156  * RI_CompareKey
157  *
158  * The key identifying an entry showing how to compare two values
159  */
160 typedef struct RI_CompareKey
161 {
162  Oid eq_opr; /* the equality operator to apply */
163  Oid typeid; /* the data type to apply it to */
165 
166 /*
167  * RI_CompareHashEntry
168  */
169 typedef struct RI_CompareHashEntry
170 {
172  bool valid; /* successfully initialized? */
173  FmgrInfo eq_opr_finfo; /* call info for equality fn */
174  FmgrInfo cast_func_finfo; /* in case we must coerce input */
176 
177 
178 /*
179  * Local data
180  */
181 static HTAB *ri_constraint_cache = NULL;
182 static HTAB *ri_query_cache = NULL;
183 static HTAB *ri_compare_cache = NULL;
185 
186 
187 /*
188  * Local function prototypes
189  */
190 static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel,
191  TupleTableSlot *oldslot,
192  const RI_ConstraintInfo *riinfo);
193 static Datum ri_restrict(TriggerData *trigdata, bool is_no_action);
194 static Datum ri_set(TriggerData *trigdata, bool is_set_null, int tgkind);
195 static void quoteOneName(char *buffer, const char *name);
196 static void quoteRelationName(char *buffer, Relation rel);
197 static void ri_GenerateQual(StringInfo buf,
198  const char *sep,
199  const char *leftop, Oid leftoptype,
200  Oid opoid,
201  const char *rightop, Oid rightoptype);
202 static void ri_GenerateQualCollation(StringInfo buf, Oid collation);
203 static int ri_NullCheck(TupleDesc tupDesc, TupleTableSlot *slot,
204  const RI_ConstraintInfo *riinfo, bool rel_is_pk);
205 static void ri_BuildQueryKey(RI_QueryKey *key,
206  const RI_ConstraintInfo *riinfo,
207  int32 constr_queryno);
208 static bool ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot,
209  const RI_ConstraintInfo *riinfo, bool rel_is_pk);
210 static bool ri_CompareWithCast(Oid eq_opr, Oid typeid,
211  Datum lhs, Datum rhs);
212 
213 static void ri_InitHashTables(void);
214 static void InvalidateConstraintCacheCallBack(Datum arg, int cacheid, uint32 hashvalue);
217 static RI_CompareHashEntry *ri_HashCompareOp(Oid eq_opr, Oid typeid);
218 
219 static void ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname,
220  int tgkind);
221 static const RI_ConstraintInfo *ri_FetchConstraintInfo(Trigger *trigger,
222  Relation trig_rel, bool rel_is_pk);
223 static const RI_ConstraintInfo *ri_LoadConstraintInfo(Oid constraintOid);
224 static Oid get_ri_constraint_root(Oid constrOid);
225 static SPIPlanPtr ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
226  RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel);
227 static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo,
228  RI_QueryKey *qkey, SPIPlanPtr qplan,
229  Relation fk_rel, Relation pk_rel,
230  TupleTableSlot *oldslot, TupleTableSlot *newslot,
231  bool detectNewRows, int expect_OK);
232 static void ri_ExtractValues(Relation rel, TupleTableSlot *slot,
233  const RI_ConstraintInfo *riinfo, bool rel_is_pk,
234  Datum *vals, char *nulls);
235 static void ri_ReportViolation(const RI_ConstraintInfo *riinfo,
236  Relation pk_rel, Relation fk_rel,
237  TupleTableSlot *violatorslot, TupleDesc tupdesc,
238  int queryno, bool partgone) pg_attribute_noreturn();
239 
240 
241 /*
242  * RI_FKey_check -
243  *
244  * Check foreign key existence (combined for INSERT and UPDATE).
245  */
246 static Datum
248 {
249  const RI_ConstraintInfo *riinfo;
250  Relation fk_rel;
251  Relation pk_rel;
252  TupleTableSlot *newslot;
253  RI_QueryKey qkey;
254  SPIPlanPtr qplan;
255 
256  riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
257  trigdata->tg_relation, false);
258 
259  if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
260  newslot = trigdata->tg_newslot;
261  else
262  newslot = trigdata->tg_trigslot;
263 
264  /*
265  * We should not even consider checking the row if it is no longer valid,
266  * since it was either deleted (so the deferred check should be skipped)
267  * or updated (in which case only the latest version of the row should be
268  * checked). Test its liveness according to SnapshotSelf. We need pin
269  * and lock on the buffer to call HeapTupleSatisfiesVisibility. Caller
270  * should be holding pin, but not lock.
271  */
272  if (!table_tuple_satisfies_snapshot(trigdata->tg_relation, newslot, SnapshotSelf))
273  return PointerGetDatum(NULL);
274 
275  /*
276  * Get the relation descriptors of the FK and PK tables.
277  *
278  * pk_rel is opened in RowShareLock mode since that's what our eventual
279  * SELECT FOR KEY SHARE will get on it.
280  */
281  fk_rel = trigdata->tg_relation;
282  pk_rel = table_open(riinfo->pk_relid, RowShareLock);
283 
284  switch (ri_NullCheck(RelationGetDescr(fk_rel), newslot, riinfo, false))
285  {
286  case RI_KEYS_ALL_NULL:
287 
288  /*
289  * No further check needed - an all-NULL key passes every type of
290  * foreign key constraint.
291  */
292  table_close(pk_rel, RowShareLock);
293  return PointerGetDatum(NULL);
294 
295  case RI_KEYS_SOME_NULL:
296 
297  /*
298  * This is the only case that differs between the three kinds of
299  * MATCH.
300  */
301  switch (riinfo->confmatchtype)
302  {
303  case FKCONSTR_MATCH_FULL:
304 
305  /*
306  * Not allowed - MATCH FULL says either all or none of the
307  * attributes can be NULLs
308  */
309  ereport(ERROR,
310  (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
311  errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
312  RelationGetRelationName(fk_rel),
313  NameStr(riinfo->conname)),
314  errdetail("MATCH FULL does not allow mixing of null and nonnull key values."),
315  errtableconstraint(fk_rel,
316  NameStr(riinfo->conname))));
317  table_close(pk_rel, RowShareLock);
318  return PointerGetDatum(NULL);
319 
321 
322  /*
323  * MATCH SIMPLE - if ANY column is null, the key passes
324  * the constraint.
325  */
326  table_close(pk_rel, RowShareLock);
327  return PointerGetDatum(NULL);
328 
329 #ifdef NOT_USED
331 
332  /*
333  * MATCH PARTIAL - all non-null columns must match. (not
334  * implemented, can be done by modifying the query below
335  * to only include non-null columns, or by writing a
336  * special version here)
337  */
338  break;
339 #endif
340  }
341 
342  case RI_KEYS_NONE_NULL:
343 
344  /*
345  * Have a full qualified key - continue below for all three kinds
346  * of MATCH.
347  */
348  break;
349  }
350 
351  if (SPI_connect() != SPI_OK_CONNECT)
352  elog(ERROR, "SPI_connect failed");
353 
354  /* Fetch or prepare a saved plan for the real check */
356 
357  if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
358  {
359  StringInfoData querybuf;
360  char pkrelname[MAX_QUOTED_REL_NAME_LEN];
362  char paramname[16];
363  const char *querysep;
364  Oid queryoids[RI_MAX_NUMKEYS];
365  const char *pk_only;
366 
367  /* ----------
368  * The query string built is
369  * SELECT 1 FROM [ONLY] <pktable> x WHERE pkatt1 = $1 [AND ...]
370  * FOR KEY SHARE OF x
371  * The type id's for the $ parameters are those of the
372  * corresponding FK attributes.
373  *
374  * But for temporal FKs we need to make sure
375  * the FK's range is completely covered.
376  * So we use this query instead:
377  * SELECT 1
378  * FROM (
379  * SELECT pkperiodatt AS r
380  * FROM [ONLY] pktable x
381  * WHERE pkatt1 = $1 [AND ...]
382  * AND pkperiodatt && $n
383  * FOR KEY SHARE OF x
384  * ) x1
385  * HAVING $n <@ range_agg(x1.r)
386  * Note if FOR KEY SHARE ever allows GROUP BY and HAVING
387  * we can make this a bit simpler.
388  * ----------
389  */
390  initStringInfo(&querybuf);
391  pk_only = pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
392  "" : "ONLY ";
393  quoteRelationName(pkrelname, pk_rel);
394  if (riinfo->hasperiod)
395  {
397  RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]));
398 
399  appendStringInfo(&querybuf,
400  "SELECT 1 FROM (SELECT %s AS r FROM %s%s x",
401  attname, pk_only, pkrelname);
402  }
403  else
404  {
405  appendStringInfo(&querybuf, "SELECT 1 FROM %s%s x",
406  pk_only, pkrelname);
407  }
408  querysep = "WHERE";
409  for (int i = 0; i < riinfo->nkeys; i++)
410  {
411  Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
412  Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
413 
415  RIAttName(pk_rel, riinfo->pk_attnums[i]));
416  sprintf(paramname, "$%d", i + 1);
417  ri_GenerateQual(&querybuf, querysep,
418  attname, pk_type,
419  riinfo->pf_eq_oprs[i],
420  paramname, fk_type);
421  querysep = "AND";
422  queryoids[i] = fk_type;
423  }
424  appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
425  if (riinfo->hasperiod)
426  {
427  Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[riinfo->nkeys - 1]);
428 
429  appendStringInfoString(&querybuf, ") x1 HAVING ");
430  sprintf(paramname, "$%d", riinfo->nkeys);
431  ri_GenerateQual(&querybuf, "",
432  paramname, fk_type,
434  "pg_catalog.range_agg", ANYMULTIRANGEOID);
435  appendStringInfoString(&querybuf, "(x1.r)");
436  }
437 
438  /* Prepare and save the plan */
439  qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
440  &qkey, fk_rel, pk_rel);
441  }
442 
443  /*
444  * Now check that foreign key exists in PK table
445  *
446  * XXX detectNewRows must be true when a partitioned table is on the
447  * referenced side. The reason is that our snapshot must be fresh in
448  * order for the hack in find_inheritance_children() to work.
449  */
450  ri_PerformCheck(riinfo, &qkey, qplan,
451  fk_rel, pk_rel,
452  NULL, newslot,
453  pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE,
454  SPI_OK_SELECT);
455 
456  if (SPI_finish() != SPI_OK_FINISH)
457  elog(ERROR, "SPI_finish failed");
458 
459  table_close(pk_rel, RowShareLock);
460 
461  return PointerGetDatum(NULL);
462 }
463 
464 
465 /*
466  * RI_FKey_check_ins -
467  *
468  * Check foreign key existence at insert event on FK table.
469  */
470 Datum
472 {
473  /* Check that this is a valid trigger call on the right time and event. */
474  ri_CheckTrigger(fcinfo, "RI_FKey_check_ins", RI_TRIGTYPE_INSERT);
475 
476  /* Share code with UPDATE case. */
477  return RI_FKey_check((TriggerData *) fcinfo->context);
478 }
479 
480 
481 /*
482  * RI_FKey_check_upd -
483  *
484  * Check foreign key existence at update event on FK table.
485  */
486 Datum
488 {
489  /* Check that this is a valid trigger call on the right time and event. */
490  ri_CheckTrigger(fcinfo, "RI_FKey_check_upd", RI_TRIGTYPE_UPDATE);
491 
492  /* Share code with INSERT case. */
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 "oldslot" 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 oldslot contains no NULL key values,
505  * since otherwise a match is impossible.
506  */
507 static bool
509  TupleTableSlot *oldslot,
510  const RI_ConstraintInfo *riinfo)
511 {
512  SPIPlanPtr qplan;
513  RI_QueryKey qkey;
514  bool result;
515 
516  /* Only called for non-null rows */
517  Assert(ri_NullCheck(RelationGetDescr(pk_rel), oldslot, riinfo, true) == RI_KEYS_NONE_NULL);
518 
519  if (SPI_connect() != SPI_OK_CONNECT)
520  elog(ERROR, "SPI_connect failed");
521 
522  /*
523  * Fetch or prepare a saved plan for checking PK table with values coming
524  * from a PK row
525  */
527 
528  if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
529  {
530  StringInfoData querybuf;
531  char pkrelname[MAX_QUOTED_REL_NAME_LEN];
533  char paramname[16];
534  const char *querysep;
535  const char *pk_only;
536  Oid queryoids[RI_MAX_NUMKEYS];
537 
538  /* ----------
539  * The query string built is
540  * SELECT 1 FROM [ONLY] <pktable> x WHERE pkatt1 = $1 [AND ...]
541  * FOR KEY SHARE OF x
542  * The type id's for the $ parameters are those of the
543  * PK attributes themselves.
544  * But for temporal FKs we need to make sure
545  * the FK's range is completely covered.
546  * So we use this query instead:
547  * SELECT 1
548  * FROM (
549  * SELECT pkperiodatt AS r
550  * FROM [ONLY] pktable x
551  * WHERE pkatt1 = $1 [AND ...]
552  * AND pkperiodatt && $n
553  * FOR KEY SHARE OF x
554  * ) x1
555  * HAVING $n <@ range_agg(x1.r)
556  * Note if FOR KEY SHARE ever allows GROUP BY and HAVING
557  * we can make this a bit simpler.
558  * ----------
559  */
560  initStringInfo(&querybuf);
561  pk_only = pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
562  "" : "ONLY ";
563  quoteRelationName(pkrelname, pk_rel);
564  if (riinfo->hasperiod)
565  {
566  quoteOneName(attname, RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]));
567 
568  appendStringInfo(&querybuf,
569  "SELECT 1 FROM (SELECT %s AS r FROM %s%s x",
570  attname, pk_only, pkrelname);
571  }
572  else
573  {
574  appendStringInfo(&querybuf, "SELECT 1 FROM %s%s x",
575  pk_only, pkrelname);
576  }
577  querysep = "WHERE";
578  for (int i = 0; i < riinfo->nkeys; i++)
579  {
580  Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
581 
583  RIAttName(pk_rel, riinfo->pk_attnums[i]));
584  sprintf(paramname, "$%d", i + 1);
585  ri_GenerateQual(&querybuf, querysep,
586  attname, pk_type,
587  riinfo->pp_eq_oprs[i],
588  paramname, pk_type);
589  querysep = "AND";
590  queryoids[i] = pk_type;
591  }
592  appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
593  if (riinfo->hasperiod)
594  {
595  Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[riinfo->nkeys - 1]);
596 
597  appendStringInfoString(&querybuf, ") x1 HAVING ");
598  sprintf(paramname, "$%d", riinfo->nkeys);
599  ri_GenerateQual(&querybuf, "",
600  paramname, fk_type,
602  "pg_catalog.range_agg", ANYMULTIRANGEOID);
603  appendStringInfoString(&querybuf, "(x1.r)");
604  }
605 
606  /* Prepare and save the plan */
607  qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
608  &qkey, fk_rel, pk_rel);
609  }
610 
611  /*
612  * We have a plan now. Run it.
613  */
614  result = ri_PerformCheck(riinfo, &qkey, qplan,
615  fk_rel, pk_rel,
616  oldslot, NULL,
617  true, /* treat like update */
618  SPI_OK_SELECT);
619 
620  if (SPI_finish() != SPI_OK_FINISH)
621  elog(ERROR, "SPI_finish failed");
622 
623  return result;
624 }
625 
626 
627 /*
628  * RI_FKey_noaction_del -
629  *
630  * Give an error and roll back the current transaction if the
631  * delete has resulted in a violation of the given referential
632  * integrity constraint.
633  */
634 Datum
636 {
637  /* Check that this is a valid trigger call on the right time and event. */
638  ri_CheckTrigger(fcinfo, "RI_FKey_noaction_del", RI_TRIGTYPE_DELETE);
639 
640  /* Share code with RESTRICT/UPDATE cases. */
641  return ri_restrict((TriggerData *) fcinfo->context, true);
642 }
643 
644 /*
645  * RI_FKey_restrict_del -
646  *
647  * Restrict delete from PK table to rows unreferenced by foreign key.
648  *
649  * The SQL standard intends that this referential action occur exactly when
650  * the delete is performed, rather than after. This appears to be
651  * the only difference between "NO ACTION" and "RESTRICT". In Postgres
652  * we still implement this as an AFTER trigger, but it's non-deferrable.
653  */
654 Datum
656 {
657  /* Check that this is a valid trigger call on the right time and event. */
658  ri_CheckTrigger(fcinfo, "RI_FKey_restrict_del", RI_TRIGTYPE_DELETE);
659 
660  /* Share code with NO ACTION/UPDATE cases. */
661  return ri_restrict((TriggerData *) fcinfo->context, false);
662 }
663 
664 /*
665  * RI_FKey_noaction_upd -
666  *
667  * Give an error and roll back the current transaction if the
668  * update has resulted in a violation of the given referential
669  * integrity constraint.
670  */
671 Datum
673 {
674  /* Check that this is a valid trigger call on the right time and event. */
675  ri_CheckTrigger(fcinfo, "RI_FKey_noaction_upd", RI_TRIGTYPE_UPDATE);
676 
677  /* Share code with RESTRICT/DELETE cases. */
678  return ri_restrict((TriggerData *) fcinfo->context, true);
679 }
680 
681 /*
682  * RI_FKey_restrict_upd -
683  *
684  * Restrict update of PK to rows unreferenced by foreign key.
685  *
686  * The SQL standard intends that this referential action occur exactly when
687  * the update is performed, rather than after. This appears to be
688  * the only difference between "NO ACTION" and "RESTRICT". In Postgres
689  * we still implement this as an AFTER trigger, but it's non-deferrable.
690  */
691 Datum
693 {
694  /* Check that this is a valid trigger call on the right time and event. */
695  ri_CheckTrigger(fcinfo, "RI_FKey_restrict_upd", RI_TRIGTYPE_UPDATE);
696 
697  /* Share code with NO ACTION/DELETE cases. */
698  return ri_restrict((TriggerData *) fcinfo->context, false);
699 }
700 
701 /*
702  * ri_restrict -
703  *
704  * Common code for ON DELETE RESTRICT, ON DELETE NO ACTION,
705  * ON UPDATE RESTRICT, and ON UPDATE NO ACTION.
706  */
707 static Datum
708 ri_restrict(TriggerData *trigdata, bool is_no_action)
709 {
710  const RI_ConstraintInfo *riinfo;
711  Relation fk_rel;
712  Relation pk_rel;
713  TupleTableSlot *oldslot;
714  RI_QueryKey qkey;
715  SPIPlanPtr qplan;
716 
717  riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
718  trigdata->tg_relation, true);
719 
720  /*
721  * Get the relation descriptors of the FK and PK tables and the old tuple.
722  *
723  * fk_rel is opened in RowShareLock mode since that's what our eventual
724  * SELECT FOR KEY SHARE will get on it.
725  */
726  fk_rel = table_open(riinfo->fk_relid, RowShareLock);
727  pk_rel = trigdata->tg_relation;
728  oldslot = trigdata->tg_trigslot;
729 
730  /*
731  * If another PK row now exists providing the old key values, we should
732  * not do anything. However, this check should only be made in the NO
733  * ACTION case; in RESTRICT cases we don't wish to allow another row to be
734  * substituted.
735  */
736  if (is_no_action &&
737  ri_Check_Pk_Match(pk_rel, fk_rel, oldslot, riinfo))
738  {
739  table_close(fk_rel, RowShareLock);
740  return PointerGetDatum(NULL);
741  }
742 
743  if (SPI_connect() != SPI_OK_CONNECT)
744  elog(ERROR, "SPI_connect failed");
745 
746  /*
747  * Fetch or prepare a saved plan for the restrict lookup (it's the same
748  * query for delete and update cases)
749  */
750  ri_BuildQueryKey(&qkey, riinfo, RI_PLAN_RESTRICT);
751 
752  if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
753  {
754  StringInfoData querybuf;
755  char fkrelname[MAX_QUOTED_REL_NAME_LEN];
757  char paramname[16];
758  const char *querysep;
759  Oid queryoids[RI_MAX_NUMKEYS];
760  const char *fk_only;
761 
762  /* ----------
763  * The query string built is
764  * SELECT 1 FROM [ONLY] <fktable> x WHERE $1 = fkatt1 [AND ...]
765  * FOR KEY SHARE OF x
766  * The type id's for the $ parameters are those of the
767  * corresponding PK attributes.
768  * ----------
769  */
770  initStringInfo(&querybuf);
771  fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
772  "" : "ONLY ";
773  quoteRelationName(fkrelname, fk_rel);
774  appendStringInfo(&querybuf, "SELECT 1 FROM %s%s x",
775  fk_only, fkrelname);
776  querysep = "WHERE";
777  for (int i = 0; i < riinfo->nkeys; i++)
778  {
779  Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
780  Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
781  Oid pk_coll = RIAttCollation(pk_rel, riinfo->pk_attnums[i]);
782  Oid fk_coll = RIAttCollation(fk_rel, riinfo->fk_attnums[i]);
783 
785  RIAttName(fk_rel, riinfo->fk_attnums[i]));
786  sprintf(paramname, "$%d", i + 1);
787  ri_GenerateQual(&querybuf, querysep,
788  paramname, pk_type,
789  riinfo->pf_eq_oprs[i],
790  attname, fk_type);
791  if (pk_coll != fk_coll && !get_collation_isdeterministic(pk_coll))
792  ri_GenerateQualCollation(&querybuf, pk_coll);
793  querysep = "AND";
794  queryoids[i] = pk_type;
795  }
796  appendStringInfoString(&querybuf, " FOR KEY SHARE OF x");
797 
798  /* Prepare and save the plan */
799  qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
800  &qkey, fk_rel, pk_rel);
801  }
802 
803  /*
804  * We have a plan now. Run it to check for existing references.
805  */
806  ri_PerformCheck(riinfo, &qkey, qplan,
807  fk_rel, pk_rel,
808  oldslot, NULL,
809  true, /* must detect new rows */
810  SPI_OK_SELECT);
811 
812  if (SPI_finish() != SPI_OK_FINISH)
813  elog(ERROR, "SPI_finish failed");
814 
815  table_close(fk_rel, RowShareLock);
816 
817  return PointerGetDatum(NULL);
818 }
819 
820 
821 /*
822  * RI_FKey_cascade_del -
823  *
824  * Cascaded delete foreign key references at delete event on PK table.
825  */
826 Datum
828 {
829  TriggerData *trigdata = (TriggerData *) fcinfo->context;
830  const RI_ConstraintInfo *riinfo;
831  Relation fk_rel;
832  Relation pk_rel;
833  TupleTableSlot *oldslot;
834  RI_QueryKey qkey;
835  SPIPlanPtr qplan;
836 
837  /* Check that this is a valid trigger call on the right time and event. */
838  ri_CheckTrigger(fcinfo, "RI_FKey_cascade_del", RI_TRIGTYPE_DELETE);
839 
840  riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
841  trigdata->tg_relation, true);
842 
843  /*
844  * Get the relation descriptors of the FK and PK tables and the old tuple.
845  *
846  * fk_rel is opened in RowExclusiveLock mode since that's what our
847  * eventual DELETE will get on it.
848  */
849  fk_rel = table_open(riinfo->fk_relid, RowExclusiveLock);
850  pk_rel = trigdata->tg_relation;
851  oldslot = trigdata->tg_trigslot;
852 
853  if (SPI_connect() != SPI_OK_CONNECT)
854  elog(ERROR, "SPI_connect failed");
855 
856  /* Fetch or prepare a saved plan for the cascaded delete */
858 
859  if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
860  {
861  StringInfoData querybuf;
862  char fkrelname[MAX_QUOTED_REL_NAME_LEN];
864  char paramname[16];
865  const char *querysep;
866  Oid queryoids[RI_MAX_NUMKEYS];
867  const char *fk_only;
868 
869  /* ----------
870  * The query string built is
871  * DELETE FROM [ONLY] <fktable> WHERE $1 = fkatt1 [AND ...]
872  * The type id's for the $ parameters are those of the
873  * corresponding PK attributes.
874  * ----------
875  */
876  initStringInfo(&querybuf);
877  fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
878  "" : "ONLY ";
879  quoteRelationName(fkrelname, fk_rel);
880  appendStringInfo(&querybuf, "DELETE FROM %s%s",
881  fk_only, fkrelname);
882  querysep = "WHERE";
883  for (int i = 0; i < riinfo->nkeys; i++)
884  {
885  Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
886  Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
887  Oid pk_coll = RIAttCollation(pk_rel, riinfo->pk_attnums[i]);
888  Oid fk_coll = RIAttCollation(fk_rel, riinfo->fk_attnums[i]);
889 
891  RIAttName(fk_rel, riinfo->fk_attnums[i]));
892  sprintf(paramname, "$%d", i + 1);
893  ri_GenerateQual(&querybuf, querysep,
894  paramname, pk_type,
895  riinfo->pf_eq_oprs[i],
896  attname, fk_type);
897  if (pk_coll != fk_coll && !get_collation_isdeterministic(pk_coll))
898  ri_GenerateQualCollation(&querybuf, pk_coll);
899  querysep = "AND";
900  queryoids[i] = pk_type;
901  }
902 
903  /* Prepare and save the plan */
904  qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
905  &qkey, fk_rel, pk_rel);
906  }
907 
908  /*
909  * We have a plan now. Build up the arguments from the key values in the
910  * deleted PK tuple and delete the referencing rows
911  */
912  ri_PerformCheck(riinfo, &qkey, qplan,
913  fk_rel, pk_rel,
914  oldslot, NULL,
915  true, /* must detect new rows */
916  SPI_OK_DELETE);
917 
918  if (SPI_finish() != SPI_OK_FINISH)
919  elog(ERROR, "SPI_finish failed");
920 
921  table_close(fk_rel, RowExclusiveLock);
922 
923  return PointerGetDatum(NULL);
924 }
925 
926 
927 /*
928  * RI_FKey_cascade_upd -
929  *
930  * Cascaded update foreign key references at update event on PK table.
931  */
932 Datum
934 {
935  TriggerData *trigdata = (TriggerData *) fcinfo->context;
936  const RI_ConstraintInfo *riinfo;
937  Relation fk_rel;
938  Relation pk_rel;
939  TupleTableSlot *newslot;
940  TupleTableSlot *oldslot;
941  RI_QueryKey qkey;
942  SPIPlanPtr qplan;
943 
944  /* Check that this is a valid trigger call on the right time and event. */
945  ri_CheckTrigger(fcinfo, "RI_FKey_cascade_upd", RI_TRIGTYPE_UPDATE);
946 
947  riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
948  trigdata->tg_relation, true);
949 
950  /*
951  * Get the relation descriptors of the FK and PK tables and the new and
952  * old tuple.
953  *
954  * fk_rel is opened in RowExclusiveLock mode since that's what our
955  * eventual UPDATE will get on it.
956  */
957  fk_rel = table_open(riinfo->fk_relid, RowExclusiveLock);
958  pk_rel = trigdata->tg_relation;
959  newslot = trigdata->tg_newslot;
960  oldslot = trigdata->tg_trigslot;
961 
962  if (SPI_connect() != SPI_OK_CONNECT)
963  elog(ERROR, "SPI_connect failed");
964 
965  /* Fetch or prepare a saved plan for the cascaded update */
967 
968  if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
969  {
970  StringInfoData querybuf;
971  StringInfoData qualbuf;
972  char fkrelname[MAX_QUOTED_REL_NAME_LEN];
974  char paramname[16];
975  const char *querysep;
976  const char *qualsep;
977  Oid queryoids[RI_MAX_NUMKEYS * 2];
978  const char *fk_only;
979 
980  /* ----------
981  * The query string built is
982  * UPDATE [ONLY] <fktable> SET fkatt1 = $1 [, ...]
983  * WHERE $n = fkatt1 [AND ...]
984  * The type id's for the $ parameters are those of the
985  * corresponding PK attributes. Note that we are assuming
986  * there is an assignment cast from the PK to the FK type;
987  * else the parser will fail.
988  * ----------
989  */
990  initStringInfo(&querybuf);
991  initStringInfo(&qualbuf);
992  fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
993  "" : "ONLY ";
994  quoteRelationName(fkrelname, fk_rel);
995  appendStringInfo(&querybuf, "UPDATE %s%s SET",
996  fk_only, fkrelname);
997  querysep = "";
998  qualsep = "WHERE";
999  for (int i = 0, j = riinfo->nkeys; i < riinfo->nkeys; i++, j++)
1000  {
1001  Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1002  Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1003  Oid pk_coll = RIAttCollation(pk_rel, riinfo->pk_attnums[i]);
1004  Oid fk_coll = RIAttCollation(fk_rel, riinfo->fk_attnums[i]);
1005 
1007  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1008  appendStringInfo(&querybuf,
1009  "%s %s = $%d",
1010  querysep, attname, i + 1);
1011  sprintf(paramname, "$%d", j + 1);
1012  ri_GenerateQual(&qualbuf, qualsep,
1013  paramname, pk_type,
1014  riinfo->pf_eq_oprs[i],
1015  attname, fk_type);
1016  if (pk_coll != fk_coll && !get_collation_isdeterministic(pk_coll))
1017  ri_GenerateQualCollation(&querybuf, pk_coll);
1018  querysep = ",";
1019  qualsep = "AND";
1020  queryoids[i] = pk_type;
1021  queryoids[j] = pk_type;
1022  }
1023  appendBinaryStringInfo(&querybuf, qualbuf.data, qualbuf.len);
1024 
1025  /* Prepare and save the plan */
1026  qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys * 2, queryoids,
1027  &qkey, fk_rel, pk_rel);
1028  }
1029 
1030  /*
1031  * We have a plan now. Run it to update the existing references.
1032  */
1033  ri_PerformCheck(riinfo, &qkey, qplan,
1034  fk_rel, pk_rel,
1035  oldslot, newslot,
1036  true, /* must detect new rows */
1037  SPI_OK_UPDATE);
1038 
1039  if (SPI_finish() != SPI_OK_FINISH)
1040  elog(ERROR, "SPI_finish failed");
1041 
1042  table_close(fk_rel, RowExclusiveLock);
1043 
1044  return PointerGetDatum(NULL);
1045 }
1046 
1047 
1048 /*
1049  * RI_FKey_setnull_del -
1050  *
1051  * Set foreign key references to NULL values at delete event on PK table.
1052  */
1053 Datum
1055 {
1056  /* Check that this is a valid trigger call on the right time and event. */
1057  ri_CheckTrigger(fcinfo, "RI_FKey_setnull_del", RI_TRIGTYPE_DELETE);
1058 
1059  /* Share code with UPDATE case */
1060  return ri_set((TriggerData *) fcinfo->context, true, RI_TRIGTYPE_DELETE);
1061 }
1062 
1063 /*
1064  * RI_FKey_setnull_upd -
1065  *
1066  * Set foreign key references to NULL at update event on PK table.
1067  */
1068 Datum
1070 {
1071  /* Check that this is a valid trigger call on the right time and event. */
1072  ri_CheckTrigger(fcinfo, "RI_FKey_setnull_upd", RI_TRIGTYPE_UPDATE);
1073 
1074  /* Share code with DELETE case */
1075  return ri_set((TriggerData *) fcinfo->context, true, RI_TRIGTYPE_UPDATE);
1076 }
1077 
1078 /*
1079  * RI_FKey_setdefault_del -
1080  *
1081  * Set foreign key references to defaults at delete event on PK table.
1082  */
1083 Datum
1085 {
1086  /* Check that this is a valid trigger call on the right time and event. */
1087  ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_del", RI_TRIGTYPE_DELETE);
1088 
1089  /* Share code with UPDATE case */
1090  return ri_set((TriggerData *) fcinfo->context, false, RI_TRIGTYPE_DELETE);
1091 }
1092 
1093 /*
1094  * RI_FKey_setdefault_upd -
1095  *
1096  * Set foreign key references to defaults at update event on PK table.
1097  */
1098 Datum
1100 {
1101  /* Check that this is a valid trigger call on the right time and event. */
1102  ri_CheckTrigger(fcinfo, "RI_FKey_setdefault_upd", RI_TRIGTYPE_UPDATE);
1103 
1104  /* Share code with DELETE case */
1105  return ri_set((TriggerData *) fcinfo->context, false, RI_TRIGTYPE_UPDATE);
1106 }
1107 
1108 /*
1109  * ri_set -
1110  *
1111  * Common code for ON DELETE SET NULL, ON DELETE SET DEFAULT, ON UPDATE SET
1112  * NULL, and ON UPDATE SET DEFAULT.
1113  */
1114 static Datum
1115 ri_set(TriggerData *trigdata, bool is_set_null, int tgkind)
1116 {
1117  const RI_ConstraintInfo *riinfo;
1118  Relation fk_rel;
1119  Relation pk_rel;
1120  TupleTableSlot *oldslot;
1121  RI_QueryKey qkey;
1122  SPIPlanPtr qplan;
1123  int32 queryno;
1124 
1125  riinfo = ri_FetchConstraintInfo(trigdata->tg_trigger,
1126  trigdata->tg_relation, true);
1127 
1128  /*
1129  * Get the relation descriptors of the FK and PK tables and the old tuple.
1130  *
1131  * fk_rel is opened in RowExclusiveLock mode since that's what our
1132  * eventual UPDATE will get on it.
1133  */
1134  fk_rel = table_open(riinfo->fk_relid, RowExclusiveLock);
1135  pk_rel = trigdata->tg_relation;
1136  oldslot = trigdata->tg_trigslot;
1137 
1138  if (SPI_connect() != SPI_OK_CONNECT)
1139  elog(ERROR, "SPI_connect failed");
1140 
1141  /*
1142  * Fetch or prepare a saved plan for the trigger.
1143  */
1144  switch (tgkind)
1145  {
1146  case RI_TRIGTYPE_UPDATE:
1147  queryno = is_set_null
1150  break;
1151  case RI_TRIGTYPE_DELETE:
1152  queryno = is_set_null
1155  break;
1156  default:
1157  elog(ERROR, "invalid tgkind passed to ri_set");
1158  }
1159 
1160  ri_BuildQueryKey(&qkey, riinfo, queryno);
1161 
1162  if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)
1163  {
1164  StringInfoData querybuf;
1165  char fkrelname[MAX_QUOTED_REL_NAME_LEN];
1167  char paramname[16];
1168  const char *querysep;
1169  const char *qualsep;
1170  Oid queryoids[RI_MAX_NUMKEYS];
1171  const char *fk_only;
1172  int num_cols_to_set;
1173  const int16 *set_cols;
1174 
1175  switch (tgkind)
1176  {
1177  case RI_TRIGTYPE_UPDATE:
1178  num_cols_to_set = riinfo->nkeys;
1179  set_cols = riinfo->fk_attnums;
1180  break;
1181  case RI_TRIGTYPE_DELETE:
1182 
1183  /*
1184  * If confdelsetcols are present, then we only update the
1185  * columns specified in that array, otherwise we update all
1186  * the referencing columns.
1187  */
1188  if (riinfo->ndelsetcols != 0)
1189  {
1190  num_cols_to_set = riinfo->ndelsetcols;
1191  set_cols = riinfo->confdelsetcols;
1192  }
1193  else
1194  {
1195  num_cols_to_set = riinfo->nkeys;
1196  set_cols = riinfo->fk_attnums;
1197  }
1198  break;
1199  default:
1200  elog(ERROR, "invalid tgkind passed to ri_set");
1201  }
1202 
1203  /* ----------
1204  * The query string built is
1205  * UPDATE [ONLY] <fktable> SET fkatt1 = {NULL|DEFAULT} [, ...]
1206  * WHERE $1 = fkatt1 [AND ...]
1207  * The type id's for the $ parameters are those of the
1208  * corresponding PK attributes.
1209  * ----------
1210  */
1211  initStringInfo(&querybuf);
1212  fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
1213  "" : "ONLY ";
1214  quoteRelationName(fkrelname, fk_rel);
1215  appendStringInfo(&querybuf, "UPDATE %s%s SET",
1216  fk_only, fkrelname);
1217 
1218  /*
1219  * Add assignment clauses
1220  */
1221  querysep = "";
1222  for (int i = 0; i < num_cols_to_set; i++)
1223  {
1224  quoteOneName(attname, RIAttName(fk_rel, set_cols[i]));
1225  appendStringInfo(&querybuf,
1226  "%s %s = %s",
1227  querysep, attname,
1228  is_set_null ? "NULL" : "DEFAULT");
1229  querysep = ",";
1230  }
1231 
1232  /*
1233  * Add WHERE clause
1234  */
1235  qualsep = "WHERE";
1236  for (int i = 0; i < riinfo->nkeys; i++)
1237  {
1238  Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1239  Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1240  Oid pk_coll = RIAttCollation(pk_rel, riinfo->pk_attnums[i]);
1241  Oid fk_coll = RIAttCollation(fk_rel, riinfo->fk_attnums[i]);
1242 
1244  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1245 
1246  sprintf(paramname, "$%d", i + 1);
1247  ri_GenerateQual(&querybuf, qualsep,
1248  paramname, pk_type,
1249  riinfo->pf_eq_oprs[i],
1250  attname, fk_type);
1251  if (pk_coll != fk_coll && !get_collation_isdeterministic(pk_coll))
1252  ri_GenerateQualCollation(&querybuf, pk_coll);
1253  qualsep = "AND";
1254  queryoids[i] = pk_type;
1255  }
1256 
1257  /* Prepare and save the plan */
1258  qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids,
1259  &qkey, fk_rel, pk_rel);
1260  }
1261 
1262  /*
1263  * We have a plan now. Run it to update the existing references.
1264  */
1265  ri_PerformCheck(riinfo, &qkey, qplan,
1266  fk_rel, pk_rel,
1267  oldslot, NULL,
1268  true, /* must detect new rows */
1269  SPI_OK_UPDATE);
1270 
1271  if (SPI_finish() != SPI_OK_FINISH)
1272  elog(ERROR, "SPI_finish failed");
1273 
1274  table_close(fk_rel, RowExclusiveLock);
1275 
1276  if (is_set_null)
1277  return PointerGetDatum(NULL);
1278  else
1279  {
1280  /*
1281  * If we just deleted or updated the PK row whose key was equal to the
1282  * FK columns' default values, and a referencing row exists in the FK
1283  * table, we would have updated that row to the same values it already
1284  * had --- and RI_FKey_fk_upd_check_required would hence believe no
1285  * check is necessary. So we need to do another lookup now and in
1286  * case a reference still exists, abort the operation. That is
1287  * already implemented in the NO ACTION trigger, so just run it. (This
1288  * recheck is only needed in the SET DEFAULT case, since CASCADE would
1289  * remove such rows in case of a DELETE operation or would change the
1290  * FK key values in case of an UPDATE, while SET NULL is certain to
1291  * result in rows that satisfy the FK constraint.)
1292  */
1293  return ri_restrict(trigdata, true);
1294  }
1295 }
1296 
1297 
1298 /*
1299  * RI_FKey_pk_upd_check_required -
1300  *
1301  * Check if we really need to fire the RI trigger for an update or delete to a PK
1302  * relation. This is called by the AFTER trigger queue manager to see if
1303  * it can skip queuing an instance of an RI trigger. Returns true if the
1304  * trigger must be fired, false if we can prove the constraint will still
1305  * be satisfied.
1306  *
1307  * newslot will be NULL if this is called for a delete.
1308  */
1309 bool
1311  TupleTableSlot *oldslot, TupleTableSlot *newslot)
1312 {
1313  const RI_ConstraintInfo *riinfo;
1314 
1315  riinfo = ri_FetchConstraintInfo(trigger, pk_rel, true);
1316 
1317  /*
1318  * If any old key value is NULL, the row could not have been referenced by
1319  * an FK row, so no check is needed.
1320  */
1321  if (ri_NullCheck(RelationGetDescr(pk_rel), oldslot, riinfo, true) != RI_KEYS_NONE_NULL)
1322  return false;
1323 
1324  /* If all old and new key values are equal, no check is needed */
1325  if (newslot && ri_KeysEqual(pk_rel, oldslot, newslot, riinfo, true))
1326  return false;
1327 
1328  /* Else we need to fire the trigger. */
1329  return true;
1330 }
1331 
1332 /*
1333  * RI_FKey_fk_upd_check_required -
1334  *
1335  * Check if we really need to fire the RI trigger for an update to an FK
1336  * relation. This is called by the AFTER trigger queue manager to see if
1337  * it can skip queuing an instance of an RI trigger. Returns true if the
1338  * trigger must be fired, false if we can prove the constraint will still
1339  * be satisfied.
1340  */
1341 bool
1343  TupleTableSlot *oldslot, TupleTableSlot *newslot)
1344 {
1345  const RI_ConstraintInfo *riinfo;
1346  int ri_nullcheck;
1347 
1348  /*
1349  * AfterTriggerSaveEvent() handles things such that this function is never
1350  * called for partitioned tables.
1351  */
1352  Assert(fk_rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE);
1353 
1354  riinfo = ri_FetchConstraintInfo(trigger, fk_rel, false);
1355 
1356  ri_nullcheck = ri_NullCheck(RelationGetDescr(fk_rel), newslot, riinfo, false);
1357 
1358  /*
1359  * If all new key values are NULL, the row satisfies the constraint, so no
1360  * check is needed.
1361  */
1362  if (ri_nullcheck == RI_KEYS_ALL_NULL)
1363  return false;
1364 
1365  /*
1366  * If some new key values are NULL, the behavior depends on the match
1367  * type.
1368  */
1369  else if (ri_nullcheck == RI_KEYS_SOME_NULL)
1370  {
1371  switch (riinfo->confmatchtype)
1372  {
1373  case FKCONSTR_MATCH_SIMPLE:
1374 
1375  /*
1376  * If any new key value is NULL, the row must satisfy the
1377  * constraint, so no check is needed.
1378  */
1379  return false;
1380 
1382 
1383  /*
1384  * Don't know, must run full check.
1385  */
1386  break;
1387 
1388  case FKCONSTR_MATCH_FULL:
1389 
1390  /*
1391  * If some new key values are NULL, the row fails the
1392  * constraint. We must not throw error here, because the row
1393  * might get invalidated before the constraint is to be
1394  * checked, but we should queue the event to apply the check
1395  * later.
1396  */
1397  return true;
1398  }
1399  }
1400 
1401  /*
1402  * Continues here for no new key values are NULL, or we couldn't decide
1403  * yet.
1404  */
1405 
1406  /*
1407  * If the original row was inserted by our own transaction, we must fire
1408  * the trigger whether or not the keys are equal. This is because our
1409  * UPDATE will invalidate the INSERT so that the INSERT RI trigger will
1410  * not do anything; so we had better do the UPDATE check. (We could skip
1411  * this if we knew the INSERT trigger already fired, but there is no easy
1412  * way to know that.)
1413  */
1414  if (slot_is_current_xact_tuple(oldslot))
1415  return true;
1416 
1417  /* If all old and new key values are equal, no check is needed */
1418  if (ri_KeysEqual(fk_rel, oldslot, newslot, riinfo, false))
1419  return false;
1420 
1421  /* Else we need to fire the trigger. */
1422  return true;
1423 }
1424 
1425 /*
1426  * RI_Initial_Check -
1427  *
1428  * Check an entire table for non-matching values using a single query.
1429  * This is not a trigger procedure, but is called during ALTER TABLE
1430  * ADD FOREIGN KEY to validate the initial table contents.
1431  *
1432  * We expect that the caller has made provision to prevent any problems
1433  * caused by concurrent actions. This could be either by locking rel and
1434  * pkrel at ShareRowExclusiveLock or higher, or by otherwise ensuring
1435  * that triggers implementing the checks are already active.
1436  * Hence, we do not need to lock individual rows for the check.
1437  *
1438  * If the check fails because the current user doesn't have permissions
1439  * to read both tables, return false to let our caller know that they will
1440  * need to do something else to check the constraint.
1441  */
1442 bool
1443 RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
1444 {
1445  const RI_ConstraintInfo *riinfo;
1446  StringInfoData querybuf;
1447  char pkrelname[MAX_QUOTED_REL_NAME_LEN];
1448  char fkrelname[MAX_QUOTED_REL_NAME_LEN];
1449  char pkattname[MAX_QUOTED_NAME_LEN + 3];
1450  char fkattname[MAX_QUOTED_NAME_LEN + 3];
1451  RangeTblEntry *rte;
1452  RTEPermissionInfo *pk_perminfo;
1453  RTEPermissionInfo *fk_perminfo;
1454  List *rtes = NIL;
1455  List *perminfos = NIL;
1456  const char *sep;
1457  const char *fk_only;
1458  const char *pk_only;
1459  int save_nestlevel;
1460  char workmembuf[32];
1461  int spi_result;
1462  SPIPlanPtr qplan;
1463 
1464  riinfo = ri_FetchConstraintInfo(trigger, fk_rel, false);
1465 
1466  /*
1467  * Check to make sure current user has enough permissions to do the test
1468  * query. (If not, caller can fall back to the trigger method, which
1469  * works because it changes user IDs on the fly.)
1470  *
1471  * XXX are there any other show-stopper conditions to check?
1472  */
1473  pk_perminfo = makeNode(RTEPermissionInfo);
1474  pk_perminfo->relid = RelationGetRelid(pk_rel);
1475  pk_perminfo->requiredPerms = ACL_SELECT;
1476  perminfos = lappend(perminfos, pk_perminfo);
1477  rte = makeNode(RangeTblEntry);
1478  rte->rtekind = RTE_RELATION;
1479  rte->relid = RelationGetRelid(pk_rel);
1480  rte->relkind = pk_rel->rd_rel->relkind;
1481  rte->rellockmode = AccessShareLock;
1482  rte->perminfoindex = list_length(perminfos);
1483  rtes = lappend(rtes, rte);
1484 
1485  fk_perminfo = makeNode(RTEPermissionInfo);
1486  fk_perminfo->relid = RelationGetRelid(fk_rel);
1487  fk_perminfo->requiredPerms = ACL_SELECT;
1488  perminfos = lappend(perminfos, fk_perminfo);
1489  rte = makeNode(RangeTblEntry);
1490  rte->rtekind = RTE_RELATION;
1491  rte->relid = RelationGetRelid(fk_rel);
1492  rte->relkind = fk_rel->rd_rel->relkind;
1493  rte->rellockmode = AccessShareLock;
1494  rte->perminfoindex = list_length(perminfos);
1495  rtes = lappend(rtes, rte);
1496 
1497  for (int i = 0; i < riinfo->nkeys; i++)
1498  {
1499  int attno;
1500 
1501  attno = riinfo->pk_attnums[i] - FirstLowInvalidHeapAttributeNumber;
1502  pk_perminfo->selectedCols = bms_add_member(pk_perminfo->selectedCols, attno);
1503 
1504  attno = riinfo->fk_attnums[i] - FirstLowInvalidHeapAttributeNumber;
1505  fk_perminfo->selectedCols = bms_add_member(fk_perminfo->selectedCols, attno);
1506  }
1507 
1508  if (!ExecCheckPermissions(rtes, perminfos, false))
1509  return false;
1510 
1511  /*
1512  * Also punt if RLS is enabled on either table unless this role has the
1513  * bypassrls right or is the table owner of the table(s) involved which
1514  * have RLS enabled.
1515  */
1517  ((pk_rel->rd_rel->relrowsecurity &&
1518  !object_ownercheck(RelationRelationId, RelationGetRelid(pk_rel),
1519  GetUserId())) ||
1520  (fk_rel->rd_rel->relrowsecurity &&
1521  !object_ownercheck(RelationRelationId, RelationGetRelid(fk_rel),
1522  GetUserId()))))
1523  return false;
1524 
1525  /*----------
1526  * The query string built is:
1527  * SELECT fk.keycols FROM [ONLY] relname fk
1528  * LEFT OUTER JOIN [ONLY] pkrelname pk
1529  * ON (pk.pkkeycol1=fk.keycol1 [AND ...])
1530  * WHERE pk.pkkeycol1 IS NULL AND
1531  * For MATCH SIMPLE:
1532  * (fk.keycol1 IS NOT NULL [AND ...])
1533  * For MATCH FULL:
1534  * (fk.keycol1 IS NOT NULL [OR ...])
1535  *
1536  * We attach COLLATE clauses to the operators when comparing columns
1537  * that have different collations.
1538  *----------
1539  */
1540  initStringInfo(&querybuf);
1541  appendStringInfoString(&querybuf, "SELECT ");
1542  sep = "";
1543  for (int i = 0; i < riinfo->nkeys; i++)
1544  {
1545  quoteOneName(fkattname,
1546  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1547  appendStringInfo(&querybuf, "%sfk.%s", sep, fkattname);
1548  sep = ", ";
1549  }
1550 
1551  quoteRelationName(pkrelname, pk_rel);
1552  quoteRelationName(fkrelname, fk_rel);
1553  fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
1554  "" : "ONLY ";
1555  pk_only = pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
1556  "" : "ONLY ";
1557  appendStringInfo(&querybuf,
1558  " FROM %s%s fk LEFT OUTER JOIN %s%s pk ON",
1559  fk_only, fkrelname, pk_only, pkrelname);
1560 
1561  strcpy(pkattname, "pk.");
1562  strcpy(fkattname, "fk.");
1563  sep = "(";
1564  for (int i = 0; i < riinfo->nkeys; i++)
1565  {
1566  Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1567  Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1568  Oid pk_coll = RIAttCollation(pk_rel, riinfo->pk_attnums[i]);
1569  Oid fk_coll = RIAttCollation(fk_rel, riinfo->fk_attnums[i]);
1570 
1571  quoteOneName(pkattname + 3,
1572  RIAttName(pk_rel, riinfo->pk_attnums[i]));
1573  quoteOneName(fkattname + 3,
1574  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1575  ri_GenerateQual(&querybuf, sep,
1576  pkattname, pk_type,
1577  riinfo->pf_eq_oprs[i],
1578  fkattname, fk_type);
1579  if (pk_coll != fk_coll)
1580  ri_GenerateQualCollation(&querybuf, pk_coll);
1581  sep = "AND";
1582  }
1583 
1584  /*
1585  * It's sufficient to test any one pk attribute for null to detect a join
1586  * failure.
1587  */
1588  quoteOneName(pkattname, RIAttName(pk_rel, riinfo->pk_attnums[0]));
1589  appendStringInfo(&querybuf, ") WHERE pk.%s IS NULL AND (", pkattname);
1590 
1591  sep = "";
1592  for (int i = 0; i < riinfo->nkeys; i++)
1593  {
1594  quoteOneName(fkattname, RIAttName(fk_rel, riinfo->fk_attnums[i]));
1595  appendStringInfo(&querybuf,
1596  "%sfk.%s IS NOT NULL",
1597  sep, fkattname);
1598  switch (riinfo->confmatchtype)
1599  {
1600  case FKCONSTR_MATCH_SIMPLE:
1601  sep = " AND ";
1602  break;
1603  case FKCONSTR_MATCH_FULL:
1604  sep = " OR ";
1605  break;
1606  }
1607  }
1608  appendStringInfoChar(&querybuf, ')');
1609 
1610  /*
1611  * Temporarily increase work_mem so that the check query can be executed
1612  * more efficiently. It seems okay to do this because the query is simple
1613  * enough to not use a multiple of work_mem, and one typically would not
1614  * have many large foreign-key validations happening concurrently. So
1615  * this seems to meet the criteria for being considered a "maintenance"
1616  * operation, and accordingly we use maintenance_work_mem. However, we
1617  * must also set hash_mem_multiplier to 1, since it is surely not okay to
1618  * let that get applied to the maintenance_work_mem value.
1619  *
1620  * We use the equivalent of a function SET option to allow the setting to
1621  * persist for exactly the duration of the check query. guc.c also takes
1622  * care of undoing the setting on error.
1623  */
1624  save_nestlevel = NewGUCNestLevel();
1625 
1626  snprintf(workmembuf, sizeof(workmembuf), "%d", maintenance_work_mem);
1627  (void) set_config_option("work_mem", workmembuf,
1629  GUC_ACTION_SAVE, true, 0, false);
1630  (void) set_config_option("hash_mem_multiplier", "1",
1632  GUC_ACTION_SAVE, true, 0, false);
1633 
1634  if (SPI_connect() != SPI_OK_CONNECT)
1635  elog(ERROR, "SPI_connect failed");
1636 
1637  /*
1638  * Generate the plan. We don't need to cache it, and there are no
1639  * arguments to the plan.
1640  */
1641  qplan = SPI_prepare(querybuf.data, 0, NULL);
1642 
1643  if (qplan == NULL)
1644  elog(ERROR, "SPI_prepare returned %s for %s",
1646 
1647  /*
1648  * Run the plan. For safety we force a current snapshot to be used. (In
1649  * transaction-snapshot mode, this arguably violates transaction isolation
1650  * rules, but we really haven't got much choice.) We don't need to
1651  * register the snapshot, because SPI_execute_snapshot will see to it. We
1652  * need at most one tuple returned, so pass limit = 1.
1653  */
1654  spi_result = SPI_execute_snapshot(qplan,
1655  NULL, NULL,
1658  true, false, 1);
1659 
1660  /* Check result */
1661  if (spi_result != SPI_OK_SELECT)
1662  elog(ERROR, "SPI_execute_snapshot returned %s", SPI_result_code_string(spi_result));
1663 
1664  /* Did we find a tuple violating the constraint? */
1665  if (SPI_processed > 0)
1666  {
1667  TupleTableSlot *slot;
1668  HeapTuple tuple = SPI_tuptable->vals[0];
1669  TupleDesc tupdesc = SPI_tuptable->tupdesc;
1670  RI_ConstraintInfo fake_riinfo;
1671 
1672  slot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual);
1673 
1674  heap_deform_tuple(tuple, tupdesc,
1675  slot->tts_values, slot->tts_isnull);
1676  ExecStoreVirtualTuple(slot);
1677 
1678  /*
1679  * The columns to look at in the result tuple are 1..N, not whatever
1680  * they are in the fk_rel. Hack up riinfo so that the subroutines
1681  * called here will behave properly.
1682  *
1683  * In addition to this, we have to pass the correct tupdesc to
1684  * ri_ReportViolation, overriding its normal habit of using the pk_rel
1685  * or fk_rel's tupdesc.
1686  */
1687  memcpy(&fake_riinfo, riinfo, sizeof(RI_ConstraintInfo));
1688  for (int i = 0; i < fake_riinfo.nkeys; i++)
1689  fake_riinfo.fk_attnums[i] = i + 1;
1690 
1691  /*
1692  * If it's MATCH FULL, and there are any nulls in the FK keys,
1693  * complain about that rather than the lack of a match. MATCH FULL
1694  * disallows partially-null FK rows.
1695  */
1696  if (fake_riinfo.confmatchtype == FKCONSTR_MATCH_FULL &&
1697  ri_NullCheck(tupdesc, slot, &fake_riinfo, false) != RI_KEYS_NONE_NULL)
1698  ereport(ERROR,
1699  (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
1700  errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
1701  RelationGetRelationName(fk_rel),
1702  NameStr(fake_riinfo.conname)),
1703  errdetail("MATCH FULL does not allow mixing of null and nonnull key values."),
1704  errtableconstraint(fk_rel,
1705  NameStr(fake_riinfo.conname))));
1706 
1707  /*
1708  * We tell ri_ReportViolation we were doing the RI_PLAN_CHECK_LOOKUPPK
1709  * query, which isn't true, but will cause it to use
1710  * fake_riinfo.fk_attnums as we need.
1711  */
1712  ri_ReportViolation(&fake_riinfo,
1713  pk_rel, fk_rel,
1714  slot, tupdesc,
1715  RI_PLAN_CHECK_LOOKUPPK, false);
1716 
1718  }
1719 
1720  if (SPI_finish() != SPI_OK_FINISH)
1721  elog(ERROR, "SPI_finish failed");
1722 
1723  /*
1724  * Restore work_mem and hash_mem_multiplier.
1725  */
1726  AtEOXact_GUC(true, save_nestlevel);
1727 
1728  return true;
1729 }
1730 
1731 /*
1732  * RI_PartitionRemove_Check -
1733  *
1734  * Verify no referencing values exist, when a partition is detached on
1735  * the referenced side of a foreign key constraint.
1736  */
1737 void
1739 {
1740  const RI_ConstraintInfo *riinfo;
1741  StringInfoData querybuf;
1742  char *constraintDef;
1743  char pkrelname[MAX_QUOTED_REL_NAME_LEN];
1744  char fkrelname[MAX_QUOTED_REL_NAME_LEN];
1745  char pkattname[MAX_QUOTED_NAME_LEN + 3];
1746  char fkattname[MAX_QUOTED_NAME_LEN + 3];
1747  const char *sep;
1748  const char *fk_only;
1749  int save_nestlevel;
1750  char workmembuf[32];
1751  int spi_result;
1752  SPIPlanPtr qplan;
1753  int i;
1754 
1755  riinfo = ri_FetchConstraintInfo(trigger, fk_rel, false);
1756 
1757  /*
1758  * We don't check permissions before displaying the error message, on the
1759  * assumption that the user detaching the partition must have enough
1760  * privileges to examine the table contents anyhow.
1761  */
1762 
1763  /*----------
1764  * The query string built is:
1765  * SELECT fk.keycols FROM [ONLY] relname fk
1766  * JOIN pkrelname pk
1767  * ON (pk.pkkeycol1=fk.keycol1 [AND ...])
1768  * WHERE (<partition constraint>) AND
1769  * For MATCH SIMPLE:
1770  * (fk.keycol1 IS NOT NULL [AND ...])
1771  * For MATCH FULL:
1772  * (fk.keycol1 IS NOT NULL [OR ...])
1773  *
1774  * We attach COLLATE clauses to the operators when comparing columns
1775  * that have different collations.
1776  *----------
1777  */
1778  initStringInfo(&querybuf);
1779  appendStringInfoString(&querybuf, "SELECT ");
1780  sep = "";
1781  for (i = 0; i < riinfo->nkeys; i++)
1782  {
1783  quoteOneName(fkattname,
1784  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1785  appendStringInfo(&querybuf, "%sfk.%s", sep, fkattname);
1786  sep = ", ";
1787  }
1788 
1789  quoteRelationName(pkrelname, pk_rel);
1790  quoteRelationName(fkrelname, fk_rel);
1791  fk_only = fk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ?
1792  "" : "ONLY ";
1793  appendStringInfo(&querybuf,
1794  " FROM %s%s fk JOIN %s pk ON",
1795  fk_only, fkrelname, pkrelname);
1796  strcpy(pkattname, "pk.");
1797  strcpy(fkattname, "fk.");
1798  sep = "(";
1799  for (i = 0; i < riinfo->nkeys; i++)
1800  {
1801  Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]);
1802  Oid fk_type = RIAttType(fk_rel, riinfo->fk_attnums[i]);
1803  Oid pk_coll = RIAttCollation(pk_rel, riinfo->pk_attnums[i]);
1804  Oid fk_coll = RIAttCollation(fk_rel, riinfo->fk_attnums[i]);
1805 
1806  quoteOneName(pkattname + 3,
1807  RIAttName(pk_rel, riinfo->pk_attnums[i]));
1808  quoteOneName(fkattname + 3,
1809  RIAttName(fk_rel, riinfo->fk_attnums[i]));
1810  ri_GenerateQual(&querybuf, sep,
1811  pkattname, pk_type,
1812  riinfo->pf_eq_oprs[i],
1813  fkattname, fk_type);
1814  if (pk_coll != fk_coll)
1815  ri_GenerateQualCollation(&querybuf, pk_coll);
1816  sep = "AND";
1817  }
1818 
1819  /*
1820  * Start the WHERE clause with the partition constraint (except if this is
1821  * the default partition and there's no other partition, because the
1822  * partition constraint is the empty string in that case.)
1823  */
1824  constraintDef = pg_get_partconstrdef_string(RelationGetRelid(pk_rel), "pk");
1825  if (constraintDef && constraintDef[0] != '\0')
1826  appendStringInfo(&querybuf, ") WHERE %s AND (",
1827  constraintDef);
1828  else
1829  appendStringInfoString(&querybuf, ") WHERE (");
1830 
1831  sep = "";
1832  for (i = 0; i < riinfo->nkeys; i++)
1833  {
1834  quoteOneName(fkattname, RIAttName(fk_rel, riinfo->fk_attnums[i]));
1835  appendStringInfo(&querybuf,
1836  "%sfk.%s IS NOT NULL",
1837  sep, fkattname);
1838  switch (riinfo->confmatchtype)
1839  {
1840  case FKCONSTR_MATCH_SIMPLE:
1841  sep = " AND ";
1842  break;
1843  case FKCONSTR_MATCH_FULL:
1844  sep = " OR ";
1845  break;
1846  }
1847  }
1848  appendStringInfoChar(&querybuf, ')');
1849 
1850  /*
1851  * Temporarily increase work_mem so that the check query can be executed
1852  * more efficiently. It seems okay to do this because the query is simple
1853  * enough to not use a multiple of work_mem, and one typically would not
1854  * have many large foreign-key validations happening concurrently. So
1855  * this seems to meet the criteria for being considered a "maintenance"
1856  * operation, and accordingly we use maintenance_work_mem. However, we
1857  * must also set hash_mem_multiplier to 1, since it is surely not okay to
1858  * let that get applied to the maintenance_work_mem value.
1859  *
1860  * We use the equivalent of a function SET option to allow the setting to
1861  * persist for exactly the duration of the check query. guc.c also takes
1862  * care of undoing the setting on error.
1863  */
1864  save_nestlevel = NewGUCNestLevel();
1865 
1866  snprintf(workmembuf, sizeof(workmembuf), "%d", maintenance_work_mem);
1867  (void) set_config_option("work_mem", workmembuf,
1869  GUC_ACTION_SAVE, true, 0, false);
1870  (void) set_config_option("hash_mem_multiplier", "1",
1872  GUC_ACTION_SAVE, true, 0, false);
1873 
1874  if (SPI_connect() != SPI_OK_CONNECT)
1875  elog(ERROR, "SPI_connect failed");
1876 
1877  /*
1878  * Generate the plan. We don't need to cache it, and there are no
1879  * arguments to the plan.
1880  */
1881  qplan = SPI_prepare(querybuf.data, 0, NULL);
1882 
1883  if (qplan == NULL)
1884  elog(ERROR, "SPI_prepare returned %s for %s",
1886 
1887  /*
1888  * Run the plan. For safety we force a current snapshot to be used. (In
1889  * transaction-snapshot mode, this arguably violates transaction isolation
1890  * rules, but we really haven't got much choice.) We don't need to
1891  * register the snapshot, because SPI_execute_snapshot will see to it. We
1892  * need at most one tuple returned, so pass limit = 1.
1893  */
1894  spi_result = SPI_execute_snapshot(qplan,
1895  NULL, NULL,
1898  true, false, 1);
1899 
1900  /* Check result */
1901  if (spi_result != SPI_OK_SELECT)
1902  elog(ERROR, "SPI_execute_snapshot returned %s", SPI_result_code_string(spi_result));
1903 
1904  /* Did we find a tuple that would violate the constraint? */
1905  if (SPI_processed > 0)
1906  {
1907  TupleTableSlot *slot;
1908  HeapTuple tuple = SPI_tuptable->vals[0];
1909  TupleDesc tupdesc = SPI_tuptable->tupdesc;
1910  RI_ConstraintInfo fake_riinfo;
1911 
1912  slot = MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual);
1913 
1914  heap_deform_tuple(tuple, tupdesc,
1915  slot->tts_values, slot->tts_isnull);
1916  ExecStoreVirtualTuple(slot);
1917 
1918  /*
1919  * The columns to look at in the result tuple are 1..N, not whatever
1920  * they are in the fk_rel. Hack up riinfo so that ri_ReportViolation
1921  * will behave properly.
1922  *
1923  * In addition to this, we have to pass the correct tupdesc to
1924  * ri_ReportViolation, overriding its normal habit of using the pk_rel
1925  * or fk_rel's tupdesc.
1926  */
1927  memcpy(&fake_riinfo, riinfo, sizeof(RI_ConstraintInfo));
1928  for (i = 0; i < fake_riinfo.nkeys; i++)
1929  fake_riinfo.pk_attnums[i] = i + 1;
1930 
1931  ri_ReportViolation(&fake_riinfo, pk_rel, fk_rel,
1932  slot, tupdesc, 0, true);
1933  }
1934 
1935  if (SPI_finish() != SPI_OK_FINISH)
1936  elog(ERROR, "SPI_finish failed");
1937 
1938  /*
1939  * Restore work_mem and hash_mem_multiplier.
1940  */
1941  AtEOXact_GUC(true, save_nestlevel);
1942 }
1943 
1944 
1945 /* ----------
1946  * Local functions below
1947  * ----------
1948  */
1949 
1950 
1951 /*
1952  * quoteOneName --- safely quote a single SQL name
1953  *
1954  * buffer must be MAX_QUOTED_NAME_LEN long (includes room for \0)
1955  */
1956 static void
1957 quoteOneName(char *buffer, const char *name)
1958 {
1959  /* Rather than trying to be smart, just always quote it. */
1960  *buffer++ = '"';
1961  while (*name)
1962  {
1963  if (*name == '"')
1964  *buffer++ = '"';
1965  *buffer++ = *name++;
1966  }
1967  *buffer++ = '"';
1968  *buffer = '\0';
1969 }
1970 
1971 /*
1972  * quoteRelationName --- safely quote a fully qualified relation name
1973  *
1974  * buffer must be MAX_QUOTED_REL_NAME_LEN long (includes room for \0)
1975  */
1976 static void
1977 quoteRelationName(char *buffer, Relation rel)
1978 {
1980  buffer += strlen(buffer);
1981  *buffer++ = '.';
1982  quoteOneName(buffer, RelationGetRelationName(rel));
1983 }
1984 
1985 /*
1986  * ri_GenerateQual --- generate a WHERE clause equating two variables
1987  *
1988  * This basically appends " sep leftop op rightop" to buf, adding casts
1989  * and schema qualification as needed to ensure that the parser will select
1990  * the operator we specify. leftop and rightop should be parenthesized
1991  * if they aren't variables or parameters.
1992  */
1993 static void
1995  const char *sep,
1996  const char *leftop, Oid leftoptype,
1997  Oid opoid,
1998  const char *rightop, Oid rightoptype)
1999 {
2000  appendStringInfo(buf, " %s ", sep);
2001  generate_operator_clause(buf, leftop, leftoptype, opoid,
2002  rightop, rightoptype);
2003 }
2004 
2005 /*
2006  * ri_GenerateQualCollation --- add a COLLATE spec to a WHERE clause
2007  *
2008  * At present, we intentionally do not use this function for RI queries that
2009  * compare a variable to a $n parameter. Since parameter symbols always have
2010  * default collation, the effect will be to use the variable's collation.
2011  * Now that is only strictly correct when testing the referenced column, since
2012  * the SQL standard specifies that RI comparisons should use the referenced
2013  * column's collation. However, so long as all collations have the same
2014  * notion of equality (which they do, because texteq reduces to bitwise
2015  * equality), there's no visible semantic impact from using the referencing
2016  * column's collation when testing it, and this is a good thing to do because
2017  * it lets us use a normal index on the referencing column. However, we do
2018  * have to use this function when directly comparing the referencing and
2019  * referenced columns, if they are of different collations; else the parser
2020  * will fail to resolve the collation to use.
2021  */
2022 static void
2024 {
2025  HeapTuple tp;
2026  Form_pg_collation colltup;
2027  char *collname;
2028  char onename[MAX_QUOTED_NAME_LEN];
2029 
2030  /* Nothing to do if it's a noncollatable data type */
2031  if (!OidIsValid(collation))
2032  return;
2033 
2034  tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation));
2035  if (!HeapTupleIsValid(tp))
2036  elog(ERROR, "cache lookup failed for collation %u", collation);
2037  colltup = (Form_pg_collation) GETSTRUCT(tp);
2038  collname = NameStr(colltup->collname);
2039 
2040  /*
2041  * We qualify the name always, for simplicity and to ensure the query is
2042  * not search-path-dependent.
2043  */
2044  quoteOneName(onename, get_namespace_name(colltup->collnamespace));
2045  appendStringInfo(buf, " COLLATE %s", onename);
2046  quoteOneName(onename, collname);
2047  appendStringInfo(buf, ".%s", onename);
2048 
2049  ReleaseSysCache(tp);
2050 }
2051 
2052 /* ----------
2053  * ri_BuildQueryKey -
2054  *
2055  * Construct a hashtable key for a prepared SPI plan of an FK constraint.
2056  *
2057  * key: output argument, *key is filled in based on the other arguments
2058  * riinfo: info derived from pg_constraint entry
2059  * constr_queryno: an internal number identifying the query type
2060  * (see RI_PLAN_XXX constants at head of file)
2061  * ----------
2062  */
2063 static void
2065  int32 constr_queryno)
2066 {
2067  /*
2068  * Inherited constraints with a common ancestor can share ri_query_cache
2069  * entries for all query types except RI_PLAN_CHECK_LOOKUPPK_FROM_PK.
2070  * Except in that case, the query processes the other table involved in
2071  * the FK constraint (i.e., not the table on which the trigger has been
2072  * fired), and so it will be the same for all members of the inheritance
2073  * tree. So we may use the root constraint's OID in the hash key, rather
2074  * than the constraint's own OID. This avoids creating duplicate SPI
2075  * plans, saving lots of work and memory when there are many partitions
2076  * with similar FK constraints.
2077  *
2078  * (Note that we must still have a separate RI_ConstraintInfo for each
2079  * constraint, because partitions can have different column orders,
2080  * resulting in different pk_attnums[] or fk_attnums[] array contents.)
2081  *
2082  * We assume struct RI_QueryKey contains no padding bytes, else we'd need
2083  * to use memset to clear them.
2084  */
2085  if (constr_queryno != RI_PLAN_CHECK_LOOKUPPK_FROM_PK)
2086  key->constr_id = riinfo->constraint_root_id;
2087  else
2088  key->constr_id = riinfo->constraint_id;
2089  key->constr_queryno = constr_queryno;
2090 }
2091 
2092 /*
2093  * Check that RI trigger function was called in expected context
2094  */
2095 static void
2096 ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname, int tgkind)
2097 {
2098  TriggerData *trigdata = (TriggerData *) fcinfo->context;
2099 
2100  if (!CALLED_AS_TRIGGER(fcinfo))
2101  ereport(ERROR,
2102  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2103  errmsg("function \"%s\" was not called by trigger manager", funcname)));
2104 
2105  /*
2106  * Check proper event
2107  */
2108  if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) ||
2109  !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
2110  ereport(ERROR,
2111  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2112  errmsg("function \"%s\" must be fired AFTER ROW", funcname)));
2113 
2114  switch (tgkind)
2115  {
2116  case RI_TRIGTYPE_INSERT:
2117  if (!TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
2118  ereport(ERROR,
2119  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2120  errmsg("function \"%s\" must be fired for INSERT", funcname)));
2121  break;
2122  case RI_TRIGTYPE_UPDATE:
2123  if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
2124  ereport(ERROR,
2125  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2126  errmsg("function \"%s\" must be fired for UPDATE", funcname)));
2127  break;
2128  case RI_TRIGTYPE_DELETE:
2129  if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
2130  ereport(ERROR,
2131  (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
2132  errmsg("function \"%s\" must be fired for DELETE", funcname)));
2133  break;
2134  }
2135 }
2136 
2137 
2138 /*
2139  * Fetch the RI_ConstraintInfo struct for the trigger's FK constraint.
2140  */
2141 static const RI_ConstraintInfo *
2142 ri_FetchConstraintInfo(Trigger *trigger, Relation trig_rel, bool rel_is_pk)
2143 {
2144  Oid constraintOid = trigger->tgconstraint;
2145  const RI_ConstraintInfo *riinfo;
2146 
2147  /*
2148  * Check that the FK constraint's OID is available; it might not be if
2149  * we've been invoked via an ordinary trigger or an old-style "constraint
2150  * trigger".
2151  */
2152  if (!OidIsValid(constraintOid))
2153  ereport(ERROR,
2154  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2155  errmsg("no pg_constraint entry for trigger \"%s\" on table \"%s\"",
2156  trigger->tgname, RelationGetRelationName(trig_rel)),
2157  errhint("Remove this referential integrity trigger and its mates, then do ALTER TABLE ADD CONSTRAINT.")));
2158 
2159  /* Find or create a hashtable entry for the constraint */
2160  riinfo = ri_LoadConstraintInfo(constraintOid);
2161 
2162  /* Do some easy cross-checks against the trigger call data */
2163  if (rel_is_pk)
2164  {
2165  if (riinfo->fk_relid != trigger->tgconstrrelid ||
2166  riinfo->pk_relid != RelationGetRelid(trig_rel))
2167  elog(ERROR, "wrong pg_constraint entry for trigger \"%s\" on table \"%s\"",
2168  trigger->tgname, RelationGetRelationName(trig_rel));
2169  }
2170  else
2171  {
2172  if (riinfo->fk_relid != RelationGetRelid(trig_rel) ||
2173  riinfo->pk_relid != trigger->tgconstrrelid)
2174  elog(ERROR, "wrong pg_constraint entry for trigger \"%s\" on table \"%s\"",
2175  trigger->tgname, RelationGetRelationName(trig_rel));
2176  }
2177 
2178  if (riinfo->confmatchtype != FKCONSTR_MATCH_FULL &&
2181  elog(ERROR, "unrecognized confmatchtype: %d",
2182  riinfo->confmatchtype);
2183 
2184  if (riinfo->confmatchtype == FKCONSTR_MATCH_PARTIAL)
2185  ereport(ERROR,
2186  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2187  errmsg("MATCH PARTIAL not yet implemented")));
2188 
2189  return riinfo;
2190 }
2191 
2192 /*
2193  * Fetch or create the RI_ConstraintInfo struct for an FK constraint.
2194  */
2195 static const RI_ConstraintInfo *
2197 {
2198  RI_ConstraintInfo *riinfo;
2199  bool found;
2200  HeapTuple tup;
2201  Form_pg_constraint conForm;
2202 
2203  /*
2204  * On the first call initialize the hashtable
2205  */
2206  if (!ri_constraint_cache)
2208 
2209  /*
2210  * Find or create a hash entry. If we find a valid one, just return it.
2211  */
2213  &constraintOid,
2214  HASH_ENTER, &found);
2215  if (!found)
2216  riinfo->valid = false;
2217  else if (riinfo->valid)
2218  return riinfo;
2219 
2220  /*
2221  * Fetch the pg_constraint row so we can fill in the entry.
2222  */
2223  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
2224  if (!HeapTupleIsValid(tup)) /* should not happen */
2225  elog(ERROR, "cache lookup failed for constraint %u", constraintOid);
2226  conForm = (Form_pg_constraint) GETSTRUCT(tup);
2227 
2228  if (conForm->contype != CONSTRAINT_FOREIGN) /* should not happen */
2229  elog(ERROR, "constraint %u is not a foreign key constraint",
2230  constraintOid);
2231 
2232  /* And extract data */
2233  Assert(riinfo->constraint_id == constraintOid);
2234  if (OidIsValid(conForm->conparentid))
2235  riinfo->constraint_root_id =
2236  get_ri_constraint_root(conForm->conparentid);
2237  else
2238  riinfo->constraint_root_id = constraintOid;
2239  riinfo->oidHashValue = GetSysCacheHashValue1(CONSTROID,
2240  ObjectIdGetDatum(constraintOid));
2241  riinfo->rootHashValue = GetSysCacheHashValue1(CONSTROID,
2243  memcpy(&riinfo->conname, &conForm->conname, sizeof(NameData));
2244  riinfo->pk_relid = conForm->confrelid;
2245  riinfo->fk_relid = conForm->conrelid;
2246  riinfo->confupdtype = conForm->confupdtype;
2247  riinfo->confdeltype = conForm->confdeltype;
2248  riinfo->confmatchtype = conForm->confmatchtype;
2249  riinfo->hasperiod = conForm->conperiod;
2250 
2252  &riinfo->nkeys,
2253  riinfo->fk_attnums,
2254  riinfo->pk_attnums,
2255  riinfo->pf_eq_oprs,
2256  riinfo->pp_eq_oprs,
2257  riinfo->ff_eq_oprs,
2258  &riinfo->ndelsetcols,
2259  riinfo->confdelsetcols);
2260 
2261  /*
2262  * For temporal FKs, get the operators and functions we need. We ask the
2263  * opclass of the PK element for these. This all gets cached (as does the
2264  * generated plan), so there's no performance issue.
2265  */
2266  if (riinfo->hasperiod)
2267  {
2268  Oid opclass = get_index_column_opclass(conForm->conindid, riinfo->nkeys);
2269 
2270  FindFKPeriodOpers(opclass,
2271  &riinfo->period_contained_by_oper,
2273  }
2274 
2275  ReleaseSysCache(tup);
2276 
2277  /*
2278  * For efficient processing of invalidation messages below, we keep a
2279  * doubly-linked count list of all currently valid entries.
2280  */
2282 
2283  riinfo->valid = true;
2284 
2285  return riinfo;
2286 }
2287 
2288 /*
2289  * get_ri_constraint_root
2290  * Returns the OID of the constraint's root parent
2291  */
2292 static Oid
2294 {
2295  for (;;)
2296  {
2297  HeapTuple tuple;
2298  Oid constrParentOid;
2299 
2300  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constrOid));
2301  if (!HeapTupleIsValid(tuple))
2302  elog(ERROR, "cache lookup failed for constraint %u", constrOid);
2303  constrParentOid = ((Form_pg_constraint) GETSTRUCT(tuple))->conparentid;
2304  ReleaseSysCache(tuple);
2305  if (!OidIsValid(constrParentOid))
2306  break; /* we reached the root constraint */
2307  constrOid = constrParentOid;
2308  }
2309  return constrOid;
2310 }
2311 
2312 /*
2313  * Callback for pg_constraint inval events
2314  *
2315  * While most syscache callbacks just flush all their entries, pg_constraint
2316  * gets enough update traffic that it's probably worth being smarter.
2317  * Invalidate any ri_constraint_cache entry associated with the syscache
2318  * entry with the specified hash value, or all entries if hashvalue == 0.
2319  *
2320  * Note: at the time a cache invalidation message is processed there may be
2321  * active references to the cache. Because of this we never remove entries
2322  * from the cache, but only mark them invalid, which is harmless to active
2323  * uses. (Any query using an entry should hold a lock sufficient to keep that
2324  * data from changing under it --- but we may get cache flushes anyway.)
2325  */
2326 static void
2328 {
2329  dlist_mutable_iter iter;
2330 
2331  Assert(ri_constraint_cache != NULL);
2332 
2333  /*
2334  * If the list of currently valid entries gets excessively large, we mark
2335  * them all invalid so we can empty the list. This arrangement avoids
2336  * O(N^2) behavior in situations where a session touches many foreign keys
2337  * and also does many ALTER TABLEs, such as a restore from pg_dump.
2338  */
2340  hashvalue = 0; /* pretend it's a cache reset */
2341 
2343  {
2345  valid_link, iter.cur);
2346 
2347  /*
2348  * We must invalidate not only entries directly matching the given
2349  * hash value, but also child entries, in case the invalidation
2350  * affects a root constraint.
2351  */
2352  if (hashvalue == 0 ||
2353  riinfo->oidHashValue == hashvalue ||
2354  riinfo->rootHashValue == hashvalue)
2355  {
2356  riinfo->valid = false;
2357  /* Remove invalidated entries from the list, too */
2359  }
2360  }
2361 }
2362 
2363 
2364 /*
2365  * Prepare execution plan for a query to enforce an RI restriction
2366  */
2367 static SPIPlanPtr
2368 ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
2369  RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel)
2370 {
2371  SPIPlanPtr qplan;
2372  Relation query_rel;
2373  Oid save_userid;
2374  int save_sec_context;
2375 
2376  /*
2377  * Use the query type code to determine whether the query is run against
2378  * the PK or FK table; we'll do the check as that table's owner
2379  */
2380  if (qkey->constr_queryno <= RI_PLAN_LAST_ON_PK)
2381  query_rel = pk_rel;
2382  else
2383  query_rel = fk_rel;
2384 
2385  /* Switch to proper UID to perform check as */
2386  GetUserIdAndSecContext(&save_userid, &save_sec_context);
2387  SetUserIdAndSecContext(RelationGetForm(query_rel)->relowner,
2388  save_sec_context | SECURITY_LOCAL_USERID_CHANGE |
2390 
2391  /* Create the plan */
2392  qplan = SPI_prepare(querystr, nargs, argtypes);
2393 
2394  if (qplan == NULL)
2395  elog(ERROR, "SPI_prepare returned %s for %s", SPI_result_code_string(SPI_result), querystr);
2396 
2397  /* Restore UID and security context */
2398  SetUserIdAndSecContext(save_userid, save_sec_context);
2399 
2400  /* Save the plan */
2401  SPI_keepplan(qplan);
2402  ri_HashPreparedPlan(qkey, qplan);
2403 
2404  return qplan;
2405 }
2406 
2407 /*
2408  * Perform a query to enforce an RI restriction
2409  */
2410 static bool
2412  RI_QueryKey *qkey, SPIPlanPtr qplan,
2413  Relation fk_rel, Relation pk_rel,
2414  TupleTableSlot *oldslot, TupleTableSlot *newslot,
2415  bool detectNewRows, int expect_OK)
2416 {
2417  Relation query_rel,
2418  source_rel;
2419  bool source_is_pk;
2420  Snapshot test_snapshot;
2421  Snapshot crosscheck_snapshot;
2422  int limit;
2423  int spi_result;
2424  Oid save_userid;
2425  int save_sec_context;
2426  Datum vals[RI_MAX_NUMKEYS * 2];
2427  char nulls[RI_MAX_NUMKEYS * 2];
2428 
2429  /*
2430  * Use the query type code to determine whether the query is run against
2431  * the PK or FK table; we'll do the check as that table's owner
2432  */
2433  if (qkey->constr_queryno <= RI_PLAN_LAST_ON_PK)
2434  query_rel = pk_rel;
2435  else
2436  query_rel = fk_rel;
2437 
2438  /*
2439  * The values for the query are taken from the table on which the trigger
2440  * is called - it is normally the other one with respect to query_rel. An
2441  * exception is ri_Check_Pk_Match(), which uses the PK table for both (and
2442  * sets queryno to RI_PLAN_CHECK_LOOKUPPK_FROM_PK). We might eventually
2443  * need some less klugy way to determine this.
2444  */
2446  {
2447  source_rel = fk_rel;
2448  source_is_pk = false;
2449  }
2450  else
2451  {
2452  source_rel = pk_rel;
2453  source_is_pk = true;
2454  }
2455 
2456  /* Extract the parameters to be passed into the query */
2457  if (newslot)
2458  {
2459  ri_ExtractValues(source_rel, newslot, riinfo, source_is_pk,
2460  vals, nulls);
2461  if (oldslot)
2462  ri_ExtractValues(source_rel, oldslot, riinfo, source_is_pk,
2463  vals + riinfo->nkeys, nulls + riinfo->nkeys);
2464  }
2465  else
2466  {
2467  ri_ExtractValues(source_rel, oldslot, riinfo, source_is_pk,
2468  vals, nulls);
2469  }
2470 
2471  /*
2472  * In READ COMMITTED mode, we just need to use an up-to-date regular
2473  * snapshot, and we will see all rows that could be interesting. But in
2474  * transaction-snapshot mode, we can't change the transaction snapshot. If
2475  * the caller passes detectNewRows == false then it's okay to do the query
2476  * with the transaction snapshot; otherwise we use a current snapshot, and
2477  * tell the executor to error out if it finds any rows under the current
2478  * snapshot that wouldn't be visible per the transaction snapshot. Note
2479  * that SPI_execute_snapshot will register the snapshots, so we don't need
2480  * to bother here.
2481  */
2482  if (IsolationUsesXactSnapshot() && detectNewRows)
2483  {
2484  CommandCounterIncrement(); /* be sure all my own work is visible */
2485  test_snapshot = GetLatestSnapshot();
2486  crosscheck_snapshot = GetTransactionSnapshot();
2487  }
2488  else
2489  {
2490  /* the default SPI behavior is okay */
2491  test_snapshot = InvalidSnapshot;
2492  crosscheck_snapshot = InvalidSnapshot;
2493  }
2494 
2495  /*
2496  * If this is a select query (e.g., for a 'no action' or 'restrict'
2497  * trigger), we only need to see if there is a single row in the table,
2498  * matching the key. Otherwise, limit = 0 - because we want the query to
2499  * affect ALL the matching rows.
2500  */
2501  limit = (expect_OK == SPI_OK_SELECT) ? 1 : 0;
2502 
2503  /* Switch to proper UID to perform check as */
2504  GetUserIdAndSecContext(&save_userid, &save_sec_context);
2505  SetUserIdAndSecContext(RelationGetForm(query_rel)->relowner,
2506  save_sec_context | SECURITY_LOCAL_USERID_CHANGE |
2508 
2509  /* Finally we can run the query. */
2510  spi_result = SPI_execute_snapshot(qplan,
2511  vals, nulls,
2512  test_snapshot, crosscheck_snapshot,
2513  false, false, limit);
2514 
2515  /* Restore UID and security context */
2516  SetUserIdAndSecContext(save_userid, save_sec_context);
2517 
2518  /* Check result */
2519  if (spi_result < 0)
2520  elog(ERROR, "SPI_execute_snapshot returned %s", SPI_result_code_string(spi_result));
2521 
2522  if (expect_OK >= 0 && spi_result != expect_OK)
2523  ereport(ERROR,
2524  (errcode(ERRCODE_INTERNAL_ERROR),
2525  errmsg("referential integrity query on \"%s\" from constraint \"%s\" on \"%s\" gave unexpected result",
2526  RelationGetRelationName(pk_rel),
2527  NameStr(riinfo->conname),
2528  RelationGetRelationName(fk_rel)),
2529  errhint("This is most likely due to a rule having rewritten the query.")));
2530 
2531  /* XXX wouldn't it be clearer to do this part at the caller? */
2533  expect_OK == SPI_OK_SELECT &&
2535  ri_ReportViolation(riinfo,
2536  pk_rel, fk_rel,
2537  newslot ? newslot : oldslot,
2538  NULL,
2539  qkey->constr_queryno, false);
2540 
2541  return SPI_processed != 0;
2542 }
2543 
2544 /*
2545  * Extract fields from a tuple into Datum/nulls arrays
2546  */
2547 static void
2549  const RI_ConstraintInfo *riinfo, bool rel_is_pk,
2550  Datum *vals, char *nulls)
2551 {
2552  const int16 *attnums;
2553  bool isnull;
2554 
2555  if (rel_is_pk)
2556  attnums = riinfo->pk_attnums;
2557  else
2558  attnums = riinfo->fk_attnums;
2559 
2560  for (int i = 0; i < riinfo->nkeys; i++)
2561  {
2562  vals[i] = slot_getattr(slot, attnums[i], &isnull);
2563  nulls[i] = isnull ? 'n' : ' ';
2564  }
2565 }
2566 
2567 /*
2568  * Produce an error report
2569  *
2570  * If the failed constraint was on insert/update to the FK table,
2571  * we want the key names and values extracted from there, and the error
2572  * message to look like 'key blah is not present in PK'.
2573  * Otherwise, the attr names and values come from the PK table and the
2574  * message looks like 'key blah is still referenced from FK'.
2575  */
2576 static void
2578  Relation pk_rel, Relation fk_rel,
2579  TupleTableSlot *violatorslot, TupleDesc tupdesc,
2580  int queryno, bool partgone)
2581 {
2582  StringInfoData key_names;
2583  StringInfoData key_values;
2584  bool onfk;
2585  const int16 *attnums;
2586  Oid rel_oid;
2587  AclResult aclresult;
2588  bool has_perm = true;
2589 
2590  /*
2591  * Determine which relation to complain about. If tupdesc wasn't passed
2592  * by caller, assume the violator tuple came from there.
2593  */
2594  onfk = (queryno == RI_PLAN_CHECK_LOOKUPPK);
2595  if (onfk)
2596  {
2597  attnums = riinfo->fk_attnums;
2598  rel_oid = fk_rel->rd_id;
2599  if (tupdesc == NULL)
2600  tupdesc = fk_rel->rd_att;
2601  }
2602  else
2603  {
2604  attnums = riinfo->pk_attnums;
2605  rel_oid = pk_rel->rd_id;
2606  if (tupdesc == NULL)
2607  tupdesc = pk_rel->rd_att;
2608  }
2609 
2610  /*
2611  * Check permissions- if the user does not have access to view the data in
2612  * any of the key columns then we don't include the errdetail() below.
2613  *
2614  * Check if RLS is enabled on the relation first. If so, we don't return
2615  * any specifics to avoid leaking data.
2616  *
2617  * Check table-level permissions next and, failing that, column-level
2618  * privileges.
2619  *
2620  * When a partition at the referenced side is being detached/dropped, we
2621  * needn't check, since the user must be the table owner anyway.
2622  */
2623  if (partgone)
2624  has_perm = true;
2625  else if (check_enable_rls(rel_oid, InvalidOid, true) != RLS_ENABLED)
2626  {
2627  aclresult = pg_class_aclcheck(rel_oid, GetUserId(), ACL_SELECT);
2628  if (aclresult != ACLCHECK_OK)
2629  {
2630  /* Try for column-level permissions */
2631  for (int idx = 0; idx < riinfo->nkeys; idx++)
2632  {
2633  aclresult = pg_attribute_aclcheck(rel_oid, attnums[idx],
2634  GetUserId(),
2635  ACL_SELECT);
2636 
2637  /* No access to the key */
2638  if (aclresult != ACLCHECK_OK)
2639  {
2640  has_perm = false;
2641  break;
2642  }
2643  }
2644  }
2645  }
2646  else
2647  has_perm = false;
2648 
2649  if (has_perm)
2650  {
2651  /* Get printable versions of the keys involved */
2652  initStringInfo(&key_names);
2653  initStringInfo(&key_values);
2654  for (int idx = 0; idx < riinfo->nkeys; idx++)
2655  {
2656  int fnum = attnums[idx];
2657  Form_pg_attribute att = TupleDescAttr(tupdesc, fnum - 1);
2658  char *name,
2659  *val;
2660  Datum datum;
2661  bool isnull;
2662 
2663  name = NameStr(att->attname);
2664 
2665  datum = slot_getattr(violatorslot, fnum, &isnull);
2666  if (!isnull)
2667  {
2668  Oid foutoid;
2669  bool typisvarlena;
2670 
2671  getTypeOutputInfo(att->atttypid, &foutoid, &typisvarlena);
2672  val = OidOutputFunctionCall(foutoid, datum);
2673  }
2674  else
2675  val = "null";
2676 
2677  if (idx > 0)
2678  {
2679  appendStringInfoString(&key_names, ", ");
2680  appendStringInfoString(&key_values, ", ");
2681  }
2682  appendStringInfoString(&key_names, name);
2683  appendStringInfoString(&key_values, val);
2684  }
2685  }
2686 
2687  if (partgone)
2688  ereport(ERROR,
2689  (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
2690  errmsg("removing partition \"%s\" violates foreign key constraint \"%s\"",
2691  RelationGetRelationName(pk_rel),
2692  NameStr(riinfo->conname)),
2693  errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
2694  key_names.data, key_values.data,
2695  RelationGetRelationName(fk_rel)),
2696  errtableconstraint(fk_rel, NameStr(riinfo->conname))));
2697  else if (onfk)
2698  ereport(ERROR,
2699  (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
2700  errmsg("insert or update on table \"%s\" violates foreign key constraint \"%s\"",
2701  RelationGetRelationName(fk_rel),
2702  NameStr(riinfo->conname)),
2703  has_perm ?
2704  errdetail("Key (%s)=(%s) is not present in table \"%s\".",
2705  key_names.data, key_values.data,
2706  RelationGetRelationName(pk_rel)) :
2707  errdetail("Key is not present in table \"%s\".",
2708  RelationGetRelationName(pk_rel)),
2709  errtableconstraint(fk_rel, NameStr(riinfo->conname))));
2710  else
2711  ereport(ERROR,
2712  (errcode(ERRCODE_FOREIGN_KEY_VIOLATION),
2713  errmsg("update or delete on table \"%s\" violates foreign key constraint \"%s\" on table \"%s\"",
2714  RelationGetRelationName(pk_rel),
2715  NameStr(riinfo->conname),
2716  RelationGetRelationName(fk_rel)),
2717  has_perm ?
2718  errdetail("Key (%s)=(%s) is still referenced from table \"%s\".",
2719  key_names.data, key_values.data,
2720  RelationGetRelationName(fk_rel)) :
2721  errdetail("Key is still referenced from table \"%s\".",
2722  RelationGetRelationName(fk_rel)),
2723  errtableconstraint(fk_rel, NameStr(riinfo->conname))));
2724 }
2725 
2726 
2727 /*
2728  * ri_NullCheck -
2729  *
2730  * Determine the NULL state of all key values in a tuple
2731  *
2732  * Returns one of RI_KEYS_ALL_NULL, RI_KEYS_NONE_NULL or RI_KEYS_SOME_NULL.
2733  */
2734 static int
2736  TupleTableSlot *slot,
2737  const RI_ConstraintInfo *riinfo, bool rel_is_pk)
2738 {
2739  const int16 *attnums;
2740  bool allnull = true;
2741  bool nonenull = true;
2742 
2743  if (rel_is_pk)
2744  attnums = riinfo->pk_attnums;
2745  else
2746  attnums = riinfo->fk_attnums;
2747 
2748  for (int i = 0; i < riinfo->nkeys; i++)
2749  {
2750  if (slot_attisnull(slot, attnums[i]))
2751  nonenull = false;
2752  else
2753  allnull = false;
2754  }
2755 
2756  if (allnull)
2757  return RI_KEYS_ALL_NULL;
2758 
2759  if (nonenull)
2760  return RI_KEYS_NONE_NULL;
2761 
2762  return RI_KEYS_SOME_NULL;
2763 }
2764 
2765 
2766 /*
2767  * ri_InitHashTables -
2768  *
2769  * Initialize our internal hash tables.
2770  */
2771 static void
2773 {
2774  HASHCTL ctl;
2775 
2776  ctl.keysize = sizeof(Oid);
2777  ctl.entrysize = sizeof(RI_ConstraintInfo);
2778  ri_constraint_cache = hash_create("RI constraint cache",
2780  &ctl, HASH_ELEM | HASH_BLOBS);
2781 
2782  /* Arrange to flush cache on pg_constraint changes */
2785  (Datum) 0);
2786 
2787  ctl.keysize = sizeof(RI_QueryKey);
2788  ctl.entrysize = sizeof(RI_QueryHashEntry);
2789  ri_query_cache = hash_create("RI query cache",
2791  &ctl, HASH_ELEM | HASH_BLOBS);
2792 
2793  ctl.keysize = sizeof(RI_CompareKey);
2794  ctl.entrysize = sizeof(RI_CompareHashEntry);
2795  ri_compare_cache = hash_create("RI compare cache",
2797  &ctl, HASH_ELEM | HASH_BLOBS);
2798 }
2799 
2800 
2801 /*
2802  * ri_FetchPreparedPlan -
2803  *
2804  * Lookup for a query key in our private hash table of prepared
2805  * and saved SPI execution plans. Return the plan if found or NULL.
2806  */
2807 static SPIPlanPtr
2809 {
2810  RI_QueryHashEntry *entry;
2811  SPIPlanPtr plan;
2812 
2813  /*
2814  * On the first call initialize the hashtable
2815  */
2816  if (!ri_query_cache)
2818 
2819  /*
2820  * Lookup for the key
2821  */
2823  key,
2824  HASH_FIND, NULL);
2825  if (entry == NULL)
2826  return NULL;
2827 
2828  /*
2829  * Check whether the plan is still valid. If it isn't, we don't want to
2830  * simply rely on plancache.c to regenerate it; rather we should start
2831  * from scratch and rebuild the query text too. This is to cover cases
2832  * such as table/column renames. We depend on the plancache machinery to
2833  * detect possible invalidations, though.
2834  *
2835  * CAUTION: this check is only trustworthy if the caller has already
2836  * locked both FK and PK rels.
2837  */
2838  plan = entry->plan;
2839  if (plan && SPI_plan_is_valid(plan))
2840  return plan;
2841 
2842  /*
2843  * Otherwise we might as well flush the cached plan now, to free a little
2844  * memory space before we make a new one.
2845  */
2846  entry->plan = NULL;
2847  if (plan)
2848  SPI_freeplan(plan);
2849 
2850  return NULL;
2851 }
2852 
2853 
2854 /*
2855  * ri_HashPreparedPlan -
2856  *
2857  * Add another plan to our private SPI query plan hashtable.
2858  */
2859 static void
2861 {
2862  RI_QueryHashEntry *entry;
2863  bool found;
2864 
2865  /*
2866  * On the first call initialize the hashtable
2867  */
2868  if (!ri_query_cache)
2870 
2871  /*
2872  * Add the new plan. We might be overwriting an entry previously found
2873  * invalid by ri_FetchPreparedPlan.
2874  */
2876  key,
2877  HASH_ENTER, &found);
2878  Assert(!found || entry->plan == NULL);
2879  entry->plan = plan;
2880 }
2881 
2882 
2883 /*
2884  * ri_KeysEqual -
2885  *
2886  * Check if all key values in OLD and NEW are "equivalent":
2887  * For normal FKs we check for equality.
2888  * For temporal FKs we check that the PK side is a superset of its old value,
2889  * or the FK side is a subset of its old value.
2890  *
2891  * Note: at some point we might wish to redefine this as checking for
2892  * "IS NOT DISTINCT" rather than "=", that is, allow two nulls to be
2893  * considered equal. Currently there is no need since all callers have
2894  * previously found at least one of the rows to contain no nulls.
2895  */
2896 static bool
2898  const RI_ConstraintInfo *riinfo, bool rel_is_pk)
2899 {
2900  const int16 *attnums;
2901 
2902  if (rel_is_pk)
2903  attnums = riinfo->pk_attnums;
2904  else
2905  attnums = riinfo->fk_attnums;
2906 
2907  /* XXX: could be worthwhile to fetch all necessary attrs at once */
2908  for (int i = 0; i < riinfo->nkeys; i++)
2909  {
2910  Datum oldvalue;
2911  Datum newvalue;
2912  bool isnull;
2913 
2914  /*
2915  * Get one attribute's oldvalue. If it is NULL - they're not equal.
2916  */
2917  oldvalue = slot_getattr(oldslot, attnums[i], &isnull);
2918  if (isnull)
2919  return false;
2920 
2921  /*
2922  * Get one attribute's newvalue. If it is NULL - they're not equal.
2923  */
2924  newvalue = slot_getattr(newslot, attnums[i], &isnull);
2925  if (isnull)
2926  return false;
2927 
2928  if (rel_is_pk)
2929  {
2930  /*
2931  * If we are looking at the PK table, then do a bytewise
2932  * comparison. We must propagate PK changes if the value is
2933  * changed to one that "looks" different but would compare as
2934  * equal using the equality operator. This only makes a
2935  * difference for ON UPDATE CASCADE, but for consistency we treat
2936  * all changes to the PK the same.
2937  */
2938  Form_pg_attribute att = TupleDescAttr(oldslot->tts_tupleDescriptor, attnums[i] - 1);
2939 
2940  if (!datum_image_eq(oldvalue, newvalue, att->attbyval, att->attlen))
2941  return false;
2942  }
2943  else
2944  {
2945  Oid eq_opr;
2946 
2947  /*
2948  * When comparing the PERIOD columns we can skip the check
2949  * whenever the referencing column stayed equal or shrank, so test
2950  * with the contained-by operator instead.
2951  */
2952  if (riinfo->hasperiod && i == riinfo->nkeys - 1)
2953  eq_opr = riinfo->period_contained_by_oper;
2954  else
2955  eq_opr = riinfo->ff_eq_oprs[i];
2956 
2957  /*
2958  * For the FK table, compare with the appropriate equality
2959  * operator. Changes that compare equal will still satisfy the
2960  * constraint after the update.
2961  */
2962  if (!ri_CompareWithCast(eq_opr, RIAttType(rel, attnums[i]),
2963  newvalue, oldvalue))
2964  return false;
2965  }
2966  }
2967 
2968  return true;
2969 }
2970 
2971 
2972 /*
2973  * ri_CompareWithCast -
2974  *
2975  * Call the appropriate comparison operator for two values.
2976  * Normally this is equality, but for the PERIOD part of foreign keys
2977  * it is ContainedBy, so the order of lhs vs rhs is significant.
2978  *
2979  * NB: we have already checked that neither value is null.
2980  */
2981 static bool
2982 ri_CompareWithCast(Oid eq_opr, Oid typeid,
2983  Datum lhs, Datum rhs)
2984 {
2985  RI_CompareHashEntry *entry = ri_HashCompareOp(eq_opr, typeid);
2986 
2987  /* Do we need to cast the values? */
2988  if (OidIsValid(entry->cast_func_finfo.fn_oid))
2989  {
2990  lhs = FunctionCall3(&entry->cast_func_finfo,
2991  lhs,
2992  Int32GetDatum(-1), /* typmod */
2993  BoolGetDatum(false)); /* implicit coercion */
2994  rhs = FunctionCall3(&entry->cast_func_finfo,
2995  rhs,
2996  Int32GetDatum(-1), /* typmod */
2997  BoolGetDatum(false)); /* implicit coercion */
2998  }
2999 
3000  /*
3001  * Apply the comparison operator.
3002  *
3003  * Note: This function is part of a call stack that determines whether an
3004  * update to a row is significant enough that it needs checking or action
3005  * on the other side of a foreign-key constraint. Therefore, the
3006  * comparison here would need to be done with the collation of the *other*
3007  * table. For simplicity (e.g., we might not even have the other table
3008  * open), we'll just use the default collation here, which could lead to
3009  * some false negatives. All this would break if we ever allow
3010  * database-wide collations to be nondeterministic.
3011  *
3012  * With range/multirangetypes, the collation of the base type is stored as
3013  * part of the rangetype (pg_range.rngcollation), and always used, so
3014  * there is no danger of inconsistency even using a non-equals operator.
3015  * But if we support arbitrary types with PERIOD, we should perhaps just
3016  * always force a re-check.
3017  */
3019  DEFAULT_COLLATION_OID,
3020  lhs, rhs));
3021 }
3022 
3023 /*
3024  * ri_HashCompareOp -
3025  *
3026  * See if we know how to compare two values, and create a new hash entry
3027  * if not.
3028  */
3029 static RI_CompareHashEntry *
3030 ri_HashCompareOp(Oid eq_opr, Oid typeid)
3031 {
3033  RI_CompareHashEntry *entry;
3034  bool found;
3035 
3036  /*
3037  * On the first call initialize the hashtable
3038  */
3039  if (!ri_compare_cache)
3041 
3042  /*
3043  * Find or create a hash entry. Note we're assuming RI_CompareKey
3044  * contains no struct padding.
3045  */
3046  key.eq_opr = eq_opr;
3047  key.typeid = typeid;
3049  &key,
3050  HASH_ENTER, &found);
3051  if (!found)
3052  entry->valid = false;
3053 
3054  /*
3055  * If not already initialized, do so. Since we'll keep this hash entry
3056  * for the life of the backend, put any subsidiary info for the function
3057  * cache structs into TopMemoryContext.
3058  */
3059  if (!entry->valid)
3060  {
3061  Oid lefttype,
3062  righttype,
3063  castfunc;
3064  CoercionPathType pathtype;
3065 
3066  /* We always need to know how to call the equality operator */
3067  fmgr_info_cxt(get_opcode(eq_opr), &entry->eq_opr_finfo,
3069 
3070  /*
3071  * If we chose to use a cast from FK to PK type, we may have to apply
3072  * the cast function to get to the operator's input type.
3073  *
3074  * XXX eventually it would be good to support array-coercion cases
3075  * here and in ri_CompareWithCast(). At the moment there is no point
3076  * because cases involving nonidentical array types will be rejected
3077  * at constraint creation time.
3078  *
3079  * XXX perhaps also consider supporting CoerceViaIO? No need at the
3080  * moment since that will never be generated for implicit coercions.
3081  */
3082  op_input_types(eq_opr, &lefttype, &righttype);
3083  Assert(lefttype == righttype);
3084  if (typeid == lefttype)
3085  castfunc = InvalidOid; /* simplest case */
3086  else
3087  {
3088  pathtype = find_coercion_pathway(lefttype, typeid,
3090  &castfunc);
3091  if (pathtype != COERCION_PATH_FUNC &&
3092  pathtype != COERCION_PATH_RELABELTYPE)
3093  {
3094  /*
3095  * The declared input type of the eq_opr might be a
3096  * polymorphic type such as ANYARRAY or ANYENUM, or other
3097  * special cases such as RECORD; find_coercion_pathway
3098  * currently doesn't subsume these special cases.
3099  */
3100  if (!IsBinaryCoercible(typeid, lefttype))
3101  elog(ERROR, "no conversion function from %s to %s",
3102  format_type_be(typeid),
3103  format_type_be(lefttype));
3104  }
3105  }
3106  if (OidIsValid(castfunc))
3107  fmgr_info_cxt(castfunc, &entry->cast_func_finfo,
3109  else
3111  entry->valid = true;
3112  }
3113 
3114  return entry;
3115 }
3116 
3117 
3118 /*
3119  * Given a trigger function OID, determine whether it is an RI trigger,
3120  * and if so whether it is attached to PK or FK relation.
3121  */
3122 int
3124 {
3125  switch (tgfoid)
3126  {
3127  case F_RI_FKEY_CASCADE_DEL:
3128  case F_RI_FKEY_CASCADE_UPD:
3129  case F_RI_FKEY_RESTRICT_DEL:
3130  case F_RI_FKEY_RESTRICT_UPD:
3131  case F_RI_FKEY_SETNULL_DEL:
3132  case F_RI_FKEY_SETNULL_UPD:
3133  case F_RI_FKEY_SETDEFAULT_DEL:
3134  case F_RI_FKEY_SETDEFAULT_UPD:
3135  case F_RI_FKEY_NOACTION_DEL:
3136  case F_RI_FKEY_NOACTION_UPD:
3137  return RI_TRIGGER_PK;
3138 
3139  case F_RI_FKEY_CHECK_INS:
3140  case F_RI_FKEY_CHECK_UPD:
3141  return RI_TRIGGER_FK;
3142  }
3143 
3144  return RI_TRIGGER_NONE;
3145 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
bool has_bypassrls_privilege(Oid roleid)
Definition: aclchk.c:4230
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:3908
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4130
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4079
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
#define NameStr(name)
Definition: c.h:746
unsigned int uint32
Definition: c.h:506
signed short int16
Definition: c.h:493
signed int int32
Definition: c.h:494
#define Assert(condition)
Definition: c.h:858
#define pg_attribute_noreturn()
Definition: c.h:217
#define OidIsValid(objectId)
Definition: c.h:775
bool datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:266
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
bool ExecCheckPermissions(List *rangeTable, List *rteperminfos, bool ereport_on_violation)
Definition: execMain.c:579
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1639
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1341
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1325
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1149
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
#define FunctionCall3(flinfo, arg1, arg2, arg3)
Definition: fmgr.h:664
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
int maintenance_work_mem
Definition: globals.c:130
int NewGUCNestLevel(void)
Definition: guc.c:2237
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:2264
int set_config_option(const char *name, const char *value, GucContext context, GucSource source, GucAction action, bool changeVal, int elevel, bool is_reload)
Definition: guc.c:3333
@ GUC_ACTION_SAVE
Definition: guc.h:201
@ PGC_S_SESSION
Definition: guc.h:122
@ PGC_USERSET
Definition: guc.h:75
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1345
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define dclist_container(type, membername, ptr)
Definition: ilist.h:947
static void dclist_push_tail(dclist_head *head, dlist_node *node)
Definition: ilist.h:709
static uint32 dclist_count(const dclist_head *head)
Definition: ilist.h:932
static void dclist_delete_from(dclist_head *head, dlist_node *node)
Definition: ilist.h:763
#define dclist_foreach_modify(iter, lhead)
Definition: ilist.h:973
#define funcname
Definition: indent_codes.h:69
long val
Definition: informix.c:670
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1516
int j
Definition: isn.c:74
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * lappend(List *list, void *datum)
Definition: list.c:339
#define AccessShareLock
Definition: lockdefs.h:36
#define RowShareLock
Definition: lockdefs.h:37
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2907
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1285
Oid get_index_column_opclass(Oid index_oid, int attno)
Definition: lsyscache.c:3512
bool get_collation_isdeterministic(Oid colloid)
Definition: lsyscache.c:1054
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:1358
MemoryContext TopMemoryContext
Definition: mcxt.c:149
#define SECURITY_NOFORCE_RLS
Definition: miscadmin.h:316
#define SECURITY_LOCAL_USERID_CHANGE
Definition: miscadmin.h:314
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:635
Oid GetUserId(void)
Definition: miscinit.c:514
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:642
#define makeNode(_type_)
Definition: nodes.h:155
CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, Oid *funcid)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
CoercionPathType
Definition: parse_coerce.h:25
@ COERCION_PATH_FUNC
Definition: parse_coerce.h:27
@ COERCION_PATH_RELABELTYPE
Definition: parse_coerce.h:28
#define FKCONSTR_MATCH_SIMPLE
Definition: parsenodes.h:2734
@ RTE_RELATION
Definition: parsenodes.h:1028
#define FKCONSTR_MATCH_PARTIAL
Definition: parsenodes.h:2733
#define ACL_SELECT
Definition: parsenodes.h:77
#define FKCONSTR_MATCH_FULL
Definition: parsenodes.h:2732
NameData attname
Definition: pg_attribute.h:41
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
void * arg
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:58
void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
void FindFKPeriodOpers(Oid opclass, Oid *containedbyoperoid, Oid *aggedcontainedbyoperoid)
FormData_pg_constraint * Form_pg_constraint
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define plan(x)
Definition: pg_regress.c:162
static char * buf
Definition: pg_test_fsync.c:73
#define sprintf
Definition: port.h:240
#define snprintf
Definition: port.h:238
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
@ COERCION_IMPLICIT
Definition: primnodes.h:684
tree ctl
Definition: radixtree.h:1847
#define RelationGetForm(relation)
Definition: rel.h:499
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationGetNamespace(relation)
Definition: rel.h:546
int errtableconstraint(Relation rel, const char *conname)
Definition: relcache.c:5999
static bool ri_CompareWithCast(Oid eq_opr, Oid typeid, Datum lhs, Datum rhs)
Definition: ri_triggers.c:2982
static Datum ri_set(TriggerData *trigdata, bool is_set_null, int tgkind)
Definition: ri_triggers.c:1115
#define RI_TRIGTYPE_INSERT
Definition: ri_triggers.c:91
struct RI_ConstraintInfo RI_ConstraintInfo
static const RI_ConstraintInfo * ri_LoadConstraintInfo(Oid constraintOid)
Definition: ri_triggers.c:2196
static Datum RI_FKey_check(TriggerData *trigdata)
Definition: ri_triggers.c:247
#define RI_PLAN_SETNULL_ONUPDATE
Definition: ri_triggers.c:80
#define RI_PLAN_CASCADE_ONUPDATE
Definition: ri_triggers.c:76
#define RI_TRIGTYPE_DELETE
Definition: ri_triggers.c:93
Datum RI_FKey_setnull_del(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:1054
static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo, RI_QueryKey *qkey, SPIPlanPtr qplan, Relation fk_rel, Relation pk_rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, bool detectNewRows, int expect_OK)
Definition: ri_triggers.c:2411
static void ri_HashPreparedPlan(RI_QueryKey *key, SPIPlanPtr plan)
Definition: ri_triggers.c:2860
static void quoteOneName(char *buffer, const char *name)
Definition: ri_triggers.c:1957
bool RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: ri_triggers.c:1310
#define RI_PLAN_LAST_ON_PK
Definition: ri_triggers.c:73
#define RIAttType(rel, attnum)
Definition: ri_triggers.c:88
static void ri_GenerateQualCollation(StringInfo buf, Oid collation)
Definition: ri_triggers.c:2023
Datum RI_FKey_cascade_del(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:827
#define RI_KEYS_SOME_NULL
Definition: ri_triggers.c:66
Datum RI_FKey_check_upd(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:487
static HTAB * ri_query_cache
Definition: ri_triggers.c:182
#define MAX_QUOTED_REL_NAME_LEN
Definition: ri_triggers.c:85
static void ri_ReportViolation(const RI_ConstraintInfo *riinfo, Relation pk_rel, Relation fk_rel, TupleTableSlot *violatorslot, TupleDesc tupdesc, int queryno, bool partgone) pg_attribute_noreturn()
Definition: ri_triggers.c:2577
Datum RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:692
static void InvalidateConstraintCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
Definition: ri_triggers.c:2327
static Datum ri_restrict(TriggerData *trigdata, bool is_no_action)
Definition: ri_triggers.c:708
Datum RI_FKey_restrict_del(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:655
#define RI_PLAN_RESTRICT
Definition: ri_triggers.c:78
Datum RI_FKey_noaction_del(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:635
static void quoteRelationName(char *buffer, Relation rel)
Definition: ri_triggers.c:1977
static int ri_NullCheck(TupleDesc tupDesc, TupleTableSlot *slot, const RI_ConstraintInfo *riinfo, bool rel_is_pk)
Definition: ri_triggers.c:2735
static void ri_GenerateQual(StringInfo buf, const char *sep, const char *leftop, Oid leftoptype, Oid opoid, const char *rightop, Oid rightoptype)
Definition: ri_triggers.c:1994
struct RI_QueryKey RI_QueryKey
static bool ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, const RI_ConstraintInfo *riinfo, bool rel_is_pk)
Definition: ri_triggers.c:2897
struct RI_CompareHashEntry RI_CompareHashEntry
static RI_CompareHashEntry * ri_HashCompareOp(Oid eq_opr, Oid typeid)
Definition: ri_triggers.c:3030
#define RI_PLAN_CHECK_LOOKUPPK_FROM_PK
Definition: ri_triggers.c:72
#define RIAttCollation(rel, attnum)
Definition: ri_triggers.c:89
static dclist_head ri_constraint_cache_valid_list
Definition: ri_triggers.c:184
static Oid get_ri_constraint_root(Oid constrOid)
Definition: ri_triggers.c:2293
Datum RI_FKey_check_ins(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:471
struct RI_QueryHashEntry RI_QueryHashEntry
#define RI_KEYS_ALL_NULL
Definition: ri_triggers.c:65
static HTAB * ri_compare_cache
Definition: ri_triggers.c:183
#define RI_KEYS_NONE_NULL
Definition: ri_triggers.c:67
#define RI_INIT_QUERYHASHSIZE
Definition: ri_triggers.c:63
static const RI_ConstraintInfo * ri_FetchConstraintInfo(Trigger *trigger, Relation trig_rel, bool rel_is_pk)
Definition: ri_triggers.c:2142
static void ri_BuildQueryKey(RI_QueryKey *key, const RI_ConstraintInfo *riinfo, int32 constr_queryno)
Definition: ri_triggers.c:2064
#define RI_PLAN_CASCADE_ONDELETE
Definition: ri_triggers.c:75
Datum RI_FKey_setnull_upd(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:1069
#define RI_PLAN_SETDEFAULT_ONDELETE
Definition: ri_triggers.c:81
Datum RI_FKey_setdefault_del(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:1084
#define RI_PLAN_SETDEFAULT_ONUPDATE
Definition: ri_triggers.c:82
#define RI_PLAN_CHECK_LOOKUPPK
Definition: ri_triggers.c:71
#define RI_PLAN_SETNULL_ONDELETE
Definition: ri_triggers.c:79
#define RI_INIT_CONSTRAINTHASHSIZE
Definition: ri_triggers.c:62
bool RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1443
static bool ri_Check_Pk_Match(Relation pk_rel, Relation fk_rel, TupleTableSlot *oldslot, const RI_ConstraintInfo *riinfo)
Definition: ri_triggers.c:508
void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:1738
static SPIPlanPtr ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes, RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel)
Definition: ri_triggers.c:2368
#define MAX_QUOTED_NAME_LEN
Definition: ri_triggers.c:84
static void ri_CheckTrigger(FunctionCallInfo fcinfo, const char *funcname, int tgkind)
Definition: ri_triggers.c:2096
#define RI_TRIGTYPE_UPDATE
Definition: ri_triggers.c:92
bool RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel, TupleTableSlot *oldslot, TupleTableSlot *newslot)
Definition: ri_triggers.c:1342
int RI_FKey_trigger_type(Oid tgfoid)
Definition: ri_triggers.c:3123
Datum RI_FKey_cascade_upd(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:933
Datum RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:672
static void ri_InitHashTables(void)
Definition: ri_triggers.c:2772
static void ri_ExtractValues(Relation rel, TupleTableSlot *slot, const RI_ConstraintInfo *riinfo, bool rel_is_pk, Datum *vals, char *nulls)
Definition: ri_triggers.c:2548
#define RIAttName(rel, attnum)
Definition: ri_triggers.c:87
#define RI_MAX_NUMKEYS
Definition: ri_triggers.c:60
static HTAB * ri_constraint_cache
Definition: ri_triggers.c:181
static SPIPlanPtr ri_FetchPreparedPlan(RI_QueryKey *key)
Definition: ri_triggers.c:2808
struct RI_CompareKey RI_CompareKey
Datum RI_FKey_setdefault_upd(PG_FUNCTION_ARGS)
Definition: ri_triggers.c:1099
int check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
Definition: rls.c:52
@ RLS_ENABLED
Definition: rls.h:45
char * pg_get_partconstrdef_string(Oid partitionId, char *aliasname)
Definition: ruleutils.c:2112
void generate_operator_clause(StringInfo buf, const char *leftop, Oid leftoptype, Oid opoid, const char *rightop, Oid rightoptype)
Definition: ruleutils.c:13031
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:291
#define SnapshotSelf
Definition: snapmgr.h:32
#define InvalidSnapshot
Definition: snapshot.h:123
bool SPI_plan_is_valid(SPIPlanPtr plan)
Definition: spi.c:1945
uint64 SPI_processed
Definition: spi.c:44
int SPI_freeplan(SPIPlanPtr plan)
Definition: spi.c:1022
SPITupleTable * SPI_tuptable
Definition: spi.c:45
int SPI_connect(void)
Definition: spi.c:94
int SPI_execute_snapshot(SPIPlanPtr plan, Datum *Values, const char *Nulls, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, long tcount)
Definition: spi.c:770
int SPI_result
Definition: spi.c:46
const char * SPI_result_code_string(int code)
Definition: spi.c:1969
int SPI_finish(void)
Definition: spi.c:182
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:857
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:973
#define SPI_OK_UPDATE
Definition: spi.h:90
#define SPI_OK_DELETE
Definition: spi.h:89
#define SPI_OK_CONNECT
Definition: spi.h:82
#define SPI_OK_FINISH
Definition: spi.h:83
#define SPI_OK_SELECT
Definition: spi.h:86
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:233
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Definition: fmgr.h:57
Oid fn_oid
Definition: fmgr.h:59
fmNodePtr context
Definition: fmgr.h:88
Definition: dynahash.c:220
Definition: pg_list.h:54
RI_CompareKey key
Definition: ri_triggers.c:171
FmgrInfo cast_func_finfo
Definition: ri_triggers.c:174
dlist_node valid_link
Definition: ri_triggers.c:132
int16 pk_attnums[RI_MAX_NUMKEYS]
Definition: ri_triggers.c:125
Oid agged_period_contained_by_oper
Definition: ri_triggers.c:131
int16 fk_attnums[RI_MAX_NUMKEYS]
Definition: ri_triggers.c:126
Oid pp_eq_oprs[RI_MAX_NUMKEYS]
Definition: ri_triggers.c:128
Oid pf_eq_oprs[RI_MAX_NUMKEYS]
Definition: ri_triggers.c:127
Oid period_contained_by_oper
Definition: ri_triggers.c:130
int16 confdelsetcols[RI_MAX_NUMKEYS]
Definition: ri_triggers.c:120
Oid ff_eq_oprs[RI_MAX_NUMKEYS]
Definition: ri_triggers.c:129
SPIPlanPtr plan
Definition: ri_triggers.c:152
RI_QueryKey key
Definition: ri_triggers.c:151
int32 constr_queryno
Definition: ri_triggers.c:143
Bitmapset * selectedCols
Definition: parsenodes.h:1297
AclMode requiredPerms
Definition: parsenodes.h:1295
RTEKind rtekind
Definition: parsenodes.h:1057
TupleDesc rd_att
Definition: rel.h:112
Oid rd_id
Definition: rel.h:113
Form_pg_class rd_rel
Definition: rel.h:111
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26
Relation tg_relation
Definition: trigger.h:35
TriggerEvent tg_event
Definition: trigger.h:34
TupleTableSlot * tg_trigslot
Definition: trigger.h:39
TupleTableSlot * tg_newslot
Definition: trigger.h:40
Trigger * tg_trigger
Definition: trigger.h:38
Oid tgconstraint
Definition: reltrigger.h:35
Oid tgconstrrelid
Definition: reltrigger.h:33
char * tgname
Definition: reltrigger.h:27
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:123
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
dlist_node * cur
Definition: ilist.h:200
Definition: c.h:741
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
#define GetSysCacheHashValue1(cacheId, key1)
Definition: syscache.h:113
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static bool table_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot, Snapshot snapshot)
Definition: tableam.h:1345
#define RI_TRIGGER_FK
Definition: trigger.h:283
#define TRIGGER_FIRED_BY_DELETE(event)
Definition: trigger.h:113
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:26
#define TRIGGER_FIRED_FOR_ROW(event)
Definition: trigger.h:122
#define RI_TRIGGER_NONE
Definition: trigger.h:284
#define TRIGGER_FIRED_AFTER(event)
Definition: trigger.h:131
#define TRIGGER_FIRED_BY_INSERT(event)
Definition: trigger.h:110
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:116
#define RI_TRIGGER_PK
Definition: trigger.h:282
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:395
static bool slot_is_current_xact_tuple(TupleTableSlot *slot)
Definition: tuptable.h:445
static bool slot_attisnull(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:381
const char * name
void CommandCounterIncrement(void)
Definition: xact.c:1097
#define IsolationUsesXactSnapshot()
Definition: xact.h:51