aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/tablecmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r--src/backend/commands/tablecmds.c123
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);