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