Alvaro Herrera <[email protected]> writes:
> 2. I think the guts of AlterExtensionNamespace (the large switch block)
> should be elsewhere, probably in alter.c
That's implemented in the alter_extension patch v2, and that's much
better, thanks for your continued input. Please note that it depends on
the new set_schema.6.patch.
(The problem with smaller patches is indeed the dependencies)
Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support
*** a/src/backend/catalog/pg_depend.c
--- b/src/backend/catalog/pg_depend.c
***************
*** 20,25 ****
--- 20,27 ----
#include "catalog/indexing.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
+ #include "catalog/pg_extension.h"
+ #include "catalog/pg_namespace.h"
#include "miscadmin.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
***************
*** 643,645 **** get_index_constraint(Oid indexId)
--- 645,699 ----
return constraintId;
}
+
+ /*
+ * get_extension_namespace
+ * Given the OID of an extension, return the OID of the schema it
+ * depends on, or InvalidOid when not found
+ */
+ Oid
+ get_extension_namespace(Oid extensionId)
+ {
+ Oid nspId = InvalidOid;
+ Relation depRel;
+ ScanKeyData key[3];
+ SysScanDesc scan;
+ HeapTuple tup;
+
+ /* Search the dependency table for the index */
+ depRel = heap_open(DependRelationId, AccessShareLock);
+
+ ScanKeyInit(&key[0],
+ Anum_pg_depend_classid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(ExtensionRelationId));
+ ScanKeyInit(&key[1],
+ Anum_pg_depend_objid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(extensionId));
+ ScanKeyInit(&key[2],
+ Anum_pg_depend_objsubid,
+ BTEqualStrategyNumber, F_INT4EQ,
+ Int32GetDatum(0));
+
+ scan = systable_beginscan(depRel, DependDependerIndexId, true,
+ SnapshotNow, 3, key);
+
+ while (HeapTupleIsValid(tup = systable_getnext(scan)))
+ {
+ Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
+
+ if (deprec->refclassid == NamespaceRelationId &&
+ deprec->refobjsubid == 0 &&
+ deprec->deptype == DEPENDENCY_NORMAL)
+ {
+ nspId = deprec->refobjid;
+ break;
+ }
+ }
+
+ systable_endscan(scan);
+ heap_close(depRel, AccessShareLock);
+
+ return nspId;
+ }
*** a/src/backend/catalog/pg_namespace.c
--- b/src/backend/catalog/pg_namespace.c
***************
*** 76,80 **** NamespaceCreate(const char *nspName, Oid ownerId)
--- 76,92 ----
/* Record dependency on owner */
recordDependencyOnOwner(NamespaceRelationId, nspoid, ownerId);
+ /* Record dependency on extension, if we're in a CREATE EXTENSION */
+ if (create_extension)
+ {
+ ObjectAddress myself;
+
+ myself.classId = NamespaceRelationId;
+ myself.objectId = nspoid;
+ myself.objectSubId = 0;
+
+ recordDependencyOn(&myself, &extension, DEPENDENCY_INTERNAL);
+ }
+
return nspoid;
}
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 22,27 ****
--- 22,28 ----
#include "commands/conversioncmds.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
+ #include "commands/extension.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
#include "commands/tablecmds.h"
***************
*** 189,194 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 190,199 ----
AlterConversionNamespace(stmt->object, stmt->newschema);
break;
+ case OBJECT_EXTENSION:
+ AlterExtensionNamespace(stmt->object, stmt->newschema);
+ break;
+
case OBJECT_FUNCTION:
AlterFunctionNamespace(stmt->object, stmt->objarg, false,
stmt->newschema);
***************
*** 334,339 **** AlterObjectNamespace(Relation rel, int cacheId,
--- 339,436 ----
NamespaceRelationId, oldNspOid, nspOid);
}
+ /*
+ * Do the SET SCHEMA depending on the object class.
+ *
+ * We only consider objects that have a namespace and that can exist
+ * without depending on another object (like a table) which will
+ * have its dependencies follow the SET SCHEMA operation.
+ */
+ void
+ AlterObjectNamespace_internal(ObjectAddress *thisobj, Oid nspOid)
+ {
+ switch (getObjectClass(thisobj))
+ {
+ case OCLASS_CLASS:
+ {
+ Relation classRel;
+ Relation rel = relation_open(thisobj->objectId, RowExclusiveLock);
+
+ switch (rel->rd_rel->relkind)
+ {
+ case RELKIND_COMPOSITE_TYPE:
+ /*
+ * just skip the pg_class entry, we have a pg_type
+ * entry too
+ */
+ break;
+
+ default:
+ classRel = heap_open(RelationRelationId, RowExclusiveLock);
+ AlterRelationNamespaceInternal(classRel,
+ RelationGetRelid(rel),
+ RelationGetNamespace(rel),
+ nspOid,
+ true);
+ heap_close(classRel, RowExclusiveLock);
+ break;
+ }
+ relation_close(rel, RowExclusiveLock);
+ break;
+ }
+
+ case OCLASS_PROC:
+ AlterFunctionNamespace_oid(thisobj->objectId, nspOid);
+ break;
+
+ case OCLASS_TYPE:
+ {
+ /* don't allow direct alteration of array types, skip */
+ Oid elemOid = get_element_type(thisobj->objectId);
+ if (OidIsValid(elemOid)
+ && get_array_type(elemOid) == thisobj->objectId)
+ break;
+
+ AlterTypeNamespace_oid(thisobj->objectId, nspOid);
+ break;
+ }
+
+ case OCLASS_CONVERSION:
+ AlterConversionNamespace_oid(thisobj->objectId, nspOid);
+ break;
+
+ case OCLASS_OPERATOR:
+ AlterOperatorNamespace_oid(thisobj->objectId, nspOid);
+ break;
+
+ case OCLASS_OPCLASS:
+ AlterOpClassNamespace_oid(thisobj->objectId, nspOid);
+ break;
+
+ case OCLASS_OPFAMILY:
+ AlterOpFamilyNamespace_oid(thisobj->objectId, nspOid);
+ break;
+
+ case OCLASS_TSPARSER:
+ AlterTSParserNamespace_oid(thisobj->objectId, nspOid);
+ break;
+
+ case OCLASS_TSDICT:
+ AlterTSDictionaryNamespace_oid(thisobj->objectId, nspOid);
+ break;
+
+ case OCLASS_TSTEMPLATE:
+ AlterTSTemplateNamespace_oid(thisobj->objectId, nspOid);
+ break;
+
+ case OCLASS_TSCONFIG:
+ AlterTSConfigurationNamespace_oid(thisobj->objectId, nspOid);
+ break;
+
+ default:
+ break;
+ }
+ }
/*
* Executes an ALTER OBJECT / OWNER TO statement. Based on the object
*** a/src/backend/commands/extension.c
--- b/src/backend/commands/extension.c
***************
*** 38,50 ****
--- 38,56 ----
#include "access/xact.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
+ #include "catalog/namespace.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_type.h"
+ #include "commands/alter.h"
#include "commands/comment.h"
+ #include "commands/conversioncmds.h"
+ #include "commands/defrem.h"
#include "commands/extension.h"
#include "commands/portalcmds.h"
+ #include "commands/tablecmds.h"
+ #include "commands/typecmds.h"
#include "funcapi.h"
#include "nodes/parsenodes.h"
#include "mb/pg_wchar.h"
***************
*** 54,59 ****
--- 60,66 ----
#include "utils/cfparser.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
+ #include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/syscache.h"
***************
*** 1276,1278 **** pg_extension_objects(PG_FUNCTION_ARGS)
--- 1283,1329 ----
releaseDependentObjects(fctx->targetObjects);
SRF_RETURN_DONE(funcctx);
}
+
+ /*
+ * Execute ALTER EXTENSION SET SCHEMA
+ */
+ void
+ AlterExtensionNamespace(List *name, const char *newschema)
+ {
+ Oid extensionOid, nspOid, oldNspOid;
+ ObjectAddress *object;
+ ObjectAddresses *targetObjects;
+ int i;
+
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ (errmsg("must be superuser to ALTER EXTENSION"))));
+
+ Assert(list_length(name) == 1);
+ extensionOid = get_extension_oid(strVal(linitial(name)), false);
+ nspOid = LookupCreationNamespace(newschema);
+
+ object = (ObjectAddress *)palloc(sizeof(ObjectAddress));
+ object->classId = ExtensionRelationId;
+ object->objectId = extensionOid;
+ object->objectSubId = 0;
+
+ oldNspOid = get_extension_namespace(extensionOid);
+
+ targetObjects = listDependentObjects(object);
+
+ for (i = 0; i < targetObjects->numrefs; i++)
+ {
+ ObjectAddress *thisobj = targetObjects->refs + i;
+
+ elog(DEBUG1, "SET SCHEMA on %u: %s",
+ thisobj->objectId, getObjectDescription(thisobj));
+
+ AlterObjectNamespace_internal(thisobj, nspOid);
+ }
+
+ /* update dependencies to point to the new schema */
+ changeDependencyFor(ExtensionRelationId, extensionOid,
+ NamespaceRelationId, oldNspOid, nspOid);
+ }
*** a/src/backend/commands/tsearchcmds.c
--- b/src/backend/commands/tsearchcmds.c
***************
*** 48,54 ****
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
- #include "commands/extension.h"
static void MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
--- 48,53 ----
*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
***************
*** 2765,2784 **** AlterTypeNamespace(List *names, const char *newschema)
TypeName *typename;
Oid typeOid;
Oid nspOid;
- Oid elemOid;
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
typeOid = typenameTypeId(NULL, typename);
/* check permissions on type */
if (!pg_type_ownercheck(typeOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
format_type_be(typeOid));
- /* get schema OID and check its permissions */
- nspOid = LookupCreationNamespace(newschema);
-
/* don't allow direct alteration of array types */
elemOid = get_element_type(typeOid);
if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
--- 2765,2791 ----
TypeName *typename;
Oid typeOid;
Oid nspOid;
/* Make a TypeName so we can use standard type lookup machinery */
typename = makeTypeNameFromNameList(names);
typeOid = typenameTypeId(NULL, typename);
+ /* get schema OID and check its permissions */
+ nspOid = LookupCreationNamespace(newschema);
+
+ AlterTypeNamespace_oid(typeOid, nspOid);
+ }
+
+ void
+ AlterTypeNamespace_oid(Oid typeOid, Oid nspOid)
+ {
+ Oid elemOid;
+
/* check permissions on type */
if (!pg_type_ownercheck(typeOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
format_type_be(typeOid));
/* don't allow direct alteration of array types */
elemOid = get_element_type(typeOid);
if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
***************
*** 2790,2796 **** AlterTypeNamespace(List *names, const char *newschema)
format_type_be(elemOid))));
/* and do the work */
! AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
}
/*
--- 2797,2803 ----
format_type_be(elemOid))));
/* and do the work */
! AlterTypeNamespaceInternal(typeOid, nspOid, false, false);
}
/*
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 6138,6143 **** AlterObjectSchemaStmt:
--- 6138,6151 ----
n->newschema = $6;
$$ = (Node *)n;
}
+ | ALTER EXTENSION any_name SET SCHEMA name
+ {
+ AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ n->objectType = OBJECT_EXTENSION;
+ n->object = $3;
+ n->newschema = $6;
+ $$ = (Node *)n;
+ }
| ALTER FUNCTION function_with_argtypes SET SCHEMA name
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 1719,1724 **** CreateCommandTag(Node *parsetree)
--- 1719,1727 ----
case OBJECT_DOMAIN:
tag = "ALTER DOMAIN";
break;
+ case OBJECT_EXTENSION:
+ tag = "ALTER EXTENSION";
+ break;
case OBJECT_OPERATOR:
tag = "ALTER OPERATOR";
break;
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
***************
*** 240,245 **** extern Oid get_constraint_index(Oid constraintId);
--- 240,248 ----
extern Oid get_index_constraint(Oid indexId);
+ extern Oid get_extension_namespace(Oid extensionId);
+
+
/* in pg_shdepend.c */
extern void recordSharedDependencyOn(ObjectAddress *depender,
*** a/src/include/commands/alter.h
--- b/src/include/commands/alter.h
***************
*** 14,19 ****
--- 14,20 ----
#ifndef ALTER_H
#define ALTER_H
+ #include "catalog/objectaddress.h"
#include "nodes/parsenodes.h"
#include "utils/relcache.h"
***************
*** 23,28 **** extern void AlterObjectNamespace(Relation rel, int cacheId,
--- 24,30 ----
Oid classId, Oid objid, Oid nspId,
int Anum_name, int Anum_namespace, int Anum_owner,
bool superuser_only);
+ extern void AlterObjectNamespace_internal(ObjectAddress *thisobj, Oid nspOid);
extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt);
#endif /* ALTER_H */
*** a/src/include/commands/extension.h
--- b/src/include/commands/extension.h
***************
*** 64,69 **** extern void DropExtension(DropExtensionStmt *stmt);
--- 64,70 ----
extern Oid get_extension_oid(const char *extname, bool missing_ok);
extern char *get_extension_name(Oid ext_oid);
extern void RemoveExtensionById(Oid extId);
+ extern void AlterExtensionNamespace(List *name, const char *newschema);
#endif /* EXTENSION_H */
*** a/src/include/commands/typecmds.h
--- b/src/include/commands/typecmds.h
***************
*** 41,46 **** extern void AlterTypeOwner(List *names, Oid newOwnerId);
--- 41,47 ----
extern void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
bool hasDependEntry);
extern void AlterTypeNamespace(List *names, const char *newschema);
+ extern void AlterTypeNamespace_oid(Oid typeOid, Oid nspOid);
extern void AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
bool isImplicitArray,
bool errorOnTableType);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers