aboutsummaryrefslogtreecommitdiff
path: root/src/backend/catalog/pg_constraint.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/catalog/pg_constraint.c')
-rw-r--r--src/backend/catalog/pg_constraint.c441
1 files changed, 1 insertions, 440 deletions
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 12a73d5a309..b10e458b449 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -19,10 +19,8 @@
#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"
@@ -566,72 +564,6 @@ ChooseConstraintName(const char *name1, const char *name2,
}
/*
- * Find and return a copy of the pg_constraint tuple that implements a
- * validated not-null constraint for the given column of the given relation.
- *
- * XXX This would be easier if we had pg_attribute.notnullconstr with the OID
- * of the constraint that implements the not-null constraint for that column.
- * I'm not sure it's worth the catalog bloat and de-normalization, however.
- */
-HeapTuple
-findNotNullConstraintAttnum(Oid relid, AttrNumber attnum)
-{
- Relation pg_constraint;
- HeapTuple conTup,
- retval = NULL;
- SysScanDesc scan;
- ScanKeyData key;
-
- pg_constraint = table_open(ConstraintRelationId, AccessShareLock);
- ScanKeyInit(&key,
- Anum_pg_constraint_conrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(relid));
- scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId,
- true, NULL, 1, &key);
-
- while (HeapTupleIsValid(conTup = systable_getnext(scan)))
- {
- Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(conTup);
- AttrNumber conkey;
-
- /*
- * We're looking for a NOTNULL constraint that's marked validated,
- * with the column we're looking for as the sole element in conkey.
- */
- if (con->contype != CONSTRAINT_NOTNULL)
- continue;
- if (!con->convalidated)
- continue;
-
- conkey = extractNotNullColumn(conTup);
- if (conkey != attnum)
- continue;
-
- /* Found it */
- retval = heap_copytuple(conTup);
- break;
- }
-
- systable_endscan(scan);
- table_close(pg_constraint, AccessShareLock);
-
- return retval;
-}
-
-/*
- * Find and return the pg_constraint tuple that implements a validated
- * not-null constraint for the given column of the given relation.
- */
-HeapTuple
-findNotNullConstraint(Oid relid, const char *colname)
-{
- AttrNumber attnum = get_attnum(relid, colname);
-
- return findNotNullConstraintAttnum(relid, attnum);
-}
-
-/*
* Find and return the pg_constraint tuple that implements a validated
* not-null constraint for the given domain.
*/
@@ -676,263 +608,6 @@ findDomainNotNullConstraint(Oid typid)
}
/*
- * Given a pg_constraint tuple for a not-null constraint, return the column
- * number it is for.
- */
-AttrNumber
-extractNotNullColumn(HeapTuple constrTup)
-{
- AttrNumber colnum;
- Datum adatum;
- ArrayType *arr;
-
- /* only tuples for not-null constraints should be given */
- Assert(((Form_pg_constraint) GETSTRUCT(constrTup))->contype == CONSTRAINT_NOTNULL);
-
- adatum = SysCacheGetAttrNotNull(CONSTROID, constrTup,
- Anum_pg_constraint_conkey);
- arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
- if (ARR_NDIM(arr) != 1 ||
- ARR_HASNULL(arr) ||
- ARR_ELEMTYPE(arr) != INT2OID ||
- ARR_DIMS(arr)[0] != 1)
- elog(ERROR, "conkey is not a 1-D smallint array");
-
- memcpy(&colnum, ARR_DATA_PTR(arr), sizeof(AttrNumber));
-
- if ((Pointer) arr != DatumGetPointer(adatum))
- pfree(arr); /* free de-toasted copy, if any */
-
- return colnum;
-}
-
-/*
- * AdjustNotNullInheritance1
- * Adjust inheritance count for a single not-null constraint
- *
- * If no not-null constraint is found for the column, return 0.
- * Caller can create one.
- * If the constraint does exist and it's inheritable, adjust its
- * inheritance count (and possibly islocal status) and return 1.
- * No further action needs to be taken.
- * If the constraint exists but is marked NO INHERIT, adjust it as above
- * and reset connoinherit to false, and return -1. Caller is
- * responsible for adding the same constraint to the children, if any.
- */
-int
-AdjustNotNullInheritance1(Oid relid, AttrNumber attnum, int count,
- bool is_no_inherit, bool allow_noinherit_change)
-{
- HeapTuple tup;
-
- Assert(count >= 0);
-
- tup = findNotNullConstraintAttnum(relid, attnum);
- if (HeapTupleIsValid(tup))
- {
- Relation pg_constraint;
- Form_pg_constraint conform;
- int retval = 1;
-
- pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
- conform = (Form_pg_constraint) GETSTRUCT(tup);
-
- /*
- * If we're asked for a NO INHERIT constraint and this relation
- * already has an inheritable one, throw an error.
- */
- if (is_no_inherit && !conform->connoinherit)
- ereport(ERROR,
- errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("cannot change NO INHERIT status of NOT NULL constraint \"%s\" on relation \"%s\"",
- NameStr(conform->conname), get_rel_name(relid)));
-
- /*
- * If the constraint already exists in this relation but it's marked
- * NO INHERIT, we can just remove that flag (provided caller allows
- * such a change), and instruct caller to recurse to add the
- * constraint to children.
- */
- if (!is_no_inherit && conform->connoinherit)
- {
- if (!allow_noinherit_change)
- ereport(ERROR,
- errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("cannot change NO INHERIT status of NOT NULL constraint \"%s\" on relation \"%s\"",
- NameStr(conform->conname), get_rel_name(relid)));
-
- conform->connoinherit = false;
- retval = -1; /* caller must add constraint on child rels */
- }
-
- if (count > 0)
- conform->coninhcount += count;
-
- /* sanity check */
- if (conform->coninhcount < 0)
- elog(ERROR, "invalid inhcount %d for constraint \"%s\" on relation \"%s\"",
- conform->coninhcount, NameStr(conform->conname),
- get_rel_name(relid));
-
- /*
- * If the constraint is no longer inherited, mark it local. It's
- * arguable that we should drop it instead, but it's hard to see that
- * being better. The user can drop it manually later.
- */
- if (conform->coninhcount == 0)
- conform->conislocal = true;
-
- CatalogTupleUpdate(pg_constraint, &tup->t_self, tup);
-
- table_close(pg_constraint, RowExclusiveLock);
-
- return retval;
- }
-
- return 0;
-}
-
-/*
- * AdjustNotNullInheritance
- * Adjust not-null constraints' inhcount/islocal for
- * ALTER TABLE [NO] INHERITS
- *
- * Mark the NOT NULL constraints for the given relation columns as
- * inherited, so that they can't be dropped.
- *
- * Caller must have checked beforehand that attnotnull was set for all
- * columns. However, some of those could be set because of a primary
- * key, so throw a proper user-visible error if one is not found.
- */
-void
-AdjustNotNullInheritance(Oid relid, Bitmapset *columns, int count)
-{
- Relation pg_constraint;
- int attnum;
-
- pg_constraint = table_open(ConstraintRelationId, RowExclusiveLock);
-
- /*
- * Scan the set of columns and bump inhcount for each.
- */
- attnum = -1;
- while ((attnum = bms_next_member(columns, attnum)) >= 0)
- {
- HeapTuple tup;
- Form_pg_constraint conform;
-
- tup = findNotNullConstraintAttnum(relid, attnum);
- if (!HeapTupleIsValid(tup))
- ereport(ERROR,
- errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("column \"%s\" in child table must be marked NOT NULL",
- get_attname(relid, attnum,
- false)));
-
- conform = (Form_pg_constraint) GETSTRUCT(tup);
- conform->coninhcount += count;
- if (conform->coninhcount < 0)
- elog(ERROR, "invalid inhcount %d for constraint \"%s\" on relation \"%s\"",
- conform->coninhcount, NameStr(conform->conname),
- get_rel_name(relid));
-
- /*
- * If the constraints are no longer inherited, mark them local. It's
- * arguable that we should drop them instead, but it's hard to see
- * that being better. The user can drop it manually later.
- */
- if (conform->coninhcount == 0)
- conform->conislocal = true;
-
- CatalogTupleUpdate(pg_constraint, &tup->t_self, tup);
- }
-
- table_close(pg_constraint, RowExclusiveLock);
-}
-
-/*
- * RelationGetNotNullConstraints
- * Return the list of not-null constraints for the given rel
- *
- * Caller can request cooked constraints, or raw.
- *
- * This is seldom needed, so we just scan pg_constraint each time.
- *
- * XXX This is only used to create derived tables, so NO INHERIT constraints
- * are always skipped.
- */
-List *
-RelationGetNotNullConstraints(Oid relid, bool cooked)
-{
- List *notnulls = NIL;
- Relation constrRel;
- HeapTuple htup;
- SysScanDesc conscan;
- ScanKeyData skey;
-
- constrRel = table_open(ConstraintRelationId, AccessShareLock);
- ScanKeyInit(&skey,
- Anum_pg_constraint_conrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(relid));
- conscan = systable_beginscan(constrRel, ConstraintRelidTypidNameIndexId, true,
- NULL, 1, &skey);
-
- while (HeapTupleIsValid(htup = systable_getnext(conscan)))
- {
- Form_pg_constraint conForm = (Form_pg_constraint) GETSTRUCT(htup);
- AttrNumber colnum;
-
- if (conForm->contype != CONSTRAINT_NOTNULL)
- continue;
- if (conForm->connoinherit)
- continue;
-
- colnum = extractNotNullColumn(htup);
-
- if (cooked)
- {
- CookedConstraint *cooked;
-
- cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
-
- cooked->contype = CONSTR_NOTNULL;
- cooked->name = pstrdup(NameStr(conForm->conname));
- cooked->attnum = colnum;
- cooked->expr = NULL;
- cooked->skip_validation = false;
- cooked->is_local = true;
- cooked->inhcount = 0;
- cooked->is_no_inherit = conForm->connoinherit;
-
- notnulls = lappend(notnulls, cooked);
- }
- else
- {
- Constraint *constr;
-
- constr = makeNode(Constraint);
- constr->contype = CONSTR_NOTNULL;
- constr->conname = pstrdup(NameStr(conForm->conname));
- constr->deferrable = false;
- constr->initdeferred = false;
- constr->location = -1;
- constr->keys = list_make1(makeString(get_attname(relid, colnum,
- false)));
- constr->skip_validation = false;
- constr->initially_valid = true;
- notnulls = lappend(notnulls, constr);
- }
- }
-
- systable_endscan(conscan);
- table_close(constrRel, AccessShareLock);
-
- return notnulls;
-}
-
-
-/*
* Delete a single constraint record.
*/
void
@@ -941,8 +616,6 @@ RemoveConstraintById(Oid conId)
Relation conDesc;
HeapTuple tup;
Form_pg_constraint con;
- bool dropping_pk = false;
- List *unconstrained_cols = NIL;
conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
@@ -967,9 +640,7 @@ RemoveConstraintById(Oid conId)
/*
* We need to update the relchecks count if it is a check constraint
* being dropped. This update will force backends to rebuild relcache
- * entries when we commit. For not-null and primary key constraints,
- * obtain the list of columns affected, so that we can reset their
- * attnotnull flags below.
+ * entries when we commit.
*/
if (con->contype == CONSTRAINT_CHECK)
{
@@ -996,36 +667,6 @@ RemoveConstraintById(Oid conId)
table_close(pgrel, RowExclusiveLock);
}
- else if (con->contype == CONSTRAINT_NOTNULL)
- {
- unconstrained_cols = list_make1_int(extractNotNullColumn(tup));
- }
- else if (con->contype == CONSTRAINT_PRIMARY)
- {
- Datum adatum;
- ArrayType *arr;
- int numkeys;
- bool isNull;
- int16 *attnums;
-
- dropping_pk = true;
-
- adatum = heap_getattr(tup, Anum_pg_constraint_conkey,
- RelationGetDescr(conDesc), &isNull);
- if (isNull)
- elog(ERROR, "null conkey for constraint %u", con->oid);
- arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */
- numkeys = ARR_DIMS(arr)[0];
- if (ARR_NDIM(arr) != 1 ||
- numkeys < 0 ||
- ARR_HASNULL(arr) ||
- ARR_ELEMTYPE(arr) != INT2OID)
- elog(ERROR, "conkey is not a 1-D smallint array");
- attnums = (int16 *) ARR_DATA_PTR(arr);
-
- for (int i = 0; i < numkeys; i++)
- unconstrained_cols = lappend_int(unconstrained_cols, attnums[i]);
- }
/* Keep lock on constraint's rel until end of xact */
table_close(rel, NoLock);
@@ -1045,86 +686,6 @@ RemoveConstraintById(Oid conId)
/* Fry the constraint itself */
CatalogTupleDelete(conDesc, &tup->t_self);
- /*
- * If this was a NOT NULL or the primary key, the constrained columns must
- * have had pg_attribute.attnotnull set. See if we need to reset it, and
- * do so.
- */
- if (unconstrained_cols != NIL)
- {
- Relation tablerel;
- Relation attrel;
- Bitmapset *pkcols;
- ListCell *lc;
-
- /* Make the above deletion visible */
- CommandCounterIncrement();
-
- tablerel = table_open(con->conrelid, NoLock); /* already have lock */
- attrel = table_open(AttributeRelationId, RowExclusiveLock);
-
- /*
- * We want to test columns for their presence in the primary key, but
- * only if we're not dropping it.
- */
- pkcols = dropping_pk ? NULL :
- RelationGetIndexAttrBitmap(tablerel,
- INDEX_ATTR_BITMAP_PRIMARY_KEY);
-
- foreach(lc, unconstrained_cols)
- {
- AttrNumber attnum = lfirst_int(lc);
- HeapTuple atttup;
- HeapTuple contup;
- Bitmapset *ircols;
- Form_pg_attribute attForm;
-
- /*
- * Obtain pg_attribute tuple and verify conditions on it. We use
- * a copy we can scribble on.
- */
- atttup = SearchSysCacheCopyAttNum(con->conrelid, attnum);
- if (!HeapTupleIsValid(atttup))
- elog(ERROR, "cache lookup failed for attribute %d of relation %u",
- attnum, con->conrelid);
- attForm = (Form_pg_attribute) GETSTRUCT(atttup);
-
- /*
- * Since the above deletion has been made visible, we can now
- * search for any remaining constraints setting this column as
- * not-nullable; if we find any, no need to reset attnotnull.
- */
- if (bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber,
- pkcols))
- continue;
- contup = findNotNullConstraintAttnum(con->conrelid, attnum);
- if (contup)
- continue;
-
- /*
- * Also no reset if the column is in the replica identity or it's
- * a generated column
- */
- if (attForm->attidentity != '\0')
- continue;
- ircols = RelationGetIndexAttrBitmap(tablerel,
- INDEX_ATTR_BITMAP_IDENTITY_KEY);
- if (bms_is_member(attnum - FirstLowInvalidHeapAttributeNumber,
- ircols))
- continue;
-
- /* Reset attnotnull */
- if (attForm->attnotnull)
- {
- attForm->attnotnull = false;
- CatalogTupleUpdate(attrel, &atttup->t_self, atttup);
- }
- }
-
- table_close(attrel, RowExclusiveLock);
- table_close(tablerel, NoLock);
- }
-
/* Clean up */
ReleaseSysCache(tup);
table_close(conDesc, RowExclusiveLock);