PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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/heapam.h"
19 #include "access/htup_details.h"
20 #include "access/sysattr.h"
21 #include "catalog/dependency.h"
22 #include "catalog/indexing.h"
23 #include "catalog/objectaccess.h"
24 #include "catalog/pg_constraint.h"
26 #include "catalog/pg_operator.h"
27 #include "catalog/pg_type.h"
28 #include "commands/defrem.h"
29 #include "utils/array.h"
30 #include "utils/builtins.h"
31 #include "utils/fmgroids.h"
32 #include "utils/lsyscache.h"
33 #include "utils/rel.h"
34 #include "utils/syscache.h"
35 #include "utils/tqual.h"
36 
37 
38 /*
39  * CreateConstraintEntry
40  * Create a constraint table entry.
41  *
42  * Subsidiary records (such as triggers or indexes to implement the
43  * constraint) are *not* created here. But we do make dependency links
44  * from the constraint to the things it depends on.
45  *
46  * The new constraint's OID is returned.
47  */
48 Oid
49 CreateConstraintEntry(const char *constraintName,
50  Oid constraintNamespace,
51  char constraintType,
52  bool isDeferrable,
53  bool isDeferred,
54  bool isValidated,
55  Oid relId,
56  const int16 *constraintKey,
57  int constraintNKeys,
58  Oid domainId,
59  Oid indexRelId,
60  Oid foreignRelId,
61  const int16 *foreignKey,
62  const Oid *pfEqOp,
63  const Oid *ppEqOp,
64  const Oid *ffEqOp,
65  int foreignNKeys,
66  char foreignUpdateType,
67  char foreignDeleteType,
68  char foreignMatchType,
69  const Oid *exclOp,
70  Node *conExpr,
71  const char *conBin,
72  const char *conSrc,
73  bool conIsLocal,
74  int conInhCount,
75  bool conNoInherit,
76  bool is_internal)
77 {
78  Relation conDesc;
79  Oid conOid;
80  HeapTuple tup;
81  bool nulls[Natts_pg_constraint];
83  ArrayType *conkeyArray;
84  ArrayType *confkeyArray;
85  ArrayType *conpfeqopArray;
86  ArrayType *conppeqopArray;
87  ArrayType *conffeqopArray;
88  ArrayType *conexclopArray;
90  int i;
91  ObjectAddress conobject;
92 
94 
95  Assert(constraintName);
96  namestrcpy(&cname, constraintName);
97 
98  /*
99  * Convert C arrays into Postgres arrays.
100  */
101  if (constraintNKeys > 0)
102  {
103  Datum *conkey;
104 
105  conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
106  for (i = 0; i < constraintNKeys; i++)
107  conkey[i] = Int16GetDatum(constraintKey[i]);
108  conkeyArray = construct_array(conkey, constraintNKeys,
109  INT2OID, 2, true, 's');
110  }
111  else
112  conkeyArray = NULL;
113 
114  if (foreignNKeys > 0)
115  {
116  Datum *fkdatums;
117 
118  fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
119  for (i = 0; i < foreignNKeys; i++)
120  fkdatums[i] = Int16GetDatum(foreignKey[i]);
121  confkeyArray = construct_array(fkdatums, foreignNKeys,
122  INT2OID, 2, true, 's');
123  for (i = 0; i < foreignNKeys; i++)
124  fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
125  conpfeqopArray = construct_array(fkdatums, foreignNKeys,
126  OIDOID, sizeof(Oid), true, 'i');
127  for (i = 0; i < foreignNKeys; i++)
128  fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
129  conppeqopArray = construct_array(fkdatums, foreignNKeys,
130  OIDOID, sizeof(Oid), true, 'i');
131  for (i = 0; i < foreignNKeys; i++)
132  fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
133  conffeqopArray = construct_array(fkdatums, foreignNKeys,
134  OIDOID, sizeof(Oid), true, 'i');
135  }
136  else
137  {
138  confkeyArray = NULL;
139  conpfeqopArray = NULL;
140  conppeqopArray = NULL;
141  conffeqopArray = NULL;
142  }
143 
144  if (exclOp != NULL)
145  {
146  Datum *opdatums;
147 
148  opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum));
149  for (i = 0; i < constraintNKeys; i++)
150  opdatums[i] = ObjectIdGetDatum(exclOp[i]);
151  conexclopArray = construct_array(opdatums, constraintNKeys,
152  OIDOID, sizeof(Oid), true, 'i');
153  }
154  else
155  conexclopArray = NULL;
156 
157  /* initialize nulls and values */
158  for (i = 0; i < Natts_pg_constraint; i++)
159  {
160  nulls[i] = false;
161  values[i] = (Datum) NULL;
162  }
163 
164  values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
165  values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
166  values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
167  values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
168  values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
169  values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated);
170  values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
171  values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
172  values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId);
173  values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
174  values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
175  values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
176  values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
177  values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
178  values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
179  values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit);
180 
181  if (conkeyArray)
182  values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
183  else
184  nulls[Anum_pg_constraint_conkey - 1] = true;
185 
186  if (confkeyArray)
187  values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
188  else
189  nulls[Anum_pg_constraint_confkey - 1] = true;
190 
191  if (conpfeqopArray)
192  values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
193  else
194  nulls[Anum_pg_constraint_conpfeqop - 1] = true;
195 
196  if (conppeqopArray)
197  values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
198  else
199  nulls[Anum_pg_constraint_conppeqop - 1] = true;
200 
201  if (conffeqopArray)
202  values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
203  else
204  nulls[Anum_pg_constraint_conffeqop - 1] = true;
205 
206  if (conexclopArray)
207  values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray);
208  else
209  nulls[Anum_pg_constraint_conexclop - 1] = true;
210 
211  /*
212  * initialize the binary form of the check constraint.
213  */
214  if (conBin)
215  values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
216  else
217  nulls[Anum_pg_constraint_conbin - 1] = true;
218 
219  /*
220  * initialize the text form of the check constraint
221  */
222  if (conSrc)
223  values[Anum_pg_constraint_consrc - 1] = CStringGetTextDatum(conSrc);
224  else
225  nulls[Anum_pg_constraint_consrc - 1] = true;
226 
227  tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
228 
229  conOid = CatalogTupleInsert(conDesc, tup);
230 
231  conobject.classId = ConstraintRelationId;
232  conobject.objectId = conOid;
233  conobject.objectSubId = 0;
234 
235  heap_close(conDesc, RowExclusiveLock);
236 
237  if (OidIsValid(relId))
238  {
239  /*
240  * Register auto dependency from constraint to owning relation, or to
241  * specific column(s) if any are mentioned.
242  */
243  ObjectAddress relobject;
244 
245  relobject.classId = RelationRelationId;
246  relobject.objectId = relId;
247  if (constraintNKeys > 0)
248  {
249  for (i = 0; i < constraintNKeys; i++)
250  {
251  relobject.objectSubId = constraintKey[i];
252 
253  recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
254  }
255  }
256  else
257  {
258  relobject.objectSubId = 0;
259 
260  recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
261  }
262  }
263 
264  if (OidIsValid(domainId))
265  {
266  /*
267  * Register auto dependency from constraint to owning domain
268  */
269  ObjectAddress domobject;
270 
271  domobject.classId = TypeRelationId;
272  domobject.objectId = domainId;
273  domobject.objectSubId = 0;
274 
275  recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
276  }
277 
278  if (OidIsValid(foreignRelId))
279  {
280  /*
281  * Register normal dependency from constraint to foreign relation, or
282  * to specific column(s) if any are mentioned.
283  */
284  ObjectAddress relobject;
285 
286  relobject.classId = RelationRelationId;
287  relobject.objectId = foreignRelId;
288  if (foreignNKeys > 0)
289  {
290  for (i = 0; i < foreignNKeys; i++)
291  {
292  relobject.objectSubId = foreignKey[i];
293 
294  recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
295  }
296  }
297  else
298  {
299  relobject.objectSubId = 0;
300 
301  recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
302  }
303  }
304 
305  if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
306  {
307  /*
308  * Register normal dependency on the unique index that supports a
309  * foreign-key constraint. (Note: for indexes associated with unique
310  * or primary-key constraints, the dependency runs the other way, and
311  * is not made here.)
312  */
313  ObjectAddress relobject;
314 
315  relobject.classId = RelationRelationId;
316  relobject.objectId = indexRelId;
317  relobject.objectSubId = 0;
318 
319  recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
320  }
321 
322  if (foreignNKeys > 0)
323  {
324  /*
325  * Register normal dependencies on the equality operators that support
326  * a foreign-key constraint. If the PK and FK types are the same then
327  * all three operators for a column are the same; otherwise they are
328  * different.
329  */
330  ObjectAddress oprobject;
331 
332  oprobject.classId = OperatorRelationId;
333  oprobject.objectSubId = 0;
334 
335  for (i = 0; i < foreignNKeys; i++)
336  {
337  oprobject.objectId = pfEqOp[i];
338  recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
339  if (ppEqOp[i] != pfEqOp[i])
340  {
341  oprobject.objectId = ppEqOp[i];
342  recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
343  }
344  if (ffEqOp[i] != pfEqOp[i])
345  {
346  oprobject.objectId = ffEqOp[i];
347  recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
348  }
349  }
350  }
351 
352  /*
353  * We don't bother to register dependencies on the exclusion operators of
354  * an exclusion constraint. We assume they are members of the opclass
355  * supporting the index, so there's an indirect dependency via that. (This
356  * would be pretty dicey for cross-type operators, but exclusion operators
357  * can never be cross-type.)
358  */
359 
360  if (conExpr != NULL)
361  {
362  /*
363  * Register dependencies from constraint to objects mentioned in CHECK
364  * expression.
365  */
366  recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
368  DEPENDENCY_NORMAL, false);
369  }
370 
371  /* Post creation hook for new constraint */
373  is_internal);
374 
375  return conOid;
376 }
377 
378 
379 /*
380  * Test whether given name is currently used as a constraint name
381  * for the given object (relation or domain).
382  *
383  * This is used to decide whether to accept a user-specified constraint name.
384  * It is deliberately not the same test as ChooseConstraintName uses to decide
385  * whether an auto-generated name is OK: here, we will allow it unless there
386  * is an identical constraint name in use *on the same object*.
387  *
388  * NB: Caller should hold exclusive lock on the given object, else
389  * this test can be fooled by concurrent additions.
390  */
391 bool
393  Oid objNamespace, const char *conname)
394 {
395  bool found;
396  Relation conDesc;
397  SysScanDesc conscan;
398  ScanKeyData skey[2];
399  HeapTuple tup;
400 
402 
403  found = false;
404 
405  ScanKeyInit(&skey[0],
407  BTEqualStrategyNumber, F_NAMEEQ,
408  CStringGetDatum(conname));
409 
410  ScanKeyInit(&skey[1],
412  BTEqualStrategyNumber, F_OIDEQ,
413  ObjectIdGetDatum(objNamespace));
414 
415  conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
416  NULL, 2, skey);
417 
418  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
419  {
421 
422  if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
423  {
424  found = true;
425  break;
426  }
427  else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
428  {
429  found = true;
430  break;
431  }
432  }
433 
434  systable_endscan(conscan);
435  heap_close(conDesc, AccessShareLock);
436 
437  return found;
438 }
439 
440 /*
441  * Select a nonconflicting name for a new constraint.
442  *
443  * The objective here is to choose a name that is unique within the
444  * specified namespace. Postgres does not require this, but the SQL
445  * spec does, and some apps depend on it. Therefore we avoid choosing
446  * default names that so conflict.
447  *
448  * name1, name2, and label are used the same way as for makeObjectName(),
449  * except that the label can't be NULL; digits will be appended to the label
450  * if needed to create a name that is unique within the specified namespace.
451  *
452  * 'others' can be a list of string names already chosen within the current
453  * command (but not yet reflected into the catalogs); we will not choose
454  * a duplicate of one of these either.
455  *
456  * Note: it is theoretically possible to get a collision anyway, if someone
457  * else chooses the same name concurrently. This is fairly unlikely to be
458  * a problem in practice, especially if one is holding an exclusive lock on
459  * the relation identified by name1.
460  *
461  * Returns a palloc'd string.
462  */
463 char *
464 ChooseConstraintName(const char *name1, const char *name2,
465  const char *label, Oid namespaceid,
466  List *others)
467 {
468  int pass = 0;
469  char *conname = NULL;
470  char modlabel[NAMEDATALEN];
471  Relation conDesc;
472  SysScanDesc conscan;
473  ScanKeyData skey[2];
474  bool found;
475  ListCell *l;
476 
478 
479  /* try the unmodified label first */
480  StrNCpy(modlabel, label, sizeof(modlabel));
481 
482  for (;;)
483  {
484  conname = makeObjectName(name1, name2, modlabel);
485 
486  found = false;
487 
488  foreach(l, others)
489  {
490  if (strcmp((char *) lfirst(l), conname) == 0)
491  {
492  found = true;
493  break;
494  }
495  }
496 
497  if (!found)
498  {
499  ScanKeyInit(&skey[0],
501  BTEqualStrategyNumber, F_NAMEEQ,
502  CStringGetDatum(conname));
503 
504  ScanKeyInit(&skey[1],
506  BTEqualStrategyNumber, F_OIDEQ,
507  ObjectIdGetDatum(namespaceid));
508 
509  conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
510  NULL, 2, skey);
511 
512  found = (HeapTupleIsValid(systable_getnext(conscan)));
513 
514  systable_endscan(conscan);
515  }
516 
517  if (!found)
518  break;
519 
520  /* found a conflict, so try a new name component */
521  pfree(conname);
522  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
523  }
524 
525  heap_close(conDesc, AccessShareLock);
526 
527  return conname;
528 }
529 
530 /*
531  * Delete a single constraint record.
532  */
533 void
535 {
536  Relation conDesc;
537  HeapTuple tup;
538  Form_pg_constraint con;
539 
541 
543  if (!HeapTupleIsValid(tup)) /* should not happen */
544  elog(ERROR, "cache lookup failed for constraint %u", conId);
545  con = (Form_pg_constraint) GETSTRUCT(tup);
546 
547  /*
548  * Special processing depending on what the constraint is for.
549  */
550  if (OidIsValid(con->conrelid))
551  {
552  Relation rel;
553 
554  /*
555  * If the constraint is for a relation, open and exclusive-lock the
556  * relation it's for.
557  */
558  rel = heap_open(con->conrelid, AccessExclusiveLock);
559 
560  /*
561  * We need to update the relcheck count if it is a check constraint
562  * being dropped. This update will force backends to rebuild relcache
563  * entries when we commit.
564  */
565  if (con->contype == CONSTRAINT_CHECK)
566  {
567  Relation pgrel;
568  HeapTuple relTup;
569  Form_pg_class classForm;
570 
572  relTup = SearchSysCacheCopy1(RELOID,
573  ObjectIdGetDatum(con->conrelid));
574  if (!HeapTupleIsValid(relTup))
575  elog(ERROR, "cache lookup failed for relation %u",
576  con->conrelid);
577  classForm = (Form_pg_class) GETSTRUCT(relTup);
578 
579  if (classForm->relchecks == 0) /* should not happen */
580  elog(ERROR, "relation \"%s\" has relchecks = 0",
582  classForm->relchecks--;
583 
584  CatalogTupleUpdate(pgrel, &relTup->t_self, relTup);
585 
586  heap_freetuple(relTup);
587 
589  }
590 
591  /* Keep lock on constraint's rel until end of xact */
592  heap_close(rel, NoLock);
593  }
594  else if (OidIsValid(con->contypid))
595  {
596  /*
597  * XXX for now, do nothing special when dropping a domain constraint
598  *
599  * Probably there should be some form of locking on the domain type,
600  * but we have no such concept at the moment.
601  */
602  }
603  else
604  elog(ERROR, "constraint %u is not of a known type", conId);
605 
606  /* Fry the constraint itself */
607  CatalogTupleDelete(conDesc, &tup->t_self);
608 
609  /* Clean up */
610  ReleaseSysCache(tup);
611  heap_close(conDesc, RowExclusiveLock);
612 }
613 
614 /*
615  * RenameConstraintById
616  * Rename a constraint.
617  *
618  * Note: this isn't intended to be a user-exposed function; it doesn't check
619  * permissions etc. Currently this is only invoked when renaming an index
620  * that is associated with a constraint, but it's made a little more general
621  * than that with the expectation of someday having ALTER TABLE RENAME
622  * CONSTRAINT.
623  */
624 void
625 RenameConstraintById(Oid conId, const char *newname)
626 {
627  Relation conDesc;
628  HeapTuple tuple;
629  Form_pg_constraint con;
630 
632 
634  if (!HeapTupleIsValid(tuple))
635  elog(ERROR, "cache lookup failed for constraint %u", conId);
636  con = (Form_pg_constraint) GETSTRUCT(tuple);
637 
638  /*
639  * We need to check whether the name is already in use --- note that there
640  * currently is not a unique index that would catch this.
641  */
642  if (OidIsValid(con->conrelid) &&
644  con->conrelid,
645  con->connamespace,
646  newname))
647  ereport(ERROR,
649  errmsg("constraint \"%s\" for relation \"%s\" already exists",
650  newname, get_rel_name(con->conrelid))));
651  if (OidIsValid(con->contypid) &&
653  con->contypid,
654  con->connamespace,
655  newname))
656  ereport(ERROR,
658  errmsg("constraint \"%s\" for domain %s already exists",
659  newname, format_type_be(con->contypid))));
660 
661  /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
662  namestrcpy(&(con->conname), newname);
663 
664  CatalogTupleUpdate(conDesc, &tuple->t_self, tuple);
665 
667 
668  heap_freetuple(tuple);
669  heap_close(conDesc, RowExclusiveLock);
670 }
671 
672 /*
673  * AlterConstraintNamespaces
674  * Find any constraints belonging to the specified object,
675  * and move them to the specified new namespace.
676  *
677  * isType indicates whether the owning object is a type or a relation.
678  */
679 void
681  Oid newNspId, bool isType, ObjectAddresses *objsMoved)
682 {
683  Relation conRel;
684  ScanKeyData key[1];
685  SysScanDesc scan;
686  HeapTuple tup;
687 
689 
690  if (isType)
691  {
692  ScanKeyInit(&key[0],
694  BTEqualStrategyNumber, F_OIDEQ,
695  ObjectIdGetDatum(ownerId));
696 
697  scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
698  NULL, 1, key);
699  }
700  else
701  {
702  ScanKeyInit(&key[0],
704  BTEqualStrategyNumber, F_OIDEQ,
705  ObjectIdGetDatum(ownerId));
706 
707  scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
708  NULL, 1, key);
709  }
710 
711  while (HeapTupleIsValid((tup = systable_getnext(scan))))
712  {
714  ObjectAddress thisobj;
715 
716  thisobj.classId = ConstraintRelationId;
717  thisobj.objectId = HeapTupleGetOid(tup);
718  thisobj.objectSubId = 0;
719 
720  if (object_address_present(&thisobj, objsMoved))
721  continue;
722 
723  /* Don't update if the object is already part of the namespace */
724  if (conform->connamespace == oldNspId && oldNspId != newNspId)
725  {
726  tup = heap_copytuple(tup);
727  conform = (Form_pg_constraint) GETSTRUCT(tup);
728 
729  conform->connamespace = newNspId;
730 
731  CatalogTupleUpdate(conRel, &tup->t_self, tup);
732 
733  /*
734  * Note: currently, the constraint will not have its own
735  * dependency on the namespace, so we don't need to do
736  * changeDependencyFor().
737  */
738  }
739 
741 
742  add_exact_object_address(&thisobj, objsMoved);
743  }
744 
745  systable_endscan(scan);
746 
747  heap_close(conRel, RowExclusiveLock);
748 }
749 
750 /*
751  * get_relation_constraint_oid
752  * Find a constraint on the specified relation with the specified name.
753  * Returns constraint's OID.
754  */
755 Oid
756 get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
757 {
758  Relation pg_constraint;
759  HeapTuple tuple;
760  SysScanDesc scan;
761  ScanKeyData skey[1];
762  Oid conOid = InvalidOid;
763 
764  /*
765  * Fetch the constraint tuple from pg_constraint. There may be more than
766  * one match, because constraints are not required to have unique names;
767  * if so, error out.
768  */
770 
771  ScanKeyInit(&skey[0],
773  BTEqualStrategyNumber, F_OIDEQ,
774  ObjectIdGetDatum(relid));
775 
776  scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
777  NULL, 1, skey);
778 
779  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
780  {
782 
783  if (strcmp(NameStr(con->conname), conname) == 0)
784  {
785  if (OidIsValid(conOid))
786  ereport(ERROR,
788  errmsg("table \"%s\" has multiple constraints named \"%s\"",
789  get_rel_name(relid), conname)));
790  conOid = HeapTupleGetOid(tuple);
791  }
792  }
793 
794  systable_endscan(scan);
795 
796  /* If no such constraint exists, complain */
797  if (!OidIsValid(conOid) && !missing_ok)
798  ereport(ERROR,
799  (errcode(ERRCODE_UNDEFINED_OBJECT),
800  errmsg("constraint \"%s\" for table \"%s\" does not exist",
801  conname, get_rel_name(relid))));
802 
803  heap_close(pg_constraint, AccessShareLock);
804 
805  return conOid;
806 }
807 
808 /*
809  * get_domain_constraint_oid
810  * Find a constraint on the specified domain with the specified name.
811  * Returns constraint's OID.
812  */
813 Oid
814 get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
815 {
816  Relation pg_constraint;
817  HeapTuple tuple;
818  SysScanDesc scan;
819  ScanKeyData skey[1];
820  Oid conOid = InvalidOid;
821 
822  /*
823  * Fetch the constraint tuple from pg_constraint. There may be more than
824  * one match, because constraints are not required to have unique names;
825  * if so, error out.
826  */
828 
829  ScanKeyInit(&skey[0],
831  BTEqualStrategyNumber, F_OIDEQ,
832  ObjectIdGetDatum(typid));
833 
834  scan = systable_beginscan(pg_constraint, ConstraintTypidIndexId, true,
835  NULL, 1, skey);
836 
837  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
838  {
840 
841  if (strcmp(NameStr(con->conname), conname) == 0)
842  {
843  if (OidIsValid(conOid))
844  ereport(ERROR,
846  errmsg("domain %s has multiple constraints named \"%s\"",
847  format_type_be(typid), conname)));
848  conOid = HeapTupleGetOid(tuple);
849  }
850  }
851 
852  systable_endscan(scan);
853 
854  /* If no such constraint exists, complain */
855  if (!OidIsValid(conOid) && !missing_ok)
856  ereport(ERROR,
857  (errcode(ERRCODE_UNDEFINED_OBJECT),
858  errmsg("constraint \"%s\" for domain %s does not exist",
859  conname, format_type_be(typid))));
860 
861  heap_close(pg_constraint, AccessShareLock);
862 
863  return conOid;
864 }
865 
866 /*
867  * get_primary_key_attnos
868  * Identify the columns in a relation's primary key, if any.
869  *
870  * Returns a Bitmapset of the column attnos of the primary key's columns,
871  * with attnos being offset by FirstLowInvalidHeapAttributeNumber so that
872  * system columns can be represented.
873  *
874  * If there is no primary key, return NULL. We also return NULL if the pkey
875  * constraint is deferrable and deferrableOk is false.
876  *
877  * *constraintOid is set to the OID of the pkey constraint, or InvalidOid
878  * on failure.
879  */
880 Bitmapset *
881 get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid)
882 {
883  Bitmapset *pkattnos = NULL;
884  Relation pg_constraint;
885  HeapTuple tuple;
886  SysScanDesc scan;
887  ScanKeyData skey[1];
888 
889  /* Set *constraintOid, to avoid complaints about uninitialized vars */
890  *constraintOid = InvalidOid;
891 
892  /* Scan pg_constraint for constraints of the target rel */
894 
895  ScanKeyInit(&skey[0],
897  BTEqualStrategyNumber, F_OIDEQ,
898  ObjectIdGetDatum(relid));
899 
900  scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
901  NULL, 1, skey);
902 
903  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
904  {
906  Datum adatum;
907  bool isNull;
908  ArrayType *arr;
909  int16 *attnums;
910  int numkeys;
911  int i;
912 
913  /* Skip constraints that are not PRIMARY KEYs */
914  if (con->contype != CONSTRAINT_PRIMARY)
915  continue;
916 
917  /*
918  * If the primary key is deferrable, but we've been instructed to
919  * ignore deferrable constraints, then we might as well give up
920  * searching, since there can only be a single primary key on a table.
921  */
922  if (con->condeferrable && !deferrableOk)
923  break;
924 
925  /* Extract the conkey array, ie, attnums of PK's columns */
926  adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
927  RelationGetDescr(pg_constraint), &isNull);
928  if (isNull)
929  elog(ERROR, "null conkey for constraint %u",
930  HeapTupleGetOid(tuple));
931  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
932  numkeys = ARR_DIMS(arr)[0];
933  if (ARR_NDIM(arr) != 1 ||
934  numkeys < 0 ||
935  ARR_HASNULL(arr) ||
936  ARR_ELEMTYPE(arr) != INT2OID)
937  elog(ERROR, "conkey is not a 1-D smallint array");
938  attnums = (int16 *) ARR_DATA_PTR(arr);
939 
940  /* Construct the result value */
941  for (i = 0; i < numkeys; i++)
942  {
943  pkattnos = bms_add_member(pkattnos,
945  }
946  *constraintOid = HeapTupleGetOid(tuple);
947 
948  /* No need to search further */
949  break;
950  }
951 
952  systable_endscan(scan);
953 
954  heap_close(pg_constraint, AccessShareLock);
955 
956  return pkattnos;
957 }
958 
959 /*
960  * Determine whether a relation can be proven functionally dependent on
961  * a set of grouping columns. If so, return TRUE and add the pg_constraint
962  * OIDs of the constraints needed for the proof to the *constraintDeps list.
963  *
964  * grouping_columns is a list of grouping expressions, in which columns of
965  * the rel of interest are Vars with the indicated varno/varlevelsup.
966  *
967  * Currently we only check to see if the rel has a primary key that is a
968  * subset of the grouping_columns. We could also use plain unique constraints
969  * if all their columns are known not null, but there's a problem: we need
970  * to be able to represent the not-null-ness as part of the constraints added
971  * to *constraintDeps. FIXME whenever not-null constraints get represented
972  * in pg_constraint.
973  */
974 bool
976  Index varno, Index varlevelsup,
977  List *grouping_columns,
978  List **constraintDeps)
979 {
980  Bitmapset *pkattnos;
981  Bitmapset *groupbyattnos;
982  Oid constraintOid;
983  ListCell *gl;
984 
985  /* If the rel has no PK, then we can't prove functional dependency */
986  pkattnos = get_primary_key_attnos(relid, false, &constraintOid);
987  if (pkattnos == NULL)
988  return false;
989 
990  /* Identify all the rel's columns that appear in grouping_columns */
991  groupbyattnos = NULL;
992  foreach(gl, grouping_columns)
993  {
994  Var *gvar = (Var *) lfirst(gl);
995 
996  if (IsA(gvar, Var) &&
997  gvar->varno == varno &&
998  gvar->varlevelsup == varlevelsup)
999  groupbyattnos = bms_add_member(groupbyattnos,
1001  }
1002 
1003  if (bms_is_subset(pkattnos, groupbyattnos))
1004  {
1005  /* The PK is a subset of grouping_columns, so we win */
1006  *constraintDeps = lappend_oid(*constraintDeps, constraintOid);
1007  return true;
1008  }
1009 
1010  return false;
1011 }
signed short int16
Definition: c.h:255
bool check_functional_grouping(Oid relid, Index varno, Index varlevelsup, List *grouping_columns, List **constraintDeps)
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:611
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
Bitmapset * get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid)
#define CONSTRAINT_FOREIGN
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
#define NameGetDatum(X)
Definition: postgres.h:601
#define Anum_pg_constraint_conislocal
#define OperatorRelationId
Definition: pg_operator.h:32
Index varlevelsup
Definition: primnodes.h:173
ConstraintCategory
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define Anum_pg_constraint_confkey
#define Anum_pg_constraint_conindid
#define RelationGetDescr(relation)
Definition: rel.h:428
Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
#define OIDOID
Definition: pg_type.h:328
#define Anum_pg_constraint_condeferred
#define PointerGetDatum(X)
Definition: postgres.h:562
#define Anum_pg_constraint_conppeqop
#define RelationRelationId
Definition: pg_class.h:29
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2167
#define Int16GetDatum(X)
Definition: postgres.h:457
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3306
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:509
int errcode(int sqlerrcode)
Definition: elog.c:575
AttrNumber varattno
Definition: primnodes.h:168
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2107
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
#define Anum_pg_constraint_conffeqop
#define heap_close(r, l)
Definition: heapam.h:97
#define Anum_pg_constraint_conname
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:163
#define TypeRelationId
Definition: pg_type.h:34
int namestrcpy(Name name, const char *str)
Definition: name.c:216
#define Anum_pg_constraint_coninhcount
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:538
#define Anum_pg_constraint_conbin
#define ConstraintTypidIndexId
Definition: indexing.h:128
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
void RenameConstraintById(Oid conId, const char *newname)
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:1499
#define NAMEDATALEN
#define CONSTRAINT_CHECK
#define CONSTRAINT_PRIMARY
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
void pfree(void *pointer)
Definition: mcxt.c:950
#define Anum_pg_constraint_convalidated
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
#define ARR_DIMS(a)
Definition: array.h:275
ItemPointerData t_self
Definition: htup.h:65
#define Anum_pg_constraint_condeferrable
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:308
Definition: c.h:493
#define INT2OID
Definition: pg_type.h:308
#define ARR_DATA_PTR(a)
Definition: array.h:303
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:584
#define RelationGetRelationName(relation)
Definition: rel.h:436
#define ARR_HASNULL(a)
Definition: array.h:272
Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define Anum_pg_constraint_confdeltype
#define Anum_pg_constraint_conkey
#define Anum_pg_constraint_contypid
Index varno
Definition: primnodes.h:166
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:769
#define Anum_pg_constraint_confmatchtype
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
static char * label
Definition: pg_basebackup.c:81
#define Anum_pg_constraint_connamespace
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
unsigned int Index
Definition: c.h:365
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:147
#define Anum_pg_constraint_contype
#define Anum_pg_constraint_confupdtype
#define BoolGetDatum(X)
Definition: postgres.h:408
#define InvalidOid
Definition: postgres_ext.h:36
#define ConstraintNameNspIndexId
Definition: indexing.h:124
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Natts_pg_constraint
#define NULL
Definition: c.h:229
#define Anum_pg_constraint_conpfeqop
#define Assert(condition)
Definition: c.h:676
#define lfirst(lc)
Definition: pg_list.h:106
#define StrNCpy(dst, src, len)
Definition: c.h:831
#define Anum_pg_constraint_consrc
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define ARR_NDIM(a)
Definition: array.h:271
#define Anum_pg_constraint_connoinherit
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool ignore_self)
Definition: dependency.c:1392
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, Oid objNamespace, const char *conname)
#define CharGetDatum(X)
Definition: postgres.h:422
static Datum values[MAXATTR]
Definition: bootstrap.c:163
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define Int32GetDatum(X)
Definition: postgres.h:485
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define NameStr(name)
Definition: c.h:499
#define Anum_pg_constraint_conrelid
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:91
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define Anum_pg_constraint_confrelid
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
#define ARR_ELEMTYPE(a)
Definition: array.h:273
void RemoveConstraintById(Oid conId)
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid relId, const int16 *constraintKey, int constraintNKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, const char *conSrc, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:49
#define Anum_pg_constraint_conexclop
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define ConstraintRelidIndexId
Definition: indexing.h:126
#define DatumGetArrayTypeP(X)
Definition: array.h:242