diff options
Diffstat (limited to 'src/backend/catalog/pg_constraint.c')
-rw-r--r-- | src/backend/catalog/pg_constraint.c | 190 |
1 files changed, 189 insertions, 1 deletions
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 60013c4d27a..6e89d6832c2 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.28 2005/11/22 18:17:08 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.29 2006/02/11 22:17:18 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -664,3 +664,191 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, heap_close(conRel, RowExclusiveLock); } + + +/* + * RenameConstraint + * Rename a single constraint record + * conId: The OID of the constraint to rename + * newName: The new name of the constraint + * implicitRename: is this an implicit rename? If so, we will issue + * a notice about the implicit rename + * cmdName: the command that triggered the rename for the "implicitly + * renames" notice message + */ +void +RenameConstraint(Oid conId, const char* newName, + bool implicitRename, const char* cmdName) +{ + Relation conRel; + ScanKeyData key[1]; + SysScanDesc scan; + HeapTuple tup; + NameData newNameData; + Relation rel; + Oid relId; + Oid nspOid; + Form_pg_constraint conform; + + /* before reading the tuple, lock the table it constraints in + * AccessExclusiveLock mode. Otherwise, if we read it before locking this + * table, the tuple might be changed by another transaction and our copy + * would be out of date + */ + relId = GetConstraintRelationId(conId); + if (!OidIsValid(relId)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("constraint with OID %d does not exist", conId))); + } + + rel = relation_open(relId, AccessExclusiveLock); + nspOid = get_rel_namespace(relId); + + conRel = heap_open(ConstraintRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(conId)); + + scan = systable_beginscan(conRel, ConstraintOidIndexId, true, + SnapshotNow, 1, key); + if (!HeapTupleIsValid((tup = systable_getnext(scan)))) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("constraint with OID %d does not exist", conId))); + } + + conform = (Form_pg_constraint) GETSTRUCT(tup); + + if (ConstraintNameIsUsed(CONSTRAINT_RELATION, + conform->conrelid, + get_rel_namespace(conform->conrelid), + newName)) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("constraint \"%s\" for relation \"%s\" already exists", + newName, + RelationGetRelationName(rel)))); + } + tup = heap_copytuple(tup); + conform = (Form_pg_constraint) GETSTRUCT(tup); + + if (implicitRename && cmdName) + { + ereport(NOTICE, + (errmsg("%s will implicitly rename constraint " + "\"%s\" to \"%s\" on table \"%s.%s\"", + cmdName, + NameStr(conform->conname), + newName, + get_namespace_name(nspOid), + RelationGetRelationName(rel)))); + } + + namestrcpy(&newNameData, newName); + conform->conname = newNameData; + + simple_heap_update(conRel, &tup->t_self, tup); + CatalogUpdateIndexes(conRel, tup); + heap_freetuple(tup); + + systable_endscan(scan); + heap_close(conRel, RowExclusiveLock); + + /* close relation but hold lock until end of transaction */ + relation_close(rel, NoLock); +} + + +/* GetRelationConstraintOid + * + * Get the contraint OID by the relation Id of the relation it constraints and + * this relations' name. We need this function in order to rename a constraint. + * This is done via "ALTER TABLE ... ALTER CONSTRAINT name" and the parser + * gives us the relation this constraint is defined on as well as the + * constraint's name. + * + * The function returns: + * + * - the unique OID of the constraint if the constraint could be found + * - the invalid OID if the constraint was not found + * + */ +Oid GetRelationConstraintOid(Oid relId, const char* name) +{ + Relation conRel; + ScanKeyData key[1]; + SysScanDesc scan; + HeapTuple tup; + Oid conId = InvalidOid; + + /* we don't change data, so an AccessShareLock is enough */ + conRel = heap_open(ConstraintRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_constraint_conrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relId)); + + scan = systable_beginscan(conRel, ConstraintRelidIndexId, true, + SnapshotNow, 1, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup); + if (pg_strcasecmp(name, NameStr(con->conname)) == 0) + { + conId = HeapTupleGetOid(tup); + Assert(OidIsValid(conId)); + } + } + + systable_endscan(scan); + heap_close(conRel, AccessShareLock); + + return conId; +} + + +/* GetConstraintRelationId + * + * Gets the OID of the relation where the constraint is defined on or the + * invalid OID if the constraint cannot be found. + */ +Oid GetConstraintRelationId(Oid conId) +{ + Relation conRel; + ScanKeyData key[1]; + SysScanDesc scan; + HeapTuple tup; + Oid relId = InvalidOid; + + /* we don't change data, so an AccessShareLock is enough */ + conRel = heap_open(ConstraintRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(conId)); + + scan = systable_beginscan(conRel, ConstraintOidIndexId, true, + SnapshotNow, 1, key); + + if (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup); + relId = con->conrelid; + Assert(OidIsValid(relId)); + } + + systable_endscan(scan); + heap_close(conRel, AccessShareLock); + + return relId; +} + |