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