Alvaro Herrera <alvhe...@commandprompt.com> 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 (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to