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-2023, 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] = Int16GetDatum(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  if (constrForm->coninhcount < 0)
809  ereport(ERROR,
810  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
811  errmsg("too many inheritance parents"));
812  constrForm->conparentid = parentConstrId;
813 
814  CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
815 
816  ObjectAddressSet(depender, ConstraintRelationId, childConstrId);
817 
818  ObjectAddressSet(referenced, ConstraintRelationId, parentConstrId);
819  recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI);
820 
821  ObjectAddressSet(referenced, RelationRelationId, childTableId);
822  recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC);
823  }
824  else
825  {
826  constrForm->coninhcount--;
827  constrForm->conislocal = true;
828  constrForm->conparentid = InvalidOid;
829 
830  /* Make sure there's no further inheritance. */
831  Assert(constrForm->coninhcount == 0);
832 
833  CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
834 
835  deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
836  ConstraintRelationId,
838  deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
839  RelationRelationId,
841  }
842 
843  ReleaseSysCache(tuple);
844  table_close(constrRel, RowExclusiveLock);
845 }
846 
847 
848 /*
849  * get_relation_constraint_oid
850  * Find a constraint on the specified relation with the specified name.
851  * Returns constraint's OID.
852  */
853 Oid
854 get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
855 {
856  Relation pg_constraint;
857  HeapTuple tuple;
858  SysScanDesc scan;
859  ScanKeyData skey[3];
860  Oid conOid = InvalidOid;
861 
862  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
863 
864  ScanKeyInit(&skey[0],
865  Anum_pg_constraint_conrelid,
866  BTEqualStrategyNumber, F_OIDEQ,
867  ObjectIdGetDatum(relid));
868  ScanKeyInit(&skey[1],
869  Anum_pg_constraint_contypid,
870  BTEqualStrategyNumber, F_OIDEQ,
872  ScanKeyInit(&skey[2],
873  Anum_pg_constraint_conname,
874  BTEqualStrategyNumber, F_NAMEEQ,
875  CStringGetDatum(conname));
876 
877  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
878  NULL, 3, skey);
879 
880  /* There can be at most one matching row */
881  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
882  conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
883 
884  systable_endscan(scan);
885 
886  /* If no such constraint exists, complain */
887  if (!OidIsValid(conOid) && !missing_ok)
888  ereport(ERROR,
889  (errcode(ERRCODE_UNDEFINED_OBJECT),
890  errmsg("constraint \"%s\" for table \"%s\" does not exist",
891  conname, get_rel_name(relid))));
892 
893  table_close(pg_constraint, AccessShareLock);
894 
895  return conOid;
896 }
897 
898 /*
899  * get_relation_constraint_attnos
900  * Find a constraint on the specified relation with the specified name
901  * and return the constrained columns.
902  *
903  * Returns a Bitmapset of the column attnos of the constrained columns, with
904  * attnos being offset by FirstLowInvalidHeapAttributeNumber so that system
905  * columns can be represented.
906  *
907  * *constraintOid is set to the OID of the constraint, or InvalidOid on
908  * failure.
909  */
910 Bitmapset *
911 get_relation_constraint_attnos(Oid relid, const char *conname,
912  bool missing_ok, Oid *constraintOid)
913 {
914  Bitmapset *conattnos = NULL;
915  Relation pg_constraint;
916  HeapTuple tuple;
917  SysScanDesc scan;
918  ScanKeyData skey[3];
919 
920  /* Set *constraintOid, to avoid complaints about uninitialized vars */
921  *constraintOid = InvalidOid;
922 
923  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
924 
925  ScanKeyInit(&skey[0],
926  Anum_pg_constraint_conrelid,
927  BTEqualStrategyNumber, F_OIDEQ,
928  ObjectIdGetDatum(relid));
929  ScanKeyInit(&skey[1],
930  Anum_pg_constraint_contypid,
931  BTEqualStrategyNumber, F_OIDEQ,
933  ScanKeyInit(&skey[2],
934  Anum_pg_constraint_conname,
935  BTEqualStrategyNumber, F_NAMEEQ,
936  CStringGetDatum(conname));
937 
938  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
939  NULL, 3, skey);
940 
941  /* There can be at most one matching row */
942  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
943  {
944  Datum adatum;
945  bool isNull;
946 
947  *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
948 
949  /* Extract the conkey array, ie, attnums of constrained columns */
950  adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
951  RelationGetDescr(pg_constraint), &isNull);
952  if (!isNull)
953  {
954  ArrayType *arr;
955  int numcols;
956  int16 *attnums;
957  int i;
958 
959  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
960  numcols = ARR_DIMS(arr)[0];
961  if (ARR_NDIM(arr) != 1 ||
962  numcols < 0 ||
963  ARR_HASNULL(arr) ||
964  ARR_ELEMTYPE(arr) != INT2OID)
965  elog(ERROR, "conkey is not a 1-D smallint array");
966  attnums = (int16 *) ARR_DATA_PTR(arr);
967 
968  /* Construct the result value */
969  for (i = 0; i < numcols; i++)
970  {
971  conattnos = bms_add_member(conattnos,
973  }
974  }
975  }
976 
977  systable_endscan(scan);
978 
979  /* If no such constraint exists, complain */
980  if (!OidIsValid(*constraintOid) && !missing_ok)
981  ereport(ERROR,
982  (errcode(ERRCODE_UNDEFINED_OBJECT),
983  errmsg("constraint \"%s\" for table \"%s\" does not exist",
984  conname, get_rel_name(relid))));
985 
986  table_close(pg_constraint, AccessShareLock);
987 
988  return conattnos;
989 }
990 
991 /*
992  * Return the OID of the constraint enforced by the given index in the
993  * given relation; or InvalidOid if no such index is catalogued.
994  *
995  * Much like get_constraint_index, this function is concerned only with the
996  * one constraint that "owns" the given index. Therefore, constraints of
997  * types other than unique, primary-key, and exclusion are ignored.
998  */
999 Oid
1001 {
1002  Relation pg_constraint;
1003  SysScanDesc scan;
1004  ScanKeyData key;
1005  HeapTuple tuple;
1006  Oid constraintId = InvalidOid;
1007 
1008  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1009 
1010  ScanKeyInit(&key,
1011  Anum_pg_constraint_conrelid,
1013  F_OIDEQ,
1014  ObjectIdGetDatum(relationId));
1015  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
1016  true, NULL, 1, &key);
1017  while ((tuple = systable_getnext(scan)) != NULL)
1018  {
1019  Form_pg_constraint constrForm;
1020 
1021  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
1022 
1023  /* See above */
1024  if (constrForm->contype != CONSTRAINT_PRIMARY &&
1025  constrForm->contype != CONSTRAINT_UNIQUE &&
1026  constrForm->contype != CONSTRAINT_EXCLUSION)
1027  continue;
1028 
1029  if (constrForm->conindid == indexId)
1030  {
1031  constraintId = constrForm->oid;
1032  break;
1033  }
1034  }
1035  systable_endscan(scan);
1036 
1037  table_close(pg_constraint, AccessShareLock);
1038  return constraintId;
1039 }
1040 
1041 /*
1042  * get_domain_constraint_oid
1043  * Find a constraint on the specified domain with the specified name.
1044  * Returns constraint's OID.
1045  */
1046 Oid
1047 get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
1048 {
1049  Relation pg_constraint;
1050  HeapTuple tuple;
1051  SysScanDesc scan;
1052  ScanKeyData skey[3];
1053  Oid conOid = InvalidOid;
1054 
1055  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1056 
1057  ScanKeyInit(&skey[0],
1058  Anum_pg_constraint_conrelid,
1059  BTEqualStrategyNumber, F_OIDEQ,
1061  ScanKeyInit(&skey[1],
1062  Anum_pg_constraint_contypid,
1063  BTEqualStrategyNumber, F_OIDEQ,
1064  ObjectIdGetDatum(typid));
1065  ScanKeyInit(&skey[2],
1066  Anum_pg_constraint_conname,
1067  BTEqualStrategyNumber, F_NAMEEQ,
1068  CStringGetDatum(conname));
1069 
1070  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1071  NULL, 3, skey);
1072 
1073  /* There can be at most one matching row */
1074  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1075  conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1076 
1077  systable_endscan(scan);
1078 
1079  /* If no such constraint exists, complain */
1080  if (!OidIsValid(conOid) && !missing_ok)
1081  ereport(ERROR,
1082  (errcode(ERRCODE_UNDEFINED_OBJECT),
1083  errmsg("constraint \"%s\" for domain %s does not exist",
1084  conname, format_type_be(typid))));
1085 
1086  table_close(pg_constraint, AccessShareLock);
1087 
1088  return conOid;
1089 }
1090 
1091 /*
1092  * get_primary_key_attnos
1093  * Identify the columns in a relation's primary key, if any.
1094  *
1095  * Returns a Bitmapset of the column attnos of the primary key's columns,
1096  * with attnos being offset by FirstLowInvalidHeapAttributeNumber so that
1097  * system columns can be represented.
1098  *
1099  * If there is no primary key, return NULL. We also return NULL if the pkey
1100  * constraint is deferrable and deferrableOk is false.
1101  *
1102  * *constraintOid is set to the OID of the pkey constraint, or InvalidOid
1103  * on failure.
1104  */
1105 Bitmapset *
1106 get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid)
1107 {
1108  Bitmapset *pkattnos = NULL;
1109  Relation pg_constraint;
1110  HeapTuple tuple;
1111  SysScanDesc scan;
1112  ScanKeyData skey[1];
1113 
1114  /* Set *constraintOid, to avoid complaints about uninitialized vars */
1115  *constraintOid = InvalidOid;
1116 
1117  /* Scan pg_constraint for constraints of the target rel */
1118  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1119 
1120  ScanKeyInit(&skey[0],
1121  Anum_pg_constraint_conrelid,
1122  BTEqualStrategyNumber, F_OIDEQ,
1123  ObjectIdGetDatum(relid));
1124 
1125  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1126  NULL, 1, skey);
1127 
1128  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1129  {
1131  Datum adatum;
1132  bool isNull;
1133  ArrayType *arr;
1134  int16 *attnums;
1135  int numkeys;
1136  int i;
1137 
1138  /* Skip constraints that are not PRIMARY KEYs */
1139  if (con->contype != CONSTRAINT_PRIMARY)
1140  continue;
1141 
1142  /*
1143  * If the primary key is deferrable, but we've been instructed to
1144  * ignore deferrable constraints, then we might as well give up
1145  * searching, since there can only be a single primary key on a table.
1146  */
1147  if (con->condeferrable && !deferrableOk)
1148  break;
1149 
1150  /* Extract the conkey array, ie, attnums of PK's columns */
1151  adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
1152  RelationGetDescr(pg_constraint), &isNull);
1153  if (isNull)
1154  elog(ERROR, "null conkey for constraint %u",
1155  ((Form_pg_constraint) GETSTRUCT(tuple))->oid);
1156  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1157  numkeys = ARR_DIMS(arr)[0];
1158  if (ARR_NDIM(arr) != 1 ||
1159  numkeys < 0 ||
1160  ARR_HASNULL(arr) ||
1161  ARR_ELEMTYPE(arr) != INT2OID)
1162  elog(ERROR, "conkey is not a 1-D smallint array");
1163  attnums = (int16 *) ARR_DATA_PTR(arr);
1164 
1165  /* Construct the result value */
1166  for (i = 0; i < numkeys; i++)
1167  {
1168  pkattnos = bms_add_member(pkattnos,
1170  }
1171  *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1172 
1173  /* No need to search further */
1174  break;
1175  }
1176 
1177  systable_endscan(scan);
1178 
1179  table_close(pg_constraint, AccessShareLock);
1180 
1181  return pkattnos;
1182 }
1183 
1184 /*
1185  * Extract data from the pg_constraint tuple of a foreign-key constraint.
1186  *
1187  * All arguments save the first are output arguments. All output arguments
1188  * other than numfks, conkey and confkey can be passed as NULL if caller
1189  * doesn't need them.
1190  */
1191 void
1193  AttrNumber *conkey, AttrNumber *confkey,
1194  Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs,
1195  int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
1196 {
1197  Datum adatum;
1198  bool isNull;
1199  ArrayType *arr;
1200  int numkeys;
1201 
1202  /*
1203  * We expect the arrays to be 1-D arrays of the right types; verify that.
1204  * We don't need to use deconstruct_array() since the array data is just
1205  * going to look like a C array of values.
1206  */
1207  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1208  Anum_pg_constraint_conkey);
1209  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1210  if (ARR_NDIM(arr) != 1 ||
1211  ARR_HASNULL(arr) ||
1212  ARR_ELEMTYPE(arr) != INT2OID)
1213  elog(ERROR, "conkey is not a 1-D smallint array");
1214  numkeys = ARR_DIMS(arr)[0];
1215  if (numkeys <= 0 || numkeys > INDEX_MAX_KEYS)
1216  elog(ERROR, "foreign key constraint cannot have %d columns", numkeys);
1217  memcpy(conkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1218  if ((Pointer) arr != DatumGetPointer(adatum))
1219  pfree(arr); /* free de-toasted copy, if any */
1220 
1221  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1222  Anum_pg_constraint_confkey);
1223  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1224  if (ARR_NDIM(arr) != 1 ||
1225  ARR_DIMS(arr)[0] != numkeys ||
1226  ARR_HASNULL(arr) ||
1227  ARR_ELEMTYPE(arr) != INT2OID)
1228  elog(ERROR, "confkey is not a 1-D smallint array");
1229  memcpy(confkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1230  if ((Pointer) arr != DatumGetPointer(adatum))
1231  pfree(arr); /* free de-toasted copy, if any */
1232 
1233  if (pf_eq_oprs)
1234  {
1235  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1236  Anum_pg_constraint_conpfeqop);
1237  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1238  /* see TryReuseForeignKey if you change the test below */
1239  if (ARR_NDIM(arr) != 1 ||
1240  ARR_DIMS(arr)[0] != numkeys ||
1241  ARR_HASNULL(arr) ||
1242  ARR_ELEMTYPE(arr) != OIDOID)
1243  elog(ERROR, "conpfeqop is not a 1-D Oid array");
1244  memcpy(pf_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1245  if ((Pointer) arr != DatumGetPointer(adatum))
1246  pfree(arr); /* free de-toasted copy, if any */
1247  }
1248 
1249  if (pp_eq_oprs)
1250  {
1251  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1252  Anum_pg_constraint_conppeqop);
1253  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1254  if (ARR_NDIM(arr) != 1 ||
1255  ARR_DIMS(arr)[0] != numkeys ||
1256  ARR_HASNULL(arr) ||
1257  ARR_ELEMTYPE(arr) != OIDOID)
1258  elog(ERROR, "conppeqop is not a 1-D Oid array");
1259  memcpy(pp_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1260  if ((Pointer) arr != DatumGetPointer(adatum))
1261  pfree(arr); /* free de-toasted copy, if any */
1262  }
1263 
1264  if (ff_eq_oprs)
1265  {
1266  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1267  Anum_pg_constraint_conffeqop);
1268  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1269  if (ARR_NDIM(arr) != 1 ||
1270  ARR_DIMS(arr)[0] != numkeys ||
1271  ARR_HASNULL(arr) ||
1272  ARR_ELEMTYPE(arr) != OIDOID)
1273  elog(ERROR, "conffeqop is not a 1-D Oid array");
1274  memcpy(ff_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1275  if ((Pointer) arr != DatumGetPointer(adatum))
1276  pfree(arr); /* free de-toasted copy, if any */
1277  }
1278 
1279  if (fk_del_set_cols)
1280  {
1281  adatum = SysCacheGetAttr(CONSTROID, tuple,
1282  Anum_pg_constraint_confdelsetcols, &isNull);
1283  if (isNull)
1284  {
1285  *num_fk_del_set_cols = 0;
1286  }
1287  else
1288  {
1289  int num_delete_cols;
1290 
1291  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1292  if (ARR_NDIM(arr) != 1 ||
1293  ARR_HASNULL(arr) ||
1294  ARR_ELEMTYPE(arr) != INT2OID)
1295  elog(ERROR, "confdelsetcols is not a 1-D smallint array");
1296  num_delete_cols = ARR_DIMS(arr)[0];
1297  memcpy(fk_del_set_cols, ARR_DATA_PTR(arr), num_delete_cols * sizeof(int16));
1298  if ((Pointer) arr != DatumGetPointer(adatum))
1299  pfree(arr); /* free de-toasted copy, if any */
1300 
1301  *num_fk_del_set_cols = num_delete_cols;
1302  }
1303  }
1304 
1305  *numfks = numkeys;
1306 }
1307 
1308 /*
1309  * Determine whether a relation can be proven functionally dependent on
1310  * a set of grouping columns. If so, return true and add the pg_constraint
1311  * OIDs of the constraints needed for the proof to the *constraintDeps list.
1312  *
1313  * grouping_columns is a list of grouping expressions, in which columns of
1314  * the rel of interest are Vars with the indicated varno/varlevelsup.
1315  *
1316  * Currently we only check to see if the rel has a primary key that is a
1317  * subset of the grouping_columns. We could also use plain unique constraints
1318  * if all their columns are known not null, but there's a problem: we need
1319  * to be able to represent the not-null-ness as part of the constraints added
1320  * to *constraintDeps. FIXME whenever not-null constraints get represented
1321  * in pg_constraint.
1322  */
1323 bool
1325  Index varno, Index varlevelsup,
1326  List *grouping_columns,
1327  List **constraintDeps)
1328 {
1329  Bitmapset *pkattnos;
1330  Bitmapset *groupbyattnos;
1331  Oid constraintOid;
1332  ListCell *gl;
1333 
1334  /* If the rel has no PK, then we can't prove functional dependency */
1335  pkattnos = get_primary_key_attnos(relid, false, &constraintOid);
1336  if (pkattnos == NULL)
1337  return false;
1338 
1339  /* Identify all the rel's columns that appear in grouping_columns */
1340  groupbyattnos = NULL;
1341  foreach(gl, grouping_columns)
1342  {
1343  Var *gvar = (Var *) lfirst(gl);
1344 
1345  if (IsA(gvar, Var) &&
1346  gvar->varno == varno &&
1347  gvar->varlevelsup == varlevelsup)
1348  groupbyattnos = bms_add_member(groupbyattnos,
1350  }
1351 
1352  if (bms_is_subset(pkattnos, groupbyattnos))
1353  {
1354  /* The PK is a subset of grouping_columns, so we win */
1355  *constraintDeps = lappend_oid(*constraintDeps, constraintOid);
1356  return true;
1357  }
1358 
1359  return false;
1360 }
#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:3361
int16 AttrNumber
Definition: attnum.h:21
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:332
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:755
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:94
signed short int16
Definition: c.h:477
char * Pointer
Definition: c.h:467
unsigned int Index
Definition: c.h:598
#define OidIsValid(objectId)
Definition: c.h:759
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:1645
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2641
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2532
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:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
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:792
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2389
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
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:1436
void * palloc(Size size)
Definition: mcxt.c:1210
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
#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:172
#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:529
#define RelationGetRelationName(relation)
Definition: rel.h:537
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:54
Definition: nodes.h:129
Definition: primnodes.h:226
AttrNumber varattno
Definition: primnodes.h:238
int varno
Definition: primnodes.h:233
Index varlevelsup
Definition: primnodes.h:258
Definition: c.h:725
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:866
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:818
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1079
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:1110
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:182
@ 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