diff --git a/contrib/isn/isn--1.0.sql b/contrib/isn/isn--1.0.sql index ce74c17..84aafcb 100644 diff --git a/src/backend/commanindex e5b813d..5901965 100644 *** a/src/backend/commands/alter.c --- b/src/backend/commands/alter.c *************** *** 247,253 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt) * object doesn't have a schema. */ Oid ! AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid) { Oid oldNspOid = InvalidOid; ObjectAddress dep; --- 247,254 ---- * object doesn't have a schema. */ Oid ! AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ! ObjectAddresses *objsMoved) { Oid oldNspOid = InvalidOid; ObjectAddress dep; *************** *** 261,280 **** AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid) case OCLASS_CLASS: { Relation rel; - Relation classRel; rel = relation_open(objid, AccessExclusiveLock); oldNspOid = RelationGetNamespace(rel); ! classRel = heap_open(RelationRelationId, RowExclusiveLock); ! ! AlterRelationNamespaceInternal(classRel, ! objid, ! oldNspOid, ! nspOid, ! true); ! ! heap_close(classRel, RowExclusiveLock); relation_close(rel, NoLock); break; --- 262,272 ---- case OCLASS_CLASS: { Relation rel; rel = relation_open(objid, AccessExclusiveLock); oldNspOid = RelationGetNamespace(rel); ! AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved); relation_close(rel, NoLock); break; diff --git a/src/backend/commands/eindex ec8aa17..c195213 100644 *** a/src/backend/commands/extension.c --- b/src/backend/commands/extension.c *************** *** 2203,2208 **** AlterExtensionNamespace(List *names, const char *newschema) --- 2203,2209 ---- Relation depRel; SysScanDesc depScan; HeapTuple depTup; + ObjectAddresses *objsMoved; if (list_length(names) != 1) ereport(ERROR, *************** *** 2277,2282 **** AlterExtensionNamespace(List *names, const char *newschema) --- 2278,2285 ---- errmsg("extension \"%s\" does not support SET SCHEMA", NameStr(extForm->extname)))); + objsMoved = new_object_addresses(); + /* * Scan pg_depend to find objects that depend directly on the extension, * and alter each one's schema. *************** *** 2316,2343 **** AlterExtensionNamespace(List *names, const char *newschema) if (dep.objectSubId != 0) /* should not happen */ elog(ERROR, "extension should not have a sub-object dependency"); ! dep_oldNspOid = AlterObjectNamespace_oid(dep.classId, ! dep.objectId, ! nspOid); ! /* ! * Remember previous namespace of first object that has one ! */ ! if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid) ! oldNspOid = dep_oldNspOid; ! /* ! * If not all the objects had the same old namespace (ignoring any ! * that are not in namespaces), complain. ! */ ! if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid) ! ereport(ERROR, ! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("extension \"%s\" does not support SET SCHEMA", ! NameStr(extForm->extname)), ! errdetail("%s is not in the extension's schema \"%s\"", ! getObjectDescription(&dep), ! get_namespace_name(oldNspOid)))); } systable_endscan(depScan); --- 2319,2351 ---- if (dep.objectSubId != 0) /* should not happen */ elog(ERROR, "extension should not have a sub-object dependency"); ! /* Relocate the object, if it hasn't been already relocated */ ! if (!object_address_present(&dep, objsMoved)) ! { ! dep_oldNspOid = AlterObjectNamespace_oid(dep.classId, ! dep.objectId, ! nspOid, ! objsMoved); ! /* ! * Remember previous namespace of first object that has one ! */ ! if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid) ! oldNspOid = dep_oldNspOid; ! /* ! * If not all the objects had the same old namespace (ignoring any ! * that are not in namespaces), complain. ! */ ! if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid) ! ereport(ERROR, ! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("extension \"%s\" does not support SET SCHEMA", ! NameStr(extForm->extname)), ! errdetail("%s is not in the extension's schema \"%s\"", ! getObjectDescription(&dep), ! get_namespace_name(oldNspOid)))); ! } } systable_endscan(depScan); diff --git a/src/backend/commands/tableindex 359d478..defe3c2 100644 *** a/src/backend/commands/tablecmds.c --- b/src/backend/commands/tablecmds.c *************** *** 263,270 **** static int findAttrByName(const char *attributeName, List *schema); static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid); static void AlterSeqNamespaces(Relation classRel, Relation rel, ! Oid oldNspOid, Oid newNspOid, ! const char *newNspName, LOCKMODE lockmode); static void ATExecValidateConstraint(Relation rel, char *constrName, bool recurse, bool recursing, LOCKMODE lockmode); static int transformColumnNameList(Oid relId, List *colList, --- 263,270 ---- static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid); static void AlterSeqNamespaces(Relation classRel, Relation rel, ! 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, *************** *** 9710,9716 **** AlterTableNamespace(AlterObjectSchemaStmt *stmt) Oid relid; Oid oldNspOid; Oid nspOid; - Relation classRel; RangeVar *newrv; relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock, --- 9710,9715 ---- *************** *** 9752,9761 **** AlterTableNamespace(AlterObjectSchemaStmt *stmt) /* common checks on switching namespaces */ CheckSetNamespace(oldNspOid, nspOid, RelationRelationId, relid); /* OK, modify the pg_class row and pg_depend entry */ classRel = heap_open(RelationRelationId, RowExclusiveLock); ! AlterRelationNamespaceInternal(classRel, relid, oldNspOid, nspOid, true); /* Fix the table's row type too */ AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid, false, false); --- 9751,9777 ---- /* common checks on switching namespaces */ CheckSetNamespace(oldNspOid, nspOid, RelationRelationId, relid); + AlterTableNamespaceInternal(rel, oldNspOid, nspOid, NULL); + + /* 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; + /* OK, modify the pg_class row and pg_depend entry */ classRel = heap_open(RelationRelationId, RowExclusiveLock); ! AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid, ! nspOid, true, objsMoved); /* Fix the table's row type too */ AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid, false, false); *************** *** 9764,9778 **** AlterTableNamespace(AlterObjectSchemaStmt *stmt) 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); } heap_close(classRel, RowExclusiveLock); - - /* close rel, but keep lock until commit */ - relation_close(rel, NoLock); } /* --- 9780,9792 ---- if (rel->rd_rel->relkind == RELKIND_RELATION) { AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid); ! AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid, ! objsMoved, AccessExclusiveLock); ! AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid, ! false); } heap_close(classRel, RowExclusiveLock); } /* *************** *** 9783,9789 **** AlterTableNamespace(AlterObjectSchemaStmt *stmt) void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, ! bool hasDependEntry) { HeapTuple classTup; Form_pg_class classForm; --- 9797,9803 ---- void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, ! bool hasDependEntry, ObjectAddresses *objsMoved) { HeapTuple classTup; Form_pg_class classForm; *************** *** 9795,9821 **** 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)))); ! /* classTup is a copy, so OK to scribble on */ ! classForm->relnamespace = newNspOid; ! 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)); heap_freetuple(classTup); } --- 9809,9849 ---- Assert(classForm->relnamespace == oldNspOid); ! /* Do nothing when there's nothing to do. */ ! if (classForm->relnamespace != newNspOid) ! { ! /* 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; ! ! 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)); ! if (objsMoved) ! { ! ObjectAddress thisobj; ! thisobj.classId = RelationRelationId; ! thisobj.objectId = relOid; ! thisobj.objectSubId = 0; ! add_exact_object_address(&thisobj, objsMoved); ! } ! } heap_freetuple(classTup); } *************** *** 9846,9852 **** AlterIndexNamespaces(Relation classRel, Relation rel, */ AlterRelationNamespaceInternal(classRel, indexOid, oldNspOid, newNspOid, ! false); } list_free(indexList); --- 9874,9880 ---- */ AlterRelationNamespaceInternal(classRel, indexOid, oldNspOid, newNspOid, ! false, NULL); } list_free(indexList); *************** *** 9861,9867 **** AlterIndexNamespaces(Relation classRel, Relation rel, */ static void AlterSeqNamespaces(Relation classRel, Relation rel, ! Oid oldNspOid, Oid newNspOid, const char *newNspName, LOCKMODE lockmode) { Relation depRel; SysScanDesc scan; --- 9889,9896 ---- */ static void AlterSeqNamespaces(Relation classRel, Relation rel, ! Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved, ! LOCKMODE lockmode) { Relation depRel; SysScanDesc scan; *************** *** 9913,9919 **** AlterSeqNamespaces(Relation classRel, Relation rel, /* Fix the pg_class and pg_depend entries */ AlterRelationNamespaceInternal(classRel, depForm->objid, oldNspOid, newNspOid, ! true); /* * Sequences have entries in pg_type. We need to be careful to move --- 9942,9948 ---- /* Fix the pg_class and pg_depend entries */ AlterRelationNamespaceInternal(classRel, depForm->objid, oldNspOid, newNspOid, ! true, objsMoved); /* * Sequences have entries in pg_type. We need to be careful to move diff --git a/src/backend/commands/typecindex 88e4287..817384c 100644 *** a/src/backend/commands/typecmds.c --- b/src/backend/commands/typecmds.c *************** *** 3448,3454 **** AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, AlterRelationNamespaceInternal(classRel, typform->typrelid, oldNspOid, nspOid, ! false); heap_close(classRel, RowExclusiveLock); --- 3448,3454 ---- AlterRelationNamespaceInternal(classRel, typform->typrelid, oldNspOid, nspOid, ! false, NULL); heap_close(classRel, RowExclusiveLock); diff --git a/src/include/commands/alteindex 210cf4e..22ae167 100644 *** a/src/include/commands/alter.h --- b/src/include/commands/alter.h *************** *** 14,25 **** #ifndef ALTER_H #define ALTER_H #include "utils/acl.h" #include "utils/relcache.h" extern void ExecRenameStmt(RenameStmt *stmt); extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt); ! extern Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid); extern Oid AlterObjectNamespace(Relation rel, int oidCacheId, int nameCacheId, Oid objid, Oid nspOid, int Anum_name, int Anum_namespace, int Anum_owner, --- 14,27 ---- #ifndef ALTER_H #define ALTER_H + #include "catalog/dependency.h" #include "utils/acl.h" #include "utils/relcache.h" extern void ExecRenameStmt(RenameStmt *stmt); extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt); ! extern Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ! ObjectAddresses *objsMoved); extern Oid AlterObjectNamespace(Relation rel, int oidCacheId, int nameCacheId, Oid objid, Oid nspOid, int Anum_name, int Anum_namespace, int Anum_owner, diff --git a/src/include/commands/tindex 15d4713..4f32062 100644 *** a/src/include/commands/tablecmds.h --- b/src/include/commands/tablecmds.h *************** *** 15,20 **** --- 15,21 ---- #define TABLECMDS_H #include "access/htup.h" + #include "catalog/dependency.h" #include "nodes/parsenodes.h" #include "storage/lock.h" #include "utils/relcache.h" *************** *** 36,44 **** extern void AlterTableInternal(Oid relid, List *cmds, bool recurse); extern void AlterTableNamespace(AlterObjectSchemaStmt *stmt); extern void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, ! bool hasDependEntry); extern void CheckTableNotInUse(Relation rel, const char *stmt); --- 37,49 ---- extern void AlterTableNamespace(AlterObjectSchemaStmt *stmt); + extern void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, + Oid nspOid, ObjectAddresses *objsMoved); + extern void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, ! bool hasDependEntry, ! ObjectAddresses *objsMoved); extern void CheckTableNotInUse(Relation rel, const char *stmt);