diff options
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 123 |
1 files changed, 85 insertions, 38 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 437c2773af0..3e3778987c0 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -254,10 +254,10 @@ static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, static int findAttrByName(const char *attributeName, List *schema); static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass); static void AlterIndexNamespaces(Relation classRel, Relation rel, - Oid oldNspOid, Oid newNspOid); + Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved); static void AlterSeqNamespaces(Relation classRel, Relation rel, - Oid oldNspOid, Oid newNspOid, - const char *newNspName, LOCKMODE lockmode); + Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, + LOCKMODE lockmode); static void ATExecValidateConstraint(Relation rel, char *constrName); static int transformColumnNameList(Oid relId, List *colList, int16 *attnums, Oid *atttypids); @@ -8950,7 +8950,7 @@ AlterTableNamespace(RangeVar *relation, const char *newschema, Oid relid; Oid oldNspOid; Oid nspOid; - Relation classRel; + ObjectAddresses *objsMoved; rel = relation_openrv(relation, lockmode); @@ -9042,26 +9042,47 @@ AlterTableNamespace(RangeVar *relation, const char *newschema, /* common checks on switching namespaces */ CheckSetNamespace(oldNspOid, nspOid, RelationRelationId, relid); + objsMoved = new_object_addresses(); + AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved); + free_object_addresses(objsMoved); + + /* close rel, but keep lock until commit */ + relation_close(rel, NoLock); +} + +/* + * The guts of relocating a table to another namespace: besides moving + * the table itself, its dependent objects are relocated to the new schema. + */ +void +AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, + ObjectAddresses *objsMoved) +{ + Relation classRel; + + Assert(objsMoved != NULL); + /* OK, modify the pg_class row and pg_depend entry */ classRel = heap_open(RelationRelationId, RowExclusiveLock); - AlterRelationNamespaceInternal(classRel, relid, oldNspOid, nspOid, true); + AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid, + nspOid, true, objsMoved); /* Fix the table's row type too */ - AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid, false, false); + AlterTypeNamespaceInternal(rel->rd_rel->reltype, + nspOid, false, false, objsMoved); /* Fix other dependent stuff */ if (rel->rd_rel->relkind == RELKIND_RELATION) { - AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid); - AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid, newschema, lockmode); - AlterConstraintNamespaces(relid, oldNspOid, nspOid, false); + AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved); + AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid, + objsMoved, AccessExclusiveLock); + AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid, + false, objsMoved); } heap_close(classRel, RowExclusiveLock); - - /* close rel, but keep lock until commit */ - relation_close(rel, NoLock); } /* @@ -9072,10 +9093,11 @@ AlterTableNamespace(RangeVar *relation, const char *newschema, void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, - bool hasDependEntry) + bool hasDependEntry, ObjectAddresses *objsMoved) { HeapTuple classTup; Form_pg_class classForm; + ObjectAddress thisobj; classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relOid)); if (!HeapTupleIsValid(classTup)) @@ -9084,27 +9106,39 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Assert(classForm->relnamespace == oldNspOid); - /* check for duplicate name (more friendly than unique-index failure) */ - if (get_relname_relid(NameStr(classForm->relname), - newNspOid) != InvalidOid) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_TABLE), - errmsg("relation \"%s\" already exists in schema \"%s\"", - NameStr(classForm->relname), - get_namespace_name(newNspOid)))); + thisobj.classId = RelationRelationId; + thisobj.objectId = relOid; + thisobj.objectSubId = 0; + + /* + * Do nothing when there's nothing to do. + */ + if (!object_address_present(&thisobj, objsMoved)) + { + /* check for duplicate name (more friendly than unique-index failure) */ + if (get_relname_relid(NameStr(classForm->relname), + newNspOid) != InvalidOid) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists in schema \"%s\"", + NameStr(classForm->relname), + get_namespace_name(newNspOid)))); - /* classTup is a copy, so OK to scribble on */ - classForm->relnamespace = newNspOid; + /* classTup is a copy, so OK to scribble on */ + classForm->relnamespace = newNspOid; - simple_heap_update(classRel, &classTup->t_self, classTup); - CatalogUpdateIndexes(classRel, classTup); + simple_heap_update(classRel, &classTup->t_self, classTup); + CatalogUpdateIndexes(classRel, classTup); - /* Update dependency on schema if caller said so */ - if (hasDependEntry && - changeDependencyFor(RelationRelationId, relOid, - NamespaceRelationId, oldNspOid, newNspOid) != 1) - elog(ERROR, "failed to change schema dependency for relation \"%s\"", - NameStr(classForm->relname)); + /* Update dependency on schema if caller said so */ + if (hasDependEntry && + changeDependencyFor(RelationRelationId, relOid, + NamespaceRelationId, oldNspOid, newNspOid) != 1) + elog(ERROR, "failed to change schema dependency for relation \"%s\"", + NameStr(classForm->relname)); + + add_exact_object_address(&thisobj, objsMoved); + } heap_freetuple(classTup); } @@ -9117,7 +9151,7 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid, */ static void AlterIndexNamespaces(Relation classRel, Relation rel, - Oid oldNspOid, Oid newNspOid) + Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved) { List *indexList; ListCell *l; @@ -9127,15 +9161,27 @@ AlterIndexNamespaces(Relation classRel, Relation rel, foreach(l, indexList) { Oid indexOid = lfirst_oid(l); + ObjectAddress thisobj; + + thisobj.classId = RelationRelationId; + thisobj.objectId = indexOid; + thisobj.objectSubId = 0; /* * Note: currently, the index will not have its own dependency on the * namespace, so we don't need to do changeDependencyFor(). There's no * row type in pg_type, either. + * + * XXX this objsMoved test may be pointless -- surely we have a single + * dependency link from a relation to each index? */ - AlterRelationNamespaceInternal(classRel, indexOid, - oldNspOid, newNspOid, - false); + if (!object_address_present(&thisobj, objsMoved)) + { + AlterRelationNamespaceInternal(classRel, indexOid, + oldNspOid, newNspOid, + false, objsMoved); + add_exact_object_address(&thisobj, objsMoved); + } } list_free(indexList); @@ -9150,7 +9196,8 @@ AlterIndexNamespaces(Relation classRel, Relation rel, */ static void AlterSeqNamespaces(Relation classRel, Relation rel, - Oid oldNspOid, Oid newNspOid, const char *newNspName, LOCKMODE lockmode) + Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, + LOCKMODE lockmode) { Relation depRel; SysScanDesc scan; @@ -9202,14 +9249,14 @@ AlterSeqNamespaces(Relation classRel, Relation rel, /* Fix the pg_class and pg_depend entries */ AlterRelationNamespaceInternal(classRel, depForm->objid, oldNspOid, newNspOid, - true); + true, objsMoved); /* * Sequences have entries in pg_type. We need to be careful to move * them to the new namespace, too. */ AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype, - newNspOid, false, false); + newNspOid, false, false, objsMoved); /* Now we can close it. Keep the lock till end of transaction. */ relation_close(seqRel, NoLock); |