PostgreSQL Source Code  git master
pg_constraint.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/gist.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for pg_constraint.c:

Go to the source code of this file.

Functions

Oid CreateConstraintEntry (const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)
 
bool ConstraintNameIsUsed (ConstraintCategory conCat, Oid objId, const char *conname)
 
bool ConstraintNameExists (const char *conname, Oid namespaceid)
 
char * ChooseConstraintName (const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
 
HeapTuple findNotNullConstraintAttnum (Oid relid, AttrNumber attnum)
 
HeapTuple findNotNullConstraint (Oid relid, const char *colname)
 
HeapTuple findDomainNotNullConstraint (Oid typid)
 
AttrNumber extractNotNullColumn (HeapTuple constrTup)
 
int AdjustNotNullInheritance1 (Oid relid, AttrNumber attnum, int count, bool is_no_inherit)
 
void AdjustNotNullInheritance (Oid relid, Bitmapset *columns, int count)
 
ListRelationGetNotNullConstraints (Oid relid, bool cooked)
 
void RemoveConstraintById (Oid conId)
 
void RenameConstraintById (Oid conId, const char *newname)
 
void AlterConstraintNamespaces (Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
 
void ConstraintSetParentConstraint (Oid childConstrId, Oid parentConstrId, Oid childTableId)
 
Oid get_relation_constraint_oid (Oid relid, const char *conname, bool missing_ok)
 
Bitmapsetget_relation_constraint_attnos (Oid relid, const char *conname, bool missing_ok, Oid *constraintOid)
 
Oid get_relation_idx_constraint_oid (Oid relationId, Oid indexId)
 
Oid get_domain_constraint_oid (Oid typid, const char *conname, bool missing_ok)
 
Bitmapsetget_primary_key_attnos (Oid relid, bool deferrableOk, Oid *constraintOid)
 
void DeconstructFkConstraintRow (HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols)
 
void FindFKPeriodOpers (Oid opclass, Oid *containedbyoperoid, Oid *aggedcontainedbyoperoid)
 
bool check_functional_grouping (Oid relid, Index varno, Index varlevelsup, List *grouping_columns, List **constraintDeps)
 

Function Documentation

◆ AdjustNotNullInheritance()

void AdjustNotNullInheritance ( Oid  relid,
Bitmapset columns,
int  count 
)

Definition at line 801 of file pg_constraint.c.

802 {
803  Relation pg_constraint;
804  int attnum;
805 
806  pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
807 
808  /*
809  * Scan the set of columns and bump inhcount for each.
810  */
811  attnum = -1;
812  while ((attnum = bms_next_member(columns, attnum)) >= 0)
813  {
814  HeapTuple tup;
815  Form_pg_constraint conform;
816 
817  tup = findNotNullConstraintAttnum(relid, attnum);
818  if (!HeapTupleIsValid(tup))
819  ereport(ERROR,
820  errcode(ERRCODE_DATATYPE_MISMATCH),
821  errmsg("column \"%s\" in child table must be marked NOT NULL",
822  get_attname(relid, attnum,
823  false)));
824 
825  conform = (Form_pg_constraint) GETSTRUCT(tup);
826  conform->coninhcount += count;
827  if (conform->coninhcount < 0)
828  elog(ERROR, "invalid inhcount %d for constraint \"%s\" on relation \"%s\"",
829  conform->coninhcount, NameStr(conform->conname),
830  get_rel_name(relid));
831 
832  /*
833  * If the constraints are no longer inherited, mark them local. It's
834  * arguable that we should drop them instead, but it's hard to see
835  * that being better. The user can drop it manually later.
836  */
837  if (conform->coninhcount == 0)
838  conform->conislocal = true;
839 
840  CatalogTupleUpdate(pg_constraint, &tup->t_self, tup);
841  }
842 
843  table_close(pg_constraint, RowExclusiveLock);
844 }
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
#define NameStr(name)
Definition: c.h:746
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
char * get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
Definition: lsyscache.c:827
int16 attnum
Definition: pg_attribute.h:74
HeapTuple findNotNullConstraintAttnum(Oid relid, AttrNumber attnum)
FormData_pg_constraint * Form_pg_constraint
ItemPointerData t_self
Definition: htup.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References attnum, bms_next_member(), CatalogTupleUpdate(), elog, ereport, errcode(), errmsg(), ERROR, findNotNullConstraintAttnum(), get_attname(), get_rel_name(), GETSTRUCT, HeapTupleIsValid, NameStr, RowExclusiveLock, HeapTupleData::t_self, table_close(), and table_open().

Referenced by ATInheritAdjustNotNulls().

◆ AdjustNotNullInheritance1()

int AdjustNotNullInheritance1 ( Oid  relid,
AttrNumber  attnum,
int  count,
bool  is_no_inherit 
)

Definition at line 723 of file pg_constraint.c.

725 {
726  HeapTuple tup;
727 
728  Assert(count >= 0);
729 
730  tup = findNotNullConstraintAttnum(relid, attnum);
731  if (HeapTupleIsValid(tup))
732  {
733  Relation pg_constraint;
734  Form_pg_constraint conform;
735  int retval = 1;
736 
737  pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
738  conform = (Form_pg_constraint) GETSTRUCT(tup);
739 
740  /*
741  * If we're asked for a NO INHERIT constraint and this relation
742  * already has an inheritable one, throw an error.
743  */
744  if (is_no_inherit && !conform->connoinherit)
745  ereport(ERROR,
746  errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
747  errmsg("cannot change NO INHERIT status of inherited NOT NULL constraint \"%s\" on relation \"%s\"",
748  NameStr(conform->conname), get_rel_name(relid)));
749 
750  /*
751  * If the constraint already exists in this relation but it's marked
752  * NO INHERIT, we can just remove that flag, and instruct caller to
753  * recurse to add the constraint to children.
754  */
755  if (!is_no_inherit && conform->connoinherit)
756  {
757  conform->connoinherit = false;
758  retval = -1; /* caller must add constraint on child rels */
759  }
760 
761  if (count > 0)
762  conform->coninhcount += count;
763 
764  /* sanity check */
765  if (conform->coninhcount < 0)
766  elog(ERROR, "invalid inhcount %d for constraint \"%s\" on relation \"%s\"",
767  conform->coninhcount, NameStr(conform->conname),
768  get_rel_name(relid));
769 
770  /*
771  * If the constraint is no longer inherited, mark it local. It's
772  * arguable that we should drop it instead, but it's hard to see that
773  * being better. The user can drop it manually later.
774  */
775  if (conform->coninhcount == 0)
776  conform->conislocal = true;
777 
778  CatalogTupleUpdate(pg_constraint, &tup->t_self, tup);
779 
780  table_close(pg_constraint, RowExclusiveLock);
781 
782  return retval;
783  }
784 
785  return 0;
786 }
#define Assert(condition)
Definition: c.h:858

References Assert, attnum, CatalogTupleUpdate(), elog, ereport, errcode(), errmsg(), ERROR, findNotNullConstraintAttnum(), get_rel_name(), GETSTRUCT, HeapTupleIsValid, NameStr, RowExclusiveLock, HeapTupleData::t_self, table_close(), and table_open().

Referenced by AddRelationNewConstraints().

◆ AlterConstraintNamespaces()

void AlterConstraintNamespaces ( Oid  ownerId,
Oid  oldNspId,
Oid  newNspId,
bool  isType,
ObjectAddresses objsMoved 
)

Definition at line 1189 of file pg_constraint.c.

1191 {
1192  Relation conRel;
1193  ScanKeyData key[2];
1194  SysScanDesc scan;
1195  HeapTuple tup;
1196 
1197  conRel = table_open(ConstraintRelationId, RowExclusiveLock);
1198 
1199  ScanKeyInit(&key[0],
1200  Anum_pg_constraint_conrelid,
1201  BTEqualStrategyNumber, F_OIDEQ,
1202  ObjectIdGetDatum(isType ? InvalidOid : ownerId));
1203  ScanKeyInit(&key[1],
1204  Anum_pg_constraint_contypid,
1205  BTEqualStrategyNumber, F_OIDEQ,
1206  ObjectIdGetDatum(isType ? ownerId : InvalidOid));
1207 
1208  scan = systable_beginscan(conRel, ConstraintRelidTypidNameIndexId, true,
1209  NULL, 2, key);
1210 
1211  while (HeapTupleIsValid((tup = systable_getnext(scan))))
1212  {
1214  ObjectAddress thisobj;
1215 
1216  ObjectAddressSet(thisobj, ConstraintRelationId, conform->oid);
1217 
1218  if (object_address_present(&thisobj, objsMoved))
1219  continue;
1220 
1221  /* Don't update if the object is already part of the namespace */
1222  if (conform->connamespace == oldNspId && oldNspId != newNspId)
1223  {
1224  tup = heap_copytuple(tup);
1225  conform = (Form_pg_constraint) GETSTRUCT(tup);
1226 
1227  conform->connamespace = newNspId;
1228 
1229  CatalogTupleUpdate(conRel, &tup->t_self, tup);
1230 
1231  /*
1232  * Note: currently, the constraint will not have its own
1233  * dependency on the namespace, so we don't need to do
1234  * changeDependencyFor().
1235  */
1236  }
1237 
1238  InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
1239 
1240  add_exact_object_address(&thisobj, objsMoved);
1241  }
1242 
1243  systable_endscan(scan);
1244 
1245  table_close(conRel, RowExclusiveLock);
1246 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2591
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2531
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define InvalidOid
Definition: postgres_ext.h:36
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31

References add_exact_object_address(), BTEqualStrategyNumber, CatalogTupleUpdate(), GETSTRUCT, heap_copytuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, sort-test::key, object_address_present(), ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by AlterTableNamespaceInternal(), and AlterTypeNamespaceInternal().

◆ check_functional_grouping()

bool check_functional_grouping ( Oid  relid,
Index  varno,
Index  varlevelsup,
List grouping_columns,
List **  constraintDeps 
)

Definition at line 1858 of file pg_constraint.c.

1862 {
1863  Bitmapset *pkattnos;
1864  Bitmapset *groupbyattnos;
1865  Oid constraintOid;
1866  ListCell *gl;
1867 
1868  /* If the rel has no PK, then we can't prove functional dependency */
1869  pkattnos = get_primary_key_attnos(relid, false, &constraintOid);
1870  if (pkattnos == NULL)
1871  return false;
1872 
1873  /* Identify all the rel's columns that appear in grouping_columns */
1874  groupbyattnos = NULL;
1875  foreach(gl, grouping_columns)
1876  {
1877  Var *gvar = (Var *) lfirst(gl);
1878 
1879  if (IsA(gvar, Var) &&
1880  gvar->varno == varno &&
1881  gvar->varlevelsup == varlevelsup)
1882  groupbyattnos = bms_add_member(groupbyattnos,
1884  }
1885 
1886  if (bms_is_subset(pkattnos, groupbyattnos))
1887  {
1888  /* The PK is a subset of grouping_columns, so we win */
1889  *constraintDeps = lappend_oid(*constraintDeps, constraintOid);
1890  return true;
1891  }
1892 
1893  return false;
1894 }
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:412
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
Bitmapset * get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid)
#define lfirst(lc)
Definition: pg_list.h:172
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:248
AttrNumber varattno
Definition: primnodes.h:260
int varno
Definition: primnodes.h:255
Index varlevelsup
Definition: primnodes.h:280
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27

References bms_add_member(), bms_is_subset(), FirstLowInvalidHeapAttributeNumber, get_primary_key_attnos(), IsA, lappend_oid(), lfirst, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by check_ungrouped_columns_walker().

◆ ChooseConstraintName()

char* ChooseConstraintName ( const char *  name1,
const char *  name2,
const char *  label,
Oid  namespaceid,
List others 
)

Definition at line 502 of file pg_constraint.c.

505 {
506  int pass = 0;
507  char *conname = NULL;
508  char modlabel[NAMEDATALEN];
509  Relation conDesc;
510  SysScanDesc conscan;
511  ScanKeyData skey[2];
512  bool found;
513  ListCell *l;
514 
515  conDesc = table_open(ConstraintRelationId, AccessShareLock);
516 
517  /* try the unmodified label first */
518  strlcpy(modlabel, label, sizeof(modlabel));
519 
520  for (;;)
521  {
522  conname = makeObjectName(name1, name2, modlabel);
523 
524  found = false;
525 
526  foreach(l, others)
527  {
528  if (strcmp((char *) lfirst(l), conname) == 0)
529  {
530  found = true;
531  break;
532  }
533  }
534 
535  if (!found)
536  {
537  ScanKeyInit(&skey[0],
538  Anum_pg_constraint_conname,
539  BTEqualStrategyNumber, F_NAMEEQ,
540  CStringGetDatum(conname));
541 
542  ScanKeyInit(&skey[1],
543  Anum_pg_constraint_connamespace,
544  BTEqualStrategyNumber, F_OIDEQ,
545  ObjectIdGetDatum(namespaceid));
546 
547  conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
548  NULL, 2, skey);
549 
550  found = (HeapTupleIsValid(systable_getnext(conscan)));
551 
552  systable_endscan(conscan);
553  }
554 
555  if (!found)
556  break;
557 
558  /* found a conflict, so try a new name component */
559  pfree(conname);
560  snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
561  }
562 
563  table_close(conDesc, AccessShareLock);
564 
565  return conname;
566 }
char * makeObjectName(const char *name1, const char *name2, const char *label)
Definition: indexcmds.c:2529
#define AccessShareLock
Definition: lockdefs.h:36
void pfree(void *pointer)
Definition: mcxt.c:1520
static char * label
#define NAMEDATALEN
#define snprintf
Definition: port.h:238
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum(), HeapTupleIsValid, label, lfirst, makeObjectName(), NAMEDATALEN, ObjectIdGetDatum(), pfree(), ScanKeyInit(), snprintf, strlcpy(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by addFkRecurseReferenced(), addFkRecurseReferencing(), AddRelationNewConstraints(), AddRelationNotNullConstraints(), ATExecAddConstraint(), ATExecSetNotNull(), CloneFkReferencing(), domainAddCheckConstraint(), and domainAddNotNullConstraint().

◆ ConstraintNameExists()

bool ConstraintNameExists ( const char *  conname,
Oid  namespaceid 
)

Definition at line 448 of file pg_constraint.c.

449 {
450  bool found;
451  Relation conDesc;
452  SysScanDesc conscan;
453  ScanKeyData skey[2];
454 
455  conDesc = table_open(ConstraintRelationId, AccessShareLock);
456 
457  ScanKeyInit(&skey[0],
458  Anum_pg_constraint_conname,
459  BTEqualStrategyNumber, F_NAMEEQ,
460  CStringGetDatum(conname));
461 
462  ScanKeyInit(&skey[1],
463  Anum_pg_constraint_connamespace,
464  BTEqualStrategyNumber, F_OIDEQ,
465  ObjectIdGetDatum(namespaceid));
466 
467  conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true,
468  NULL, 2, skey);
469 
470  found = (HeapTupleIsValid(systable_getnext(conscan)));
471 
472  systable_endscan(conscan);
473  table_close(conDesc, AccessShareLock);
474 
475  return found;
476 }

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum(), HeapTupleIsValid, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ChooseRelationName().

◆ ConstraintNameIsUsed()

bool ConstraintNameIsUsed ( ConstraintCategory  conCat,
Oid  objId,
const char *  conname 
)

Definition at line 403 of file pg_constraint.c.

405 {
406  bool found;
407  Relation conDesc;
408  SysScanDesc conscan;
409  ScanKeyData skey[3];
410 
411  conDesc = table_open(ConstraintRelationId, AccessShareLock);
412 
413  ScanKeyInit(&skey[0],
414  Anum_pg_constraint_conrelid,
415  BTEqualStrategyNumber, F_OIDEQ,
417  ? objId : InvalidOid));
418  ScanKeyInit(&skey[1],
419  Anum_pg_constraint_contypid,
420  BTEqualStrategyNumber, F_OIDEQ,
422  ? objId : InvalidOid));
423  ScanKeyInit(&skey[2],
424  Anum_pg_constraint_conname,
425  BTEqualStrategyNumber, F_NAMEEQ,
426  CStringGetDatum(conname));
427 
428  conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId,
429  true, NULL, 3, skey);
430 
431  /* There can be at most one matching row */
432  found = (HeapTupleIsValid(systable_getnext(conscan)));
433 
434  systable_endscan(conscan);
435  table_close(conDesc, AccessShareLock);
436 
437  return found;
438 }
@ CONSTRAINT_DOMAIN
@ CONSTRAINT_RELATION

