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-2022, 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/htup_details.h"
19 #include "access/sysattr.h"
20 #include "access/table.h"
21 #include "access/xact.h"
22 #include "catalog/catalog.h"
23 #include "catalog/dependency.h"
24 #include "catalog/indexing.h"
25 #include "catalog/objectaccess.h"
26 #include "catalog/pg_constraint.h"
27 #include "catalog/pg_operator.h"
28 #include "catalog/pg_type.h"
29 #include "commands/defrem.h"
30 #include "commands/tablecmds.h"
31 #include "utils/array.h"
32 #include "utils/builtins.h"
33 #include "utils/fmgroids.h"
34 #include "utils/lsyscache.h"
35 #include "utils/rel.h"
36 #include "utils/syscache.h"
37 
38 
39 /*
40  * CreateConstraintEntry
41  * Create a constraint table entry.
42  *
43  * Subsidiary records (such as triggers or indexes to implement the
44  * constraint) are *not* created here. But we do make dependency links
45  * from the constraint to the things it depends on.
46  *
47  * The new constraint's OID is returned.
48  */
49 Oid
50 CreateConstraintEntry(const char *constraintName,
51  Oid constraintNamespace,
52  char constraintType,
53  bool isDeferrable,
54  bool isDeferred,
55  bool isValidated,
56  Oid parentConstrId,
57  Oid relId,
58  const int16 *constraintKey,
59  int constraintNKeys,
60  int constraintNTotalKeys,
61  Oid domainId,
62  Oid indexRelId,
63  Oid foreignRelId,
64  const int16 *foreignKey,
65  const Oid *pfEqOp,
66  const Oid *ppEqOp,
67  const Oid *ffEqOp,
68  int foreignNKeys,
69  char foreignUpdateType,
70  char foreignDeleteType,
71  const int16 *fkDeleteSetCols,
72  int numFkDeleteSetCols,
73  char foreignMatchType,
74  const Oid *exclOp,
75  Node *conExpr,
76  const char *conBin,
77  bool conIsLocal,
78  int conInhCount,
79  bool conNoInherit,
80  bool is_internal)
81 {
82  Relation conDesc;
83  Oid conOid;
84  HeapTuple tup;
85  bool nulls[Natts_pg_constraint];
86  Datum values[Natts_pg_constraint];
87  ArrayType *conkeyArray;
88  ArrayType *confkeyArray;
89  ArrayType *conpfeqopArray;
90  ArrayType *conppeqopArray;
91  ArrayType *conffeqopArray;
92  ArrayType *conexclopArray;
93  ArrayType *confdelsetcolsArray;
95  int i;
96  ObjectAddress conobject;
97  ObjectAddresses *addrs_auto;
98  ObjectAddresses *addrs_normal;
99 
100  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
101 
102  Assert(constraintName);
103  namestrcpy(&cname, constraintName);
104 
105  /*
106  * Convert C arrays into Postgres arrays.
107  */
108  if (constraintNKeys > 0)
109  {
110  Datum *conkey;
111 
112  conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
113  for (i = 0; i < constraintNKeys; i++)
114  conkey[i] = Int16GetDatum(constraintKey[i]);
115  conkeyArray = construct_array_builtin(conkey, constraintNKeys, INT2OID);
116  }
117  else
118  conkeyArray = NULL;
119 
120  if (foreignNKeys > 0)
121  {
122  Datum *fkdatums;
123 
124  fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
125  for (i = 0; i < foreignNKeys; i++)
126  fkdatums[i] = Int16GetDatum(foreignKey[i]);
127  confkeyArray = construct_array_builtin(fkdatums, foreignNKeys, INT2OID);
128  for (i = 0; i < foreignNKeys; i++)
129  fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
130  conpfeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
131  for (i = 0; i < foreignNKeys; i++)
132  fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
133  conppeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
134  for (i = 0; i < foreignNKeys; i++)
135  fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
136  conffeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
137 
138  if (numFkDeleteSetCols > 0)
139  {
140  for (i = 0; i < numFkDeleteSetCols; i++)
141  fkdatums[i] = Int16GetDatum(fkDeleteSetCols[i]);
142  confdelsetcolsArray = construct_array_builtin(fkdatums, numFkDeleteSetCols, INT2OID);
143  }
144  else
145  confdelsetcolsArray = NULL;
146  }
147  else
148  {
149  confkeyArray = NULL;
150  conpfeqopArray = NULL;
151  conppeqopArray = NULL;
152  conffeqopArray = NULL;
153  confdelsetcolsArray = NULL;
154  }
155 
156  if (exclOp != NULL)
157  {
158  Datum *opdatums;
159 
160  opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum));
161  for (i = 0; i < constraintNKeys; i++)
162  opdatums[i] = ObjectIdGetDatum(exclOp[i]);
163  conexclopArray = construct_array_builtin(opdatums, constraintNKeys, OIDOID);
164  }
165  else
166  conexclopArray = NULL;
167 
168  /* initialize nulls and values */
169  for (i = 0; i < Natts_pg_constraint; i++)
170  {
171  nulls[i] = false;
172  values[i] = (Datum) NULL;
173  }
174 
175  conOid = GetNewOidWithIndex(conDesc, ConstraintOidIndexId,
176  Anum_pg_constraint_oid);
177  values[Anum_pg_constraint_oid - 1] = ObjectIdGetDatum(conOid);
178  values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
179  values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
180  values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
181  values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
182  values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
183  values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated);
184  values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
185  values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
186  values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId);
187  values[Anum_pg_constraint_conparentid - 1] = ObjectIdGetDatum(parentConstrId);
188  values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
189  values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
190  values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
191  values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
192  values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
193  values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
194  values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit);
195 
196  if (conkeyArray)
197  values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
198  else
199  nulls[Anum_pg_constraint_conkey - 1] = true;
200 
201  if (confkeyArray)
202  values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
203  else
204  nulls[Anum_pg_constraint_confkey - 1] = true;
205 
206  if (conpfeqopArray)
207  values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
208  else
209  nulls[Anum_pg_constraint_conpfeqop - 1] = true;
210 
211  if (conppeqopArray)
212  values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
213  else
214  nulls[Anum_pg_constraint_conppeqop - 1] = true;
215 
216  if (conffeqopArray)
217  values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
218  else
219  nulls[Anum_pg_constraint_conffeqop - 1] = true;
220 
221  if (confdelsetcolsArray)
222  values[Anum_pg_constraint_confdelsetcols - 1] = PointerGetDatum(confdelsetcolsArray);
223  else
224  nulls[Anum_pg_constraint_confdelsetcols - 1] = true;
225 
226  if (conexclopArray)
227  values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray);
228  else
229  nulls[Anum_pg_constraint_conexclop - 1] = true;
230 
231  if (conBin)
232  values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
233  else
234  nulls[Anum_pg_constraint_conbin - 1] = true;
235 
236  tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
237 
238  CatalogTupleInsert(conDesc, tup);
239 
240  ObjectAddressSet(conobject, ConstraintRelationId, conOid);
241 
242  table_close(conDesc, RowExclusiveLock);
243 
244  /* Handle set of auto dependencies */
245  addrs_auto = new_object_addresses();
246 
247  if (OidIsValid(relId))
248  {
249  /*
250  * Register auto dependency from constraint to owning relation, or to
251  * specific column(s) if any are mentioned.
252  */
253  ObjectAddress relobject;
254 
255  if (constraintNTotalKeys > 0)
256  {
257  for (i = 0; i < constraintNTotalKeys; i++)
258  {
259  ObjectAddressSubSet(relobject, RelationRelationId, relId,
260  constraintKey[i]);
261  add_exact_object_address(&relobject, addrs_auto);
262  }
263  }
264  else
265  {
266  ObjectAddressSet(relobject, RelationRelationId, relId);
267  add_exact_object_address(&relobject, addrs_auto);
268  }
269  }
270 
271  if (OidIsValid(domainId))
272  {
273  /*
274  * Register auto dependency from constraint to owning domain
275  */
276  ObjectAddress domobject;
277 
278  ObjectAddressSet(domobject, TypeRelationId, domainId);
279  add_exact_object_address(&domobject, addrs_auto);
280  }
281 
282  record_object_address_dependencies(&conobject, addrs_auto,
284  free_object_addresses(addrs_auto);
285 
286  /* Handle set of normal dependencies */
287  addrs_normal = new_object_addresses();
288 
289  if (OidIsValid(foreignRelId))
290  {
291  /*
292  * Register normal dependency from constraint to foreign relation, or
293  * to specific column(s) if any are mentioned.
294  */
295  ObjectAddress relobject;
296 
297  if (foreignNKeys > 0)
298  {
299  for (i = 0; i < foreignNKeys; i++)
300  {
301  ObjectAddressSubSet(relobject, RelationRelationId,
302  foreignRelId, foreignKey[i]);
303  add_exact_object_address(&relobject, addrs_normal);
304  }
305  }
306  else
307  {
308  ObjectAddressSet(relobject, RelationRelationId, foreignRelId);
309  add_exact_object_address(&relobject, addrs_normal);
310  }
311  }
312 
313  if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
314  {
315  /*
316  * Register normal dependency on the unique index that supports a
317  * foreign-key constraint. (Note: for indexes associated with unique
318  * or primary-key constraints, the dependency runs the other way, and
319  * is not made here.)
320  */
321  ObjectAddress relobject;
322 
323  ObjectAddressSet(relobject, RelationRelationId, indexRelId);
324  add_exact_object_address(&relobject, addrs_normal);
325  }
326 
327  if (foreignNKeys > 0)
328  {
329  /*
330  * Register normal dependencies on the equality operators that support
331  * a foreign-key constraint. If the PK and FK types are the same then
332  * all three operators for a column are the same; otherwise they are
333  * different.
334  */
335  ObjectAddress oprobject;
336 
337  oprobject.classId = OperatorRelationId;
338  oprobject.objectSubId = 0;
339 
340  for (i = 0; i < foreignNKeys; i++)
341  {
342  oprobject.objectId = pfEqOp[i];
343  add_exact_object_address(&oprobject, addrs_normal);
344  if (ppEqOp[i] != pfEqOp[i])
345  {
346  oprobject.objectId = ppEqOp[i];
347  add_exact_object_address(&oprobject, addrs_normal);
348  }
349  if (ffEqOp[i] != pfEqOp[i])
350  {
351  oprobject.objectId = ffEqOp[i];
352  add_exact_object_address(&oprobject, addrs_normal);
353  }
354  }
355  }
356 
357  record_object_address_dependencies(&conobject, addrs_normal,
359  free_object_addresses(addrs_normal);
360 
361  /*
362  * We don't bother to register dependencies on the exclusion operators of
363  * an exclusion constraint. We assume they are members of the opclass
364  * supporting the index, so there's an indirect dependency via that. (This
365  * would be pretty dicey for cross-type operators, but exclusion operators
366  * can never be cross-type.)
367  */
368 
369  if (conExpr != NULL)
370  {
371  /*
372  * Register dependencies from constraint to objects mentioned in CHECK
373  * expression.
374  */
375  recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
377  DEPENDENCY_NORMAL, false);
378  }
379 
380  /* Post creation hook for new constraint */
381  InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
382  is_internal);
383 
384  return conOid;
385 }
386 
387 /*
388  * Test whether given name is currently used as a constraint name
389  * for the given object (relation or domain).
390  *
391  * This is used to decide whether to accept a user-specified constraint name.
392  * It is deliberately not the same test as ChooseConstraintName uses to decide
393  * whether an auto-generated name is OK: here, we will allow it unless there
394  * is an identical constraint name in use *on the same object*.
395  *
396  * NB: Caller should hold exclusive lock on the given object, else
397  * this test can be fooled by concurrent additions.
398  */
399 bool
401  const char *conname)
402 {
403  bool found;
404  Relation conDesc;
405  SysScanDesc conscan;
406  ScanKeyData skey[3];
407 
408  conDesc = table_open(ConstraintRelationId, AccessShareLock);
409 
410  ScanKeyInit(&skey[0],
411  Anum_pg_constraint_conrelid,
412  BTEqualStrategyNumber, F_OIDEQ,
414  ? objId : InvalidOid));
415  ScanKeyInit(&skey[1],
416  Anum_pg_constraint_contypid,
417  BTEqualStrategyNumber, F_OIDEQ,
419  ? objId : InvalidOid));
420  ScanKeyInit(&skey[2],
421  Anum_pg_constraint_conname,
422  BTEqualStrategyNumber, F_NAMEEQ,
423  CStringGetDatum(conname));
424 
425  conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId,
426  true, NULL, 3, skey);
427 
428  /* There can be at most one matching row */
429  found = (HeapTupleIsValid(systable_getnext(conscan)));
430 
431  systable_endscan(conscan);
432  table_close(conDesc, AccessShareLock);
433 
434  return found;
435 }
436 
437 /*
438  * Does any constraint of the given name exist in the given namespace?
439  *
440  * This is used for code that wants to match ChooseConstraintName's rule
441  * that we should avoid autogenerating duplicate constraint names within a
442  * namespace.
443  */
444 bool
445 ConstraintNameExists(const char *conname, Oid namespaceid)
446 {
447  bool found;
448  Relation conDesc;
449  SysScanDesc conscan;
450  ScanKeyData skey[2];
451 
452  conDesc = table_open(ConstraintRelationId, AccessShareLock);
453 
454  ScanKeyInit(&skey[0],
455  Anum_pg_constraint_conname,
456  BTEqualStrategyNumber, F_NAMEEQ,
457  CStringGetDatum(conname));
458 
459  ScanKeyInit(&skey[1],
460  Anum_pg_constraint_connamespace,
461  BTEqualStrategyNumber, F_OIDEQ,
462  ObjectIdGetDatum(namespaceid));
463 
464  conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
465  NULL, 2, skey);
466 
467  found = (HeapTupleIsValid(systable_getnext(conscan)));
468 
469  systable_endscan(conscan);
470  table_close(conDesc, AccessShareLock);
471 
472  return found;
473 }
474 
475 /*
476  * Select a nonconflicting name for a new constraint.
477  *
478  * The objective here is to choose a name that is unique within the
479  * specified namespace. Postgres does not require this, but the SQL
480  * spec does, and some apps depend on it. Therefore we avoid choosing
481  * default names that so conflict.
482  *
483  * name1, name2, and label are used the same way as for makeObjectName(),
484  * except that the label can't be NULL; digits will be appended to the label
485  * if needed to create a name that is unique within the specified namespace.
486  *
487  * 'others' can be a list of string names already chosen within the current
488  * command (but not yet reflected into the catalogs); we will not choose
489  * a duplicate of one of these either.
490  *
491  * Note: it is theoretically possible to get a collision anyway, if someone
492  * else chooses the same name concurrently. This is fairly unlikely to be
493  * a problem in practice, especially if one is holding an exclusive lock on
494  * the relation identified by name1.
495  *
496  * Returns a palloc'd string.
497  */
498 char *
499 ChooseConstraintName(const char *name1, const char *name2,
500  const char *label, Oid namespaceid,
501  List *others)
502 {
503  int pass = 0;
504  char *conname = NULL;
505  char modlabel[NAMEDATALEN];
506  Relation conDesc;
507  SysScanDesc conscan;
508  ScanKeyData skey[2];
509  bool found;
510  ListCell *l;
511 
512  conDesc = table_open(ConstraintRelationId, AccessShareLock);
513 
514  /* try the unmodified label first */
515  strlcpy(modlabel, label, sizeof(modlabel));
516 
517  for (;;)
518  {
519  conname = makeObjectName(name1, name2, modlabel);
520 
521  found = false;
522 
523  foreach(l, others)
524  {
525  if (strcmp((char *) lfirst(l), conname) == 0)
526  {
527  found = true;
528  break;
529  }
530  }
531 
532  if (!found)
533  {
534  ScanKeyInit(&skey[0],
535  Anum_pg_constraint_conname,
536  BTEqualStrategyNumber, F_NAMEEQ,
537  CStringGetDatum(conname));
538 
539  ScanKeyInit(&skey[1],
540  Anum_pg_constraint_connamespace,
541  BTEqualStrategyNumber, F_OIDEQ,
542  ObjectIdGetDatum(namespaceid));
543 
544  conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
545  NULL, 2, skey);
546 
547  found = (HeapTupleIsValid(systable_getnext(conscan)));
548 
549  systable_endscan(conscan);
550  }
551 
552  if (!found)
553  break;
554 
555  /* found a conflict, so try a new name component */
556  pfree(conname);
557  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
558  }
559 
560  table_close(conDesc, AccessShareLock);
561 
562  return conname;
563 }
564 
565 /*
566  * Delete a single constraint record.
567  */
568 void
570 {
571  Relation conDesc;
572  HeapTuple tup;
573  Form_pg_constraint con;
574 
575  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
576 
578  if (!HeapTupleIsValid(tup)) /* should not happen */
579  elog(ERROR, "cache lookup failed for constraint %u", conId);
580  con = (Form_pg_constraint) GETSTRUCT(tup);
581 
582  /*
583  * Special processing depending on what the constraint is for.
584  */
585  if (OidIsValid(con->conrelid))
586  {
587  Relation rel;
588 
589  /*
590  * If the constraint is for a relation, open and exclusive-lock the
591  * relation it's for.
592  */
593  rel = table_open(con->conrelid, AccessExclusiveLock);
594 
595  /*
596  * We need to update the relchecks count if it is a check constraint
597  * being dropped. This update will force backends to rebuild relcache
598  * entries when we commit.
599  */
600  if (con->contype == CONSTRAINT_CHECK)
601  {
602  Relation pgrel;
603  HeapTuple relTup;
604  Form_pg_class classForm;
605 
606  pgrel = table_open(RelationRelationId, RowExclusiveLock);
607  relTup = SearchSysCacheCopy1(RELOID,
608  ObjectIdGetDatum(con->conrelid));
609  if (!HeapTupleIsValid(relTup))
610  elog(ERROR, "cache lookup failed for relation %u",
611  con->conrelid);
612  classForm = (Form_pg_class) GETSTRUCT(relTup);
613 
614  if (classForm->relchecks == 0) /* should not happen */
615  elog(ERROR, "relation \"%s\" has relchecks = 0",
617  classForm->relchecks--;
618 
619  CatalogTupleUpdate(pgrel, &relTup->t_self, relTup);
620 
621  heap_freetuple(relTup);
622 
624  }
625 
626  /* Keep lock on constraint's rel until end of xact */
627  table_close(rel, NoLock);
628  }
629  else if (OidIsValid(con->contypid))
630  {
631  /*
632  * XXX for now, do nothing special when dropping a domain constraint
633  *
634  * Probably there should be some form of locking on the domain type,
635  * but we have no such concept at the moment.
636  */
637  }
638  else
639  elog(ERROR, "constraint %u is not of a known type", conId);
640 
641  /* Fry the constraint itself */
642  CatalogTupleDelete(conDesc, &tup->t_self);
643 
644  /* Clean up */
645  ReleaseSysCache(tup);
646  table_close(conDesc, RowExclusiveLock);
647 }
648 
649 /*
650  * RenameConstraintById
651  * Rename a constraint.
652  *
653  * Note: this isn't intended to be a user-exposed function; it doesn't check
654  * permissions etc. Currently this is only invoked when renaming an index
655  * that is associated with a constraint, but it's made a little more general
656  * than that with the expectation of someday having ALTER TABLE RENAME
657  * CONSTRAINT.
658  */
659 void
660 RenameConstraintById(Oid conId, const char *newname)
661 {
662  Relation conDesc;
663  HeapTuple tuple;
664  Form_pg_constraint con;
665 
666  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
667 
669  if (!HeapTupleIsValid(tuple))
670  elog(ERROR, "cache lookup failed for constraint %u", conId);
671  con = (Form_pg_constraint) GETSTRUCT(tuple);
672 
673  /*
674  * For user-friendliness, check whether the name is already in use.
675  */
676  if (OidIsValid(con->conrelid) &&
678  con->conrelid,
679  newname))
680  ereport(ERROR,
682  errmsg("constraint \"%s\" for relation \"%s\" already exists",
683  newname, get_rel_name(con->conrelid))));
684  if (OidIsValid(con->contypid) &&
686  con->contypid,
687  newname))
688  ereport(ERROR,
690  errmsg("constraint \"%s\" for domain %s already exists",
691  newname, format_type_be(con->contypid))));
692 
693  /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
694  namestrcpy(&(con->conname), newname);
695 
696  CatalogTupleUpdate(conDesc, &tuple->t_self, tuple);
697 
698  InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
699 
700  heap_freetuple(tuple);
701  table_close(conDesc, RowExclusiveLock);
702 }
703 
704 /*
705  * AlterConstraintNamespaces
706  * Find any constraints belonging to the specified object,
707  * and move them to the specified new namespace.
708  *
709  * isType indicates whether the owning object is a type or a relation.
710  */
711 void
713  Oid newNspId, bool isType, ObjectAddresses *objsMoved)
714 {
715  Relation conRel;
716  ScanKeyData key[2];
717  SysScanDesc scan;
718  HeapTuple tup;
719 
720  conRel = table_open(ConstraintRelationId, RowExclusiveLock);
721 
722  ScanKeyInit(&key[0],
723  Anum_pg_constraint_conrelid,
724  BTEqualStrategyNumber, F_OIDEQ,
725  ObjectIdGetDatum(isType ? InvalidOid : ownerId));
726  ScanKeyInit(&key[1],
727  Anum_pg_constraint_contypid,
728  BTEqualStrategyNumber, F_OIDEQ,
729  ObjectIdGetDatum(isType ? ownerId : InvalidOid));
730 
731  scan = systable_beginscan(conRel, ConstraintRelidTypidNameIndexId, true,
732  NULL, 2, key);
733 
734  while (HeapTupleIsValid((tup = systable_getnext(scan))))
735  {
737  ObjectAddress thisobj;
738 
739  ObjectAddressSet(thisobj, ConstraintRelationId, conform->oid);
740 
741  if (object_address_present(&thisobj, objsMoved))
742  continue;
743 
744  /* Don't update if the object is already part of the namespace */
745  if (conform->connamespace == oldNspId && oldNspId != newNspId)
746  {
747  tup = heap_copytuple(tup);
748  conform = (Form_pg_constraint) GETSTRUCT(tup);
749 
750  conform->connamespace = newNspId;
751 
752  CatalogTupleUpdate(conRel, &tup->t_self, tup);
753 
754  /*
755  * Note: currently, the constraint will not have its own
756  * dependency on the namespace, so we don't need to do
757  * changeDependencyFor().
758  */
759  }
760 
761  InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
762 
763  add_exact_object_address(&thisobj, objsMoved);
764  }
765 
766  systable_endscan(scan);
767 
768  table_close(conRel, RowExclusiveLock);
769 }
770 
771 /*
772  * ConstraintSetParentConstraint
773  * Set a partition's constraint as child of its parent constraint,
774  * or remove the linkage if parentConstrId is InvalidOid.
775  *
776  * This updates the constraint's pg_constraint row to show it as inherited, and
777  * adds PARTITION dependencies to prevent the constraint from being deleted
778  * on its own. Alternatively, reverse that.
779  */
780 void
782  Oid parentConstrId,
783  Oid childTableId)
784 {
785  Relation constrRel;
786  Form_pg_constraint constrForm;
787  HeapTuple tuple,
788  newtup;
789  ObjectAddress depender;
790  ObjectAddress referenced;
791 
792  constrRel = table_open(ConstraintRelationId, RowExclusiveLock);
793  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(childConstrId));
794  if (!HeapTupleIsValid(tuple))
795  elog(ERROR, "cache lookup failed for constraint %u", childConstrId);
796  newtup = heap_copytuple(tuple);
797  constrForm = (Form_pg_constraint) GETSTRUCT(newtup);
798  if (OidIsValid(parentConstrId))
799  {
800  /* don't allow setting parent for a constraint that already has one */
801  Assert(constrForm->coninhcount == 0);
802  if (constrForm->conparentid != InvalidOid)
803  elog(ERROR, "constraint %u already has a parent constraint",
804  childConstrId);
805 
806  constrForm->conislocal = false;
807  constrForm->coninhcount++;
808  constrForm->conparentid = parentConstrId;
809 
810  CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
811 
812  ObjectAddressSet(depender, ConstraintRelationId, childConstrId);
813 
814  ObjectAddressSet(referenced, ConstraintRelationId, parentConstrId);
815  recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI);
816 
817  ObjectAddressSet(referenced, RelationRelationId, childTableId);
818  recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC);
819  }
820  else
821  {
822  constrForm->coninhcount--;
823  constrForm->conislocal = true;
824  constrForm->conparentid = InvalidOid;
825 
826  /* Make sure there's no further inheritance. */
827  Assert(constrForm->coninhcount == 0);
828 
829  CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
830 
831  deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
832  ConstraintRelationId,
834  deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
835  RelationRelationId,
837  }
838 
839  ReleaseSysCache(tuple);
840  table_close(constrRel, RowExclusiveLock);
841 }
842 
843 
844 /*
845  * get_relation_constraint_oid
846  * Find a constraint on the specified relation with the specified name.
847  * Returns constraint's OID.
848  */
849 Oid
850 get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
851 {
852  Relation pg_constraint;
853  HeapTuple tuple;
854  SysScanDesc scan;
855  ScanKeyData skey[3];
856  Oid conOid = InvalidOid;
857 
858  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
859 
860  ScanKeyInit(&skey[0],
861  Anum_pg_constraint_conrelid,
862  BTEqualStrategyNumber, F_OIDEQ,
863  ObjectIdGetDatum(relid));
864  ScanKeyInit(&skey[1],
865  Anum_pg_constraint_contypid,
866  BTEqualStrategyNumber, F_OIDEQ,
868  ScanKeyInit(&skey[2],
869  Anum_pg_constraint_conname,
870  BTEqualStrategyNumber, F_NAMEEQ,
871  CStringGetDatum(conname));
872 
873  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
874  NULL, 3, skey);
875 
876  /* There can be at most one matching row */
877  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
878  conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
879 
880  systable_endscan(scan);
881 
882  /* If no such constraint exists, complain */
883  if (!OidIsValid(conOid) && !missing_ok)
884  ereport(ERROR,
885  (errcode(ERRCODE_UNDEFINED_OBJECT),
886  errmsg("constraint \"%s\" for table \"%s\" does not exist",
887  conname, get_rel_name(relid))));
888 
889  table_close(pg_constraint, AccessShareLock);
890 
891  return conOid;
892 }
893 
894 /*
895  * get_relation_constraint_attnos
896  * Find a constraint on the specified relation with the specified name
897  * and return the constrained columns.
898  *
899  * Returns a Bitmapset of the column attnos of the constrained columns, with
900  * attnos being offset by FirstLowInvalidHeapAttributeNumber so that system
901  * columns can be represented.
902  *
903  * *constraintOid is set to the OID of the constraint, or InvalidOid on
904  * failure.
905  */
906 Bitmapset *
907 get_relation_constraint_attnos(Oid relid, const char *conname,
908  bool missing_ok, Oid *constraintOid)
909 {
910  Bitmapset *conattnos = NULL;
911  Relation pg_constraint;
912  HeapTuple tuple;
913  SysScanDesc scan;
914  ScanKeyData skey[3];
915 
916  /* Set *constraintOid, to avoid complaints about uninitialized vars */
917  *constraintOid = InvalidOid;
918 
919  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
920 
921  ScanKeyInit(&skey[0],
922  Anum_pg_constraint_conrelid,
923  BTEqualStrategyNumber, F_OIDEQ,
924  ObjectIdGetDatum(relid));
925  ScanKeyInit(&skey[1],
926  Anum_pg_constraint_contypid,
927  BTEqualStrategyNumber, F_OIDEQ,
929  ScanKeyInit(&skey[2],
930  Anum_pg_constraint_conname,
931  BTEqualStrategyNumber, F_NAMEEQ,
932  CStringGetDatum(conname));
933 
934  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
935  NULL, 3, skey);
936 
937  /* There can be at most one matching row */
938  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
939  {
940  Datum adatum;
941  bool isNull;
942 
943  *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
944 
945  /* Extract the conkey array, ie, attnums of constrained columns */
946  adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
947  RelationGetDescr(pg_constraint), &isNull);
948  if (!isNull)
949  {
950  ArrayType *arr;
951  int numcols;
952  int16 *attnums;
953  int i;
954 
955  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
956  numcols = ARR_DIMS(arr)[0];
957  if (ARR_NDIM(arr) != 1 ||
958  numcols < 0 ||
959  ARR_HASNULL(arr) ||
960  ARR_ELEMTYPE(arr) != INT2OID)
961  elog(ERROR, "conkey is not a 1-D smallint array");
962  attnums = (int16 *) ARR_DATA_PTR(arr);
963 
964  /* Construct the result value */
965  for (i = 0; i < numcols; i++)
966  {
967  conattnos = bms_add_member(conattnos,
969  }
970  }
971  }
972 
973  systable_endscan(scan);
974 
975  /* If no such constraint exists, complain */
976  if (!OidIsValid(*constraintOid) && !missing_ok)
977  ereport(ERROR,
978  (errcode(ERRCODE_UNDEFINED_OBJECT),
979  errmsg("constraint \"%s\" for table \"%s\" does not exist",
980  conname, get_rel_name(relid))));
981 
982  table_close(pg_constraint, AccessShareLock);
983 
984  return conattnos;
985 }
986 
987 /*
988  * Return the OID of the constraint enforced by the given index in the
989  * given relation; or InvalidOid if no such index is catalogued.
990  *
991  * Much like get_constraint_index, this function is concerned only with the
992  * one constraint that "owns" the given index. Therefore, constraints of
993  * types other than unique, primary-key, and exclusion are ignored.
994  */
995 Oid
997 {
998  Relation pg_constraint;
999  SysScanDesc scan;
1000  ScanKeyData key;
1001  HeapTuple tuple;
1002  Oid constraintId = InvalidOid;
1003 
1004  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1005 
1006  ScanKeyInit(&key,
1007  Anum_pg_constraint_conrelid,
1009  F_OIDEQ,
1010  ObjectIdGetDatum(relationId));
1011  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
1012  true, NULL, 1, &key);
1013  while ((tuple = systable_getnext(scan)) != NULL)
1014  {
1015  Form_pg_constraint constrForm;
1016 
1017  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
1018 
1019  /* See above */
1020  if (constrForm->contype != CONSTRAINT_PRIMARY &&
1021  constrForm->contype != CONSTRAINT_UNIQUE &&
1022  constrForm->contype != CONSTRAINT_EXCLUSION)
1023  continue;
1024 
1025  if (constrForm->conindid == indexId)
1026  {
1027  constraintId = constrForm->oid;
1028  break;
1029  }
1030  }
1031  systable_endscan(scan);
1032 
1033  table_close(pg_constraint, AccessShareLock);
1034  return constraintId;
1035 }
1036 
1037 /*
1038  * get_domain_constraint_oid
1039  * Find a constraint on the specified domain with the specified name.
1040  * Returns constraint's OID.
1041  */
1042 Oid
1043 get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
1044 {
1045  Relation pg_constraint;
1046  HeapTuple tuple;
1047  SysScanDesc scan;
1048  ScanKeyData skey[3];
1049  Oid conOid = InvalidOid;
1050 
1051  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1052 
1053  ScanKeyInit(&skey[0],
1054  Anum_pg_constraint_conrelid,
1055  BTEqualStrategyNumber, F_OIDEQ,
1057  ScanKeyInit(&skey[1],
1058  Anum_pg_constraint_contypid,
1059  BTEqualStrategyNumber, F_OIDEQ,
1060  ObjectIdGetDatum(typid));
1061  ScanKeyInit(&skey[2],
1062  Anum_pg_constraint_conname,
1063  BTEqualStrategyNumber, F_NAMEEQ,
1064  CStringGetDatum(conname));
1065 
1066  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1067  NULL, 3, skey);
1068 
1069  /* There can be at most one matching row */
1070  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1071  conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1072 
1073  systable_endscan(scan);
1074 
1075  /* If no such constraint exists, complain */
1076  if (!OidIsValid(conOid) && !missing_ok)
1077  ereport(ERROR,
1078  (errcode(ERRCODE_UNDEFINED_OBJECT),
1079  errmsg("constraint \"%s\" for domain %s does not exist",
1080  conname, format_type_be(typid))));
1081 
1082  table_close(pg_constraint, AccessShareLock);
1083 
1084  return conOid;
1085 }
1086 
1087 /*
1088  * get_primary_key_attnos
1089  * Identify the columns in a relation's primary key, if any.
1090  *
1091  * Returns a Bitmapset of the column attnos of the primary key's columns,
1092  * with attnos being offset by FirstLowInvalidHeapAttributeNumber so that
1093  * system columns can be represented.
1094  *
1095  * If there is no primary key, return NULL. We also return NULL if the pkey
1096  * constraint is deferrable and deferrableOk is false.
1097  *
1098  * *constraintOid is set to the OID of the pkey constraint, or InvalidOid
1099  * on failure.
1100  */
1101 Bitmapset *
1102 get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid)
1103 {
1104  Bitmapset *pkattnos = NULL;
1105  Relation pg_constraint;
1106  HeapTuple tuple;
1107  SysScanDesc scan;
1108  ScanKeyData skey[1];
1109 
1110  /* Set *constraintOid, to avoid complaints about uninitialized vars */
1111  *constraintOid = InvalidOid;
1112 
1113  /* Scan pg_constraint for constraints of the target rel */
1114  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1115 
1116  ScanKeyInit(&skey[0],
1117  Anum_pg_constraint_conrelid,
1118  BTEqualStrategyNumber, F_OIDEQ,
1119  ObjectIdGetDatum(relid));
1120 
1121  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1122  NULL, 1, skey);
1123 
1124  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1125  {
1127  Datum adatum;
1128  bool isNull;
1129  ArrayType *arr;
1130  int16 *attnums;
1131  int numkeys;
1132  int i;
1133 
1134  /* Skip constraints that are not PRIMARY KEYs */
1135  if (con->contype != CONSTRAINT_PRIMARY)
1136  continue;
1137 
1138  /*
1139  * If the primary key is deferrable, but we've been instructed to
1140  * ignore deferrable constraints, then we might as well give up
1141  * searching, since there can only be a single primary key on a table.
1142  */
1143  if (con->condeferrable && !deferrableOk)
1144  break;
1145 
1146  /* Extract the conkey array, ie, attnums of PK's columns */
1147  adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
1148  RelationGetDescr(pg_constraint), &isNull);
1149  if (isNull)
1150  elog(ERROR, "null conkey for constraint %u",
1151  ((Form_pg_constraint) GETSTRUCT(tuple))->oid);
1152  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1153  numkeys = ARR_DIMS(arr)[0];
1154  if (ARR_NDIM(arr) != 1 ||
1155  numkeys < 0 ||
1156  ARR_HASNULL(arr) ||
1157  ARR_ELEMTYPE(arr) != INT2OID)
1158  elog(ERROR, "conkey is not a 1-D smallint array");
1159  attnums = (int16 *) ARR_DATA_PTR(arr);
1160 
1161  /* Construct the result value */
1162  for (i = 0; i < numkeys; i++)
1163  {
1164  pkattnos = bms_add_member(pkattnos,
1166  }
1167  *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1168 
1169  /* No need to search further */
1170  break;
1171  }
1172 
1173  systable_endscan(scan);
1174 
1175  table_close(pg_constraint, AccessShareLock);
1176 
1177  return pkattnos;
1178 }
1179 
1180 /*
1181  * Extract data from the pg_constraint tuple of a foreign-key constraint.
1182  *
1183  * All arguments save the first are output arguments. All output arguments
1184  * other than numfks, conkey and confkey can be passed as NULL if caller
1185  * doesn't need them.
1186  */
1187 void
1189  AttrNumber *conkey, AttrNumber *confkey,
1190  Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs,
1191  int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
1192 {
1193  Oid constrId;
1194  Datum adatum;
1195  bool isNull;
1196  ArrayType *arr;
1197  int numkeys;
1198 
1199  constrId = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1200 
1201  /*
1202  * We expect the arrays to be 1-D arrays of the right types; verify that.
1203  * We don't need to use deconstruct_array() since the array data is just
1204  * going to look like a C array of values.
1205  */
1206  adatum = SysCacheGetAttr(CONSTROID, tuple,
1207  Anum_pg_constraint_conkey, &isNull);
1208  if (isNull)
1209  elog(ERROR, "null conkey for constraint %u", constrId);
1210  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1211  if (ARR_NDIM(arr) != 1 ||
1212  ARR_HASNULL(arr) ||
1213  ARR_ELEMTYPE(arr) != INT2OID)
1214  elog(ERROR, "conkey is not a 1-D smallint array");
1215  numkeys = ARR_DIMS(arr)[0];
1216  if (numkeys <= 0 || numkeys > INDEX_MAX_KEYS)
1217  elog(ERROR, "foreign key constraint cannot have %d columns", numkeys);
1218  memcpy(conkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1219  if ((Pointer) arr != DatumGetPointer(adatum))
1220  pfree(arr); /* free de-toasted copy, if any */
1221 
1222  adatum = SysCacheGetAttr(CONSTROID, tuple,
1223  Anum_pg_constraint_confkey, &isNull);
1224  if (isNull)
1225  elog(ERROR, "null confkey for constraint %u", constrId);
1226  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1227  if (ARR_NDIM(arr) != 1 ||
1228  ARR_DIMS(arr)[0] != numkeys ||
1229  ARR_HASNULL(arr) ||
1230  ARR_ELEMTYPE(arr) != INT2OID)
1231  elog(ERROR, "confkey is not a 1-D smallint array");
1232  memcpy(confkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1233  if ((Pointer) arr != DatumGetPointer(adatum))
1234  pfree(arr); /* free de-toasted copy, if any */
1235 
1236  if (pf_eq_oprs)
1237  {
1238  adatum = SysCacheGetAttr(CONSTROID, tuple,
1239  Anum_pg_constraint_conpfeqop, &isNull);
1240  if (isNull)
1241  elog(ERROR, "null conpfeqop for constraint %u", constrId);
1242  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1243  /* see TryReuseForeignKey if you change the test below */
1244  if (ARR_NDIM(arr) != 1 ||
1245  ARR_DIMS(arr)[0] != numkeys ||
1246  ARR_HASNULL(arr) ||
1247  ARR_ELEMTYPE(arr) != OIDOID)
1248  elog(ERROR, "conpfeqop is not a 1-D Oid array");
1249  memcpy(pf_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1250  if ((Pointer) arr != DatumGetPointer(adatum))
1251  pfree(arr); /* free de-toasted copy, if any */
1252  }
1253 
1254  if (pp_eq_oprs)
1255  {
1256  adatum = SysCacheGetAttr(CONSTROID, tuple,
1257  Anum_pg_constraint_conppeqop, &isNull);
1258  if (isNull)
1259  elog(ERROR, "null conppeqop for constraint %u", constrId);
1260  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1261  if (ARR_NDIM(arr) != 1 ||
1262  ARR_DIMS(arr)[0] != numkeys ||
1263  ARR_HASNULL(arr) ||
1264  ARR_ELEMTYPE(arr) != OIDOID)
1265  elog(ERROR, "conppeqop is not a 1-D Oid array");
1266  memcpy(pp_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1267  if ((Pointer) arr != DatumGetPointer(adatum))
1268  pfree(arr); /* free de-toasted copy, if any */
1269  }
1270 
1271  if (ff_eq_oprs)
1272  {
1273  adatum = SysCacheGetAttr(CONSTROID, tuple,
1274  Anum_pg_constraint_conffeqop, &isNull);
1275  if (isNull)
1276  elog(ERROR, "null conffeqop for constraint %u", constrId);
1277  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1278  if (ARR_NDIM(arr) != 1 ||
1279  ARR_DIMS(arr)[0] != numkeys ||
1280  ARR_HASNULL(arr) ||
1281  ARR_ELEMTYPE(arr) != OIDOID)
1282  elog(ERROR, "conffeqop is not a 1-D Oid array");
1283  memcpy(ff_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1284  if ((Pointer) arr != DatumGetPointer(adatum))
1285  pfree(arr); /* free de-toasted copy, if any */
1286  }
1287 
1288  if (fk_del_set_cols)
1289  {
1290  adatum = SysCacheGetAttr(CONSTROID, tuple,
1291  Anum_pg_constraint_confdelsetcols, &isNull);
1292  if (isNull)
1293  {
1294  *num_fk_del_set_cols = 0;
1295  }
1296  else
1297  {
1298  int num_delete_cols;
1299 
1300  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1301  if (ARR_NDIM(arr) != 1 ||
1302  ARR_HASNULL(arr) ||
1303  ARR_ELEMTYPE(arr) != INT2OID)
1304  elog(ERROR, "confdelsetcols is not a 1-D smallint array");
1305  num_delete_cols = ARR_DIMS(arr)[0];
1306  memcpy(fk_del_set_cols, ARR_DATA_PTR(arr), num_delete_cols * sizeof(int16));
1307  if ((Pointer) arr != DatumGetPointer(adatum))
1308  pfree(arr); /* free de-toasted copy, if any */
1309 
1310  *num_fk_del_set_cols = num_delete_cols;
1311  }
1312  }
1313 
1314  *numfks = numkeys;
1315 }
1316 
1317 /*
1318  * Determine whether a relation can be proven functionally dependent on
1319  * a set of grouping columns. If so, return true and add the pg_constraint
1320  * OIDs of the constraints needed for the proof to the *constraintDeps list.
1321  *
1322  * grouping_columns is a list of grouping expressions, in which columns of
1323  * the rel of interest are Vars with the indicated varno/varlevelsup.
1324  *
1325  * Currently we only check to see if the rel has a primary key that is a
1326  * subset of the grouping_columns. We could also use plain unique constraints
1327  * if all their columns are known not null, but there's a problem: we need
1328  * to be able to represent the not-null-ness as part of the constraints added
1329  * to *constraintDeps. FIXME whenever not-null constraints get represented
1330  * in pg_constraint.
1331  */
1332 bool
1334  Index varno, Index varlevelsup,
1335  List *grouping_columns,
1336  List **constraintDeps)
1337 {
1338  Bitmapset *pkattnos;
1339  Bitmapset *groupbyattnos;
1340  Oid constraintOid;
1341  ListCell *gl;
1342 
1343  /* If the rel has no PK, then we can't prove functional dependency */
1344  pkattnos = get_primary_key_attnos(relid, false, &constraintOid);
1345  if (pkattnos == NULL)
1346  return false;
1347 
1348  /* Identify all the rel's columns that appear in grouping_columns */
1349  groupbyattnos = NULL;
1350  foreach(gl, grouping_columns)
1351  {
1352  Var *gvar = (Var *) lfirst(gl);
1353 
1354  if (IsA(gvar, Var) &&
1355  gvar->varno == varno &&
1356  gvar->varlevelsup == varlevelsup)
1357  groupbyattnos = bms_add_member(groupbyattnos,
1359  }
1360 
1361  if (bms_is_subset(pkattnos, groupbyattnos))
1362  {
1363  /* The PK is a subset of grouping_columns, so we win */
1364  *constraintDeps = lappend_oid(*constraintDeps, constraintOid);
1365  return true;
1366  }
1367 
1368  return false;
1369 }
#define ARR_NDIM(a)
Definition: array.h:283
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define ARR_DIMS(a)
Definition: array.h:287
#define ARR_HASNULL(a)
Definition: array.h:284
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3338
int16 AttrNumber
Definition: attnum.h:21
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:316
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:739
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:85
signed short int16
Definition: c.h:429
char * Pointer
Definition: c.h:419
unsigned int Index
Definition: c.h:550
#define OidIsValid(objectId)
Definition: c.h:711
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:393
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2790
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1639
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2641
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2526
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2581
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2821
@ 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 errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define ERROR
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:145
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:788
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2330
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define AccessShareLock
Definition: lockdefs.h:36
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1910
void pfree(void *pointer)
Definition: mcxt.c:1306
void * palloc(Size size)
Definition: mcxt.c:1199
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define IsA(nodeptr, _type_)
Definition: nodes.h:162
#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
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)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
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)
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 AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
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 is_internal)
Definition: pg_constraint.c:50
bool ConstraintNameExists(const char *conname, Oid namespaceid)
bool check_functional_grouping(Oid relid, Index varno, Index varlevelsup, List *grouping_columns, List **constraintDeps)
Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
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:170
#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:670
uintptr_t Datum
Definition: postgres.h:412
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:520
static Datum BoolGetDatum(bool X)
Definition: postgres.h:450
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:721
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:660
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:698
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:560
static Datum CharGetDatum(char X)
Definition: postgres.h:470
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:527
#define RelationGetRelationName(relation)
Definition: rel.h:535
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:52
Definition: nodes.h:112
Definition: primnodes.h:205
AttrNumber varattno
Definition: primnodes.h:217
int varno
Definition: primnodes.h:212
Index varlevelsup
Definition: primnodes.h:230
Definition: c.h:677
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1221
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1173
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ RELOID
Definition: syscache.h:89
@ CONSTROID
Definition: syscache.h:53
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40