PostgreSQL Source Code  git master
pg_constraint.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_constraint.c
4  * routines to support manipulation of the pg_constraint relation
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/catalog/pg_constraint.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/genam.h"
18 #include "access/gist.h"
19 #include "access/htup_details.h"
20 #include "access/sysattr.h"
21 #include "access/table.h"
22 #include "access/xact.h"
23 #include "catalog/catalog.h"
24 #include "catalog/dependency.h"
25 #include "catalog/heap.h"
26 #include "catalog/indexing.h"
27 #include "catalog/objectaccess.h"
28 #include "catalog/pg_constraint.h"
29 #include "catalog/pg_operator.h"
30 #include "catalog/pg_type.h"
31 #include "commands/defrem.h"
32 #include "utils/array.h"
33 #include "utils/builtins.h"
34 #include "utils/fmgroids.h"
35 #include "utils/lsyscache.h"
36 #include "utils/rel.h"
37 #include "utils/syscache.h"
38 
39 
40 /*
41  * CreateConstraintEntry
42  * Create a constraint table entry.
43  *
44  * Subsidiary records (such as triggers or indexes to implement the
45  * constraint) are *not* created here. But we do make dependency links
46  * from the constraint to the things it depends on.
47  *
48  * The new constraint's OID is returned.
49  */
50 Oid
51 CreateConstraintEntry(const char *constraintName,
52  Oid constraintNamespace,
53  char constraintType,
54  bool isDeferrable,
55  bool isDeferred,
56  bool isValidated,
57  Oid parentConstrId,
58  Oid relId,
59  const int16 *constraintKey,
60  int constraintNKeys,
61  int constraintNTotalKeys,
62  Oid domainId,
63  Oid indexRelId,
64  Oid foreignRelId,
65  const int16 *foreignKey,
66  const Oid *pfEqOp,
67  const Oid *ppEqOp,
68  const Oid *ffEqOp,
69  int foreignNKeys,
70  char foreignUpdateType,
71  char foreignDeleteType,
72  const int16 *fkDeleteSetCols,
73  int numFkDeleteSetCols,
74  char foreignMatchType,
75  const Oid *exclOp,
76  Node *conExpr,
77  const char *conBin,
78  bool conIsLocal,
79  int conInhCount,
80  bool conNoInherit,
81  bool conPeriod,
82  bool is_internal)
83 {
84  Relation conDesc;
85  Oid conOid;
86  HeapTuple tup;
87  bool nulls[Natts_pg_constraint];
88  Datum values[Natts_pg_constraint];
89  ArrayType *conkeyArray;
90  ArrayType *confkeyArray;
91  ArrayType *conpfeqopArray;
92  ArrayType *conppeqopArray;
93  ArrayType *conffeqopArray;
94  ArrayType *conexclopArray;
95  ArrayType *confdelsetcolsArray;
97  int i;
98  ObjectAddress conobject;
99  ObjectAddresses *addrs_auto;
100  ObjectAddresses *addrs_normal;
101 
102  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
103 
104  Assert(constraintName);
105  namestrcpy(&cname, constraintName);
106 
107  /*
108  * Convert C arrays into Postgres arrays.
109  */
110  if (constraintNKeys > 0)
111  {
112  Datum *conkey;
113 
114  conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
115  for (i = 0; i < constraintNKeys; i++)
116  conkey[i] = Int16GetDatum(constraintKey[i]);
117  conkeyArray = construct_array_builtin(conkey, constraintNKeys, INT2OID);
118  }
119  else
120  conkeyArray = NULL;
121 
122  if (foreignNKeys > 0)
123  {
124  Datum *fkdatums;
125 
126  fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
127  for (i = 0; i < foreignNKeys; i++)
128  fkdatums[i] = Int16GetDatum(foreignKey[i]);
129  confkeyArray = construct_array_builtin(fkdatums, foreignNKeys, INT2OID);
130  for (i = 0; i < foreignNKeys; i++)
131  fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
132  conpfeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
133  for (i = 0; i < foreignNKeys; i++)
134  fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
135  conppeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
136  for (i = 0; i < foreignNKeys; i++)
137  fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
138  conffeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
139 
140  if (numFkDeleteSetCols > 0)
141  {
142  for (i = 0; i < numFkDeleteSetCols; i++)
143  fkdatums[i] = Int16GetDatum(fkDeleteSetCols[i]);
144  confdelsetcolsArray = construct_array_builtin(fkdatums, numFkDeleteSetCols, INT2OID);
145  }
146  else
147  confdelsetcolsArray = NULL;
148  }
149  else
150  {
151  confkeyArray = NULL;
152  conpfeqopArray = NULL;
153  conppeqopArray = NULL;
154  conffeqopArray = NULL;
155  confdelsetcolsArray = NULL;
156  }
157 
158  if (exclOp != NULL)
159  {
160  Datum *opdatums;
161 
162  opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum));
163  for (i = 0; i < constraintNKeys; i++)
164  opdatums[i] = ObjectIdGetDatum(exclOp[i]);
165  conexclopArray = construct_array_builtin(opdatums, constraintNKeys, OIDOID);
166  }
167  else
168  conexclopArray = NULL;
169 
170  /* initialize nulls and values */
171  for (i = 0; i < Natts_pg_constraint; i++)
172  {
173  nulls[i] = false;
174  values[i] = (Datum) NULL;
175  }
176 
177  conOid = GetNewOidWithIndex(conDesc, ConstraintOidIndexId,
178  Anum_pg_constraint_oid);
179  values[Anum_pg_constraint_oid - 1] = ObjectIdGetDatum(conOid);
180  values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
181  values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
182  values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
183  values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
184  values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
185  values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated);
186  values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
187  values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
188  values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId);
189  values[Anum_pg_constraint_conparentid - 1] = ObjectIdGetDatum(parentConstrId);
190  values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
191  values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
192  values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
193  values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
194  values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
195  values[Anum_pg_constraint_coninhcount - 1] = Int16GetDatum(conInhCount);
196  values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit);
197  values[Anum_pg_constraint_conperiod - 1] = BoolGetDatum(conPeriod);
198 
199  if (conkeyArray)
200  values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
201  else
202  nulls[Anum_pg_constraint_conkey - 1] = true;
203 
204  if (confkeyArray)
205  values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
206  else
207  nulls[Anum_pg_constraint_confkey - 1] = true;
208 
209  if (conpfeqopArray)
210  values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
211  else
212  nulls[Anum_pg_constraint_conpfeqop - 1] = true;
213 
214  if (conppeqopArray)
215  values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
216  else
217  nulls[Anum_pg_constraint_conppeqop - 1] = true;
218 
219  if (conffeqopArray)
220  values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
221  else
222  nulls[Anum_pg_constraint_conffeqop - 1] = true;
223 
224  if (confdelsetcolsArray)
225  values[Anum_pg_constraint_confdelsetcols - 1] = PointerGetDatum(confdelsetcolsArray);
226  else
227  nulls[Anum_pg_constraint_confdelsetcols - 1] = true;
228 
229  if (conexclopArray)
230  values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray);
231  else
232  nulls[Anum_pg_constraint_conexclop - 1] = true;
233 
234  if (conBin)
235  values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
236  else
237  nulls[Anum_pg_constraint_conbin - 1] = true;
238 
239  tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
240 
241  CatalogTupleInsert(conDesc, tup);
242 
243  ObjectAddressSet(conobject, ConstraintRelationId, conOid);
244 
245  table_close(conDesc, RowExclusiveLock);
246 
247  /* Handle set of auto dependencies */
248  addrs_auto = new_object_addresses();
249 
250  if (OidIsValid(relId))
251  {
252  /*
253  * Register auto dependency from constraint to owning relation, or to
254  * specific column(s) if any are mentioned.
255  */
256  ObjectAddress relobject;
257 
258  if (constraintNTotalKeys > 0)
259  {
260  for (i = 0; i < constraintNTotalKeys; i++)
261  {
262  ObjectAddressSubSet(relobject, RelationRelationId, relId,
263  constraintKey[i]);
264  add_exact_object_address(&relobject, addrs_auto);
265  }
266  }
267  else
268  {
269  ObjectAddressSet(relobject, RelationRelationId, relId);
270  add_exact_object_address(&relobject, addrs_auto);
271  }
272  }
273 
274  if (OidIsValid(domainId))
275  {
276  /*
277  * Register auto dependency from constraint to owning domain
278  */
279  ObjectAddress domobject;
280 
281  ObjectAddressSet(domobject, TypeRelationId, domainId);
282  add_exact_object_address(&domobject, addrs_auto);
283  }
284 
285  record_object_address_dependencies(&conobject, addrs_auto,
287  free_object_addresses(addrs_auto);
288 
289  /* Handle set of normal dependencies */
290  addrs_normal = new_object_addresses();
291 
292  if (OidIsValid(foreignRelId))
293  {
294  /*
295  * Register normal dependency from constraint to foreign relation, or
296  * to specific column(s) if any are mentioned.
297  */
298  ObjectAddress relobject;
299 
300  if (foreignNKeys > 0)
301  {
302  for (i = 0; i < foreignNKeys; i++)
303  {
304  ObjectAddressSubSet(relobject, RelationRelationId,
305  foreignRelId, foreignKey[i]);
306  add_exact_object_address(&relobject, addrs_normal);
307  }
308  }
309  else
310  {
311  ObjectAddressSet(relobject, RelationRelationId, foreignRelId);
312  add_exact_object_address(&relobject, addrs_normal);
313  }
314  }
315 
316  if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
317  {
318  /*
319  * Register normal dependency on the unique index that supports a
320  * foreign-key constraint. (Note: for indexes associated with unique
321  * or primary-key constraints, the dependency runs the other way, and
322  * is not made here.)
323  */
324  ObjectAddress relobject;
325 
326  ObjectAddressSet(relobject, RelationRelationId, indexRelId);
327  add_exact_object_address(&relobject, addrs_normal);
328  }
329 
330  if (foreignNKeys > 0)
331  {
332  /*
333  * Register normal dependencies on the equality operators that support
334  * a foreign-key constraint. If the PK and FK types are the same then
335  * all three operators for a column are the same; otherwise they are
336  * different.
337  */
338  ObjectAddress oprobject;
339 
340  oprobject.classId = OperatorRelationId;
341  oprobject.objectSubId = 0;
342 
343  for (i = 0; i < foreignNKeys; i++)
344  {
345  oprobject.objectId = pfEqOp[i];
346  add_exact_object_address(&oprobject, addrs_normal);
347  if (ppEqOp[i] != pfEqOp[i])
348  {
349  oprobject.objectId = ppEqOp[i];
350  add_exact_object_address(&oprobject, addrs_normal);
351  }
352  if (ffEqOp[i] != pfEqOp[i])
353  {
354  oprobject.objectId = ffEqOp[i];
355  add_exact_object_address(&oprobject, addrs_normal);
356  }
357  }
358  }
359 
360  record_object_address_dependencies(&conobject, addrs_normal,
362  free_object_addresses(addrs_normal);
363 
364  /*
365  * We don't bother to register dependencies on the exclusion operators of
366  * an exclusion constraint. We assume they are members of the opclass
367  * supporting the index, so there's an indirect dependency via that. (This
368  * would be pretty dicey for cross-type operators, but exclusion operators
369  * can never be cross-type.)
370  */
371 
372  if (conExpr != NULL)
373  {
374  /*
375  * Register dependencies from constraint to objects mentioned in CHECK
376  * expression.
377  */
378  recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
380  DEPENDENCY_NORMAL, false);
381  }
382 
383  /* Post creation hook for new constraint */
384  InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
385  is_internal);
386 
387  return conOid;
388 }
389 
390 /*
391  * Test whether given name is currently used as a constraint name
392  * for the given object (relation or domain).
393  *
394  * This is used to decide whether to accept a user-specified constraint name.
395  * It is deliberately not the same test as ChooseConstraintName uses to decide
396  * whether an auto-generated name is OK: here, we will allow it unless there
397  * is an identical constraint name in use *on the same object*.
398  *
399  * NB: Caller should hold exclusive lock on the given object, else
400  * this test can be fooled by concurrent additions.
401  */
402 bool
404  const char *conname)
405 {
406  bool found;
407  Relation conDesc;
408  SysScanDesc conscan;
409  ScanKeyData skey[3];
410 
411  conDesc = table_open(ConstraintRelationId, AccessShareLock);
412 
413  ScanKeyInit(&skey[0],
414  Anum_pg_constraint_conrelid,
415  BTEqualStrategyNumber, F_OIDEQ,
417  ? objId : InvalidOid));
418  ScanKeyInit(&skey[1],
419  Anum_pg_constraint_contypid,
420  BTEqualStrategyNumber, F_OIDEQ,
422  ? objId : InvalidOid));
423  ScanKeyInit(&skey[2],
424  Anum_pg_constraint_conname,
425  BTEqualStrategyNumber, F_NAMEEQ,
426  CStringGetDatum(conname));
427 
428  conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId,
429  true, NULL, 3, skey);
430 
431  /* There can be at most one matching row */
432  found = (HeapTupleIsValid(systable_getnext(conscan)));
433 
434  systable_endscan(conscan);
435  table_close(conDesc, AccessShareLock);
436 
437  return found;
438 }
439 
440 /*
441  * Does any constraint of the given name exist in the given namespace?
442  *
443  * This is used for code that wants to match ChooseConstraintName's rule
444  * that we should avoid autogenerating duplicate constraint names within a
445  * namespace.
446  */
447 bool
448 ConstraintNameExists(const char *conname, Oid namespaceid)
449 {
450  bool found;
451  Relation conDesc;
452  SysScanDesc conscan;
453  ScanKeyData skey[2];
454 
455  conDesc = table_open(ConstraintRelationId, AccessShareLock);
456 
457  ScanKeyInit(&skey[0],
458  Anum_pg_constraint_conname,
459  BTEqualStrategyNumber, F_NAMEEQ,
460  CStringGetDatum(conname));
461 
462  ScanKeyInit(&skey[1],
463  Anum_pg_constraint_connamespace,
464  BTEqualStrategyNumber, F_OIDEQ,
465  ObjectIdGetDatum(namespaceid));
466 
467  conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
468  NULL, 2, skey);
469 
470  found = (HeapTupleIsValid(systable_getnext(conscan)));
471 
472  systable_endscan(conscan);
473  table_close(conDesc, AccessShareLock);
474 
475  return found;
476 }
477 
478 /*
479  * Select a nonconflicting name for a new constraint.
480  *
481  * The objective here is to choose a name that is unique within the
482  * specified namespace. Postgres does not require this, but the SQL
483  * spec does, and some apps depend on it. Therefore we avoid choosing
484  * default names that so conflict.
485  *
486  * name1, name2, and label are used the same way as for makeObjectName(),
487  * except that the label can't be NULL; digits will be appended to the label
488  * if needed to create a name that is unique within the specified namespace.
489  *
490  * 'others' can be a list of string names already chosen within the current
491  * command (but not yet reflected into the catalogs); we will not choose
492  * a duplicate of one of these either.
493  *
494  * Note: it is theoretically possible to get a collision anyway, if someone
495  * else chooses the same name concurrently. This is fairly unlikely to be
496  * a problem in practice, especially if one is holding an exclusive lock on
497  * the relation identified by name1.
498  *
499  * Returns a palloc'd string.
500  */
501 char *
502 ChooseConstraintName(const char *name1, const char *name2,
503  const char *label, Oid namespaceid,
504  List *others)
505 {
506  int pass = 0;
507  char *conname = NULL;
508  char modlabel[NAMEDATALEN];
509  Relation conDesc;
510  SysScanDesc conscan;
511  ScanKeyData skey[2];
512  bool found;
513  ListCell *l;
514 
515  conDesc = table_open(ConstraintRelationId, AccessShareLock);
516 
517  /* try the unmodified label first */
518  strlcpy(modlabel, label, sizeof(modlabel));
519 
520  for (;;)
521  {
522  conname = makeObjectName(name1, name2, modlabel);
523 
524  found = false;
525 
526  foreach(l, others)
527  {
528  if (strcmp((char *) lfirst(l), conname) == 0)
529  {
530  found = true;
531  break;
532  }
533  }
534 
535  if (!found)
536  {
537  ScanKeyInit(&skey[0],
538  Anum_pg_constraint_conname,
539  BTEqualStrategyNumber, F_NAMEEQ,
540  CStringGetDatum(conname));
541 
542  ScanKeyInit(&skey[1],
543  Anum_pg_constraint_connamespace,
544  BTEqualStrategyNumber, F_OIDEQ,
545  ObjectIdGetDatum(namespaceid));
546 
547  conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
548  NULL, 2, skey);
549 
550  found = (HeapTupleIsValid(systable_getnext(conscan)));
551 
552  systable_endscan(conscan);
553  }
554 
555  if (!found)
556  break;
557 
558  /* found a conflict, so try a new name component */
559  pfree(conname);
560  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
561  }
562 
563  table_close(conDesc, AccessShareLock);
564 
565  return conname;
566 }
567 
568 /*
569  * Find and return a copy of the pg_constraint tuple that implements a
570  * validated not-null constraint for the given column of the given relation.
571  *
572  * XXX This would be easier if we had pg_attribute.notnullconstr with the OID
573  * of the constraint that implements the not-null constraint for that column.
574  * I'm not sure it's worth the catalog bloat and de-normalization, however.
575  */
576 HeapTuple
578 {
579  Relation pg_constraint;
580  HeapTuple conTup,
581  retval = NULL;
582  SysScanDesc scan;
584 
585  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
586  ScanKeyInit(&key,
587  Anum_pg_constraint_conrelid,
588  BTEqualStrategyNumber, F_OIDEQ,
589  ObjectIdGetDatum(relid));
590  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
591  true, NULL, 1, &key);
592 
593  while (HeapTupleIsValid(conTup = systable_getnext(scan)))
594  {
596  AttrNumber conkey;
597 
598  /*
599  * We're looking for a NOTNULL constraint that's marked validated,
600  * with the column we're looking for as the sole element in conkey.
601  */
602  if (con->contype != CONSTRAINT_NOTNULL)
603  continue;
604  if (!con->convalidated)
605  continue;
606 
607  conkey = extractNotNullColumn(conTup);
608  if (conkey != attnum)
609  continue;
610 
611  /* Found it */
612  retval = heap_copytuple(conTup);
613  break;
614  }
615 
616  systable_endscan(scan);
617  table_close(pg_constraint, AccessShareLock);
618 
619  return retval;
620 }
621 
622 /*
623  * Find and return the pg_constraint tuple that implements a validated
624  * not-null constraint for the given column of the given relation.
625  */
626 HeapTuple
627 findNotNullConstraint(Oid relid, const char *colname)
628 {
629  AttrNumber attnum = get_attnum(relid, colname);
630 
631  return findNotNullConstraintAttnum(relid, attnum);
632 }
633 
634 /*
635  * Find and return the pg_constraint tuple that implements a validated
636  * not-null constraint for the given domain.
637  */
638 HeapTuple
640 {
641  Relation pg_constraint;
642  HeapTuple conTup,
643  retval = NULL;
644  SysScanDesc scan;
646 
647  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
648  ScanKeyInit(&key,
649  Anum_pg_constraint_contypid,
650  BTEqualStrategyNumber, F_OIDEQ,
651  ObjectIdGetDatum(typid));
652  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
653  true, NULL, 1, &key);
654 
655  while (HeapTupleIsValid(conTup = systable_getnext(scan)))
656  {
658 
659  /*
660  * We're looking for a NOTNULL constraint that's marked validated.
661  */
662  if (con->contype != CONSTRAINT_NOTNULL)
663  continue;
664  if (!con->convalidated)
665  continue;
666 
667  /* Found it */
668  retval = heap_copytuple(conTup);
669  break;
670  }
671 
672  systable_endscan(scan);
673  table_close(pg_constraint, AccessShareLock);
674 
675  return retval;
676 }
677 
678 /*
679  * Given a pg_constraint tuple for a not-null constraint, return the column
680  * number it is for.
681  */
684 {
685  AttrNumber colnum;
686  Datum adatum;
687  ArrayType *arr;
688 
689  /* only tuples for not-null constraints should be given */
690  Assert(((Form_pg_constraint) GETSTRUCT(constrTup))->contype == CONSTRAINT_NOTNULL);
691 
692  adatum = SysCacheGetAttrNotNull(CONSTROID, constrTup,
693  Anum_pg_constraint_conkey);
694  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
695  if (ARR_NDIM(arr) != 1 ||
696  ARR_HASNULL(arr) ||
697  ARR_ELEMTYPE(arr) != INT2OID ||
698  ARR_DIMS(arr)[0] != 1)
699  elog(ERROR, "conkey is not a 1-D smallint array");
700 
701  memcpy(&colnum, ARR_DATA_PTR(arr), sizeof(AttrNumber));
702 
703  if ((Pointer) arr != DatumGetPointer(adatum))
704  pfree(arr); /* free de-toasted copy, if any */
705 
706  return colnum;
707 }
708 
709 /*
710  * AdjustNotNullInheritance1
711  * Adjust inheritance count for a single not-null constraint
712  *
713  * If no not-null constraint is found for the column, return 0.
714  * Caller can create one.
715  * If the constraint does exist and it's inheritable, adjust its
716  * inheritance count (and possibly islocal status) and return 1.
717  * No further action needs to be taken.
718  * If the constraint exists but is marked NO INHERIT, adjust it as above
719  * and reset connoinherit to false, and return -1. Caller is
720  * responsible for adding the same constraint to the children, if any.
721  */
722 int
724  bool is_no_inherit)
725 {
726  HeapTuple tup;
727 
728  Assert(count >= 0);
729 
730  tup = findNotNullConstraintAttnum(relid, attnum);
731  if (HeapTupleIsValid(tup))
732  {
733  Relation pg_constraint;
734  Form_pg_constraint conform;
735  int retval = 1;
736 
737  pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
738  conform = (Form_pg_constraint) GETSTRUCT(tup);
739 
740  /*
741  * If we're asked for a NO INHERIT constraint and this relation
742  * already has an inheritable one, throw an error.
743  */
744  if (is_no_inherit && !conform->connoinherit)
745  ereport(ERROR,
746  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
747  errmsg("cannot change NO INHERIT status of inherited NOT NULL constraint \"%s\" on relation \"%s\"",
748  NameStr(conform->conname), get_rel_name(relid)));
749 
750  /*
751  * If the constraint already exists in this relation but it's marked
752  * NO INHERIT, we can just remove that flag, and instruct caller to
753  * recurse to add the constraint to children.
754  */
755  if (!is_no_inherit && conform->connoinherit)
756  {
757  conform->connoinherit = false;
758  retval = -1; /* caller must add constraint on child rels */
759  }
760 
761  if (count > 0)
762  conform->coninhcount += count;
763 
764  /* sanity check */
765  if (conform->coninhcount < 0)
766  elog(ERROR, "invalid inhcount %d for constraint \"%s\" on relation \"%s\"",
767  conform->coninhcount, NameStr(conform->conname),
768  get_rel_name(relid));
769 
770  /*
771  * If the constraint is no longer inherited, mark it local. It's
772  * arguable that we should drop it instead, but it's hard to see that
773  * being better. The user can drop it manually later.
774  */
775  if (conform->coninhcount == 0)
776  conform->conislocal = true;
777 
778  CatalogTupleUpdate(pg_constraint, &tup->t_self, tup);
779 
780  table_close(pg_constraint, RowExclusiveLock);
781 
782  return retval;
783  }
784 
785  return 0;
786 }
787 
788 /*
789  * AdjustNotNullInheritance
790  * Adjust not-null constraints' inhcount/islocal for
791  * ALTER TABLE [NO] INHERITS
792  *
793  * Mark the NOT NULL constraints for the given relation columns as
794  * inherited, so that they can't be dropped.
795  *
796  * Caller must have checked beforehand that attnotnull was set for all
797  * columns. However, some of those could be set because of a primary
798  * key, so throw a proper user-visible error if one is not found.
799  */
800 void
801 AdjustNotNullInheritance(Oid relid, Bitmapset *columns, int count)
802 {
803  Relation pg_constraint;
804  int attnum;
805 
806  pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
807 
808  /*
809  * Scan the set of columns and bump inhcount for each.
810  */
811  attnum = -1;
812  while ((attnum = bms_next_member(columns, attnum)) >= 0)
813  {
814  HeapTuple tup;
815  Form_pg_constraint conform;
816 
817  tup = findNotNullConstraintAttnum(relid, attnum);
818  if (!HeapTupleIsValid(tup))
819  ereport(ERROR,
820  errcode(ERRCODE_DATATYPE_MISMATCH),
821  errmsg("column \"%s\" in child table must be marked NOT NULL",
822  get_attname(relid, attnum,
823  false)));
824 
825  conform = (Form_pg_constraint) GETSTRUCT(tup);
826  conform->coninhcount += count;
827  if (conform->coninhcount < 0)
828  elog(ERROR, "invalid inhcount %d for constraint \"%s\" on relation \"%s\"",
829  conform->coninhcount, NameStr(conform->conname),
830  get_rel_name(relid));
831 
832  /*
833  * If the constraints are no longer inherited, mark them local. It's
834  * arguable that we should drop them instead, but it's hard to see
835  * that being better. The user can drop it manually later.
836  */
837  if (conform->coninhcount == 0)
838  conform->conislocal = true;
839 
840  CatalogTupleUpdate(pg_constraint, &tup->t_self, tup);
841  }
842 
843  table_close(pg_constraint, RowExclusiveLock);
844 }
845 
846 /*
847  * RelationGetNotNullConstraints
848  * Return the list of not-null constraints for the given rel
849  *
850  * Caller can request cooked constraints, or raw.
851  *
852  * This is seldom needed, so we just scan pg_constraint each time.
853  *
854  * XXX This is only used to create derived tables, so NO INHERIT constraints
855  * are always skipped.
856  */
857 List *
859 {
860  List *notnulls = NIL;
861  Relation constrRel;
862  HeapTuple htup;
863  SysScanDesc conscan;
864  ScanKeyData skey;
865 
866  constrRel = table_open(ConstraintRelationId, AccessShareLock);
867  ScanKeyInit(&skey,
868  Anum_pg_constraint_conrelid,
869  BTEqualStrategyNumber, F_OIDEQ,
870  ObjectIdGetDatum(relid));
871  conscan = systable_beginscan(constrRel, ConstraintRelidTypidNameIndexId, true,
872  NULL, 1, &skey);
873 
874  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
875  {
877  AttrNumber colnum;
878 
879  if (conForm->contype != CONSTRAINT_NOTNULL)
880  continue;
881  if (conForm->connoinherit)
882  continue;
883 
884  colnum = extractNotNullColumn(htup);
885 
886  if (cooked)
887  {
888  CookedConstraint *cooked;
889 
890  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
891 
892  cooked->contype = CONSTR_NOTNULL;
893  cooked->name = pstrdup(NameStr(conForm->conname));
894  cooked->attnum = colnum;
895  cooked->expr = NULL;
896  cooked->skip_validation = false;
897  cooked->is_local = true;
898  cooked->inhcount = 0;
899  cooked->is_no_inherit = conForm->connoinherit;
900 
901  notnulls = lappend(notnulls, cooked);
902  }
903  else
904  {
905  Constraint *constr;
906 
907  constr = makeNode(Constraint);
908  constr->contype = CONSTR_NOTNULL;
909  constr->conname = pstrdup(NameStr(conForm->conname));
910  constr->deferrable = false;
911  constr->initdeferred = false;
912  constr->location = -1;
913  constr->keys = list_make1(makeString(get_attname(relid, colnum,
914  false)));
915  constr->skip_validation = false;
916  constr->initially_valid = true;
917  notnulls = lappend(notnulls, constr);
918  }
919  }
920 
921  systable_endscan(conscan);
922  table_close(constrRel, AccessShareLock);
923 
924  return notnulls;
925 }
926 
927 
928 /*
929  * Delete a single constraint record.
930  */
931 void
933 {
934  Relation conDesc;
935  HeapTuple tup;
936  Form_pg_constraint con;
937  bool dropping_pk = false;
938  List *unconstrained_cols = NIL;
939 
940  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
941 
942  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conId));
943  if (!HeapTupleIsValid(tup)) /* should not happen */
944  elog(ERROR, "cache lookup failed for constraint %u", conId);
945  con = (Form_pg_constraint) GETSTRUCT(tup);
946 
947  /*
948  * Special processing depending on what the constraint is for.
949  */
950  if (OidIsValid(con->conrelid))
951  {
952  Relation rel;
953 
954  /*
955  * If the constraint is for a relation, open and exclusive-lock the
956  * relation it's for.
957  */
958  rel = table_open(con->conrelid, AccessExclusiveLock);
959 
960  /*
961  * We need to update the relchecks count if it is a check constraint
962  * being dropped. This update will force backends to rebuild relcache
963  * entries when we commit. For not-null and primary key constraints,
964  * obtain the list of columns affected, so that we can reset their
965  * attnotnull flags below.
966  */
967  if (con->contype == CONSTRAINT_CHECK)
968  {
969  Relation pgrel;
970  HeapTuple relTup;
971  Form_pg_class classForm;
972 
973  pgrel = table_open(RelationRelationId, RowExclusiveLock);
974  relTup = SearchSysCacheCopy1(RELOID,
975  ObjectIdGetDatum(con->conrelid));
976  if (!HeapTupleIsValid(relTup))
977  elog(ERROR, "cache lookup failed for relation %u",
978  con->conrelid);
979  classForm = (Form_pg_class) GETSTRUCT(relTup);
980 
981  if (classForm->relchecks == 0) /* should not happen */
982  elog(ERROR, "relation \"%s\" has relchecks = 0",
984  classForm->relchecks--;
985 
986  CatalogTupleUpdate(pgrel, &relTup->t_self, relTup);
987 
988  heap_freetuple(relTup);
989 
991  }
992  else if (con->contype == CONSTRAINT_NOTNULL)
993  {
994  unconstrained_cols = list_make1_int(extractNotNullColumn(tup));
995  }
996  else if (con->contype == CONSTRAINT_PRIMARY)
997  {
998  Datum adatum;
999  ArrayType *arr;
1000  int numkeys;
1001  bool isNull;
1002  int16 *attnums;
1003 
1004  dropping_pk = true;
1005 
1006  adatum = heap_getattr(tup, Anum_pg_constraint_conkey,
1007  RelationGetDescr(conDesc), &isNull);
1008  if (isNull)
1009  elog(ERROR, "null conkey for constraint %u", con->oid);
1010  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1011  numkeys = ARR_DIMS(arr)[0];
1012  if (ARR_NDIM(arr) != 1 ||
1013  numkeys < 0 ||
1014  ARR_HASNULL(arr) ||
1015  ARR_ELEMTYPE(arr) != INT2OID)
1016  elog(ERROR, "conkey is not a 1-D smallint array");
1017  attnums = (int16 *) ARR_DATA_PTR(arr);
1018 
1019  for (int i = 0; i < numkeys; i++)
1020  unconstrained_cols = lappend_int(unconstrained_cols, attnums[i]);
1021  }
1022 
1023  /* Keep lock on constraint's rel until end of xact */
1024  table_close(rel, NoLock);
1025  }
1026  else if (OidIsValid(con->contypid))
1027  {
1028  /*
1029  * XXX for now, do nothing special when dropping a domain constraint
1030  *
1031  * Probably there should be some form of locking on the domain type,
1032  * but we have no such concept at the moment.
1033  */
1034  }
1035  else
1036  elog(ERROR, "constraint %u is not of a known type", conId);
1037 
1038  /* Fry the constraint itself */
1039  CatalogTupleDelete(conDesc, &tup->t_self);
1040 
1041  /*
1042  * If this was a NOT NULL or the primary key, the constrained columns must
1043  * have had pg_attribute.attnotnull set. See if we need to reset it, and
1044  * do so.
1045  */
1046  if (unconstrained_cols != NIL)
1047  {
1048  Relation tablerel;
1049  Relation attrel;
1050  Bitmapset *pkcols;
1051  ListCell *lc;
1052 
1053  /* Make the above deletion visible */
1055 
1056  tablerel = table_open(con->conrelid, NoLock); /* already have lock */
1057  attrel = table_open(AttributeRelationId, RowExclusiveLock);
1058 
1059  /*
1060  * We want to test columns for their presence in the primary key, but
1061  * only if we're not dropping it.
1062  */
1063  pkcols = dropping_pk ? NULL :
1064  RelationGetIndexAttrBitmap(tablerel,
1066 
1067  foreach(lc, unconstrained_cols)
1068  {
1070  HeapTuple atttup;
1071  HeapTuple contup;
1072  Bitmapset *ircols;
1073  Form_pg_attribute attForm;
1074 
1075  /*
1076  * Obtain pg_attribute tuple and verify conditions on it. We use
1077  * a copy we can scribble on.
1078  */
1079  atttup = SearchSysCacheCopyAttNum(con->conrelid, attnum);
1080  if (!HeapTupleIsValid(atttup))
1081  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1082  attnum, con->conrelid);
1083  attForm = (Form_pg_attribute) GETSTRUCT(atttup);
1084 
1085  /*
1086  * Since the above deletion has been made visible, we can now
1087  * search for any remaining constraints setting this column as
1088  * not-nullable; if we find any, no need to reset attnotnull.
1089  */
1091  pkcols))
1092  continue;
1093  contup = findNotNullConstraintAttnum(con->conrelid, attnum);
1094  if (contup)
1095  continue;
1096 
1097  /*
1098  * Also no reset if the column is in the replica identity or it's
1099  * a generated column
1100  */
1101  if (attForm->attidentity != '\0')
1102  continue;
1103  ircols = RelationGetIndexAttrBitmap(tablerel,
1106  ircols))
1107  continue;
1108 
1109  /* Reset attnotnull */
1110  if (attForm->attnotnull)
1111  {
1112  attForm->attnotnull = false;
1113  CatalogTupleUpdate(attrel, &atttup->t_self, atttup);
1114  }
1115  }
1116 
1117  table_close(attrel, RowExclusiveLock);
1118  table_close(tablerel, NoLock);
1119  }
1120 
1121  /* Clean up */
1122  ReleaseSysCache(tup);
1123  table_close(conDesc, RowExclusiveLock);
1124 }
1125 
1126 /*
1127  * RenameConstraintById
1128  * Rename a constraint.
1129  *
1130  * Note: this isn't intended to be a user-exposed function; it doesn't check
1131  * permissions etc. Currently this is only invoked when renaming an index
1132  * that is associated with a constraint, but it's made a little more general
1133  * than that with the expectation of someday having ALTER TABLE RENAME
1134  * CONSTRAINT.
1135  */
1136 void
1137 RenameConstraintById(Oid conId, const char *newname)
1138 {
1139  Relation conDesc;
1140  HeapTuple tuple;
1141  Form_pg_constraint con;
1142 
1143  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
1144 
1145  tuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(conId));
1146  if (!HeapTupleIsValid(tuple))
1147  elog(ERROR, "cache lookup failed for constraint %u", conId);
1148  con = (Form_pg_constraint) GETSTRUCT(tuple);
1149 
1150  /*
1151  * For user-friendliness, check whether the name is already in use.
1152  */
1153  if (OidIsValid(con->conrelid) &&
1155  con->conrelid,
1156  newname))
1157  ereport(ERROR,
1159  errmsg("constraint \"%s\" for relation \"%s\" already exists",
1160  newname, get_rel_name(con->conrelid))));
1161  if (OidIsValid(con->contypid) &&
1163  con->contypid,
1164  newname))
1165  ereport(ERROR,
1167  errmsg("constraint \"%s\" for domain %s already exists",
1168  newname, format_type_be(con->contypid))));
1169 
1170  /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
1171  namestrcpy(&(con->conname), newname);
1172 
1173  CatalogTupleUpdate(conDesc, &tuple->t_self, tuple);
1174 
1175  InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
1176 
1177  heap_freetuple(tuple);
1178  table_close(conDesc, RowExclusiveLock);
1179 }
1180 
1181 /*
1182  * AlterConstraintNamespaces
1183  * Find any constraints belonging to the specified object,
1184  * and move them to the specified new namespace.
1185  *
1186  * isType indicates whether the owning object is a type or a relation.
1187  */
1188 void
1190  Oid newNspId, bool isType, ObjectAddresses *objsMoved)
1191 {
1192  Relation conRel;
1193  ScanKeyData key[2];
1194  SysScanDesc scan;
1195  HeapTuple tup;
1196 
1197  conRel = table_open(ConstraintRelationId, RowExclusiveLock);
1198 
1199  ScanKeyInit(&key[0],
1200  Anum_pg_constraint_conrelid,
1201  BTEqualStrategyNumber, F_OIDEQ,
1202  ObjectIdGetDatum(isType ? InvalidOid : ownerId));
1203  ScanKeyInit(&key[1],
1204  Anum_pg_constraint_contypid,
1205  BTEqualStrategyNumber, F_OIDEQ,
1206  ObjectIdGetDatum(isType ? ownerId : InvalidOid));
1207 
1208  scan = systable_beginscan(conRel, ConstraintRelidTypidNameIndexId, true,
1209  NULL, 2, key);
1210 
1211  while (HeapTupleIsValid((tup = systable_getnext(scan))))
1212  {
1214  ObjectAddress thisobj;
1215 
1216  ObjectAddressSet(thisobj, ConstraintRelationId, conform->oid);
1217 
1218  if (object_address_present(&thisobj, objsMoved))
1219  continue;
1220 
1221  /* Don't update if the object is already part of the namespace */
1222  if (conform->connamespace == oldNspId && oldNspId != newNspId)
1223  {
1224  tup = heap_copytuple(tup);
1225  conform = (Form_pg_constraint) GETSTRUCT(tup);
1226 
1227  conform->connamespace = newNspId;
1228 
1229  CatalogTupleUpdate(conRel, &tup->t_self, tup);
1230 
1231  /*
1232  * Note: currently, the constraint will not have its own
1233  * dependency on the namespace, so we don't need to do
1234  * changeDependencyFor().
1235  */
1236  }
1237 
1238  InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
1239 
1240  add_exact_object_address(&thisobj, objsMoved);
1241  }
1242 
1243  systable_endscan(scan);
1244 
1245  table_close(conRel, RowExclusiveLock);
1246 }
1247 
1248 /*
1249  * ConstraintSetParentConstraint
1250  * Set a partition's constraint as child of its parent constraint,
1251  * or remove the linkage if parentConstrId is InvalidOid.
1252  *
1253  * This updates the constraint's pg_constraint row to show it as inherited, and
1254  * adds PARTITION dependencies to prevent the constraint from being deleted
1255  * on its own. Alternatively, reverse that.
1256  */
1257 void
1259  Oid parentConstrId,
1260  Oid childTableId)
1261 {
1262  Relation constrRel;
1263  Form_pg_constraint constrForm;
1264  HeapTuple tuple,
1265  newtup;
1266  ObjectAddress depender;
1267  ObjectAddress referenced;
1268 
1269  constrRel = table_open(ConstraintRelationId, RowExclusiveLock);
1270  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(childConstrId));
1271  if (!HeapTupleIsValid(tuple))
1272  elog(ERROR, "cache lookup failed for constraint %u", childConstrId);
1273  newtup = heap_copytuple(tuple);
1274  constrForm = (Form_pg_constraint) GETSTRUCT(newtup);
1275  if (OidIsValid(parentConstrId))
1276  {
1277  /* don't allow setting parent for a constraint that already has one */
1278  Assert(constrForm->coninhcount == 0);
1279  if (constrForm->conparentid != InvalidOid)
1280  elog(ERROR, "constraint %u already has a parent constraint",
1281  childConstrId);
1282 
1283  constrForm->conislocal = false;
1284  constrForm->coninhcount++;
1285  if (constrForm->coninhcount < 0)
1286  ereport(ERROR,
1287  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1288  errmsg("too many inheritance parents"));
1289  constrForm->conparentid = parentConstrId;
1290 
1291  CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
1292 
1293  ObjectAddressSet(depender, ConstraintRelationId, childConstrId);
1294 
1295  ObjectAddressSet(referenced, ConstraintRelationId, parentConstrId);
1296  recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI);
1297 
1298  ObjectAddressSet(referenced, RelationRelationId, childTableId);
1299  recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC);
1300  }
1301  else
1302  {
1303  constrForm->coninhcount--;
1304  constrForm->conislocal = true;
1305  constrForm->conparentid = InvalidOid;
1306 
1307  /* Make sure there's no further inheritance. */
1308  Assert(constrForm->coninhcount == 0);
1309 
1310  CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
1311 
1312  deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
1313  ConstraintRelationId,
1315  deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
1316  RelationRelationId,
1318  }
1319 
1320  ReleaseSysCache(tuple);
1321  table_close(constrRel, RowExclusiveLock);
1322 }
1323 
1324 
1325 /*
1326  * get_relation_constraint_oid
1327  * Find a constraint on the specified relation with the specified name.
1328  * Returns constraint's OID.
1329  */
1330 Oid
1331 get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
1332 {
1333  Relation pg_constraint;
1334  HeapTuple tuple;
1335  SysScanDesc scan;
1336  ScanKeyData skey[3];
1337  Oid conOid = InvalidOid;
1338 
1339  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1340 
1341  ScanKeyInit(&skey[0],
1342  Anum_pg_constraint_conrelid,
1343  BTEqualStrategyNumber, F_OIDEQ,
1344  ObjectIdGetDatum(relid));
1345  ScanKeyInit(&skey[1],
1346  Anum_pg_constraint_contypid,
1347  BTEqualStrategyNumber, F_OIDEQ,
1349  ScanKeyInit(&skey[2],
1350  Anum_pg_constraint_conname,
1351  BTEqualStrategyNumber, F_NAMEEQ,
1352  CStringGetDatum(conname));
1353 
1354  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1355  NULL, 3, skey);
1356 
1357  /* There can be at most one matching row */
1358  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1359  conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1360 
1361  systable_endscan(scan);
1362 
1363  /* If no such constraint exists, complain */
1364  if (!OidIsValid(conOid) && !missing_ok)
1365  ereport(ERROR,
1366  (errcode(ERRCODE_UNDEFINED_OBJECT),
1367  errmsg("constraint \"%s\" for table \"%s\" does not exist",
1368  conname, get_rel_name(relid))));
1369 
1370  table_close(pg_constraint, AccessShareLock);
1371 
1372  return conOid;
1373 }
1374 
1375 /*
1376  * get_relation_constraint_attnos
1377  * Find a constraint on the specified relation with the specified name
1378  * and return the constrained columns.
1379  *
1380  * Returns a Bitmapset of the column attnos of the constrained columns, with
1381  * attnos being offset by FirstLowInvalidHeapAttributeNumber so that system
1382  * columns can be represented.
1383  *
1384  * *constraintOid is set to the OID of the constraint, or InvalidOid on
1385  * failure.
1386  */
1387 Bitmapset *
1388 get_relation_constraint_attnos(Oid relid, const char *conname,
1389  bool missing_ok, Oid *constraintOid)
1390 {
1391  Bitmapset *conattnos = NULL;
1392  Relation pg_constraint;
1393  HeapTuple tuple;
1394  SysScanDesc scan;
1395  ScanKeyData skey[3];
1396 
1397  /* Set *constraintOid, to avoid complaints about uninitialized vars */
1398  *constraintOid = InvalidOid;
1399 
1400  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1401 
1402  ScanKeyInit(&skey[0],
1403  Anum_pg_constraint_conrelid,
1404  BTEqualStrategyNumber, F_OIDEQ,
1405  ObjectIdGetDatum(relid));
1406  ScanKeyInit(&skey[1],
1407  Anum_pg_constraint_contypid,
1408  BTEqualStrategyNumber, F_OIDEQ,
1410  ScanKeyInit(&skey[2],
1411  Anum_pg_constraint_conname,
1412  BTEqualStrategyNumber, F_NAMEEQ,
1413  CStringGetDatum(conname));
1414 
1415  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1416  NULL, 3, skey);
1417 
1418  /* There can be at most one matching row */
1419  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1420  {
1421  Datum adatum;
1422  bool isNull;
1423 
1424  *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1425 
1426  /* Extract the conkey array, ie, attnums of constrained columns */
1427  adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
1428  RelationGetDescr(pg_constraint), &isNull);
1429  if (!isNull)
1430  {
1431  ArrayType *arr;
1432  int numcols;
1433  int16 *attnums;
1434  int i;
1435 
1436  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1437  numcols = ARR_DIMS(arr)[0];
1438  if (ARR_NDIM(arr) != 1 ||
1439  numcols < 0 ||
1440  ARR_HASNULL(arr) ||
1441  ARR_ELEMTYPE(arr) != INT2OID)
1442  elog(ERROR, "conkey is not a 1-D smallint array");
1443  attnums = (int16 *) ARR_DATA_PTR(arr);
1444 
1445  /* Construct the result value */
1446  for (i = 0; i < numcols; i++)
1447  {
1448  conattnos = bms_add_member(conattnos,
1450  }
1451  }
1452  }
1453 
1454  systable_endscan(scan);
1455 
1456  /* If no such constraint exists, complain */
1457  if (!OidIsValid(*constraintOid) && !missing_ok)
1458  ereport(ERROR,
1459  (errcode(ERRCODE_UNDEFINED_OBJECT),
1460  errmsg("constraint \"%s\" for table \"%s\" does not exist",
1461  conname, get_rel_name(relid))));
1462 
1463  table_close(pg_constraint, AccessShareLock);
1464 
1465  return conattnos;
1466 }
1467 
1468 /*
1469  * Return the OID of the constraint enforced by the given index in the
1470  * given relation; or InvalidOid if no such index is cataloged.
1471  *
1472  * Much like get_constraint_index, this function is concerned only with the
1473  * one constraint that "owns" the given index. Therefore, constraints of
1474  * types other than unique, primary-key, and exclusion are ignored.
1475  */
1476 Oid
1478 {
1479  Relation pg_constraint;
1480  SysScanDesc scan;
1481  ScanKeyData key;
1482  HeapTuple tuple;
1483  Oid constraintId = InvalidOid;
1484 
1485  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1486 
1487  ScanKeyInit(&key,
1488  Anum_pg_constraint_conrelid,
1490  F_OIDEQ,
1491  ObjectIdGetDatum(relationId));
1492  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
1493  true, NULL, 1, &key);
1494  while ((tuple = systable_getnext(scan)) != NULL)
1495  {
1496  Form_pg_constraint constrForm;
1497 
1498  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
1499 
1500  /* See above */
1501  if (constrForm->contype != CONSTRAINT_PRIMARY &&
1502  constrForm->contype != CONSTRAINT_UNIQUE &&
1503  constrForm->contype != CONSTRAINT_EXCLUSION)
1504  continue;
1505 
1506  if (constrForm->conindid == indexId)
1507  {
1508  constraintId = constrForm->oid;
1509  break;
1510  }
1511  }
1512  systable_endscan(scan);
1513 
1514  table_close(pg_constraint, AccessShareLock);
1515  return constraintId;
1516 }
1517 
1518 /*
1519  * get_domain_constraint_oid
1520  * Find a constraint on the specified domain with the specified name.
1521  * Returns constraint's OID.
1522  */
1523 Oid
1524 get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
1525 {
1526  Relation pg_constraint;
1527  HeapTuple tuple;
1528  SysScanDesc scan;
1529  ScanKeyData skey[3];
1530  Oid conOid = InvalidOid;
1531 
1532  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1533 
1534  ScanKeyInit(&skey[0],
1535  Anum_pg_constraint_conrelid,
1536  BTEqualStrategyNumber, F_OIDEQ,
1538  ScanKeyInit(&skey[1],
1539  Anum_pg_constraint_contypid,
1540  BTEqualStrategyNumber, F_OIDEQ,
1541  ObjectIdGetDatum(typid));
1542  ScanKeyInit(&skey[2],
1543  Anum_pg_constraint_conname,
1544  BTEqualStrategyNumber, F_NAMEEQ,
1545  CStringGetDatum(conname));
1546 
1547  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1548  NULL, 3, skey);
1549 
1550  /* There can be at most one matching row */
1551  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1552  conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1553 
1554  systable_endscan(scan);
1555 
1556  /* If no such constraint exists, complain */
1557  if (!OidIsValid(conOid) && !missing_ok)
1558  ereport(ERROR,
1559  (errcode(ERRCODE_UNDEFINED_OBJECT),
1560  errmsg("constraint \"%s\" for domain %s does not exist",
1561  conname, format_type_be(typid))));
1562 
1563  table_close(pg_constraint, AccessShareLock);
1564 
1565  return conOid;
1566 }
1567 
1568 /*
1569  * get_primary_key_attnos
1570  * Identify the columns in a relation's primary key, if any.
1571  *
1572  * Returns a Bitmapset of the column attnos of the primary key's columns,
1573  * with attnos being offset by FirstLowInvalidHeapAttributeNumber so that
1574  * system columns can be represented.
1575  *
1576  * If there is no primary key, return NULL. We also return NULL if the pkey
1577  * constraint is deferrable and deferrableOk is false.
1578  *
1579  * *constraintOid is set to the OID of the pkey constraint, or InvalidOid
1580  * on failure.
1581  */
1582 Bitmapset *
1583 get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid)
1584 {
1585  Bitmapset *pkattnos = NULL;
1586  Relation pg_constraint;
1587  HeapTuple tuple;
1588  SysScanDesc scan;
1589  ScanKeyData skey[1];
1590 
1591  /* Set *constraintOid, to avoid complaints about uninitialized vars */
1592  *constraintOid = InvalidOid;
1593 
1594  /* Scan pg_constraint for constraints of the target rel */
1595  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1596 
1597  ScanKeyInit(&skey[0],
1598  Anum_pg_constraint_conrelid,
1599  BTEqualStrategyNumber, F_OIDEQ,
1600  ObjectIdGetDatum(relid));
1601 
1602  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1603  NULL, 1, skey);
1604 
1605  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1606  {
1608  Datum adatum;
1609  bool isNull;
1610  ArrayType *arr;
1611  int16 *attnums;
1612  int numkeys;
1613  int i;
1614 
1615  /* Skip constraints that are not PRIMARY KEYs */
1616  if (con->contype != CONSTRAINT_PRIMARY)
1617  continue;
1618 
1619  /*
1620  * If the primary key is deferrable, but we've been instructed to
1621  * ignore deferrable constraints, then we might as well give up
1622  * searching, since there can only be a single primary key on a table.
1623  */
1624  if (con->condeferrable && !deferrableOk)
1625  break;
1626 
1627  /* Extract the conkey array, ie, attnums of PK's columns */
1628  adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
1629  RelationGetDescr(pg_constraint), &isNull);
1630  if (isNull)
1631  elog(ERROR, "null conkey for constraint %u",
1632  ((Form_pg_constraint) GETSTRUCT(tuple))->oid);
1633  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1634  numkeys = ARR_DIMS(arr)[0];
1635  if (ARR_NDIM(arr) != 1 ||
1636  numkeys < 0 ||
1637  ARR_HASNULL(arr) ||
1638  ARR_ELEMTYPE(arr) != INT2OID)
1639  elog(ERROR, "conkey is not a 1-D smallint array");
1640  attnums = (int16 *) ARR_DATA_PTR(arr);
1641 
1642  /* Construct the result value */
1643  for (i = 0; i < numkeys; i++)
1644  {
1645  pkattnos = bms_add_member(pkattnos,
1647  }
1648  *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1649 
1650  /* No need to search further */
1651  break;
1652  }
1653 
1654  systable_endscan(scan);
1655 
1656  table_close(pg_constraint, AccessShareLock);
1657 
1658  return pkattnos;
1659 }
1660 
1661 /*
1662  * Extract data from the pg_constraint tuple of a foreign-key constraint.
1663  *
1664  * All arguments save the first are output arguments. All output arguments
1665  * other than numfks, conkey and confkey can be passed as NULL if caller
1666  * doesn't need them.
1667  */
1668 void
1670  AttrNumber *conkey, AttrNumber *confkey,
1671  Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs,
1672  int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
1673 {
1674  Datum adatum;
1675  bool isNull;
1676  ArrayType *arr;
1677  int numkeys;
1678 
1679  /*
1680  * We expect the arrays to be 1-D arrays of the right types; verify that.
1681  * We don't need to use deconstruct_array() since the array data is just
1682  * going to look like a C array of values.
1683  */
1684  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1685  Anum_pg_constraint_conkey);
1686  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1687  if (ARR_NDIM(arr) != 1 ||
1688  ARR_HASNULL(arr) ||
1689  ARR_ELEMTYPE(arr) != INT2OID)
1690  elog(ERROR, "conkey is not a 1-D smallint array");
1691  numkeys = ARR_DIMS(arr)[0];
1692  if (numkeys <= 0 || numkeys > INDEX_MAX_KEYS)
1693  elog(ERROR, "foreign key constraint cannot have %d columns", numkeys);
1694  memcpy(conkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1695  if ((Pointer) arr != DatumGetPointer(adatum))
1696  pfree(arr); /* free de-toasted copy, if any */
1697 
1698  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1699  Anum_pg_constraint_confkey);
1700  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1701  if (ARR_NDIM(arr) != 1 ||
1702  ARR_DIMS(arr)[0] != numkeys ||
1703  ARR_HASNULL(arr) ||
1704  ARR_ELEMTYPE(arr) != INT2OID)
1705  elog(ERROR, "confkey is not a 1-D smallint array");
1706  memcpy(confkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1707  if ((Pointer) arr != DatumGetPointer(adatum))
1708  pfree(arr); /* free de-toasted copy, if any */
1709 
1710  if (pf_eq_oprs)
1711  {
1712  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1713  Anum_pg_constraint_conpfeqop);
1714  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1715  /* see TryReuseForeignKey if you change the test below */
1716  if (ARR_NDIM(arr) != 1 ||
1717  ARR_DIMS(arr)[0] != numkeys ||
1718  ARR_HASNULL(arr) ||
1719  ARR_ELEMTYPE(arr) != OIDOID)
1720  elog(ERROR, "conpfeqop is not a 1-D Oid array");
1721  memcpy(pf_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1722  if ((Pointer) arr != DatumGetPointer(adatum))
1723  pfree(arr); /* free de-toasted copy, if any */
1724  }
1725 
1726  if (pp_eq_oprs)
1727  {
1728  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1729  Anum_pg_constraint_conppeqop);
1730  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1731  if (ARR_NDIM(arr) != 1 ||
1732  ARR_DIMS(arr)[0] != numkeys ||
1733  ARR_HASNULL(arr) ||
1734  ARR_ELEMTYPE(arr) != OIDOID)
1735  elog(ERROR, "conppeqop is not a 1-D Oid array");
1736  memcpy(pp_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1737  if ((Pointer) arr != DatumGetPointer(adatum))
1738  pfree(arr); /* free de-toasted copy, if any */
1739  }
1740 
1741  if (ff_eq_oprs)
1742  {
1743  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1744  Anum_pg_constraint_conffeqop);
1745  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1746  if (ARR_NDIM(arr) != 1 ||
1747  ARR_DIMS(arr)[0] != numkeys ||
1748  ARR_HASNULL(arr) ||
1749  ARR_ELEMTYPE(arr) != OIDOID)
1750  elog(ERROR, "conffeqop is not a 1-D Oid array");
1751  memcpy(ff_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1752  if ((Pointer) arr != DatumGetPointer(adatum))
1753  pfree(arr); /* free de-toasted copy, if any */
1754  }
1755 
1756  if (fk_del_set_cols)
1757  {
1758  adatum = SysCacheGetAttr(CONSTROID, tuple,
1759  Anum_pg_constraint_confdelsetcols, &isNull);
1760  if (isNull)
1761  {
1762  *num_fk_del_set_cols = 0;
1763  }
1764  else
1765  {
1766  int num_delete_cols;
1767 
1768  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1769  if (ARR_NDIM(arr) != 1 ||
1770  ARR_HASNULL(arr) ||
1771  ARR_ELEMTYPE(arr) != INT2OID)
1772  elog(ERROR, "confdelsetcols is not a 1-D smallint array");
1773  num_delete_cols = ARR_DIMS(arr)[0];
1774  memcpy(fk_del_set_cols, ARR_DATA_PTR(arr), num_delete_cols * sizeof(int16));
1775  if ((Pointer) arr != DatumGetPointer(adatum))
1776  pfree(arr); /* free de-toasted copy, if any */
1777 
1778  *num_fk_del_set_cols = num_delete_cols;
1779  }
1780  }
1781 
1782  *numfks = numkeys;
1783 }
1784 
1785 /*
1786  * FindFKPeriodOpers -
1787  *
1788  * Looks up the operator oids used for the PERIOD part of a temporal foreign key.
1789  * The opclass should be the opclass of that PERIOD element.
1790  * Everything else is an output: containedbyoperoid is the ContainedBy operator for
1791  * types matching the PERIOD element.
1792  * aggedcontainedbyoperoid is also a ContainedBy operator,
1793  * but one whose rhs is a multirange.
1794  * That way foreign keys can compare fkattr <@ range_agg(pkattr).
1795  */
1796 void
1798  Oid *containedbyoperoid,
1799  Oid *aggedcontainedbyoperoid)
1800 {
1801  Oid opfamily = InvalidOid;
1802  Oid opcintype = InvalidOid;
1803  StrategyNumber strat;
1804 
1805  /* Make sure we have a range or multirange. */
1806  if (get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
1807  {
1808  if (opcintype != ANYRANGEOID && opcintype != ANYMULTIRANGEOID)
1809  ereport(ERROR,
1810  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1811  errmsg("invalid type for PERIOD part of foreign key"),
1812  errdetail("Only range and multirange are supported."));
1813 
1814  }
1815  else
1816  elog(ERROR, "cache lookup failed for opclass %u", opclass);
1817 
1818  /*
1819  * Look up the ContainedBy operator whose lhs and rhs are the opclass's
1820  * type. We use this to optimize RI checks: if the new value includes all
1821  * of the old value, then we can treat the attribute as if it didn't
1822  * change, and skip the RI check.
1823  */
1826  InvalidOid,
1827  containedbyoperoid,
1828  &strat);
1829 
1830  /*
1831  * Now look up the ContainedBy operator. Its left arg must be the type of
1832  * the column (or rather of the opclass). Its right arg must match the
1833  * return type of the support proc.
1834  */
1837  ANYMULTIRANGEOID,
1838  aggedcontainedbyoperoid,
1839  &strat);
1840 }
1841 
1842 /*
1843  * Determine whether a relation can be proven functionally dependent on
1844  * a set of grouping columns. If so, return true and add the pg_constraint
1845  * OIDs of the constraints needed for the proof to the *constraintDeps list.
1846  *
1847  * grouping_columns is a list of grouping expressions, in which columns of
1848  * the rel of interest are Vars with the indicated varno/varlevelsup.
1849  *
1850  * Currently we only check to see if the rel has a primary key that is a
1851  * subset of the grouping_columns. We could also use plain unique constraints
1852  * if all their columns are known not null, but there's a problem: we need
1853  * to be able to represent the not-null-ness as part of the constraints added
1854  * to *constraintDeps. FIXME whenever not-null constraints get represented
1855  * in pg_constraint.
1856  */
1857 bool
1859  Index varno, Index varlevelsup,
1860  List *grouping_columns,
1861  List **constraintDeps)
1862 {
1863  Bitmapset *pkattnos;
1864  Bitmapset *groupbyattnos;
1865  Oid constraintOid;
1866  ListCell *gl;
1867 
1868  /* If the rel has no PK, then we can't prove functional dependency */
1869  pkattnos = get_primary_key_attnos(relid, false, &constraintOid);
1870  if (pkattnos == NULL)
1871  return false;
1872 
1873  /* Identify all the rel's columns that appear in grouping_columns */
1874  groupbyattnos = NULL;
1875  foreach(gl, grouping_columns)
1876  {
1877  Var *gvar = (Var *) lfirst(gl);
1878 
1879  if (IsA(gvar, Var) &&
1880  gvar->varno == varno &&
1881  gvar->varlevelsup == varlevelsup)
1882  groupbyattnos = bms_add_member(groupbyattnos,
1884  }
1885 
1886  if (bms_is_subset(pkattnos, groupbyattnos))
1887  {
1888  /* The PK is a subset of grouping_columns, so we win */
1889  *constraintDeps = lappend_oid(*constraintDeps, constraintOid);
1890  return true;
1891  }
1892 
1893  return false;
1894 }
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3374
int16 AttrNumber
Definition: attnum.h:21
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define NameStr(name)
Definition: c.h:746
signed short int16
Definition: c.h:493
char * Pointer
Definition: c.h:483
#define Assert(condition)
Definition: c.h:858
unsigned int Index
Definition: c.h:614
#define OidIsValid(objectId)
Definition: c.h:775
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:391
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2740
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1594
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2591
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2485
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2531
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2771
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errdetail(const char *fmt,...)
Definition: elog.c:1205
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
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2529
void GetOperatorFromWellKnownStrategy(Oid opclass, Oid rhstype, Oid *opid, StrategyNumber *strat)
Definition: indexcmds.c:2441
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
int i
Definition: isn.c:73
List * lappend(List *list, void *datum)
Definition: list.c:339
List * lappend_int(List *list, int datum)
Definition: list.c:357
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define AccessShareLock
Definition: lockdefs.h:36
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1235
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
char * pstrdup(const char *in)
Definition: mcxt.c:1695
void pfree(void *pointer)
Definition: mcxt.c:1520
void * palloc(Size size)
Definition: mcxt.c:1316
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define makeNode(_type_)
Definition: nodes.h:155
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:175
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
@ CONSTR_NOTNULL
Definition: parsenodes.h:2709
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
static char * label
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define INDEX_MAX_KEYS
#define NAMEDATALEN
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
HeapTuple findNotNullConstraint(Oid relid, const char *colname)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
int AdjustNotNullInheritance1(Oid relid, AttrNumber attnum, int count, bool is_no_inherit)
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)
Definition: pg_constraint.c:51
void RemoveConstraintById(Oid conId)
void RenameConstraintById(Oid conId, const char *newname)
Oid get_relation_idx_constraint_oid(Oid relationId, Oid indexId)
void ConstraintSetParentConstraint(Oid childConstrId, Oid parentConstrId, Oid childTableId)
List * RelationGetNotNullConstraints(Oid relid, bool cooked)
HeapTuple findDomainNotNullConstraint(Oid typid)
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 AdjustNotNullInheritance(Oid relid, Bitmapset *columns, int count)
HeapTuple findNotNullConstraintAttnum(Oid relid, AttrNumber attnum)
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
bool ConstraintNameExists(const char *conname, Oid namespaceid)
bool check_functional_grouping(Oid relid, Index varno, Index varlevelsup, List *grouping_columns, List **constraintDeps)
void FindFKPeriodOpers(Oid opclass, Oid *containedbyoperoid, Oid *aggedcontainedbyoperoid)
Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
AttrNumber extractNotNullColumn(HeapTuple constrTup)
Bitmapset * get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid)
Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
Bitmapset * get_relation_constraint_attnos(Oid relid, const char *conname, bool missing_ok, Oid *constraintOid)
FormData_pg_constraint * Form_pg_constraint
ConstraintCategory
@ CONSTRAINT_DOMAIN
@ CONSTRAINT_RELATION
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:350
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define list_make1(x1)
Definition: pg_list.h:212
#define list_make1_int(x1)
Definition: pg_list.h:227
#define snprintf
Definition: port.h:238
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:373
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationGetRelationName(relation)
Definition: rel.h:539
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:5231
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:62
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:63
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
uint16 StrategyNumber
Definition: stratnum.h:22
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define RTContainedByStrategyNumber
Definition: stratnum.h:58
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
bool initdeferred
Definition: parsenodes.h:2742
ParseLoc location
Definition: parsenodes.h:2783
List * keys
Definition: parsenodes.h:2754
ConstrType contype
Definition: parsenodes.h:2739
bool initially_valid
Definition: parsenodes.h:2744
bool skip_validation
Definition: parsenodes.h:2743
bool deferrable
Definition: parsenodes.h:2741
char * conname
Definition: parsenodes.h:2740
char * name
Definition: heap.h:40
AttrNumber attnum
Definition: heap.h:41
bool skip_validation
Definition: heap.h:43
bool is_no_inherit
Definition: heap.h:46
int inhcount
Definition: heap.h:45
bool is_local
Definition: heap.h:44
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:42
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
Definition: nodes.h:129
Definition: primnodes.h:248
AttrNumber varattno
Definition: primnodes.h:260
int varno
Definition: primnodes.h:255
Index varlevelsup
Definition: primnodes.h:280
Definition: c.h:741
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
HeapTuple SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
Definition: syscache.c:445
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:510
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
String * makeString(char *str)
Definition: value.c:63
void CommandCounterIncrement(void)
Definition: xact.c:1097