References AccessShareLock, BTEqualStrategyNumber, CONSTRAINT_DOMAIN, CONSTRAINT_RELATION, CStringGetDatum(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by addFkRecurseReferenced(), addFkRecurseReferencing(), AddRelationNewConstraints(), ATExecAddConstraint(), CloneFkReferencing(), domainAddCheckConstraint(), domainAddNotNullConstraint(), index_create(), and RenameConstraintById().

◆ ConstraintSetParentConstraint()

void ConstraintSetParentConstraint ( Oid  childConstrId,
Oid  parentConstrId,
Oid  childTableId 
)

Definition at line 1258 of file pg_constraint.c.

1261 {
1262  Relation constrRel;
1263  Form_pg_constraint constrForm;
1264  HeapTuple tuple,
1265  newtup;
1266  ObjectAddress depender;
1267  ObjectAddress referenced;
1268 
1269  constrRel = table_open(ConstraintRelationId, RowExclusiveLock);
1270  tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(childConstrId));
1271  if (!HeapTupleIsValid(tuple))
1272  elog(ERROR, "cache lookup failed for constraint %u", childConstrId);
1273  newtup = heap_copytuple(tuple);
1274  constrForm = (Form_pg_constraint) GETSTRUCT(newtup);
1275  if (OidIsValid(parentConstrId))
1276  {
1277  /* don't allow setting parent for a constraint that already has one */
1278  Assert(constrForm->coninhcount == 0);
1279  if (constrForm->conparentid != InvalidOid)
1280  elog(ERROR, "constraint %u already has a parent constraint",
1281  childConstrId);
1282 
1283  constrForm->conislocal = false;
1284  constrForm->coninhcount++;
1285  if (constrForm->coninhcount < 0)
1286  ereport(ERROR,
1287  errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1288  errmsg("too many inheritance parents"));
1289  constrForm->conparentid = parentConstrId;
1290 
1291  CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
1292 
1293  ObjectAddressSet(depender, ConstraintRelationId, childConstrId);
1294 
1295  ObjectAddressSet(referenced, ConstraintRelationId, parentConstrId);
1296  recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI);
1297 
1298  ObjectAddressSet(referenced, RelationRelationId, childTableId);
1299  recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC);
1300  }
1301  else
1302  {
1303  constrForm->coninhcount--;
1304  constrForm->conislocal = true;
1305  constrForm->conparentid = InvalidOid;
1306 
1307  /* Make sure there's no further inheritance. */
1308  Assert(constrForm->coninhcount == 0);
1309 
1310  CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
1311 
1312  deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
1313  ConstraintRelationId,
1315  deleteDependencyRecordsForClass(ConstraintRelationId, childConstrId,
1316  RelationRelationId,
1318  }
1319 
1320  ReleaseSysCache(tuple);
1321  table_close(constrRel, RowExclusiveLock);
1322 }
#define OidIsValid(objectId)
Definition: c.h:775
@ DEPENDENCY_PARTITION_PRI
Definition: dependency.h:36
@ DEPENDENCY_PARTITION_SEC
Definition: dependency.h:37
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:350
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

