int16 seqNumber, Relation inhRelation);
static int findAttrByName(const char *attributeName, List *schema);
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,
bool recurse, bool recursing, LOCKMODE lockmode);
static int transformColumnNameList(Oid relId, List *colList,
Oid relid;
Oid oldNspOid;
Oid nspOid;
- Relation classRel;
RangeVar *newrv;
+ ObjectAddresses *objsMoved;
relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
stmt->missing_ok, false,
/* 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, stmt->newschema,
- AccessExclusiveLock);
- 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);
}
/*
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))
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);
}
*/
static void
AlterIndexNamespaces(Relation classRel, Relation rel,
- Oid oldNspOid, Oid newNspOid)
+ Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved)
{
List *indexList;
ListCell *l;
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);
*/
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;
/* 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);
TypeName *typename;
Oid typeOid;
Oid nspOid;
+ ObjectAddresses *objsMoved;
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
/* get schema OID and check its permissions */
nspOid = LookupCreationNamespace(newschema);
- AlterTypeNamespace_oid(typeOid, nspOid);
+ objsMoved = new_object_addresses();
+ AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
+ free_object_addresses(objsMoved);
}
Oid
-AlterTypeNamespace_oid(Oid typeOid, Oid nspOid)
+AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
{
Oid elemOid;
format_type_be(elemOid))));
/* and do the work */
- return AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
+ return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
}
/*
Oid
AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
bool isImplicitArray,
- bool errorOnTableType)
+ bool errorOnTableType,
+ ObjectAddresses *objsMoved)
{
Relation rel;
HeapTuple tup;
Oid oldNspOid;
Oid arrayOid;
bool isCompositeType;
+ ObjectAddress thisobj;
+
+ /*
+ * Make sure we haven't moved this object previously.
+ */
+ thisobj.classId = TypeRelationId;
+ thisobj.objectId = typeOid;
+ thisobj.objectSubId = 0;
+
+ if (object_address_present(&thisobj, objsMoved))
+ return InvalidOid;
rel = heap_open(TypeRelationId, RowExclusiveLock);
AlterRelationNamespaceInternal(classRel, typform->typrelid,
oldNspOid, nspOid,
- false);
+ false, objsMoved);
heap_close(classRel, RowExclusiveLock);
* currently support this, but probably will someday).
*/
AlterConstraintNamespaces(typform->typrelid, oldNspOid,
- nspOid, false);
+ nspOid, false, objsMoved);
}
else
{
/* If it's a domain, it might have constraints */
if (typform->typtype == TYPTYPE_DOMAIN)
- AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
+ AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
+ objsMoved);
}
/*
heap_close(rel, RowExclusiveLock);
+ add_exact_object_address(&thisobj, objsMoved);
+
/* Recursively alter the associated array type, if any */
if (OidIsValid(arrayOid))
- AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);
+ AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
return oldNspOid;
}