diff options
Diffstat (limited to 'src/backend/catalog/pg_constraint.c')
-rw-r--r-- | src/backend/catalog/pg_constraint.c | 254 |
1 files changed, 124 insertions, 130 deletions
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index ea844413608..6781b00c6e6 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -422,7 +422,7 @@ CloneForeignKeyConstraints(Oid parentId, Oid relationId, List **cloned) ScanKeyInit(&key, Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(parentId)); - scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true, + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true, NULL, 1, &key); while ((tuple = systable_getnext(scan)) != NULL) @@ -632,17 +632,58 @@ CloneForeignKeyConstraints(Oid parentId, Oid relationId, List **cloned) */ bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, - Oid objNamespace, const char *conname) + const char *conname) { bool found; Relation conDesc; SysScanDesc conscan; - ScanKeyData skey[2]; - HeapTuple tup; + ScanKeyData skey[3]; conDesc = heap_open(ConstraintRelationId, AccessShareLock); - found = false; + ScanKeyInit(&skey[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum((conCat == CONSTRAINT_RELATION) + ? objId : InvalidOid)); + ScanKeyInit(&skey[1], + Anum_pg_constraint_contypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum((conCat == CONSTRAINT_DOMAIN) + ? objId : InvalidOid)); + ScanKeyInit(&skey[2], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); + + conscan = systable_beginscan(conDesc, ConstraintRelidTypidNameIndexId, + true, NULL, 3, skey); + + /* There can be at most one matching row */ + found = (HeapTupleIsValid(systable_getnext(conscan))); + + systable_endscan(conscan); + heap_close(conDesc, AccessShareLock); + + return found; +} + +/* + * Does any constraint of the given name exist in the given namespace? + * + * This is used for code that wants to match ChooseConstraintName's rule + * that we should avoid autogenerating duplicate constraint names within a + * namespace. + */ +bool +ConstraintNameExists(const char *conname, Oid namespaceid) +{ + bool found; + Relation conDesc; + SysScanDesc conscan; + ScanKeyData skey[2]; + + conDesc = heap_open(ConstraintRelationId, AccessShareLock); ScanKeyInit(&skey[0], Anum_pg_constraint_conname, @@ -652,26 +693,12 @@ ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, ScanKeyInit(&skey[1], Anum_pg_constraint_connamespace, BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(objNamespace)); + ObjectIdGetDatum(namespaceid)); conscan = systable_beginscan(conDesc, ConstraintNameNspIndexId, true, NULL, 2, skey); - while (HeapTupleIsValid(tup = systable_getnext(conscan))) - { - Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup); - - if (conCat == CONSTRAINT_RELATION && con->conrelid == objId) - { - found = true; - break; - } - else if (conCat == CONSTRAINT_DOMAIN && con->contypid == objId) - { - found = true; - break; - } - } + found = (HeapTupleIsValid(systable_getnext(conscan))); systable_endscan(conscan); heap_close(conDesc, AccessShareLock); @@ -878,13 +905,11 @@ RenameConstraintById(Oid conId, const char *newname) con = (Form_pg_constraint) GETSTRUCT(tuple); /* - * We need to check whether the name is already in use --- note that there - * currently is not a unique index that would catch this. + * For user-friendliness, check whether the name is already in use. */ if (OidIsValid(con->conrelid) && ConstraintNameIsUsed(CONSTRAINT_RELATION, con->conrelid, - con->connamespace, newname)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), @@ -893,7 +918,6 @@ RenameConstraintById(Oid conId, const char *newname) if (OidIsValid(con->contypid) && ConstraintNameIsUsed(CONSTRAINT_DOMAIN, con->contypid, - con->connamespace, newname)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), @@ -923,32 +947,23 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved) { Relation conRel; - ScanKeyData key[1]; + ScanKeyData key[2]; SysScanDesc scan; HeapTuple tup; conRel = heap_open(ConstraintRelationId, RowExclusiveLock); - if (isType) - { - ScanKeyInit(&key[0], - Anum_pg_constraint_contypid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(ownerId)); - - scan = systable_beginscan(conRel, ConstraintTypidIndexId, true, - NULL, 1, key); - } - else - { - ScanKeyInit(&key[0], - Anum_pg_constraint_conrelid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(ownerId)); + ScanKeyInit(&key[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(isType ? InvalidOid : ownerId)); + ScanKeyInit(&key[1], + Anum_pg_constraint_contypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(isType ? ownerId : InvalidOid)); - scan = systable_beginscan(conRel, ConstraintRelidIndexId, true, - NULL, 1, key); - } + scan = systable_beginscan(conRel, ConstraintRelidTypidNameIndexId, true, + NULL, 2, key); while (HeapTupleIsValid((tup = systable_getnext(scan)))) { @@ -1038,38 +1053,30 @@ get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok) Relation pg_constraint; HeapTuple tuple; SysScanDesc scan; - ScanKeyData skey[1]; + ScanKeyData skey[3]; Oid conOid = InvalidOid; - /* - * Fetch the constraint tuple from pg_constraint. There may be more than - * one match, because constraints are not required to have unique names; - * if so, error out. - */ pg_constraint = heap_open(ConstraintRelationId, AccessShareLock); ScanKeyInit(&skey[0], Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); + ScanKeyInit(&skey[1], + Anum_pg_constraint_contypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(InvalidOid)); + ScanKeyInit(&skey[2], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); - scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true, - NULL, 1, skey); - - while (HeapTupleIsValid(tuple = systable_getnext(scan))) - { - Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true, + NULL, 3, skey); - if (strcmp(NameStr(con->conname), conname) == 0) - { - if (OidIsValid(conOid)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("table \"%s\" has multiple constraints named \"%s\"", - get_rel_name(relid), conname))); - conOid = HeapTupleGetOid(tuple); - } - } + /* There can be at most one matching row */ + if (HeapTupleIsValid(tuple = systable_getnext(scan))) + conOid = HeapTupleGetOid(tuple); systable_endscan(scan); @@ -1105,67 +1112,62 @@ get_relation_constraint_attnos(Oid relid, const char *conname, Relation pg_constraint; HeapTuple tuple; SysScanDesc scan; - ScanKeyData skey[1]; + ScanKeyData skey[3]; /* Set *constraintOid, to avoid complaints about uninitialized vars */ *constraintOid = InvalidOid; - /* - * Fetch the constraint tuple from pg_constraint. There may be more than - * one match, because constraints are not required to have unique names; - * if so, error out. - */ pg_constraint = heap_open(ConstraintRelationId, AccessShareLock); ScanKeyInit(&skey[0], Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); + ScanKeyInit(&skey[1], + Anum_pg_constraint_contypid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(InvalidOid)); + ScanKeyInit(&skey[2], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); - scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true, - NULL, 1, skey); + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true, + NULL, 3, skey); - while (HeapTupleIsValid(tuple = systable_getnext(scan))) + /* There can be at most one matching row */ + if (HeapTupleIsValid(tuple = systable_getnext(scan))) { - Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); Datum adatum; bool isNull; - ArrayType *arr; - int16 *attnums; - int numcols; - int i; - - /* Check the constraint name */ - if (strcmp(NameStr(con->conname), conname) != 0) - continue; - if (OidIsValid(*constraintOid)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("table \"%s\" has multiple constraints named \"%s\"", - get_rel_name(relid), conname))); *constraintOid = HeapTupleGetOid(tuple); /* Extract the conkey array, ie, attnums of constrained columns */ adatum = heap_getattr(tuple, Anum_pg_constraint_conkey, RelationGetDescr(pg_constraint), &isNull); - if (isNull) - continue; /* no constrained columns */ - - arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ - numcols = ARR_DIMS(arr)[0]; - if (ARR_NDIM(arr) != 1 || - numcols < 0 || - ARR_HASNULL(arr) || - ARR_ELEMTYPE(arr) != INT2OID) - elog(ERROR, "conkey is not a 1-D smallint array"); - attnums = (int16 *) ARR_DATA_PTR(arr); - - /* Construct the result value */ - for (i = 0; i < numcols; i++) + if (!isNull) { - conattnos = bms_add_member(conattnos, - attnums[i] - FirstLowInvalidHeapAttributeNumber); + ArrayType *arr; + int numcols; + int16 *attnums; + int i; + + arr = DatumGetArrayTypeP(adatum); /* ensure not toasted */ + numcols = ARR_DIMS(arr)[0]; + if (ARR_NDIM(arr) != 1 || + numcols < 0 || + ARR_HASNULL(arr) || + ARR_ELEMTYPE(arr) != INT2OID) + elog(ERROR, "conkey is not a 1-D smallint array"); + attnums = (int16 *) ARR_DATA_PTR(arr); + + /* Construct the result value */ + for (i = 0; i < numcols; i++) + { + conattnos = bms_add_member(conattnos, + attnums[i] - FirstLowInvalidHeapAttributeNumber); + } } } @@ -1203,7 +1205,7 @@ get_relation_idx_constraint_oid(Oid relationId, Oid indexId) BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relationId)); - scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true, NULL, 1, &key); while ((tuple = systable_getnext(scan)) != NULL) { @@ -1233,38 +1235,30 @@ get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok) Relation pg_constraint; HeapTuple tuple; SysScanDesc scan; - ScanKeyData skey[1]; + ScanKeyData skey[3]; Oid conOid = InvalidOid; - /* - * Fetch the constraint tuple from pg_constraint. There may be more than - * one match, because constraints are not required to have unique names; - * if so, error out. - */ pg_constraint = heap_open(ConstraintRelationId, AccessShareLock); ScanKeyInit(&skey[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(InvalidOid)); + ScanKeyInit(&skey[1], Anum_pg_constraint_contypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(typid)); + ScanKeyInit(&skey[2], + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); - scan = systable_beginscan(pg_constraint, ConstraintTypidIndexId, true, - NULL, 1, skey); - - while (HeapTupleIsValid(tuple = systable_getnext(scan))) - { - Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true, + NULL, 3, skey); - if (strcmp(NameStr(con->conname), conname) == 0) - { - if (OidIsValid(conOid)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("domain %s has multiple constraints named \"%s\"", - format_type_be(typid), conname))); - conOid = HeapTupleGetOid(tuple); - } - } + /* There can be at most one matching row */ + if (HeapTupleIsValid(tuple = systable_getnext(scan))) + conOid = HeapTupleGetOid(tuple); systable_endscan(scan); @@ -1314,7 +1308,7 @@ get_primary_key_attnos(Oid relid, bool deferrableOk, Oid *constraintOid) BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); - scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true, + scan = systable_beginscan(pg_constraint, ConstraintRelidTypidNameIndexId, true, NULL, 1, skey); while (HeapTupleIsValid(tuple = systable_getnext(scan))) |