References Assert, CatalogTupleUpdate(), deleteDependencyRecordsForClass(), DEPENDENCY_PARTITION_PRI, DEPENDENCY_PARTITION_SEC, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_copytuple(), HeapTupleIsValid, InvalidOid, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, recordDependencyOn(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by ATExecAttachPartitionIdx(), AttachPartitionEnsureIndexes(), DefineIndex(), DetachPartitionFinalize(), and tryAttachPartitionForeignKey().

◆ CreateConstraintEntry()

Oid CreateConstraintEntry ( const char *  constraintName,
Oid  constraintNamespace,
char  constraintType,
bool  isDeferrable,
bool  isDeferred,
bool  isValidated,
Oid  parentConstrId,
Oid  relId,
const int16 constraintKey,
int  constraintNKeys,
int  constraintNTotalKeys,
Oid  domainId,
Oid  indexRelId,
Oid  foreignRelId,
const int16 foreignKey,
const Oid pfEqOp,
const Oid ppEqOp,
const Oid ffEqOp,
int  foreignNKeys,
char  foreignUpdateType,
char  foreignDeleteType,
const int16 fkDeleteSetCols,
int  numFkDeleteSetCols,
char  foreignMatchType,
const Oid exclOp,
Node conExpr,
const char *  conBin,
bool  conIsLocal,
int  conInhCount,
bool  conNoInherit,
bool  conPeriod,
bool  is_internal 
)

Definition at line 51 of file pg_constraint.c.

83 {
84  Relation conDesc;
85  Oid conOid;
86  HeapTuple tup;
87  bool nulls[Natts_pg_constraint];
88  Datum values[Natts_pg_constraint];
89  ArrayType *conkeyArray;
90  ArrayType *confkeyArray;
91  ArrayType *conpfeqopArray;
92  ArrayType *conppeqopArray;
93  ArrayType *conffeqopArray;
94  ArrayType *conexclopArray;
95  ArrayType *confdelsetcolsArray;
97  int i;
98  ObjectAddress conobject;
99  ObjectAddresses *addrs_auto;
100  ObjectAddresses *addrs_normal;
101 
102  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
103 
104  Assert(constraintName);
105  namestrcpy(&cname, constraintName);
106 
107  /*
108  * Convert C arrays into Postgres arrays.
109  */
110  if (constraintNKeys > 0)
111  {
112  Datum *conkey;
113 
114  conkey = (Datum *) palloc(constraintNKeys * sizeof(Datum));
115  for (i = 0; i < constraintNKeys; i++)
116  conkey[i] = Int16GetDatum(constraintKey[i]);
117  conkeyArray = construct_array_builtin(conkey, constraintNKeys, INT2OID);
118  }
119  else
120  conkeyArray = NULL;
121 
122  if (foreignNKeys > 0)
123  {
124  Datum *fkdatums;
125 
126  fkdatums = (Datum *) palloc(foreignNKeys * sizeof(Datum));
127  for (i = 0; i < foreignNKeys; i++)
128  fkdatums[i] = Int16GetDatum(foreignKey[i]);
129  confkeyArray = construct_array_builtin(fkdatums, foreignNKeys, INT2OID);
130  for (i = 0; i < foreignNKeys; i++)
131  fkdatums[i] = ObjectIdGetDatum(pfEqOp[i]);
132  conpfeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
133  for (i = 0; i < foreignNKeys; i++)
134  fkdatums[i] = ObjectIdGetDatum(ppEqOp[i]);
135  conppeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
136  for (i = 0; i < foreignNKeys; i++)
137  fkdatums[i] = ObjectIdGetDatum(ffEqOp[i]);
138  conffeqopArray = construct_array_builtin(fkdatums, foreignNKeys, OIDOID);
139 
140  if (numFkDeleteSetCols > 0)
141  {
142  for (i = 0; i < numFkDeleteSetCols; i++)
143  fkdatums[i] = Int16GetDatum(fkDeleteSetCols[i]);
144  confdelsetcolsArray = construct_array_builtin(fkdatums, numFkDeleteSetCols, INT2OID);
145  }
146  else
147  confdelsetcolsArray = NULL;
148  }
149  else
150  {
151  confkeyArray = NULL;
152  conpfeqopArray = NULL;
153  conppeqopArray = NULL;
154  conffeqopArray = NULL;
155  confdelsetcolsArray = NULL;
156  }
157 
158  if (exclOp != NULL)
159  {
160  Datum *opdatums;
161 
162  opdatums = (Datum *) palloc(constraintNKeys * sizeof(Datum));
163  for (i = 0; i < constraintNKeys; i++)
164  opdatums[i] = ObjectIdGetDatum(exclOp[i]);
165  conexclopArray = construct_array_builtin(opdatums, constraintNKeys, OIDOID);
166  }
167  else
168  conexclopArray = NULL;
169 
170  /* initialize nulls and values */
171  for (i = 0; i < Natts_pg_constraint; i++)
172  {
173  nulls[i] = false;
174  values[i] = (Datum) NULL;
175  }
176 
177  conOid = GetNewOidWithIndex(conDesc, ConstraintOidIndexId,
178  Anum_pg_constraint_oid);
179  values[Anum_pg_constraint_oid - 1] = ObjectIdGetDatum(conOid);
180  values[Anum_pg_constraint_conname - 1] = NameGetDatum(&cname);
181  values[Anum_pg_constraint_connamespace - 1] = ObjectIdGetDatum(constraintNamespace);
182  values[Anum_pg_constraint_contype - 1] = CharGetDatum(constraintType);
183  values[Anum_pg_constraint_condeferrable - 1] = BoolGetDatum(isDeferrable);
184  values[Anum_pg_constraint_condeferred - 1] = BoolGetDatum(isDeferred);
185  values[Anum_pg_constraint_convalidated - 1] = BoolGetDatum(isValidated);
186  values[Anum_pg_constraint_conrelid - 1] = ObjectIdGetDatum(relId);
187  values[Anum_pg_constraint_contypid - 1] = ObjectIdGetDatum(domainId);
188  values[Anum_pg_constraint_conindid - 1] = ObjectIdGetDatum(indexRelId);
189  values[Anum_pg_constraint_conparentid - 1] = ObjectIdGetDatum(parentConstrId);
190  values[Anum_pg_constraint_confrelid - 1] = ObjectIdGetDatum(foreignRelId);
191  values[Anum_pg_constraint_confupdtype - 1] = CharGetDatum(foreignUpdateType);
192  values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
193  values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
194  values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
195  values[Anum_pg_constraint_coninhcount - 1] = Int16GetDatum(conInhCount);
196  values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit);
197  values[Anum_pg_constraint_conperiod - 1] = BoolGetDatum(conPeriod);
198 
199  if (conkeyArray)
200  values[Anum_pg_constraint_conkey - 1] = PointerGetDatum(conkeyArray);
201  else
202  nulls[Anum_pg_constraint_conkey - 1] = true;
203 
204  if (confkeyArray)
205  values[Anum_pg_constraint_confkey - 1] = PointerGetDatum(confkeyArray);
206  else
207  nulls[Anum_pg_constraint_confkey - 1] = true;
208 
209  if (conpfeqopArray)
210  values[Anum_pg_constraint_conpfeqop - 1] = PointerGetDatum(conpfeqopArray);
211  else
212  nulls[Anum_pg_constraint_conpfeqop - 1] = true;
213 
214  if (conppeqopArray)
215  values[Anum_pg_constraint_conppeqop - 1] = PointerGetDatum(conppeqopArray);
216  else
217  nulls[Anum_pg_constraint_conppeqop - 1] = true;
218 
219  if (conffeqopArray)
220  values[Anum_pg_constraint_conffeqop - 1] = PointerGetDatum(conffeqopArray);
221  else
222  nulls[Anum_pg_constraint_conffeqop - 1] = true;
223 
224  if (confdelsetcolsArray)
225  values[Anum_pg_constraint_confdelsetcols - 1] = PointerGetDatum(confdelsetcolsArray);
226  else
227  nulls[Anum_pg_constraint_confdelsetcols - 1] = true;
228 
229  if (conexclopArray)
230  values[Anum_pg_constraint_conexclop - 1] = PointerGetDatum(conexclopArray);
231  else
232  nulls[Anum_pg_constraint_conexclop - 1] = true;
233 
234  if (conBin)
235  values[Anum_pg_constraint_conbin - 1] = CStringGetTextDatum(conBin);
236  else
237  nulls[Anum_pg_constraint_conbin - 1] = true;
238 
239  tup = heap_form_tuple(RelationGetDescr(conDesc), values, nulls);
240 
241  CatalogTupleInsert(conDesc, tup);
242 
243  ObjectAddressSet(conobject, ConstraintRelationId, conOid);
244 
245  table_close(conDesc, RowExclusiveLock);
246 
247  /* Handle set of auto dependencies */
248  addrs_auto = new_object_addresses();
249 
250  if (OidIsValid(relId))
251  {
252  /*
253  * Register auto dependency from constraint to owning relation, or to
254  * specific column(s) if any are mentioned.
255  */
256  ObjectAddress relobject;
257 
258  if (constraintNTotalKeys > 0)
259  {
260  for (i = 0; i < constraintNTotalKeys; i++)
261  {
262  ObjectAddressSubSet(relobject, RelationRelationId, relId,
263  constraintKey[i]);
264  add_exact_object_address(&relobject, addrs_auto);
265  }
266  }
267  else
268  {
269  ObjectAddressSet(relobject, RelationRelationId, relId);
270  add_exact_object_address(&relobject, addrs_auto);
271  }
272  }
273 
274  if (OidIsValid(domainId))
275  {
276  /*
277  * Register auto dependency from constraint to owning domain
278  */
279  ObjectAddress domobject;
280 
281  ObjectAddressSet(domobject, TypeRelationId, domainId);
282  add_exact_object_address(&domobject, addrs_auto);
283  }
284 
285  record_object_address_dependencies(&conobject, addrs_auto,
287  free_object_addresses(addrs_auto);
288 
289  /* Handle set of normal dependencies */
290  addrs_normal = new_object_addresses();
291 
292  if (OidIsValid(foreignRelId))
293  {
294  /*
295  * Register normal dependency from constraint to foreign relation, or
296  * to specific column(s) if any are mentioned.
297  */
298  ObjectAddress relobject;
299 
300  if (foreignNKeys > 0)
301  {
302  for (i = 0; i < foreignNKeys; i++)
303  {
304  ObjectAddressSubSet(relobject, RelationRelationId,
305  foreignRelId, foreignKey[i]);
306  add_exact_object_address(&relobject, addrs_normal);
307  }
308  }
309  else
310  {
311  ObjectAddressSet(relobject, RelationRelationId, foreignRelId);
312  add_exact_object_address(&relobject, addrs_normal);
313  }
314  }
315 
316  if (OidIsValid(indexRelId) && constraintType == CONSTRAINT_FOREIGN)
317  {
318  /*
319  * Register normal dependency on the unique index that supports a
320  * foreign-key constraint. (Note: for indexes associated with unique
321  * or primary-key constraints, the dependency runs the other way, and
322  * is not made here.)
323  */
324  ObjectAddress relobject;
325 
326  ObjectAddressSet(relobject, RelationRelationId, indexRelId);
327  add_exact_object_address(&relobject, addrs_normal);
328  }
329 
330  if (foreignNKeys > 0)
331  {
332  /*
333  * Register normal dependencies on the equality operators that support
334  * a foreign-key constraint. If the PK and FK types are the same then
335  * all three operators for a column are the same; otherwise they are
336  * different.
337  */
338  ObjectAddress oprobject;
339 
340  oprobject.classId = OperatorRelationId;
341  oprobject.objectSubId = 0;
342 
343  for (i = 0; i < foreignNKeys; i++)
344  {
345  oprobject.objectId = pfEqOp[i];
346  add_exact_object_address(&oprobject, addrs_normal);
347  if (ppEqOp[i] != pfEqOp[i])
348  {
349  oprobject.objectId = ppEqOp[i];
350  add_exact_object_address(&oprobject, addrs_normal);
351  }
352  if (ffEqOp[i] != pfEqOp[i])
353  {
354  oprobject.objectId = ffEqOp[i];
355  add_exact_object_address(&oprobject, addrs_normal);
356  }
357  }
358  }
359 
360  record_object_address_dependencies(&conobject, addrs_normal,
362  free_object_addresses(addrs_normal);
363 
364  /*
365  * We don't bother to register dependencies on the exclusion operators of
366  * an exclusion constraint. We assume they are members of the opclass
367  * supporting the index, so there's an indirect dependency via that. (This
368  * would be pretty dicey for cross-type operators, but exclusion operators
369  * can never be cross-type.)
370  */
371 
372  if (conExpr != NULL)
373  {
374  /*
375  * Register dependencies from constraint to objects mentioned in CHECK
376  * expression.
377  */
378  recordDependencyOnSingleRelExpr(&conobject, conExpr, relId,
380  DEPENDENCY_NORMAL, false);
381  }
382 
383  /* Post creation hook for new constraint */
384  InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
385  is_internal);
386 
387  return conOid;
388 }
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3374
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define CStringGetTextDatum(s)
Definition: builtins.h:97
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:391
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2740
void recordDependencyOnSingleRelExpr(const ObjectAddress *depender, Node *expr, Oid relId, DependencyType behavior, DependencyType self_behavior, bool reverse_self)
Definition: dependency.c:1594
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2485
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2771
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int i
Definition: isn.c:73
void * palloc(Size size)
Definition: mcxt.c:1316
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define InvokeObjectPostCreateHookArg(classId, objectId, subId, is_internal)
Definition: objectaccess.h:175
#define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id)
Definition: objectaddress.h:33
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:373
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define RelationGetDescr(relation)
Definition: rel.h:531
Definition: c.h:741

References add_exact_object_address(), Assert, BoolGetDatum(), CatalogTupleInsert(), CharGetDatum(), ObjectAddress::classId, construct_array_builtin(), CStringGetTextDatum, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, free_object_addresses(), GetNewOidWithIndex(), heap_form_tuple(), i, Int16GetDatum(), InvokeObjectPostCreateHookArg, NameGetDatum(), namestrcpy(), new_object_addresses(), ObjectAddressSet, ObjectAddressSubSet, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, palloc(), PointerGetDatum(), record_object_address_dependencies(), recordDependencyOnSingleRelExpr(), RelationGetDescr, RowExclusiveLock, table_close(), table_open(), and values.

Referenced by addFkRecurseReferenced(), addFkRecurseReferencing(), CloneFkReferencing(), CreateTriggerFiringOn(), domainAddCheckConstraint(), domainAddNotNullConstraint(), index_constraint_create(), StoreRelCheck(), and StoreRelNotNull().

◆ DeconstructFkConstraintRow()

void DeconstructFkConstraintRow ( HeapTuple  tuple,
int *  numfks,
AttrNumber conkey,
AttrNumber confkey,
Oid pf_eq_oprs,
Oid pp_eq_oprs,
Oid ff_eq_oprs,
int *  num_fk_del_set_cols,
AttrNumber fk_del_set_cols 
)

Definition at line 1669 of file pg_constraint.c.

1673 {
1674  Datum adatum;
1675  bool isNull;
1676  ArrayType *arr;
1677  int numkeys;
1678 
1679  /*
1680  * We expect the arrays to be 1-D arrays of the right types; verify that.
1681  * We don't need to use deconstruct_array() since the array data is just
1682  * going to look like a C array of values.
1683  */
1684  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1685  Anum_pg_constraint_conkey);
1686  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1687  if (ARR_NDIM(arr) != 1 ||
1688  ARR_HASNULL(arr) ||
1689  ARR_ELEMTYPE(arr) != INT2OID)
1690  elog(ERROR, "conkey is not a 1-D smallint array");
1691  numkeys = ARR_DIMS(arr)[0];
1692  if (numkeys <= 0 || numkeys > INDEX_MAX_KEYS)
1693  elog(ERROR, "foreign key constraint cannot have %d columns", numkeys);
1694  memcpy(conkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1695  if ((Pointer) arr != DatumGetPointer(adatum))
1696  pfree(arr); /* free de-toasted copy, if any */
1697 
1698  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1699  Anum_pg_constraint_confkey);
1700  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1701  if (ARR_NDIM(arr) != 1 ||
1702  ARR_DIMS(arr)[0] != numkeys ||
1703  ARR_HASNULL(arr) ||
1704  ARR_ELEMTYPE(arr) != INT2OID)
1705  elog(ERROR, "confkey is not a 1-D smallint array");
1706  memcpy(confkey, ARR_DATA_PTR(arr), numkeys * sizeof(int16));
1707  if ((Pointer) arr != DatumGetPointer(adatum))
1708  pfree(arr); /* free de-toasted copy, if any */
1709 
1710  if (pf_eq_oprs)
1711  {
1712  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1713  Anum_pg_constraint_conpfeqop);
1714  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1715  /* see TryReuseForeignKey if you change the test below */
1716  if (ARR_NDIM(arr) != 1 ||
1717  ARR_DIMS(arr)[0] != numkeys ||
1718  ARR_HASNULL(arr) ||
1719  ARR_ELEMTYPE(arr) != OIDOID)
1720  elog(ERROR, "conpfeqop is not a 1-D Oid array");
1721  memcpy(pf_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1722  if ((Pointer) arr != DatumGetPointer(adatum))
1723  pfree(arr); /* free de-toasted copy, if any */
1724  }
1725 
1726  if (pp_eq_oprs)
1727  {
1728  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1729  Anum_pg_constraint_conppeqop);
1730  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1731  if (ARR_NDIM(arr) != 1 ||
1732  ARR_DIMS(arr)[0] != numkeys ||
1733  ARR_HASNULL(arr) ||
1734  ARR_ELEMTYPE(arr) != OIDOID)
1735  elog(ERROR, "conppeqop is not a 1-D Oid array");
1736  memcpy(pp_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1737  if ((Pointer) arr != DatumGetPointer(adatum))
1738  pfree(arr); /* free de-toasted copy, if any */
1739  }
1740 
1741  if (ff_eq_oprs)
1742  {
1743  adatum = SysCacheGetAttrNotNull(CONSTROID, tuple,
1744  Anum_pg_constraint_conffeqop);
1745  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1746  if (ARR_NDIM(arr) != 1 ||
1747  ARR_DIMS(arr)[0] != numkeys ||
1748  ARR_HASNULL(arr) ||
1749  ARR_ELEMTYPE(arr) != OIDOID)
1750  elog(ERROR, "conffeqop is not a 1-D Oid array");
1751  memcpy(ff_eq_oprs, ARR_DATA_PTR(arr), numkeys * sizeof(Oid));
1752  if ((Pointer) arr != DatumGetPointer(adatum))
1753  pfree(arr); /* free de-toasted copy, if any */
1754  }
1755 
1756  if (fk_del_set_cols)
1757  {
1758  adatum = SysCacheGetAttr(CONSTROID, tuple,
1759  Anum_pg_constraint_confdelsetcols, &isNull);
1760  if (isNull)
1761  {
1762  *num_fk_del_set_cols = 0;
1763  }
1764  else
1765  {
1766  int num_delete_cols;
1767 
1768  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1769  if (ARR_NDIM(arr) != 1 ||
1770  ARR_HASNULL(arr) ||
1771  ARR_ELEMTYPE(arr) != INT2OID)
1772  elog(ERROR, "confdelsetcols is not a 1-D smallint array");
1773  num_delete_cols = ARR_DIMS(arr)[0];
1774  memcpy(fk_del_set_cols, ARR_DATA_PTR(arr), num_delete_cols * sizeof(int16));
1775  if ((Pointer) arr != DatumGetPointer(adatum))
1776  pfree(arr); /* free de-toasted copy, if any */
1777 
1778  *num_fk_del_set_cols = num_delete_cols;
1779  }
1780  }
1781 
1782  *numfks = numkeys;
1783 }
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
signed short int16
Definition: c.h:493
char * Pointer
Definition: c.h:483
#define INDEX_MAX_KEYS
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:510

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, DatumGetArrayTypeP, DatumGetPointer(), elog, ERROR, INDEX_MAX_KEYS, pfree(), SysCacheGetAttr(), and SysCacheGetAttrNotNull().

