alter_extension.1.patch

text/x-patch

Filename: alter_extension.1.patch
Type: text/x-patch
Part: 1
Message: Re: ALTER OBJECT any_name SET SCHEMA name

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: context
File+
src/backend/catalog/pg_depend.c 54 0
src/backend/catalog/pg_namespace.c 12 0
src/backend/commands/alter.c 5 0
src/backend/commands/extension.c 125 0
src/backend/commands/typecmds.c 12 0
src/backend/parser/gram.y 8 0
src/backend/tcop/utility.c 3 0
src/include/catalog/dependency.h 3 0
src/include/commands/extension.h 1 0
src/include/commands/typecmds.h 1 0
*** 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
***************
*** 20,25 ****
--- 20,26 ----
  #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"
***************
*** 186,191 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 187,196 ----
  			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);
*** a/src/backend/commands/extension.c
--- b/src/backend/commands/extension.c
***************
*** 38,50 ****
--- 38,55 ----
  #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/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 ****
--- 59,65 ----
  #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)
--- 1282,1403 ----
  	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));
+ 
+ 		/*
+ 		 * Do the SET SCHEMA now.
+ 		 *
+ 		 * 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.
+ 		 */
+ 		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;
+ 		}
+ 	}
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(ExtensionRelationId, extensionOid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
*** 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/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);