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-2016, 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 = simple_heap_insert(conDesc, tup);
230 
231  /* update catalog indexes */
232  CatalogUpdateIndexes(conDesc, tup);
233 
234  conobject.classId = ConstraintRelationId;
235  conobject.objectId = conOid;
236  conobject.objectSubId = 0;
237 
238  heap_close(conDesc, RowExclusiveLock);
239 
240  if (OidIsValid(relId))
241  {
242  /*
243  * Register auto dependency from constraint to owning relation, or to
244  * specific column(s) if any are mentioned.
245  */
246  ObjectAddress relobject;
247 
248  relobject.classId = RelationRelationId;
249  relobject.objectId = relId;
250  if (constraintNKeys > 0)
251  {
252  for (i = 0; i < constraintNKeys; i++)
253  {
254  relobject.objectSubId = constraintKey[i];
255 
256  recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
257  }
258  }
259  else
260  {
261  relobject.objectSubId = 0;
262 
263  recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
264  }
265  }
266 
267  if (OidIsValid(domainId))
268  {
269  /*
270  * Register auto dependency from constraint to owning domain
271  */
272  ObjectAddress domobject;
273 
274  domobject.classId = TypeRelationId;
275  domobject.objectId = domainId;
276  domobject.objectSubId = 0;
277 
278  recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
279  }
280 
281  if (OidIsValid(foreignRelId))
282  {
283  /*
284  * Register normal dependency from constraint to foreign relation, or
285  * to specific column(s) if any are mentioned.
286  */
287  ObjectAddress relobject;
288 
289  relobject.classId = RelationRelationId;
290  relobject.objectId = foreignRelId;
291  if (foreignNKeys > 0)
292  {
293  for (i = 0; i < foreignNKeys; i++)
294  {
295  relobject.objectSubId = foreignKey[i];
296 
297  recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
298  }
299  }
300  else
301  {
302  relobject.objectSubId = 0;
303 
304  recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
305  }
306  }
307 
308  if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
309  {
310  /*
311  * Register normal dependency on the unique index that supports a
312  * foreign-key constraint. (Note: for indexes associated with unique
313  * or primary-key constraints, the dependency runs the other way, and
314  * is not made here.)
315  */
316  ObjectAddress relobject;
317 
318  relobject.classId = RelationRelationId;
319  relobject.objectId = indexRelId;
320  relobject.objectSubId = 0;
321 
322  recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
323  }
324 
325  if (foreignNKeys > 0)
326  {
327  /*
328  * Register normal dependencies on the equality operators that support
329  * a foreign-key constraint. If the PK and FK types are the same then
330  * all three operators for a column are the same; otherwise they are
331  * different.
332  */
333  ObjectAddress oprobject;
334 
335  oprobject.classId = OperatorRelationId;
336  oprobject.objectSubId = 0;
337 
338  for (i = 0; i < foreignNKeys; i++)
339  {
340  oprobject.objectId = pfEqOp[i];
341  recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
342  if (ppEqOp[i] != pfEqOp[i])
343  {
344  oprobject.objectId = ppEqOp[i];
345  recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
346  }
347  if (ffEqOp[i] != pfEqOp[i])
348  {
349  oprobject.objectId = ffEqOp[i];
350  recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
351  }
352  }
353  }
354 
355  /*
356  * We don't bother to register dependencies on the exclusion operators of
357  * an exclusion constraint. We assume they are members of the opclass
358  * supporting the index, so there's an indirect dependency via that. (This
359  * would be pretty dicey for cross-type operators, but exclusion operators
360  * can never be cross-type.)
361  */
362 
363  if (conExpr != NULL)
364  {
365  /*
366  * Register dependencies from constraint to objects mentioned in CHECK
367  * expression.
368  */
369  recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
372  }
373 
374  /* Post creation hook for new constraint */
376  is_internal);
377 
378  return conOid;
379 }
380 
381 
382 /*
383  * Test whether given name is currently used as a constraint name
384  * for the given object (relation or domain).
385  *
386  * This is used to decide whether to accept a user-specified constraint name.
387  * It is deliberately not the same test as ChooseConstraintName uses to decide
388  * whether an auto-generated name is OK: here, we will allow it unless there
389  * is an identical constraint name in use *on the same object*.
390  *
391  * NB: Caller should hold exclusive lock on the given object, else
392  * this test can be fooled by concurrent additions.
393  */
394 bool
396  Oid objNamespace, const char *conname)
397 {
398  bool found;
399  Relation conDesc;
400  SysScanDesc conscan;
401  ScanKeyData skey[2];
402  HeapTuple tup;
403 
405 
406  found = false;
407 
408  ScanKeyInit(&skey[0],
410  BTEqualStrategyNumber, F_NAMEEQ,
411  CStringGetDatum(conname));
412 
413  ScanKeyInit(&skey[1],
415  BTEqualStrategyNumber, F_OIDEQ,
416  ObjectIdGetDatum(objNamespace));
417 
418  conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
419  NULL, 2, skey);
420 
421  while (HeapTupleIsValid(tup = systable_getnext(conscan)))
422  {
424 
425  if (conCat == CONSTRAINT_RELATION && con->conrelid == objId)
426  {
427  found = true;
428  break;
429  }
430  else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId)
431  {
432  found = true;
433  break;
434  }
435  }
436 
437  systable_endscan(conscan);
438  heap_close(conDesc, AccessShareLock);
439 
440  return found;
441 }
442 
443 /*
444  * Select a nonconflicting name for a new constraint.
445  *
446  * The objective here is to choose a name that is unique within the
447  * specified namespace. Postgres does not require this, but the SQL
448  * spec does, and some apps depend on it. Therefore we avoid choosing
449  * default names that so conflict.
450  *
451  * name1, name2, and label are used the same way as for makeObjectName(),
452  * except that the label can't be NULL; digits will be appended to the label
453  * if needed to create a name that is unique within the specified namespace.
454  *
455  * 'others' can be a list of string names already chosen within the current
456  * command (but not yet reflected into the catalogs); we will not choose
457  * a duplicate of one of these either.
458  *
459  * Note: it is theoretically possible to get a collision anyway, if someone
460  * else chooses the same name concurrently. This is fairly unlikely to be
461  * a problem in practice, especially if one is holding an exclusive lock on
462  * the relation identified by name1.
463  *
464  * Returns a palloc'd string.
465  */
466 char *
467 ChooseConstraintName(const char *name1, const char *name2,
468  const char *label, Oid namespaceid,
469  List *others)
470 {
471  int pass = 0;
472  char *conname = NULL;
473  char modlabel[NAMEDATALEN];
474  Relation conDesc;
475  SysScanDesc conscan;
476  ScanKeyData skey[2];
477  bool found;
478  ListCell *l;
479 
481 
482  /* try the unmodified label first */
483  StrNCpy(modlabel, label, sizeof(modlabel));
484 
485  for (;;)
486  {
487  conname = makeObjectName(name1, name2, modlabel);
488 
489  found = false;
490 
491  foreach(l, others)
492  {
493  if (strcmp((char *) lfirst(l), conname) == 0)
494  {
495  found = true;
496  break;
497  }
498  }
499 
500  if (!found)
501  {
502  ScanKeyInit(&skey[0],
504  BTEqualStrategyNumber, F_NAMEEQ,
505  CStringGetDatum(conname));
506 
507  ScanKeyInit(&skey[1],
509  BTEqualStrategyNumber, F_OIDEQ,
510  ObjectIdGetDatum(namespaceid));
511 
512  conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
513  NULL, 2, skey);
514 
515  found = (HeapTupleIsValid(systable_getnext(conscan)));
516 
517  systable_endscan(conscan);
518  }
519 
520  if (!found)
521  break;
522 
523  /* found a conflict, so try a new name component */
524  pfree(conname);
525  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
526  }
527 
528  heap_close(conDesc, AccessShareLock);
529 
530  return conname;
531 }
532 
533 /*
534  * Delete a single constraint record.
535  */
536 void
538 {
539  Relation conDesc;
540  HeapTuple tup;
541  Form_pg_constraint con;
542 
544 
546  if (!HeapTupleIsValid(tup)) /* should not happen */
547  elog(ERROR, "cache lookup failed for constraint %u", conId);
548  con = (Form_pg_constraint) GETSTRUCT(tup);
549 
550  /*
551  * Special processing depending on what the constraint is for.
552  */
553  if (OidIsValid(con->conrelid))
554  {
555  Relation rel;
556 
557  /*
558  * If the constraint is for a relation, open and exclusive-lock the
559  * relation it's for.
560  */
561  rel = heap_open(con->conrelid, AccessExclusiveLock);
562 
563  /*
564  * We need to update the relcheck count if it is a check constraint
565  * being dropped. This update will force backends to rebuild relcache
566  * entries when we commit.
567  */
568  if (con->contype == CONSTRAINT_CHECK)
569  {
570  Relation pgrel;
571  HeapTuple relTup;
572  Form_pg_class classForm;
573 
575  relTup = SearchSysCacheCopy1(RELOID,
576  ObjectIdGetDatum(con->conrelid));
577  if (!HeapTupleIsValid(relTup))
578  elog(ERROR, "cache lookup failed for relation %u",
579  con->conrelid);
580  classForm = (Form_pg_class) GETSTRUCT(relTup);
581 
582  if (classForm->relchecks == 0) /* should not happen */
583  elog(ERROR, "relation \"%s\" has relchecks = 0",
585  classForm->relchecks--;
586 
587  simple_heap_update(pgrel, &relTup->t_self, relTup);
588 
589  CatalogUpdateIndexes(pgrel, relTup);
590 
591  heap_freetuple(relTup);
592 
594  }
595 
596  /* Keep lock on constraint's rel until end of xact */
597  heap_close(rel, NoLock);
598  }
599  else if (OidIsValid(con->contypid))
600  {
601  /*
602  * XXX for now, do nothing special when dropping a domain constraint
603  *
604  * Probably there should be some form of locking on the domain type,
605  * but we have no such concept at the moment.
606  */
607  }
608  else
609  elog(ERROR, "constraint %u is not of a known type", conId);
610 
611  /* Fry the constraint itself */
612  simple_heap_delete(conDesc, &tup->t_self);
613 
614  /* Clean up */
615  ReleaseSysCache(tup);
616  heap_close(conDesc, RowExclusiveLock);
617 }
618 
619 /*
620  * RenameConstraintById
621  * Rename a constraint.
622  *
623  * Note: this isn't intended to be a user-exposed function; it doesn't check
624  * permissions etc. Currently this is only invoked when renaming an index
625  * that is associated with a constraint, but it's made a little more general
626  * than that with the expectation of someday having ALTER TABLE RENAME
627  * CONSTRAINT.
628  */
629 void
630 RenameConstraintById(Oid conId, const char *newname)
631 {
632  Relation conDesc;
633  HeapTuple tuple;
634  Form_pg_constraint con;
635 
637 
639  if (!HeapTupleIsValid(tuple))
640  elog(ERROR, "cache lookup failed for constraint %u", conId);
641  con = (Form_pg_constraint) GETSTRUCT(tuple);
642 
643  /*
644  * We need to check whether the name is already in use --- note that there
645  * currently is not a unique index that would catch this.
646  */
647  if (OidIsValid(con->conrelid) &&
649  con->conrelid,
650  con->connamespace,
651  newname))
652  ereport(ERROR,
654  errmsg("constraint \"%s\" for relation \"%s\" already exists",
655  newname, get_rel_name(con->conrelid))));
656  if (OidIsValid(con->contypid) &&
658  con->contypid,
659  con->connamespace,
660  newname))
661  ereport(ERROR,
663  errmsg("constraint \"%s\" for domain %s already exists",
664  newname, format_type_be(con->contypid))));
665 
666  /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
667  namestrcpy(&(con->conname), newname);
668 
669  simple_heap_update(conDesc, &tuple->t_self, tuple);
670 
671  /* update the system catalog indexes */
672  CatalogUpdateIndexes(conDesc, tuple);
673 
675 
676  heap_freetuple(tuple);
677  heap_close(conDesc, RowExclusiveLock);
678 }
679 
680 /*
681  * AlterConstraintNamespaces
682  * Find any constraints belonging to the specified object,
683  * and move them to the specified new namespace.
684  *
685  * isType indicates whether the owning object is a type or a relation.
686  */
687 void
689  Oid newNspId, bool isType, ObjectAddresses *objsMoved)
690 {
691  Relation conRel;
692  ScanKeyData key[1];
693  SysScanDesc scan;
694  HeapTuple tup;
695 
697 
698  if (isType)
699  {
700  ScanKeyInit(&key[0],
702  BTEqualStrategyNumber, F_OIDEQ,
703  ObjectIdGetDatum(ownerId));
704 
705  scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
706  NULL, 1, key);
707  }
708  else
709  {
710  ScanKeyInit(&key[0],
712  BTEqualStrategyNumber, F_OIDEQ,
713  ObjectIdGetDatum(ownerId));
714 
715  scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
716  NULL, 1, key);
717  }
718 
719  while (HeapTupleIsValid((tup = systable_getnext(scan))))
720  {
722  ObjectAddress thisobj;
723 
724  thisobj.classId = ConstraintRelationId;
725  thisobj.objectId = HeapTupleGetOid(tup);
726  thisobj.objectSubId = 0;
727 
728  if (object_address_present(&thisobj, objsMoved))
729  continue;
730 
731  /* Don't update if the object is already part of the namespace */
732  if (conform->connamespace == oldNspId && oldNspId != newNspId)
733  {
734  tup = heap_copytuple(tup);
735  conform = (Form_pg_constraint) GETSTRUCT(tup);
736 
737  conform->connamespace = newNspId;
738 
739  simple_heap_update(conRel, &tup->t_self, tup);
740  CatalogUpdateIndexes(conRel, tup);
741 
742  /*
743  * Note: currently, the constraint will not have its own
744  * dependency on the namespace, so we don't need to do
745  * changeDependencyFor().
746  */
747  }
748 
750 
751  add_exact_object_address(&thisobj, objsMoved);
752  }
753 
754  systable_endscan(scan);
755 
756  heap_close(conRel, RowExclusiveLock);
757 }
758 
759 /*
760  * get_relation_constraint_oid
761  * Find a constraint on the specified relation with the specified name.
762  * Returns constraint's OID.
763  */
764 Oid
765 get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
766 {
767  Relation pg_constraint;
768  HeapTuple tuple;
769  SysScanDesc scan;
770  ScanKeyData skey[1];
771  Oid conOid = InvalidOid;
772 
773  /*
774  * Fetch the constraint tuple from pg_constraint. There may be more than
775  * one match, because constraints are not required to have unique names;
776  * if so, error out.
777  */
779 
780  ScanKeyInit(&skey[0],
782  BTEqualStrategyNumber, F_OIDEQ,
783  ObjectIdGetDatum(relid));
784 
785  scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
786  NULL, 1, skey);
787 
788  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
789  {
791 
792  if (strcmp(NameStr(con->conname), conname) == 0)
793  {
794  if (OidIsValid(conOid))
795  ereport(ERROR,
797  errmsg("table \"%s\" has multiple constraints named \"%s\"",
798  get_rel_name(relid), conname)));
799  conOid = HeapTupleGetOid(tuple);
800  }
801  }
802 
803  systable_endscan(scan);
804 
805  /* If no such constraint exists, complain */
806  if (!OidIsValid(conOid) && !missing_ok)
807  ereport(ERROR,
808  (errcode(ERRCODE_UNDEFINED_OBJECT),
809  errmsg("constraint \"%s\" for table \"%s\" does not exist",
810  conname, get_rel_name(relid))));
811 
812  heap_close(pg_constraint, AccessShareLock);
813 
814  return conOid;
815 }
816 
817 /*
818  * get_domain_constraint_oid
819  * Find a constraint on the specified domain with the specified name.
820  * Returns constraint's OID.
821  */
822 Oid
823 get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
824 {
825  Relation pg_constraint;
826  HeapTuple tuple;
827  SysScanDesc scan;
828  ScanKeyData skey[1];
829  Oid conOid = InvalidOid;
830 
831  /*
832  * Fetch the constraint tuple from pg_constraint. There may be more than
833  * one match, because constraints are not required to have unique names;
834  * if so, error out.
835  */
837 
838  ScanKeyInit(&skey[0],
840  BTEqualStrategyNumber, F_OIDEQ,
841  ObjectIdGetDatum(typid));
842 
843  scan = systable_beginscan(pg_constraint, ConstraintTypidIndexId, true,
844  NULL, 1, skey);
845 
846  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
847  {
849 
850  if (strcmp(NameStr(con->conname), conname) == 0)
851  {
852  if (OidIsValid(conOid))
853  ereport(ERROR,
855  errmsg("domain \"%s\" has multiple constraints named \"%s\"",
856  format_type_be(typid), conname)));
857  conOid = HeapTupleGetOid(tuple);
858  }
859  }
860 
861  systable_endscan(scan);
862 
863  /* If no such constraint exists, complain */
864  if (!OidIsValid(conOid) && !missing_ok)
865  ereport(ERROR,
866  (errcode(ERRCODE_UNDEFINED_OBJECT),
867  errmsg("constraint \"%s\" for domain \"%s\" does not exist",
868  conname, format_type_be(typid))));
869 
870  heap_close(pg_constraint, AccessShareLock);
871 
872  return conOid;
873 }
874 
875 /*
876  * get_primary_key_attnos
877  * Identify the columns in a relation's primary key, if any.
878  *
879  * Returns a Bitmapset of the column attnos of the primary key's columns,
880  * with attnos being offset by FirstLowInvalidHeapAttributeNumber so that
881  * system columns can be represented.
882  *
883  * If there is no primary key, return NULL. We also return NULL if the pkey
884  * constraint is deferrable and deferrableOk is false.
885  *
886  * *constraintOid is set to the OID of the pkey constraint, or InvalidOid
887  * on failure.
888  */
889 Bitmapset *
890 get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid)
891 {
892  Bitmapset *pkattnos = NULL;
893  Relation pg_constraint;
894  HeapTuple tuple;
895  SysScanDesc scan;
896  ScanKeyData skey[1];
897 
898  /* Set *constraintOid, to avoid complaints about uninitialized vars */
899  *constraintOid = InvalidOid;
900 
901  /* Scan pg_constraint for constraints of the target rel */
903 
904  ScanKeyInit(&skey[0],
906  BTEqualStrategyNumber, F_OIDEQ,
907  ObjectIdGetDatum(relid));
908 
909  scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
910  NULL, 1, skey);
911 
912  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
913  {
915  Datum adatum;
916  bool isNull;
917  ArrayType *arr;
918  int16 *attnums;
919  int numkeys;
920  int i;
921 
922  /* Skip constraints that are not PRIMARY KEYs */
923  if (con->contype != CONSTRAINT_PRIMARY)
924  continue;
925 
926  /*
927  * If the primary key is deferrable, but we've been instructed to
928  * ignore deferrable constraints, then we might as well give up
929  * searching, since there can only be a single primary key on a table.
930  */
931  if (con->condeferrable && !deferrableOk)
932  break;
933 
934  /* Extract the conkey array, ie, attnums of PK's columns */
935  adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
936  RelationGetDescr(pg_constraint), &isNull);
937  if (isNull)
938  elog(ERROR, "null conkey for constraint %u",
939  HeapTupleGetOid(tuple));
940  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
941  numkeys = ARR_DIMS(arr)[0];
942  if (ARR_NDIM(arr) != 1 ||
943  numkeys < 0 ||
944  ARR_HASNULL(arr) ||
945  ARR_ELEMTYPE(arr) != INT2OID)
946  elog(ERROR, "conkey is not a 1-D smallint array");
947  attnums = (int16 *) ARR_DATA_PTR(arr);
948 
949  /* Construct the result value */
950  for (i = 0; i < numkeys; i++)
951  {
952  pkattnos = bms_add_member(pkattnos,
954  }
955  *constraintOid = HeapTupleGetOid(tuple);
956 
957  /* No need to search further */
958  break;
959  }
960 
961  systable_endscan(scan);
962 
963  heap_close(pg_constraint, AccessShareLock);
964 
965  return pkattnos;
966 }
967 
968 /*
969  * Determine whether a relation can be proven functionally dependent on
970  * a set of grouping columns. If so, return TRUE and add the pg_constraint
971  * OIDs of the constraints needed for the proof to the *constraintDeps list.
972  *
973  * grouping_columns is a list of grouping expressions, in which columns of
974  * the rel of interest are Vars with the indicated varno/varlevelsup.
975  *
976  * Currently we only check to see if the rel has a primary key that is a
977  * subset of the grouping_columns. We could also use plain unique constraints
978  * if all their columns are known not null, but there's a problem: we need
979  * to be able to represent the not-null-ness as part of the constraints added
980  * to *constraintDeps. FIXME whenever not-null constraints get represented
981  * in pg_constraint.
982  */
983 bool
985  Index varno, Index varlevelsup,
986  List *grouping_columns,
987  List **constraintDeps)
988 {
989  Bitmapset *pkattnos;
990  Bitmapset *groupbyattnos;
991  Oid constraintOid;
992  ListCell *gl;
993 
994  /* If the rel has no PK, then we can't prove functional dependency */
995  pkattnos = get_primary_key_attnos(relid, false, &constraintOid);
996  if (pkattnos == NULL)
997  return false;
998 
999  /* Identify all the rel's columns that appear in grouping_columns */
1000  groupbyattnos = NULL;
1001  foreach(gl, grouping_columns)
1002  {
1003  Var *gvar = (Var *) lfirst(gl);
1004 
1005  if (IsA(gvar, Var) &&
1006  gvar->varno == varno &&
1007  gvar->varlevelsup == varlevelsup)
1008  groupbyattnos = bms_add_member(groupbyattnos,
1010  }
1011 
1012  if (bms_is_subset(pkattnos, groupbyattnos))
1013  {
1014  /* The PK is a subset of grouping_columns, so we win */
1015  *constraintDeps = lappend_oid(*constraintDeps, constraintOid);
1016  return true;
1017  }
1018 
1019  return false;
1020 }
signed short int16
Definition: c.h:252
bool check_functional_grouping(Oid relid, Index varno, Index varlevelsup, List *grouping_columns, List **constraintDeps)
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
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:542
#define NameGetDatum(X)
Definition: postgres.h:603
#define Anum_pg_constraint_conislocal
#define OperatorRelationId
Definition: pg_operator.h:32
Index varlevelsup
Definition: primnodes.h:158
ConstraintCategory
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:631
#define Anum_pg_constraint_confkey
#define Anum_pg_constraint_conindid
#define RelationGetDescr(relation)
Definition: rel.h:353
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:564
#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:2158
#define Int16GetDatum(X)
Definition: postgres.h:459
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:491
int errcode(int sqlerrcode)
Definition: elog.c:575
AttrNumber varattno
Definition: primnodes.h:153
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 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:2098
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#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:1306
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:148
#define TypeRelationId
Definition: pg_type.h:34
int namestrcpy(Name name, const char *str)
Definition: name.c:217
#define Anum_pg_constraint_coninhcount
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:530
#define Anum_pg_constraint_conbin
#define ConstraintTypidIndexId
Definition: indexing.h:122
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:141
void RenameConstraintById(Oid conId, const char *newname)
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:1479
#define NAMEDATALEN
#define CONSTRAINT_CHECK
#define CONSTRAINT_PRIMARY
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
void pfree(void *pointer)
Definition: mcxt.c:995
#define Anum_pg_constraint_convalidated
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
#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:307
Definition: c.h:488
#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:586
#define RelationGetRelationName(relation)
Definition: rel.h:361
#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:151
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:744
#define Anum_pg_constraint_confmatchtype
uintptr_t Datum
Definition: postgres.h:374
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:990
static char * label
Definition: pg_basebackup.c:59
Oid simple_heap_insert(Relation relation, HeapTuple tup)
Definition: heapam.c:2926
#define Anum_pg_constraint_connamespace
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1298
unsigned int Index
Definition: c.h:361
#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:410
#define InvalidOid
Definition: postgres_ext.h:36
#define ConstraintNameNspIndexId
Definition: indexing.h:118
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Natts_pg_constraint
#define NULL
Definition: c.h:226
#define Anum_pg_constraint_conpfeqop
#define Assert(condition)
Definition: c.h:667
#define lfirst(lc)
Definition: pg_list.h:106
#define StrNCpy(dst, src, len)
Definition: c.h:822
void CatalogUpdateIndexes(Relation heapRel, HeapTuple heapTuple)
Definition: indexing.c:157
#define Anum_pg_constraint_consrc
void simple_heap_delete(Relation relation, ItemPointer tid)
Definition: heapam.c:3385
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
Definition: heapam.c:4422
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:668
#define ARR_NDIM(a)
Definition: array.h:271
#define Anum_pg_constraint_connoinherit
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, Oid objNamespace, const char *conname)
#define CharGetDatum(X)
Definition: postgres.h:424
static Datum values[MAXATTR]
Definition: bootstrap.c:160
FormData_pg_class * Form_pg_class
Definition: pg_class.h:92
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:150
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior)
Definition: dependency.c:1393
#define AccessExclusiveLock
Definition: lockdefs.h:46
#define Int32GetDatum(X)
Definition: postgres.h:487
void * palloc(Size size)
Definition: mcxt.c:894
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define NameStr(name)
Definition: c.h:494
#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:806
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define Anum_pg_constraint_confrelid
#define elog
Definition: elog.h:218
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:670
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:34
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
#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:120
#define DatumGetArrayTypeP(X)
Definition: array.h:242