Referenced by CloneFkReferenced(), CloneFkReferencing(), RelationGetFKeyList(), and ri_LoadConstraintInfo().

◆ extractNotNullColumn()

AttrNumber extractNotNullColumn ( HeapTuple  constrTup)

Definition at line 683 of file pg_constraint.c.

684 {
685  AttrNumber colnum;
686  Datum adatum;
687  ArrayType *arr;
688 
689  /* only tuples for not-null constraints should be given */
690  Assert(((Form_pg_constraint) GETSTRUCT(constrTup))->contype == CONSTRAINT_NOTNULL);
691 
692  adatum = SysCacheGetAttrNotNull(CONSTROID, constrTup,
693  Anum_pg_constraint_conkey);
694  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
695  if (ARR_NDIM(arr) != 1 ||
696  ARR_HASNULL(arr) ||
697  ARR_ELEMTYPE(arr) != INT2OID ||
698  ARR_DIMS(arr)[0] != 1)
699  elog(ERROR, "conkey is not a 1-D smallint array");
700 
701  memcpy(&colnum, ARR_DATA_PTR(arr), sizeof(AttrNumber));
702 
703  if ((Pointer) arr != DatumGetPointer(adatum))
704  pfree(arr); /* free de-toasted copy, if any */
705 
706  return colnum;
707 }
int16 AttrNumber
Definition: attnum.h:21

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, Assert, DatumGetArrayTypeP, DatumGetPointer(), elog, ERROR, GETSTRUCT, pfree(), and SysCacheGetAttrNotNull().

Referenced by ATExecSetNotNull(), dropconstraint_internal(), findNotNullConstraintAttnum(), MergeConstraintsIntoExisting(), pg_get_constraintdef_worker(), RelationGetNotNullConstraints(), RemoveConstraintById(), and RemoveInheritance().

◆ findDomainNotNullConstraint()

HeapTuple findDomainNotNullConstraint ( Oid  typid)

Definition at line 639 of file pg_constraint.c.

640 {
641  Relation pg_constraint;
642  HeapTuple conTup,
643  retval = NULL;
644  SysScanDesc scan;
646 
647  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
648  ScanKeyInit(&key,
649  Anum_pg_constraint_contypid,
650  BTEqualStrategyNumber, F_OIDEQ,
651  ObjectIdGetDatum(typid));
652  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
653  true, NULL, 1, &key);
654 
655  while (HeapTupleIsValid(conTup = systable_getnext(scan)))
656  {
658 
659  /*
660  * We're looking for a NOTNULL constraint that's marked validated.
661  */
662  if (con->contype != CONSTRAINT_NOTNULL)
663  continue;
664  if (!con->convalidated)
665  continue;
666 
667  /* Found it */
668  retval = heap_copytuple(conTup);
669  break;
670  }
671 
672  systable_endscan(scan);
673  table_close(pg_constraint, AccessShareLock);
674 
675  return retval;
676 }

References AccessShareLock, BTEqualStrategyNumber, GETSTRUCT, heap_copytuple(), HeapTupleIsValid, sort-test::key, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterDomainNotNull().

◆ FindFKPeriodOpers()

void FindFKPeriodOpers ( Oid  opclass,
Oid containedbyoperoid,
Oid aggedcontainedbyoperoid 
)

Definition at line 1797 of file pg_constraint.c.

1800 {
1801  Oid opfamily = InvalidOid;
1802  Oid opcintype = InvalidOid;
1803  StrategyNumber strat;
1804 
1805  /* Make sure we have a range or multirange. */
1806  if (get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
1807  {
1808  if (opcintype != ANYRANGEOID && opcintype != ANYMULTIRANGEOID)
1809  ereport(ERROR,
1810  errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1811  errmsg("invalid type for PERIOD part of foreign key"),
1812  errdetail("Only range and multirange are supported."));
1813 
1814  }
1815  else
1816  elog(ERROR, "cache lookup failed for opclass %u", opclass);
1817 
1818  /*
1819  * Look up the ContainedBy operator whose lhs and rhs are the opclass's
1820  * type. We use this to optimize RI checks: if the new value includes all
1821  * of the old value, then we can treat the attribute as if it didn't
1822  * change, and skip the RI check.
1823  */
1826  InvalidOid,
1827  containedbyoperoid,
1828  &strat);
1829 
1830  /*
1831  * Now look up the ContainedBy operator. Its left arg must be the type of
1832  * the column (or rather of the opclass). Its right arg must match the
1833  * return type of the support proc.
1834  */
1837  ANYMULTIRANGEOID,
1838  aggedcontainedbyoperoid,
1839  &strat);
1840 }
int errdetail(const char *fmt,...)
Definition: elog.c:1205
void GetOperatorFromWellKnownStrategy(Oid opclass, Oid rhstype, Oid *opid, StrategyNumber *strat)
Definition: indexcmds.c:2441
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1235
uint16 StrategyNumber
Definition: stratnum.h:22
#define RTContainedByStrategyNumber
Definition: stratnum.h:58

References elog, ereport, errcode(), errdetail(), errmsg(), ERROR, get_opclass_opfamily_and_input_type(), GetOperatorFromWellKnownStrategy(), InvalidOid, and RTContainedByStrategyNumber.

Referenced by ATAddForeignKeyConstraint(), and ri_LoadConstraintInfo().

◆ findNotNullConstraint()

HeapTuple findNotNullConstraint ( Oid  relid,
const char *  colname 
)

Definition at line 627 of file pg_constraint.c.

628 {
629  AttrNumber attnum = get_attnum(relid, colname);
630 
631  return findNotNullConstraintAttnum(relid, attnum);
632 }
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:858

References attnum, findNotNullConstraintAttnum(), and get_attnum().

Referenced by ATExecDropNotNull(), and dropconstraint_internal().

◆ findNotNullConstraintAttnum()

HeapTuple findNotNullConstraintAttnum ( Oid  relid,
AttrNumber  attnum 
)

Definition at line 577 of file pg_constraint.c.

578 {
579  Relation pg_constraint;
580  HeapTuple conTup,
581  retval = NULL;
582  SysScanDesc scan;
584 
585  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
586  ScanKeyInit(&key,
587  Anum_pg_constraint_conrelid,
588  BTEqualStrategyNumber, F_OIDEQ,
589  ObjectIdGetDatum(relid));
590  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
591  true, NULL, 1, &key);
592 
593  while (HeapTupleIsValid(conTup = systable_getnext(scan)))
594  {
596  AttrNumber conkey;
597 
598  /*
599  * We're looking for a NOTNULL constraint that's marked validated,
600  * with the column we're looking for as the sole element in conkey.
601  */
602  if (con->contype != CONSTRAINT_NOTNULL)
603  continue;
604  if (!con->convalidated)
605  continue;
606 
607  conkey = extractNotNullColumn(conTup);
608  if (conkey != attnum)
609  continue;
610 
611  /* Found it */
612  retval = heap_copytuple(conTup);
613  break;
614  }
615 
616  systable_endscan(scan);
617  table_close(pg_constraint, AccessShareLock);
618 
619  return retval;
620 }
AttrNumber extractNotNullColumn(HeapTuple constrTup)

References AccessShareLock, attnum, BTEqualStrategyNumber, extractNotNullColumn(), GETSTRUCT, heap_copytuple(), HeapTupleIsValid, sort-test::key, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AdjustNotNullInheritance(), AdjustNotNullInheritance1(), dropconstraint_internal(), findNotNullConstraint(), MergeAttributesIntoExisting(), and RemoveConstraintById().

◆ get_domain_constraint_oid()

Oid get_domain_constraint_oid ( Oid  typid,
const char *  conname,
bool  missing_ok 
)

Definition at line 1524 of file pg_constraint.c.

1525 {
1526  Relation pg_constraint;
1527  HeapTuple tuple;
1528  SysScanDesc scan;
1529  ScanKeyData skey[3];
1530  Oid conOid = InvalidOid;
1531 
1532  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1533 
1534  ScanKeyInit(&skey[0],
1535  Anum_pg_constraint_conrelid,
1536  BTEqualStrategyNumber, F_OIDEQ,
1538  ScanKeyInit(&skey[1],
1539  Anum_pg_constraint_contypid,
1540  BTEqualStrategyNumber, F_OIDEQ,
1541  ObjectIdGetDatum(typid));
1542  ScanKeyInit(&skey[2],
1543  Anum_pg_constraint_conname,
1544  BTEqualStrategyNumber, F_NAMEEQ,
1545  CStringGetDatum(conname));
1546 
1547  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1548  NULL, 3, skey);
1549 
1550  /* There can be at most one matching row */
1551  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1552  conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1553 
1554  systable_endscan(scan);
1555 
1556  /* If no such constraint exists, complain */
1557  if (!OidIsValid(conOid) && !missing_ok)
1558  ereport(ERROR,
1559  (errcode(ERRCODE_UNDEFINED_OBJECT),
1560  errmsg("constraint \"%s\" for domain %s does not exist",
1561  conname, format_type_be(typid))));
1562 
1563  table_close(pg_constraint, AccessShareLock);
1564 
1565  return conOid;
1566 }
char * format_type_be(Oid type_oid)
Definition: format_type.c:343

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, format_type_be(), GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), OidIsValid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by get_object_address(), and rename_constraint_internal().

◆ get_primary_key_attnos()

Bitmapset* get_primary_key_attnos ( Oid  relid,
bool  deferrableOk,
Oid constraintOid 
)

Definition at line 1583 of file pg_constraint.c.

1584 {
1585  Bitmapset *pkattnos = NULL;
1586  Relation pg_constraint;
1587  HeapTuple tuple;
1588  SysScanDesc scan;
1589  ScanKeyData skey[1];
1590 
1591  /* Set *constraintOid, to avoid complaints about uninitialized vars */
1592  *constraintOid = InvalidOid;
1593 
1594  /* Scan pg_constraint for constraints of the target rel */
1595  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1596 
1597  ScanKeyInit(&skey[0],
1598  Anum_pg_constraint_conrelid,
1599  BTEqualStrategyNumber, F_OIDEQ,
1600  ObjectIdGetDatum(relid));
1601 
1602  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1603  NULL, 1, skey);
1604 
1605  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
1606  {
1608  Datum adatum;
1609  bool isNull;
1610  ArrayType *arr;
1611  int16 *attnums;
1612  int numkeys;
1613  int i;
1614 
1615  /* Skip constraints that are not PRIMARY KEYs */
1616  if (con->contype != CONSTRAINT_PRIMARY)
1617  continue;
1618 
1619  /*
1620  * If the primary key is deferrable, but we've been instructed to
1621  * ignore deferrable constraints, then we might as well give up
1622  * searching, since there can only be a single primary key on a table.
1623  */
1624  if (con->condeferrable && !deferrableOk)
1625  break;
1626 
1627  /* Extract the conkey array, ie, attnums of PK's columns */
1628  adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
1629  RelationGetDescr(pg_constraint), &isNull);
1630  if (isNull)
1631  elog(ERROR, "null conkey for constraint %u",
1632  ((Form_pg_constraint) GETSTRUCT(tuple))->oid);
1633  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1634  numkeys = ARR_DIMS(arr)[0];
1635  if (ARR_NDIM(arr) != 1 ||
1636  numkeys < 0 ||
1637  ARR_HASNULL(arr) ||
1638  ARR_ELEMTYPE(arr) != INT2OID)
1639  elog(ERROR, "conkey is not a 1-D smallint array");
1640  attnums = (int16 *) ARR_DATA_PTR(arr);
1641 
1642  /* Construct the result value */
1643  for (i = 0; i < numkeys; i++)
1644  {
1645  pkattnos = bms_add_member(pkattnos,
1647  }
1648  *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1649 
1650  /* No need to search further */
1651  break;
1652  }
1653 
1654  systable_endscan(scan);
1655 
1656  table_close(pg_constraint, AccessShareLock);
1657 
1658  return pkattnos;
1659 }
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792

References AccessShareLock, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, bms_add_member(), BTEqualStrategyNumber, DatumGetArrayTypeP, elog, ERROR, FirstLowInvalidHeapAttributeNumber, GETSTRUCT, heap_getattr(), HeapTupleIsValid, i, InvalidOid, ObjectIdGetDatum(), RelationGetDescr, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by check_functional_grouping(), and remove_useless_groupby_columns().

◆ get_relation_constraint_attnos()

Bitmapset* get_relation_constraint_attnos ( Oid  relid,
const char *  conname,
bool  missing_ok,
Oid constraintOid 
)

Definition at line 1388 of file pg_constraint.c.

1390 {
1391  Bitmapset *conattnos = NULL;
1392  Relation pg_constraint;
1393  HeapTuple tuple;
1394  SysScanDesc scan;
1395  ScanKeyData skey[3];
1396 
1397  /* Set *constraintOid, to avoid complaints about uninitialized vars */
1398  *constraintOid = InvalidOid;
1399 
1400  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1401 
1402  ScanKeyInit(&skey[0],
1403  Anum_pg_constraint_conrelid,
1404  BTEqualStrategyNumber, F_OIDEQ,
1405  ObjectIdGetDatum(relid));
1406  ScanKeyInit(&skey[1],
1407  Anum_pg_constraint_contypid,
1408  BTEqualStrategyNumber, F_OIDEQ,
1410  ScanKeyInit(&skey[2],
1411  Anum_pg_constraint_conname,
1412  BTEqualStrategyNumber, F_NAMEEQ,
1413  CStringGetDatum(conname));
1414 
1415  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1416  NULL, 3, skey);
1417 
1418  /* There can be at most one matching row */
1419  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1420  {
1421  Datum adatum;
1422  bool isNull;
1423 
1424  *constraintOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1425 
1426  /* Extract the conkey array, ie, attnums of constrained columns */
1427  adatum = heap_getattr(tuple, Anum_pg_constraint_conkey,
1428  RelationGetDescr(pg_constraint), &isNull);
1429  if (!isNull)
1430  {
1431  ArrayType *arr;
1432  int numcols;
1433  int16 *attnums;
1434  int i;
1435 
1436  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1437  numcols = ARR_DIMS(arr)[0];
1438  if (ARR_NDIM(arr) != 1 ||
1439  numcols < 0 ||
1440  ARR_HASNULL(arr) ||
1441  ARR_ELEMTYPE(arr) != INT2OID)
1442  elog(ERROR, "conkey is not a 1-D smallint array");
1443  attnums = (int16 *) ARR_DATA_PTR(arr);
1444 
1445  /* Construct the result value */
1446  for (i = 0; i < numcols; i++)
1447  {
1448  conattnos = bms_add_member(conattnos,
1450  }
1451  }
1452  }
1453 
1454  systable_endscan(scan);
1455 
1456  /* If no such constraint exists, complain */
1457  if (!OidIsValid(*constraintOid) && !missing_ok)
1458  ereport(ERROR,
1459  (errcode(ERRCODE_UNDEFINED_OBJECT),
1460  errmsg("constraint \"%s\" for table \"%s\" does not exist",
1461  conname, get_rel_name(relid))));
1462 
1463  table_close(pg_constraint, AccessShareLock);
1464 
1465  return conattnos;
1466 }

References AccessShareLock, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, bms_add_member(), BTEqualStrategyNumber, CStringGetDatum(), DatumGetArrayTypeP, elog, ereport, errcode(), errmsg(), ERROR, FirstLowInvalidHeapAttributeNumber, get_rel_name(), GETSTRUCT, heap_getattr(), HeapTupleIsValid, i, InvalidOid, ObjectIdGetDatum(), OidIsValid, RelationGetDescr, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by transformOnConflictArbiter().

◆ get_relation_constraint_oid()

Oid get_relation_constraint_oid ( Oid  relid,
const char *  conname,
bool  missing_ok 
)

Definition at line 1331 of file pg_constraint.c.

1332 {
1333  Relation pg_constraint;
1334  HeapTuple tuple;
1335  SysScanDesc scan;
1336  ScanKeyData skey[3];
1337  Oid conOid = InvalidOid;
1338 
1339  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1340 
1341  ScanKeyInit(&skey[0],
1342  Anum_pg_constraint_conrelid,
1343  BTEqualStrategyNumber, F_OIDEQ,
1344  ObjectIdGetDatum(relid));
1345  ScanKeyInit(&skey[1],
1346  Anum_pg_constraint_contypid,
1347  BTEqualStrategyNumber, F_OIDEQ,
1349  ScanKeyInit(&skey[2],
1350  Anum_pg_constraint_conname,
1351  BTEqualStrategyNumber, F_NAMEEQ,
1352  CStringGetDatum(conname));
1353 
1354  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true,
1355  NULL, 3, skey);
1356 
1357  /* There can be at most one matching row */
1358  if (HeapTupleIsValid(tuple = systable_getnext(scan)))
1359  conOid = ((Form_pg_constraint) GETSTRUCT(tuple))->oid;
1360 
1361  systable_endscan(scan);
1362 
1363  /* If no such constraint exists, complain */
1364  if (!OidIsValid(conOid) && !missing_ok)
1365  ereport(ERROR,
1366  (errcode(ERRCODE_UNDEFINED_OBJECT),
1367  errmsg("constraint \"%s\" for table \"%s\" does not exist",
1368  conname, get_rel_name(relid))));
1369 
1370  table_close(pg_constraint, AccessShareLock);
1371 
1372  return conOid;
1373 }

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, get_rel_name(), GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), OidIsValid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by expandTableLikeClause(), get_object_address_relobject(), and rename_constraint_internal().

◆ get_relation_idx_constraint_oid()

Oid get_relation_idx_constraint_oid ( Oid  relationId,
Oid  indexId 
)

Definition at line 1477 of file pg_constraint.c.

1478 {
1479  Relation pg_constraint;
1480  SysScanDesc scan;
1481  ScanKeyData key;
1482  HeapTuple tuple;
1483  Oid constraintId = InvalidOid;
1484 
1485  pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
1486 
1487  ScanKeyInit(&key,
1488  Anum_pg_constraint_conrelid,
1490  F_OIDEQ,
1491  ObjectIdGetDatum(relationId));
1492  scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
1493  true, NULL, 1, &key);
1494  while ((tuple = systable_getnext(scan)) != NULL)
1495  {
1496  Form_pg_constraint constrForm;
1497 
1498  constrForm = (Form_pg_constraint) GETSTRUCT(tuple);
1499 
1500  /* See above */
1501  if (constrForm->contype != CONSTRAINT_PRIMARY &&
1502  constrForm->contype != CONSTRAINT_UNIQUE &&
1503  constrForm->contype != CONSTRAINT_EXCLUSION)
1504  continue;
1505 
1506  if (constrForm->conindid == indexId)
1507  {
1508  constraintId = constrForm->oid;
1509  break;
1510  }
1511  }
1512  systable_endscan(scan);
1513 
1514  table_close(pg_constraint, AccessShareLock);
1515  return constraintId;
1516 }

References AccessShareLock, BTEqualStrategyNumber, GETSTRUCT, InvalidOid, sort-test::key, ObjectIdGetDatum(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ATExecAttachPartitionIdx(), AttachPartitionEnsureIndexes(), DefineIndex(), and DetachPartitionFinalize().

◆ RelationGetNotNullConstraints()

List* RelationGetNotNullConstraints ( Oid  relid,
bool  cooked 
)

Definition at line 858 of file pg_constraint.c.

859 {
860  List *notnulls = NIL;
861  Relation constrRel;
862  HeapTuple htup;
863  SysScanDesc conscan;
864  ScanKeyData skey;
865 
866  constrRel = table_open(ConstraintRelationId, AccessShareLock);
867  ScanKeyInit(&skey,
868  Anum_pg_constraint_conrelid,
869  BTEqualStrategyNumber, F_OIDEQ,
870  ObjectIdGetDatum(relid));
871  conscan = systable_beginscan(constrRel, ConstraintRelidTypidNameIndexId, true,
872  NULL, 1, &skey);
873 
874  while (HeapTupleIsValid(htup = systable_getnext(conscan)))
875  {
877  AttrNumber colnum;
878 
879  if (conForm->contype != CONSTRAINT_NOTNULL)
880  continue;
881  if (conForm->connoinherit)
882  continue;
883 
884  colnum = extractNotNullColumn(htup);
885 
886  if (cooked)
887  {
888  CookedConstraint *cooked;
889 
890  cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
891 
892  cooked->contype = CONSTR_NOTNULL;
893  cooked->name = pstrdup(NameStr(conForm->conname));
894  cooked->attnum = colnum;
895  cooked->expr = NULL;
896  cooked->skip_validation = false;
897  cooked->is_local = true;
898  cooked->inhcount = 0;
899  cooked->is_no_inherit = conForm->connoinherit;
900 
901  notnulls = lappend(notnulls, cooked);
902  }
903  else
904  {
905  Constraint *constr;
906 
907  constr = makeNode(Constraint);
908  constr->contype = CONSTR_NOTNULL;
909  constr->conname = pstrdup(NameStr(conForm->conname));
910  constr->deferrable = false;
911  constr->initdeferred = false;
912  constr->location = -1;
913  constr->keys = list_make1(makeString(get_attname(relid, colnum,
914  false)));
915  constr->skip_validation = false;
916  constr->initially_valid = true;
917  notnulls = lappend(notnulls, constr);
918  }
919  }
920 
921  systable_endscan(conscan);
922  table_close(constrRel, AccessShareLock);
923 
924  return notnulls;
925 }
List * lappend(List *list, void *datum)
Definition: list.c:339
char * pstrdup(const char *in)
Definition: mcxt.c:1695
#define makeNode(_type_)
Definition: nodes.h:155
@ CONSTR_NOTNULL
Definition: parsenodes.h:2709
#define NIL
Definition: pg_list.h:68
#define list_make1(x1)
Definition: pg_list.h:212
bool initdeferred
Definition: parsenodes.h:2742
ParseLoc location
Definition: parsenodes.h:2783
List * keys
Definition: parsenodes.h:2754
ConstrType contype
Definition: parsenodes.h:2739
bool initially_valid
Definition: parsenodes.h:2744
bool skip_validation
Definition: parsenodes.h:2743
bool deferrable
Definition: parsenodes.h:2741
char * conname
Definition: parsenodes.h:2740
char * name
Definition: heap.h:40
AttrNumber attnum
Definition: heap.h:41
bool skip_validation
Definition: heap.h:43
bool is_no_inherit
Definition: heap.h:46
int inhcount
Definition: heap.h:45
bool is_local
Definition: heap.h:44
ConstrType contype
Definition: heap.h:37
Node * expr
Definition: heap.h:42
Definition: pg_list.h:54
String * makeString(char *str)
Definition: value.c:63

References AccessShareLock, CookedConstraint::attnum, BTEqualStrategyNumber, Constraint::conname, CONSTR_NOTNULL, CookedConstraint::contype, Constraint::contype, Constraint::deferrable, CookedConstraint::expr, extractNotNullColumn(), get_attname(), GETSTRUCT, HeapTupleIsValid, CookedConstraint::inhcount, Constraint::initdeferred, Constraint::initially_valid, CookedConstraint::is_local, CookedConstraint::is_no_inherit, Constraint::keys, lappend(), list_make1, Constraint::location, makeNode, makeString(), CookedConstraint::name, NameStr, NIL, ObjectIdGetDatum(), palloc(), pstrdup(), ScanKeyInit(), CookedConstraint::skip_validation, Constraint::skip_validation, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by expandTableLikeClause(), MergeAttributes(), and transformTableLikeClause().

◆ RemoveConstraintById()

void RemoveConstraintById ( Oid  conId)

Definition at line 932 of file pg_constraint.c.

933 {
934  Relation conDesc;
935  HeapTuple tup;
936  Form_pg_constraint con;
937  bool dropping_pk = false;
938  List *unconstrained_cols = NIL;
939 
940  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
941 
942  tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conId));
943  if (!HeapTupleIsValid(tup)) /* should not happen */
944  elog(ERROR, "cache lookup failed for constraint %u", conId);
945  con = (Form_pg_constraint) GETSTRUCT(tup);
946 
947  /*
948  * Special processing depending on what the constraint is for.
949  */
950  if (OidIsValid(con->conrelid))
951  {
952  Relation rel;
953 
954  /*
955  * If the constraint is for a relation, open and exclusive-lock the
956  * relation it's for.
957  */
958  rel = table_open(con->conrelid, AccessExclusiveLock);
959 
960  /*
961  * We need to update the relchecks count if it is a check constraint
962  * being dropped. This update will force backends to rebuild relcache
963  * entries when we commit. For not-null and primary key constraints,
964  * obtain the list of columns affected, so that we can reset their
965  * attnotnull flags below.
966  */
967  if (con->contype == CONSTRAINT_CHECK)
968  {
969  Relation pgrel;
970  HeapTuple relTup;
971  Form_pg_class classForm;
972 
973  pgrel = table_open(RelationRelationId, RowExclusiveLock);
974  relTup = SearchSysCacheCopy1(RELOID,
975  ObjectIdGetDatum(con->conrelid));
976  if (!HeapTupleIsValid(relTup))
977  elog(ERROR, "cache lookup failed for relation %u",
978  con->conrelid);
979  classForm = (Form_pg_class) GETSTRUCT(relTup);
980 
981  if (classForm->relchecks == 0) /* should not happen */
982  elog(ERROR, "relation \"%s\" has relchecks = 0",
984  classForm->relchecks--;
985 
986  CatalogTupleUpdate(pgrel, &relTup->t_self, relTup);
987 
988  heap_freetuple(relTup);
989 
991  }
992  else if (con->contype == CONSTRAINT_NOTNULL)
993  {
994  unconstrained_cols = list_make1_int(extractNotNullColumn(tup));
995  }
996  else if (con->contype == CONSTRAINT_PRIMARY)
997  {
998  Datum adatum;
999  ArrayType *arr;
1000  int numkeys;
1001  bool isNull;
1002  int16 *attnums;
1003 
1004  dropping_pk = true;
1005 
1006  adatum = heap_getattr(tup, Anum_pg_constraint_conkey,
1007  RelationGetDescr(conDesc), &isNull);
1008  if (isNull)
1009  elog(ERROR, "null conkey for constraint %u", con->oid);
1010  arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
1011  numkeys = ARR_DIMS(arr)[0];
1012  if (ARR_NDIM(arr) != 1 ||
1013  numkeys < 0 ||
1014  ARR_HASNULL(arr) ||
1015  ARR_ELEMTYPE(arr) != INT2OID)
1016  elog(ERROR, "conkey is not a 1-D smallint array");
1017  attnums = (int16 *) ARR_DATA_PTR(arr);
1018 
1019  for (int i = 0; i < numkeys; i++)
1020  unconstrained_cols = lappend_int(unconstrained_cols, attnums[i]);
1021  }
1022 
1023  /* Keep lock on constraint's rel until end of xact */
1024  table_close(rel, NoLock);
1025  }
1026  else if (OidIsValid(con->contypid))
1027  {
1028  /*
1029  * XXX for now, do nothing special when dropping a domain constraint
1030  *
1031  * Probably there should be some form of locking on the domain type,
1032  * but we have no such concept at the moment.
1033  */
1034  }
1035  else
1036  elog(ERROR, "constraint %u is not of a known type", conId);
1037 
1038  /* Fry the constraint itself */
1039  CatalogTupleDelete(conDesc, &tup->t_self);
1040 
1041  /*
1042  * If this was a NOT NULL or the primary key, the constrained columns must
1043  * have had pg_attribute.attnotnull set. See if we need to reset it, and
1044  * do so.
1045  */
1046  if (unconstrained_cols != NIL)
1047  {
1048  Relation tablerel;
1049  Relation attrel;
1050  Bitmapset *pkcols;
1051  ListCell *lc;
1052 
1053  /* Make the above deletion visible */
1055 
1056  tablerel = table_open(con->conrelid, NoLock); /* already have lock */
1057  attrel = table_open(AttributeRelationId, RowExclusiveLock);
1058 
1059  /*
1060  * We want to test columns for their presence in the primary key, but
1061  * only if we're not dropping it.
1062  */
1063  pkcols = dropping_pk ? NULL :
1064  RelationGetIndexAttrBitmap(tablerel,
1066 
1067  foreach(lc, unconstrained_cols)
1068  {
1070  HeapTuple atttup;
1071  HeapTuple contup;
1072  Bitmapset *ircols;
1073  Form_pg_attribute attForm;
1074 
1075  /*
1076  * Obtain pg_attribute tuple and verify conditions on it. We use
1077  * a copy we can scribble on.
1078  */
1079  atttup = SearchSysCacheCopyAttNum(con->conrelid, attnum);
1080  if (!HeapTupleIsValid(atttup))
1081  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1082  attnum, con->conrelid);
1083  attForm = (Form_pg_attribute) GETSTRUCT(atttup);
1084 
1085  /*
1086  * Since the above deletion has been made visible, we can now
1087  * search for any remaining constraints setting this column as
1088  * not-nullable; if we find any, no need to reset attnotnull.
1089  */
1091  pkcols))
1092  continue;
1093  contup = findNotNullConstraintAttnum(con->conrelid, attnum);
1094  if (contup)
1095  continue;
1096 
1097  /*
1098  * Also no reset if the column is in the replica identity or it's
1099  * a generated column
1100  */
1101  if (attForm->attidentity != '\0')
1102  continue;
1103  ircols = RelationGetIndexAttrBitmap(tablerel,
1106  ircols))
1107  continue;
1108 
1109  /* Reset attnotnull */
1110  if (attForm->attnotnull)
1111  {
1112  attForm->attnotnull = false;
1113  CatalogTupleUpdate(attrel, &atttup->t_self, atttup);
1114  }
1115  }
1116 
1117  table_close(attrel, RowExclusiveLock);
1118  table_close(tablerel, NoLock);
1119  }
1120 
1121  /* Clean up */
1122  ReleaseSysCache(tup);
1123  table_close(conDesc, RowExclusiveLock);
1124 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
List * lappend_int(List *list, int datum)
Definition: list.c:357
#define NoLock
Definition: lockdefs.h:34
#define AccessExclusiveLock
Definition: lockdefs.h:43
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define lfirst_int(lc)
Definition: pg_list.h:173
#define list_make1_int(x1)
Definition: pg_list.h:227
#define RelationGetRelationName(relation)
Definition: rel.h:539
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:5231
@ INDEX_ATTR_BITMAP_PRIMARY_KEY
Definition: relcache.h:62
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition: relcache.h:63
HeapTuple SearchSysCacheCopyAttNum(Oid relid, int16 attnum)
Definition: syscache.c:445
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
void CommandCounterIncrement(void)
Definition: xact.c:1097

References AccessExclusiveLock, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, attnum, bms_is_member(), CatalogTupleDelete(), CatalogTupleUpdate(), CommandCounterIncrement(), DatumGetArrayTypeP, elog, ERROR, extractNotNullColumn(), findNotNullConstraintAttnum(), FirstLowInvalidHeapAttributeNumber, GETSTRUCT, heap_freetuple(), heap_getattr(), HeapTupleIsValid, i, INDEX_ATTR_BITMAP_IDENTITY_KEY, INDEX_ATTR_BITMAP_PRIMARY_KEY, lappend_int(), lfirst_int, list_make1_int, NIL, NoLock, ObjectIdGetDatum(), OidIsValid, RelationGetDescr, RelationGetIndexAttrBitmap(), RelationGetRelationName, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), SearchSysCacheCopy1, SearchSysCacheCopyAttNum(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ RenameConstraintById()

void RenameConstraintById ( Oid  conId,
const char *  newname 
)

Definition at line 1137 of file pg_constraint.c.

1138 {
1139  Relation conDesc;
1140  HeapTuple tuple;
1141  Form_pg_constraint con;
1142 
1143  conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
1144 
1145  tuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(conId));
1146  if (!HeapTupleIsValid(tuple))
1147  elog(ERROR, "cache lookup failed for constraint %u", conId);
1148  con = (Form_pg_constraint) GETSTRUCT(tuple);
1149 
1150  /*
1151  * For user-friendliness, check whether the name is already in use.
1152  */
1153  if (OidIsValid(con->conrelid) &&
1155  con->conrelid,
1156  newname))
1157  ereport(ERROR,
1159  errmsg("constraint \"%s\" for relation \"%s\" already exists",
1160  newname, get_rel_name(con->conrelid))));
1161  if (OidIsValid(con->contypid) &&
1163  con->contypid,
1164  newname))
1165  ereport(ERROR,
1167  errmsg("constraint \"%s\" for domain %s already exists",
1168  newname, format_type_be(con->contypid))));
1169 
1170  /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
1171  namestrcpy(&(con->conname), newname);
1172 
1173  CatalogTupleUpdate(conDesc, &tuple->t_self, tuple);
1174 
1175  InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
1176 
1177  heap_freetuple(tuple);
1178  table_close(conDesc, RowExclusiveLock);
1179 }
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32

References CatalogTupleUpdate(), CONSTRAINT_DOMAIN, CONSTRAINT_RELATION, ConstraintNameIsUsed(), elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), get_rel_name(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, namestrcpy(), ObjectIdGetDatum(), OidIsValid, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by rename_constraint_internal(), and RenameRelationInternal().