ALTER OBJECT any_name SET SCHEMA name

Started by Dimitri Fontaineabout 15 years ago65 messages
#1Dimitri Fontaine
dimitri@2ndQuadrant.fr
1 attachment(s)

Hi,

In the road to the extension patch, we already found some parts that
have to be separated into their own patch. Here's another one. It
occurred to me while implementing the pg_extension_objects() SRF that if
we can list all objects that belong to an extension, certainly we also
are able to move them to another schema.

As soon as we have that ability, we are able to provide for relocatable
extensions with the following command:

ALTER EXTENSION ext SET SCHEMA name;
ALTER EXTENSION ext SET SCHEMA foo TO bar;

I think that would end the open debate about search_path vs extension,
because each user would be able to relocate his local extensions easily,
wherever the main script has installed them (often enough, public).

Please find attached a work-in-progress patch (it's missing
documentation) implementing support for setting a new schema to SQL
objects of types conversion, operator, operator class, operator family,
text search parser, dictionary, template and configuration.

If there's will to apply such a patch, I'll finish it by writing the
necessary documentation for the 8 new SQL commands.

Note: CreateCommandTag() already has support for tags for ALTER TEXT
SEARCH <OBJECT> … SET SCHEMA …, but the implementation I've not
found, in the grammar nor in tsearchcmds.c. It's in the patch.

As usual, you can also get to the development version by using git:
http://git.postgresql.org/gitweb?p=postgresql-extension.git;a=shortlog;h=refs/heads/set_schema

git --no-pager diff master..|diffstat
backend/catalog/pg_namespace.c | 38 ++++
backend/commands/alter.c | 32 ++++
backend/commands/conversioncmds.c | 84 ++++++++++
backend/commands/opclasscmds.c | 215 +++++++++++++++++++++++++++
backend/commands/operatorcmds.c | 90 +++++++++++
backend/commands/tsearchcmds.c | 295 ++++++++++++++++++++++++++++++++++++++
backend/parser/gram.y | 67 ++++++++
backend/tcop/utility.c | 12 +
include/catalog/pg_namespace.h | 2
include/commands/conversioncmds.h | 5
include/commands/defrem.h | 23 ++
11 files changed, 863 insertions(+)

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

set_schema.3.patchtext/x-patchDownload
*** a/src/backend/catalog/pg_namespace.c
--- b/src/backend/catalog/pg_namespace.c
***************
*** 17,24 ****
--- 17,26 ----
  #include "access/heapam.h"
  #include "catalog/dependency.h"
  #include "catalog/indexing.h"
+ #include "catalog/namespace.h"
  #include "catalog/pg_namespace.h"
  #include "utils/builtins.h"
+ #include "utils/lsyscache.h"
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
***************
*** 77,79 **** NamespaceCreate(const char *nspName, Oid ownerId)
--- 79,117 ----
  
  	return nspoid;
  }
+ 
+ /*
+  * Check new namespace validity in ALTER OBJECT ... SET SCHEMA ... and
+  * ereport(ERROR, ...) in case of any problem.
+  */
+ void
+ CheckSetNamespace(Oid oldNspOid, Oid nspOid,
+ 				  const char *name, const char *objtype)
+ {
+ 	if (oldNspOid == nspOid)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s \"%s\" already exists in schema \"%s\"",
+ 						objtype, name, get_namespace_name(nspOid))));
+ 
+ 	/* disallow renaming into or out of temp schemas */
+ 	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 			errmsg("cannot move objects into or out of temporary schemas")));
+ 
+ 	/* same for TOAST schema */
+ 	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of TOAST schema")));
+ 
+ 	/* check for duplicate name (more friendly than unique-index failure) */
+ 	if (SearchSysCacheExists2(TYPENAMENSP,
+ 							  CStringGetDatum(name),
+ 							  ObjectIdGetDatum(nspOid)))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s \"%s\" already exists in schema \"%s\"",
+ 						objtype, name, get_namespace_name(nspOid))));
+ }
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 182,192 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 182,208 ----
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_CONVERSION:
+ 			AlterConversionNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_FUNCTION:
  			AlterFunctionNamespace(stmt->object, stmt->objarg, false,
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_OPERATOR:
+ 			AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPCLASS:
+ 			AlterOpClassNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPFAMILY:
+ 			AlterOpFamilyNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_SEQUENCE:
  		case OBJECT_TABLE:
  		case OBJECT_VIEW:
***************
*** 195,200 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 211,232 ----
  								stmt->objectType, AccessExclusiveLock);
  			break;
  
+ 		case OBJECT_TSPARSER:
+ 			AlterTSParserNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSDICTIONARY:
+ 			AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSTEMPLATE:
+ 			AlterTSTemplateNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSCONFIGURATION:
+ 			AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_TYPE:
  		case OBJECT_DOMAIN:
  			AlterTypeNamespace(stmt->object, stmt->newschema);
*** a/src/backend/commands/conversioncmds.c
--- b/src/backend/commands/conversioncmds.c
***************
*** 19,24 ****
--- 19,25 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_conversion.h"
  #include "catalog/pg_conversion_fn.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
  #include "commands/conversioncmds.h"
  #include "mb/pg_wchar.h"
***************
*** 326,328 **** AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId)
--- 327,412 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER CONVERSION SET SCHEMA
+  */
+ void
+ AlterConversionNamespace(List *name, const char *newschema)
+ {
+ 	Oid			conversionOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	conversionOid = get_conversion_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterConversionNamespace_internal(rel, conversionOid, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
+  * Change conversion owner, by oid
+  */
+ void
+ AlterConversionNamespace_oid(Oid conversionOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	AlterConversionNamespace_internal(rel, conversionOid, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterConversionNamespace_internal(Relation rel, Oid conversionOid, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 	Form_pg_conversion convForm;
+ 
+ 	Assert(RelationGetRelid(rel) == ConversionRelationId);
+ 
+ 	tup = SearchSysCacheCopy1(CONVOID, ObjectIdGetDatum(conversionOid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for conversion %u", conversionOid);
+ 
+ 	convForm = (Form_pg_conversion) GETSTRUCT(tup);
+ 	oldNspOid = convForm->connamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(convForm->conname), "conversion");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_conversion_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
+ 						   NameStr(convForm->conname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(convForm->connamespace,
+ 										  GetUserId(),
+ 										  ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(convForm->connamespace));
+ 	}
+ 
+ 	convForm->connamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(ConversionRelationId, conversionOid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 1912,1917 **** AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
--- 1912,2007 ----
  }
  
  /*
+  * ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpClassNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup, origtup;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	/* Look up the opclass. */
+ 	origtup = OpClassCacheLookup(amOid, name, false);
+ 	tup = heap_copytuple(origtup);
+ 	ReleaseSysCache(origtup);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterOpClassNamespace_internal(rel, tup, nspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(CLAOID, ObjectIdGetDatum(opclassOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
+ 
+ 	AlterOpClassOwner_internal(rel, tup, newNspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpClassNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	Form_pg_opclass opcForm;
+ 
+ 	opcForm = (Form_pg_opclass) GETSTRUCT(tup);
+ 	oldNspOid = opcForm->opcnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(opcForm->opcname), "operator class");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_opclass_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
+ 						   NameStr(opcForm->opcname));
+ 
+ 		/* New owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(nspOid));
+ 	}
+ 
+ 	/* tup is a copy, so we can scribble directly on it */
+ 	opcForm->opcnamespace = nspOid;
+ 
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(OperatorClassRelationId, HeapTupleGetOid(tup),
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
+ 
+ /*
   * Change opfamily owner by name
   */
  void
***************
*** 2067,2069 **** get_am_oid(const char *amname, bool missing_ok)
--- 2157,2284 ----
  				 errmsg("access method \"%s\" does not exist", amname)));
  	return oid;
  }
+ 
+ /*
+  * ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpFamilyNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup;
+ 	char	   *opfname, *schemaname;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	/*
+ 	 * Look up the opfamily
+ 	 */
+ 	DeconstructQualifiedName(name, &schemaname, &opfname);
+ 
+ 	if (schemaname)
+ 	{
+ 		Oid			namespaceOid;
+ 
+ 		namespaceOid = LookupExplicitNamespace(schemaname);
+ 
+ 		tup = SearchSysCacheCopy3(OPFAMILYAMNAMENSP,
+ 								  ObjectIdGetDatum(amOid),
+ 								  PointerGetDatum(opfname),
+ 								  ObjectIdGetDatum(namespaceOid));
+ 		if (!HeapTupleIsValid(tup))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 	}
+ 	else
+ 	{
+ 		Oid			opfOid;
+ 
+ 		opfOid = OpfamilynameGetOpfid(amOid, opfname);
+ 		if (!OidIsValid(opfOid))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 
+ 		tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfOid));
+ 		if (!HeapTupleIsValid(tup))		/* should not happen */
+ 			elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
+ 	}
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterOpFamilyNamespace_internal(rel, tup, nspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
+ 
+ 	AlterOpFamilyOwner_internal(rel, tup, newNspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpFamilyNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	Form_pg_opfamily opfForm;
+ 
+ 	Assert(tup->t_tableOid == OperatorFamilyRelationId);
+ 	Assert(RelationGetRelid(rel) == OperatorFamilyRelationId);
+ 
+ 	opfForm = (Form_pg_opfamily) GETSTRUCT(tup);
+ 	oldNspOid = opfForm->opfnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(opfForm->opfname), "operator family");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_opfamily_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
+ 						   NameStr(opfForm->opfname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(nspOid));
+ 	}
+ 
+ 	/* tup is a copy, so we can scribble directly on it */
+ 	opfForm->opfnamespace = nspOid;
+ 
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(OperatorFamilyRelationId, HeapTupleGetOid(tup),
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
*** a/src/backend/commands/operatorcmds.c
--- b/src/backend/commands/operatorcmds.c
***************
*** 39,44 ****
--- 39,45 ----
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_operator.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
***************
*** 452,454 **** AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
--- 453,544 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER OPERATOR SET SCHEMA
+  */
+ void
+ AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	AlterOperatorOwner_internal(rel, operOid, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOperatorNamespace(List *names, List *argtypes, const char *newschema)
+ {
+ 	List	   *operatorName = names;
+ 	TypeName   *typeName1 = (TypeName *) linitial(argtypes);
+ 	TypeName   *typeName2 = (TypeName *) lsecond(argtypes);
+ 	Oid			operOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	Assert(list_length(argtypes) == 2);
+ 	operOid = LookupOperNameTypeNames(NULL, operatorName,
+ 									  typeName1, typeName2,
+ 									  false, -1);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterOperatorNamespace_internal(rel, operOid, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOperatorNamespace_internal(Relation rel, Oid operOid, Oid nspOid)
+ {
+ 	Form_pg_operator oprForm;
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 
+ 	Assert(RelationGetRelid(rel) == OperatorRelationId);
+ 
+ 	tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(operOid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for operator %u", operOid);
+ 
+ 	oprForm = (Form_pg_operator) GETSTRUCT(tup);
+ 	oldNspOid = oprForm->oprnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid, NameStr(oprForm->oprname), "operator");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_oper_ownercheck(operOid, GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
+ 						   NameStr(oprForm->oprname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oprForm->oprnamespace,
+ 										  GetUserId(),
+ 										  ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(oprForm->oprnamespace));
+ 	}
+ 
+ 	/* tup is a copy, so we can scribble directly on it */
+ 	oprForm->oprnamespace = nspOid;
+ 
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(OperatorRelationId, operOid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
*** a/src/backend/commands/tsearchcmds.c
--- b/src/backend/commands/tsearchcmds.c
***************
*** 393,398 **** RenameTSParser(List *oldname, const char *newname)
--- 393,465 ----
  	heap_freetuple(tup);
  }
  
+ /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSParserNamespace(List *name, const char *newschema)
+ {
+ 	Oid			prsId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	prsId = get_ts_parser_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSParserNamespace_internal(rel, prsId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	AlterTSParserNamespace_internal(rel, prsId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSParserNamespace_internal(Relation rel, Oid prsId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_parser prs;
+ 
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 				 errmsg("must be superuser to rename text search parsers")));
+ 
+ 	tup = SearchSysCacheCopy1(TSPARSEROID, ObjectIdGetDatum(prsId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search parser %u", prsId);
+ 
+ 	prs = (Form_pg_ts_parser) GETSTRUCT(tup);
+ 	oldNspOid = prs->prsnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(prs->prsname), "text search parser");
+ 
+ 	prs->prsnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSParserRelationId, prsId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
  /* ---------------------- TS Dictionary commands -----------------------*/
  
  /*
***************
*** 620,625 **** RenameTSDictionary(List *oldname, const char *newname)
--- 687,772 ----
  }
  
  /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSDictionaryNamespace(List *name, const char *newschema)
+ {
+ 	Oid			dictId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	dictId = get_ts_dict_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSDictionaryNamespace_internal(rel, dictId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	AlterTSDictionaryNamespace_internal(rel, dictId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSDictionaryNamespace_internal(Relation rel, Oid dictId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_dict dict;
+ 
+ 	tup = SearchSysCacheCopy1(TSDICTOID, ObjectIdGetDatum(dictId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search dictionary %u",
+ 			 dictId);
+ 
+ 	dict = ((Form_pg_ts_dict) GETSTRUCT(tup));
+ 	oldNspOid = dict->dictnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(dict->dictname), "text search dictionary");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_ts_dict_ownercheck(dictId, GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
+ 						   NameStr(dict->dictname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(oldNspOid));
+ 	}
+ 
+ 	dict->dictnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSDictionaryRelationId, dictId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
+ /*
   * DROP TEXT SEARCH DICTIONARY
   */
  void
***************
*** 1100,1105 **** RenameTSTemplate(List *oldname, const char *newname)
--- 1247,1321 ----
  }
  
  /*
+  * ALTER TEXT SEARCH TEMPLATE any_name SET SCHEMA name
+  */
+ void
+ AlterTSTemplateNamespace(List *name, const char *newschema)
+ {
+ 	Oid			tmplId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	tmplId = get_ts_template_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSTemplateNamespace_internal(rel, tmplId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	AlterTSTemplateNamespace_internal(rel, tmplId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSTemplateNamespace_internal(Relation rel, Oid tmplId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_template tmpl;
+ 
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 			   errmsg("must be superuser to rename text search templates")));
+ 
+ 	tup = SearchSysCacheCopy1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search template %u",
+ 			 tmplId);
+ 
+ 	tmpl = (Form_pg_ts_template) GETSTRUCT(tup);
+ 	oldNspOid = tmpl->tmplnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(tmpl->tmplname), "text search template");
+ 
+ 	tmpl->tmplnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSTemplateRelationId, tmplId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH TEMPLATE
   */
  void
***************
*** 1498,1503 **** RenameTSConfiguration(List *oldname, const char *newname)
--- 1714,1798 ----
  }
  
  /*
+  * ALTER TEXT SEARCH CONFIGURATION any_name SET SCHEMA name
+  */
+ void
+ AlterTSConfigurationNamespace(List *name, const char *newschema)
+ {
+ 	Oid			cfgId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	cfgId = get_ts_config_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSConfigurationNamespace_internal(rel, cfgId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	AlterTSConfigurationNamespace_internal(rel, cfgId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSConfigurationNamespace_internal(Relation rel, Oid cfgId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_config cfg;
+ 
+ 	tup = SearchSysCacheCopy1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search configuration %u",
+ 			 cfgId);
+ 
+ 	cfg = (Form_pg_ts_config) GETSTRUCT(tup);
+ 	oldNspOid = cfg->cfgnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(cfg->cfgname), "text search configuration");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_ts_config_ownercheck(cfgId, GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
+ 						   NameStr(cfg->cfgname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
+ 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 					   get_namespace_name(oldNspOid));
+ 	}
+ 
+ 	cfg->cfgnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSConfigRelationId, cfgId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
+ /*
   * DROP TEXT SEARCH CONFIGURATION
   */
  void
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 6040,6045 **** AlterObjectSchemaStmt:
--- 6040,6053 ----
  					n->newschema = $7;
  					$$ = (Node *)n;
  				}
+ 			| ALTER CONVERSION_P any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_CONVERSION;
+ 					n->object = $3;
+ 					n->newschema = $6;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER DOMAIN_P any_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6057,6062 **** AlterObjectSchemaStmt:
--- 6065,6097 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER OPERATOR any_operator oper_argtypes SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPERATOR;
+ 					n->object = $3;
+ 					n->objarg = $4;
+ 					n->newschema = $7;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPCLASS;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPFAMILY;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER TABLE relation_expr SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6065,6070 **** AlterObjectSchemaStmt:
--- 6100,6137 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSPARSER;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSDICTIONARY;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSTEMPLATE;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSCONFIGURATION;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER SEQUENCE qualified_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 1694,1702 **** CreateCommandTag(Node *parsetree)
--- 1694,1714 ----
  				case OBJECT_AGGREGATE:
  					tag = "ALTER AGGREGATE";
  					break;
+ 				case OBJECT_CONVERSION:
+ 					tag = "ALTER CONVERSION";
+ 					break;
  				case OBJECT_DOMAIN:
  					tag = "ALTER DOMAIN";
  					break;
+ 				case OBJECT_OPERATOR:
+ 					tag = "ALTER OPERATOR";
+ 					break;
+ 				case OBJECT_OPCLASS:
+ 					tag = "ALTER OPERATOR CLASS";
+ 					break;
+ 				case OBJECT_OPFAMILY:
+ 					tag = "ALTER OPERATOR FAMILY";
+ 					break;
  				case OBJECT_FUNCTION:
  					tag = "ALTER FUNCTION";
  					break;
*** a/src/include/catalog/pg_namespace.h
--- b/src/include/catalog/pg_namespace.h
***************
*** 78,82 **** DESCR("standard public schema");
--- 78,84 ----
   * prototypes for functions in pg_namespace.c
   */
  extern Oid	NamespaceCreate(const char *nspName, Oid ownerId);
+ extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid,
+ 							  const char *name, const char *objtype);
  
  #endif   /* PG_NAMESPACE_H */
*** a/src/include/commands/conversioncmds.h
--- b/src/include/commands/conversioncmds.h
***************
*** 16,26 ****
--- 16,31 ----
  #define CONVERSIONCMDS_H
  
  #include "nodes/parsenodes.h"
+ #include "utils/relcache.h"
  
  extern void CreateConversionCommand(CreateConversionStmt *parsetree);
  extern void DropConversionsCommand(DropStmt *drop);
  extern void RenameConversion(List *name, const char *newname);
  extern void AlterConversionOwner(List *name, Oid newOwnerId);
  extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
+ extern void AlterConversionNamespace(List *name, const char *newschema);
+ extern void AlterConversionNamespace_oid(Oid conversionOid, Oid newNspOid);
+ extern void AlterConversionNamespace_internal(Relation rel, Oid conversionOid, Oid nspOid);
+ 
  
  #endif   /* CONVERSIONCMDS_H */
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 14,20 ****
--- 14,22 ----
  #ifndef DEFREM_H
  #define DEFREM_H
  
+ #include "access/htup.h"
  #include "nodes/parsenodes.h"
+ #include "utils/relcache.h"
  
  
  /* commands/indexcmds.c */
***************
*** 78,83 **** extern void AlterOperatorOwner(List *name, TypeName *typeName1,
--- 80,88 ----
  extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId);
  extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
  extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern void AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid);
+ extern void AlterOperatorNamespace(List *names, List *argtypes, const char *newschema);
+ extern void AlterOperatorNamespace_internal(Relation rel, Oid operoid, Oid nspOid);
  
  /* commands/aggregatecmds.c */
  extern void DefineAggregate(List *name, List *args, bool oldstyle,
***************
*** 100,114 **** extern void RenameOpClass(List *name, const char *access_method, const char *new
--- 105,128 ----
  extern void RenameOpFamily(List *name, const char *access_method, const char *newname);
  extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId);
+ extern void AlterOpClassNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid);
+ extern void AlterOpClassNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid);
  extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId);
  extern Oid get_am_oid(const char *amname, bool missing_ok);
+ extern void AlterOpFamilyNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid);
+ extern void AlterOpFamilyNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid);
  
  /* commands/tsearchcmds.c */
  extern void DefineTSParser(List *names, List *parameters);
  extern void RenameTSParser(List *oldname, const char *newname);
  extern void RemoveTSParsers(DropStmt *drop);
  extern void RemoveTSParserById(Oid prsId);
+ extern void AlterTSParserNamespace(List *name, const char *newschema);
+ extern void AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
+ extern void AlterTSParserNamespace_internal(Relation rel, Oid prsId, Oid nspOid);
  
  extern void DefineTSDictionary(List *names, List *parameters);
  extern void RenameTSDictionary(List *oldname, const char *newname);
***************
*** 116,129 **** extern void RemoveTSDictionaries(DropStmt *drop);
--- 130,152 ----
  extern void RemoveTSDictionaryById(Oid dictId);
  extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
  extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
+ extern void AlterTSDictionaryNamespace(List *name, const char *newschema);
+ extern void AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid);
+ extern void AlterTSDictionaryNamespace_internal(Relation rel, Oid dictId, Oid nspOid);
  
  extern void DefineTSTemplate(List *names, List *parameters);
  extern void RenameTSTemplate(List *oldname, const char *newname);
+ extern void AlterTSTemplateNamespace(List *name, const char *newschema);
+ extern void AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
+ extern void AlterTSTemplateNamespace_internal(Relation rel, Oid tmplId, Oid nspOid);
  extern void RemoveTSTemplates(DropStmt *stmt);
  extern void RemoveTSTemplateById(Oid tmplId);
  
  extern void DefineTSConfiguration(List *names, List *parameters);
  extern void RenameTSConfiguration(List *oldname, const char *newname);
+ extern void AlterTSConfigurationNamespace(List *name, const char *newschema);
+ extern void AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid);
+ extern void AlterTSConfigurationNamespace_internal(Relation rel, Oid cfgId, Oid nspOid);
  extern void RemoveTSConfigurations(DropStmt *stmt);
  extern void RemoveTSConfigurationById(Oid cfgId);
  extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Dimitri Fontaine (#1)
Re: ALTER OBJECT any_name SET SCHEMA name

Dimitri Fontaine <dimitri@2ndQuadrant.fr> writes:

As soon as we have that ability, we are able to provide for relocatable
extensions with the following command:

ALTER EXTENSION ext SET SCHEMA name;
ALTER EXTENSION ext SET SCHEMA foo TO bar;

I think that would end the open debate about search_path vs extension,
because each user would be able to relocate his local extensions easily,
wherever the main script has installed them (often enough, public).

I'm not sure whether that really fixes anything, or just provides people
with a larger-caliber foot-gun. See for example recent complaints about
citext misbehaving if it's not in the public schema (or more generally,
any schema not in the search path). I think we'd need to think a bit
harder about the behavior of objects that aren't in the search path
before creating a facility like this, since it seems to be tantamount
to promising that extensions won't break when pushed around to different
schemas.

I'm also a bit less than enthused about the implementation approach.
If we're going to have a policy that every object type must support
ALTER SET SCHEMA, I think it might be time to refactor, rather than
copying-and-pasting similar boilerplate code for every one.

regards, tom lane

#3Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Tom Lane (#2)
Re: ALTER OBJECT any_name SET SCHEMA name

Hi,

Thanks for your review!

Tom Lane <tgl@sss.pgh.pa.us> writes:

Dimitri Fontaine <dimitri@2ndQuadrant.fr> writes:

ALTER EXTENSION ext SET SCHEMA name;
ALTER EXTENSION ext SET SCHEMA foo TO bar;

I think that would end the open debate about search_path vs extension,
because each user would be able to relocate his local extensions easily,
wherever the main script has installed them (often enough, public).

I'm not sure whether that really fixes anything, or just provides people
with a larger-caliber foot-gun. See for example recent complaints about
citext misbehaving if it's not in the public schema (or more generally,
any schema not in the search path). I think we'd need to think a bit
harder about the behavior of objects that aren't in the search path
before creating a facility like this, since it seems to be tantamount
to promising that extensions won't break when pushed around to different
schemas.

Well AFAIK we have only two choices here. Either we impose the schema
where to find any extension's object or we offer more facilities for
users to support their choices.

In the former case, we have problems with upgrades and hosting several
versions of the same extension at the same time (think PostGIS 1.4 and
1.5 e.g.). Not being able to choose a schema where to host an
extension's objects only makes sense when the user can't set the
search_path, which is what we do with pg_catalog.

In the latter case, following your example, all it would take the user
to fix his setup would be a SET SCHEMA command on the citext extension.
The only goal of this proposal is not to have to rethink object
visibility, by offering the tools users need to manage the situation.

All in all, I don't think it'll be ever possible to both support
search_path flexibility and extension robustness when search_path
changes.

What we could do is offer extension's author a way to find their
operator or functions or whatever dynamically in SQL, so that writing
robust pure-SQL functions is possible. What comes to mind now would be a
way to call a function/operator/... by OID at the SQL level. Not pretty
but with the pg_extension_objects() SRF and maybe a layer atop that,
that would do the trick. Brain dumping still.

I'm also a bit less than enthused about the implementation approach.
If we're going to have a policy that every object type must support
ALTER SET SCHEMA, I think it might be time to refactor, rather than
copying-and-pasting similar boilerplate code for every one.

I've begun the effort with the CheckSetNamespace() function, about half
of the rest of the code could receive some abstraction too (syscache
searches, tuple access and editing, dependency changing, but ACL checks
looks harder. How much easier would it be with defmacro...

I'll have a try at it soon, happy to hear what you have in mind here
before I start, so that I follow your guidance.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#4Bernd Helmle
mailings@oopsware.de
In reply to: Tom Lane (#2)
Re: ALTER OBJECT any_name SET SCHEMA name

--On 30. Oktober 2010 18:59:30 -0400 Tom Lane <tgl@sss.pgh.pa.us> wrote:

I'm not sure whether that really fixes anything, or just provides people
with a larger-caliber foot-gun. See for example recent complaints about
citext misbehaving if it's not in the public schema (or more generally,
any schema not in the search path). I think we'd need to think a bit
harder about the behavior of objects that aren't in the search path
before creating a facility like this, since it seems to be tantamount
to promising that extensions won't break when pushed around to different
schemas.

I'm also a bit less than enthused about the implementation approach.
If we're going to have a policy that every object type must support
ALTER SET SCHEMA, I think it might be time to refactor, rather than
copying-and-pasting similar boilerplate code for every one.

This reminds me of a small discussion we had some years ago when i targeted
this for the sake of completeness of ASS (see
<http://archives.postgresql.org/pgsql-patches/2006-06/msg00021.php&gt;).

I didn't follow the previous discussions about EXTENSION very closely, but
to amend the idea made in the mentioned thread, couldn't we just invent a
facility to move classes of objects belonging to an extension, only?

--
Thanks

Bernd

#5Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Bernd Helmle (#4)
Re: ALTER OBJECT any_name SET SCHEMA name

Bernd Helmle <mailings@oopsware.de> writes:

This reminds me of a small discussion we had some years ago when i targeted
this for the sake of completeness of ASS (see
<http://archives.postgresql.org/pgsql-patches/2006-06/msg00021.php&gt;).

Discovered it, thanks for the pointer.

I didn't follow the previous discussions about EXTENSION very closely, but
to amend the idea made in the mentioned thread, couldn't we just invent a
facility to move classes of objects belonging to an extension, only?

Well under the hood you still need about the same code. In the current
patch version I have, that would mean forgetting about a ~20 lines long
function and keeping the other two, 10+30 lines about.

Now if someone has a idea on how to have a single routine that knows how
to deal with any object type and change its namespace, I'm all ears, and
willing to have a try at it. Coding in C is for me a twice a year
exercise, so whatever I come up with will be... improvable, I fear.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#6Heikki Linnakangas
heikki.linnakangas@enterprisedb.com
In reply to: Dimitri Fontaine (#3)
Re: ALTER OBJECT any_name SET SCHEMA name

On 31.10.2010 14:46, Dimitri Fontaine wrote:

What we could do is offer extension's author a way to find their
operator or functions or whatever dynamically in SQL, so that writing
robust pure-SQL functions is possible. What comes to mind now would be a
way to call a function/operator/... by OID at the SQL level. Not pretty
but with the pg_extension_objects() SRF and maybe a layer atop that,
that would do the trick. Brain dumping still.

How about something like:

CREATE EXTENSION myextension ... SCHEMA myschema;

And in the .sql file in the extension you could have special markers for
the schema, something like:

CREATE FUNCTION otherfunction() AS ...;
CREATE FUNCTION foo() AS $$ SELECT 'foo', @extschema@.otherfunction() $$;

@extschema@ would be search&replaced at CREATE EXTENSION time with the
schema specified by the user.

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

#7Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Heikki Linnakangas (#6)
Re: ALTER OBJECT any_name SET SCHEMA name

Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:

CREATE EXTENSION myextension ... SCHEMA myschema;

And in the .sql file in the extension you could have special markers for the
schema, something like:

That's exactly the road I want to avoid, because of the script parsing issues.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#8Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Dimitri Fontaine (#7)
Re: ALTER OBJECT any_name SET SCHEMA name

Sorry for the interruption, our program now continues...

Dimitri Fontaine <dimitri@2ndQuadrant.fr> writes:

That's exactly the road I want to avoid, because of the script parsing issues.

In particular, embedded and/or dynamic calls in PLs will get hairy if
not turing complete and outright impossible to solve.

--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#9Heikki Linnakangas
heikki.linnakangas@enterprisedb.com
In reply to: Dimitri Fontaine (#8)
Re: ALTER OBJECT any_name SET SCHEMA name

On 31.10.2010 19:38, Dimitri Fontaine wrote:

Sorry for the interruption, our program now continues...

Dimitri Fontaine<dimitri@2ndQuadrant.fr> writes:

That's exactly the road I want to avoid, because of the script parsing issues.

In particular, embedded and/or dynamic calls in PLs will get hairy if
not turing complete and outright impossible to solve.

Sorry, I don't follow. Got an example?

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

#10Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Heikki Linnakangas (#9)
Re: ALTER OBJECT any_name SET SCHEMA name

Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:

In particular, embedded and/or dynamic calls in PLs will get hairy if
not turing complete and outright impossible to solve.

Sorry, I don't follow. Got an example?

Well, who's to say the following hypothetical plpgsql example should be
forgiven only in an exception's script?

v_sql := 'SELECT * FROM ' || p_fun || '()';
FOR rec in EXECUTE v_sql
LOOP

END LOOP;

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#11Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#5)
Re: ALTER OBJECT any_name SET SCHEMA name

On Sun, Oct 31, 2010 at 12:45 PM, Dimitri Fontaine
<dimitri@2ndquadrant.fr> wrote:

Bernd Helmle <mailings@oopsware.de> writes:

This reminds me of a small discussion we had some years ago when i targeted
this for the sake of completeness of ASS (see
<http://archives.postgresql.org/pgsql-patches/2006-06/msg00021.php&gt;).

Discovered it, thanks for the pointer.

I didn't follow the previous discussions about EXTENSION very closely, but
to amend the idea made in the mentioned thread, couldn't we just invent a
facility to move classes of objects belonging to an extension, only?

Well under the hood you still need about the same code. In the current
patch version I have, that would mean forgetting about a ~20 lines long
function and keeping the other two, 10+30 lines about.

Now if someone has a idea on how to have a single routine that knows how
to deal with any object type and change its namespace, I'm all ears, and
willing to have a try at it. Coding in C is for me a twice a year
exercise, so whatever I come up with will be... improvable, I fear.

I guess it's a question of how much special case code there is. The
new objectaddress.c code knows how to deal with lots of different
object types, but for example in the case of ALTER TABLE .. SET
SCHEMA, what's there now is enmeshed in a complex structure so as to
allow multiple ALTER TABLE subcommands in a single statement, and it
has further special-case logic to handle moving the rowtype and
related indexes, sequences, and constraints. It seems hard to fit
that into a general framework, but maybe it could be done for other
object types.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#12Heikki Linnakangas
heikki.linnakangas@enterprisedb.com
In reply to: Dimitri Fontaine (#10)
Re: ALTER OBJECT any_name SET SCHEMA name

On 31.10.2010 20:19, Dimitri Fontaine wrote:

Heikki Linnakangas<heikki.linnakangas@enterprisedb.com> writes:

In particular, embedded and/or dynamic calls in PLs will get hairy if
not turing complete and outright impossible to solve.

Sorry, I don't follow. Got an example?

Well, who's to say the following hypothetical plpgsql example should be
forgiven only in an exception's script?

v_sql := 'SELECT * FROM ' || p_fun || '()';
FOR rec in EXECUTE v_sql
LOOP

END LOOP;

If I understand that correctly, the idea is that p_fun holds the name of
a function that's in the same schema as the extension? You would write
that as

v_sql := 'SELECT * FROM @extschema@.' || p_fun || '()';
FOR rec in EXECUTE v_sql
LOOP

END LOOP;

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

#13Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Robert Haas (#11)
Re: ALTER OBJECT any_name SET SCHEMA name

Robert Haas <robertmhaas@gmail.com> writes:
...

related indexes, sequences, and constraints. It seems hard to fit
that into a general framework, but maybe it could be done for other
object types.

My guess is that we're talking about having a generic code that would
get exercised directly from src/backend/commands/alter.c in the function
ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt), rather than
having a switch() statement and very similar functions implemented all
over the place to do the actual bit editing.

Let's see some details, if we're getting there.

This line of code is repeated in lots of places, but always a little different:

+ conversionOid = get_conversion_oid(name, false);

+ 	operOid = LookupOperNameTypeNames(NULL, operatorName,
+ 									  typeName1, typeName2,
+ 									  false, -1);

+ prsId = get_ts_parser_oid(name, false);

+ dictId = get_ts_dict_oid(name, false);

And for operator class and operator family, we're dealing with HeapTuple
objects directly, rather than Oids, because the lookup ain't so
easy. But all in all that code could get moved into another layer in the
generic function, in a object type switch, if we get to HeapTuple based
internal API, because next example shows that in most cases we get the
tuple from the Oid in the same way.

In the following code part, I can see how to get generic code with some
parameters for the first 3 lines, but not so much for the other 2 lines:

+ 	tup = SearchSysCacheCopy1(CONVOID, ObjectIdGetDatum(conversionOid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for conversion %u", conversionOid);
+ 
+ 	convForm = (Form_pg_conversion) GETSTRUCT(tup);
+ 	oldNspOid = convForm->connamespace;

Then there's this code which looks even harder to get generic:

+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_conversion_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
+ 						   NameStr(convForm->conname));

Now the following part could get moved easily to the CheckSetNamespace()
function introduced in the patch, with a boolean to trigger the check,
because as it is not all objects are open to non-superuser changes.

+ 		/* New owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(nspOid));

Then in the end of the function, we have the real work, where I can see
a generic function for the heap update and the dependency tracking, but
not for the tuple editing itself:

+ 	/* tup is a copy, so we can scribble directly on it */
+ 	opfForm->opfnamespace = nspOid;
+ 
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(OperatorFamilyRelationId, HeapTupleGetOid(tup),
+ 						NamespaceRelationId, oldNspOid, nspOid);

So it seems to get down to C'fu related to handling Form_pg_* pointers
to get to values and change them then simple_heap_update the tuple. The
other parts are all about the same code with different RelationId and
such.

Well of course you think you could just have a pointer as argument, but
how to get the pointer is something we'd prefer generic too. Maybe we
need a 3-step code here, in aforementioned ExecAlterObjectSchemaStmt:

1. call a generic function that switch on stmt->objectType and
returns an HeapTuple

2. switch on stmt->objectType to get oldNspOid from the tuple and to
check for permissions

3. call another generic function to do the namespace related checks
then the heap update etc

This way the only specific code we need to maintain are the second step
here, object dependent, and in the first function too, but that's not an
entire API like in current patch.

Well of course there's the question of how to do that in a way that
allows some other backend's code to get the action done with Oids as
input rather than a statement, but that looks workable: get from classid
to objectype (aren't they equal?) then call the step 1. function to get
the HeapTyple, and proceed. So in fact the 3 steps are a separate
function that is called either from ExecAlterObjectSchemaStmt or from
the extension's code.

And there's also the question whether that has anything to do with what
Tom would want to see happening, too (or I'll be talking about those
ideas with gcc rather than with the list) :)

Comments?
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#14Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Heikki Linnakangas (#12)
Re: ALTER OBJECT any_name SET SCHEMA name

Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:

If I understand that correctly, the idea is that p_fun holds the name of a
function that's in the same schema as the extension? You would write that as

v_sql := 'SELECT * FROM @extschema@.' || p_fun || '()';

Fair enough. Now what about the citext example, where IIRC the failure
is not on function names but operators and opclass not found, etc.

Forcing extension's author to get to always use the following notation
seems to me like pushing it:

- WHERE foo = bar
+ WHERE foo operator(@extschema@.=) bar

Also, those examples are plpgsql but extensions are free to depend on
plperl or plpython, or even some pljs or plscheme out there.

The alternative is to give DBAs the tools to move their local extensions
in some schema that is part of their edited search_path, should they
remove public from there.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#15Heikki Linnakangas
heikki.linnakangas@enterprisedb.com
In reply to: Dimitri Fontaine (#14)
Re: ALTER OBJECT any_name SET SCHEMA name

On 31.10.2010 21:42, Dimitri Fontaine wrote:

Heikki Linnakangas<heikki.linnakangas@enterprisedb.com> writes:

If I understand that correctly, the idea is that p_fun holds the name of a
function that's in the same schema as the extension? You would write that as

v_sql := 'SELECT * FROM @extschema@.' || p_fun || '()';

Fair enough. Now what about the citext example, where IIRC the failure
is not on function names but operators and opclass not found, etc.

Just do "SET search_path=@extschema@" at the beginning of the install
script, just like we have "SET search_path=public" there now.

Forcing extension's author to get to always use the following notation
seems to me like pushing it:

- WHERE foo = bar
+ WHERE foo operator(@extschema@.=) bar

Also, those examples are plpgsql but extensions are free to depend on
plperl or plpython, or even some pljs or plscheme out there.

Well, in case of functions you can always do "CREATE FUNCTION ... AS $$
... $$ SET search_path=@extschema".

"ALTER ... SET SCHEMA" wouldn't do anything for SQL statements embedded
in plperl or plpython anyway.

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

#16Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Heikki Linnakangas (#15)
Re: ALTER OBJECT any_name SET SCHEMA name

Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:

Just do "SET search_path=@extschema@" at the beginning of the install
script, just like we have "SET search_path=public" there now.

Well there's the installation itself then the "runtime", as you say
later...

Well, in case of functions you can always do "CREATE FUNCTION ... AS $$
... $$ SET search_path=@extschema".

Fair enough.

"ALTER ... SET SCHEMA" wouldn't do anything for SQL statements embedded in
plperl or plpython anyway.

That's why I was thinking about adding the possibility to:
- easily find your function's etc OID, that's already mainly done
- be able to call/use those objects per OID

Ok that sucks somehow. I think it's better than @extschema@ replacing in
the extension's script parsing, though.

Maybe we should just shut down this attempt at working on search_path
and extensions together, again. I though it was a simple and good enough
solution though, and that it would avoid the usual rat holes. But we're
deep in them already.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#17Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#16)
Re: ALTER OBJECT any_name SET SCHEMA name

On Sun, Oct 31, 2010 at 5:46 PM, Dimitri Fontaine
<dimitri@2ndquadrant.fr> wrote:

Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:

Just do "SET search_path=@extschema@" at the beginning of the install
script, just like we have "SET search_path=public" there now.

Well there's the installation itself then the "runtime", as you say
later...

Well, in case of functions you can always do "CREATE FUNCTION ... AS $$
... $$ SET search_path=@extschema".

Fair enough.

"ALTER ... SET SCHEMA" wouldn't do anything for SQL statements embedded in
plperl or plpython anyway.

That's why I was thinking about adding the possibility to:
 - easily find your function's etc OID, that's already mainly done
 - be able to call/use those objects per OID

Ok that sucks somehow.

Yeah, I think that sucks a lot. I don't see what's wrong with
Heikki's solution, actually.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#18Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Robert Haas (#17)
Re: ALTER OBJECT any_name SET SCHEMA name

Robert Haas <robertmhaas@gmail.com> writes:

Yeah, I think that sucks a lot. I don't see what's wrong with
Heikki's solution, actually.

Coding the parser and replace. If all it takes is calling our replace
function on the all-in-memory query string that we have in
pg_execute_from_file() function, I can have a try at it.

Main wrong point is that it puts the burden on the extension's authors
rather than on the one who manages the search_path for its
applications...
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#19Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Heikki Linnakangas (#6)
2 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:

How about something like:

CREATE EXTENSION myextension ... SCHEMA myschema;

And in the .sql file in the extension you could have special markers for the
schema, something like:

CREATE FUNCTION otherfunction() AS ...;
CREATE FUNCTION foo() AS $$ SELECT 'foo', @extschema@.otherfunction() $$;

@extschema@ would be search&replaced at CREATE EXTENSION time with the
schema specified by the user.

Please find attached v12 of the patch, which implements that idea.

And a new pg_execute_from_file patch version too: the function now has a
second (documented) variant accepting a VARIADIC text[] argument where
to put pairs of name and value for the placeholders in the script.

I guess it would be cleaner with hstore in core, but we're not there
yet, so meanwhile it's a variable length array.

The CREATE EXTENSION ... WITH SCHEMA ... command will then use the
variadic form of pg_execute_from_file() with a single variable in there,
the proposed @extschema@. When the option is not used, the placeholder
is still set, hard-coded to 'public'.

Contrib scripts have been all changed this way:

- SET search_path = public;
+ SET search_path = @extschema@;

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

extension.v12.patch.gzapplication/octet-streamDownload
pg_execute_from_file.v4.patchtext/x-patchDownload
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 13897,13902 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
--- 13897,13911 ----
         <entry><type>record</type></entry>
         <entry>Return information about a file</entry>
        </row>
+       <row>
+        <entry>
+         <literal><function>pg_execute_from_file(<parameter>filename</> <type>text</>
+ [, <parameter>variable</parameter> <type>text</type>, <parameter>value</parameter> <type>text</type>
+ [, ...] ]) )</function></literal>
+        </entry>
+        <entry><type>void</type></entry>
+        <entry>Executes the <acronym>SQL</> commands contained in a file, replacing given placeholders.</entry>
+       </row>
       </tbody>
      </tgroup>
     </table>
***************
*** 13935,13940 **** SELECT (pg_stat_file('filename')).modification;
--- 13944,13963 ----
  </programlisting>
     </para>
  
+    <indexterm>
+     <primary>pg_execute_from_file</primary>
+    </indexterm>
+    <para>
+     <function>pg_execute_from_file</> makes the server
+     execute <acronym>SQL</> commands to be found in a file. This function is
+     reserved to superusers.
+    </para>
+    <para>
+     The script might contain placeholders that will be replaced by the
+     values given in the <literal>VARIADIC</literal> arguments, which must be
+     a pair of variable names and values.
+    </para>
+ 
     <para>
      The functions shown in <xref linkend="functions-advisory-locks"> manage
      advisory locks.  For details about proper use of these functions, see
***************
*** 13957,13962 **** SELECT (pg_stat_file('filename')).modification;
--- 13980,13986 ----
         <entry><type>void</type></entry>
         <entry>Obtain exclusive advisory lock</entry>
        </row>
+ 
        <row>
         <entry>
          <literal><function>pg_advisory_lock(<parameter>key1</> <type>int</>, <parameter>key2</> <type>int</>)</function></literal>
*** a/src/backend/utils/adt/genfile.c
--- b/src/backend/utils/adt/genfile.c
***************
*** 7,12 ****
--- 7,13 ----
   * Copyright (c) 2004-2010, PostgreSQL Global Development Group
   *
   * Author: Andreas Pflug <pgadmin@pse-consulting.de>
+  *         Dimitri Fontaine <dimitri@2ndQuadrant.fr>
   *
   * IDENTIFICATION
   *	  src/backend/utils/adt/genfile.c
***************
*** 21,31 ****
--- 22,34 ----
  #include <dirent.h>
  
  #include "catalog/pg_type.h"
+ #include "executor/spi.h"
  #include "funcapi.h"
  #include "mb/pg_wchar.h"
  #include "miscadmin.h"
  #include "postmaster/syslogger.h"
  #include "storage/fd.h"
+ #include "utils/array.h"
  #include "utils/builtins.h"
  #include "utils/memutils.h"
  #include "utils/timestamp.h"
***************
*** 264,266 **** pg_ls_dir(PG_FUNCTION_ARGS)
--- 267,389 ----
  
  	SRF_RETURN_DONE(funcctx);
  }
+ 
+ /*
+  * Read a file then execute the SQL commands it contains.
+  *
+  * There's a variant accepting a VARIADIC text parameter containing
+  * placeholder variables and values, one after the other (so the variadic
+  * array length must be even).
+  *
+  * The main use case of the replacement facility is for setting the
+  * extension's schema, using @pg_extschema@ variable and a user given
+  * schema.
+  */
+ Datum
+ pg_execute_from_file(PG_FUNCTION_ARGS)
+ {
+ 	text	   *filename_t = PG_GETARG_TEXT_P(0);
+ 	char	   *filename;
+ 	FILE       *file;
+ 	int64       fsize = -1, nbytes;
+ 	struct stat fst;
+ 	char       *query_string = NULL;
+ 
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 				 (errmsg("must be superuser to get file information"))));
+ 
+ 	/*
+ 	 * Only superuser can call pg_execute_from_file, and CREATE EXTENSION
+ 	 * uses that too. Don't double check the PATH. Also note that
+ 	 * extension's install files are not in $PGDATA but `pg_config
+ 	 * --sharedir`.
+ 	 */
+ 	filename = text_to_cstring(filename_t);
+ 
+ 	if (stat(filename, &fst) < 0)
+ 		ereport(ERROR,
+ 				(errcode_for_file_access(),
+ 				 errmsg("could not stat file \"%s\": %m", filename)));
+ 
+ 	fsize = Int64GetDatum((int64) fst.st_size);
+ 
+ 	if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
+ 		ereport(ERROR,
+ 				(errcode_for_file_access(),
+ 				 errmsg("could not open file \"%s\" for reading: %m",
+ 						filename)));
+ 
+ 	if (ferror(file))
+ 		ereport(ERROR,
+ 				(errcode_for_file_access(),
+ 				 errmsg("could not read file \"%s\": %m", filename)));
+ 
+ 	query_string = (char *)palloc((fsize+1)*sizeof(char));
+ 	memset(query_string, 0, fsize+1);
+ 	nbytes = fread(query_string, 1, (size_t) fsize, file);
+ 	pg_verifymbstr(query_string, nbytes, false);
+ 	FreeFile(file);
+ 
+ 	/*
+ 	 * Replace any given variable with its value, by calling replace_text
+ 	 * over each pair of arguments.
+ 	 */
+ 	if (PG_NARGS() == 2)
+ 	{
+ 		text       *src = cstring_to_text(query_string);
+ 		ArrayType  *array = PG_GETARG_ARRAYTYPE_P(1);
+ 		Datum	   *replacements;
+ 		int			nrep;
+ 		int			i;
+ 
+ 		Assert(ARR_ELEMTYPE(array) == TEXTOID);
+ 
+ 		deconstruct_array(array, TEXTOID, -1, false, 'i',
+ 						  &replacements, NULL, &nrep);
+ 
+ 		if (nrep % 2 != 0)
+ 			ereport(ERROR,
+ 					(errmsg("Expected pairs of variable names and values"),
+ 					 errdetail("Please give an even number of replacement parameters")));
+ 
+ 		for (i = 0; i < nrep; i+=2)
+ 		{
+ 			Datum	    rep;
+ 
+ 			elog(DEBUG1,
+ 				 "pg_execute_from_file replaces '%s' with '%s'",
+ 				 text_to_cstring(DatumGetTextP(replacements[i])),
+ 				 text_to_cstring(DatumGetTextP(replacements[i+1])));
+ 
+ 			rep = DirectFunctionCall3(replace_text,
+ 									  PointerGetDatum(src),
+ 									  replacements[i], replacements[i+1]);
+ 			src = DatumGetTextP(rep);
+ 		}
+ 		query_string = text_to_cstring(src);
+ 		elog(DEBUG2, "pg_execute_from_file: %s", query_string);
+ 	}
+ 
+ 	/*
+ 	 * We abuse some internal knowledge from spi.h here. As we don't know
+ 	 * which queries are going to get executed, we don't know what to expect
+ 	 * as an OK return code from SPI_execute().  We assume that
+ 	 * SPI_OK_CONNECT, SPI_OK_FINISH and SPI_OK_FETCH are quite improbable,
+ 	 * though, and the errors are negatives.  So a valid return code is
+ 	 * considered to be SPI_OK_UTILITY or anything from there.
+ 	 */
+ 	if (SPI_connect() != SPI_OK_CONNECT)
+ 		elog(ERROR, "SPI_connect failed");
+ 
+ 	if (SPI_execute(query_string, false, 0) < SPI_OK_UTILITY)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DATA_EXCEPTION),
+ 				 errmsg("File '%s' could not be executed", filename)));
+ 
+ 	if (SPI_finish() != SPI_OK_FINISH)
+ 		elog(ERROR, "SPI_finish failed");
+ 
+ 	PG_RETURN_VOID();
+ }
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 3386,3399 **** DESCR("reload configuration files");
  DATA(insert OID = 2622 ( pg_rotate_logfile		PGNSP PGUID 12 1 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ ));
  DESCR("rotate log file");
  
! DATA(insert OID = 2623 ( pg_stat_file		PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2249 "25" "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" _null_ pg_stat_file _null_ _null_ _null_ ));
  DESCR("return file information");
! DATA(insert OID = 2624 ( pg_read_file		PGNSP PGUID 12 1 0 0 f f f t f v 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ ));
  DESCR("read text from a file");
! DATA(insert OID = 2625 ( pg_ls_dir			PGNSP PGUID 12 1 1000 0 f f f t t v 1 0 25 "25" _null_ _null_ _null_ _null_ pg_ls_dir _null_ _null_ _null_ ));
  DESCR("list all files in a directory");
! DATA(insert OID = 2626 ( pg_sleep			PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "701" _null_ _null_ _null_ _null_ pg_sleep _null_ _null_ _null_ ));
  DESCR("sleep for the specified time in seconds");
  
  DATA(insert OID = 2971 (  text				PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "16" _null_ _null_ _null_ _null_ booltext _null_ _null_ _null_ ));
  DESCR("convert boolean to text");
--- 3386,3403 ----
  DATA(insert OID = 2622 ( pg_rotate_logfile		PGNSP PGUID 12 1 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_rotate_logfile _null_ _null_ _null_ ));
  DESCR("rotate log file");
  
! DATA(insert OID = 2623 ( pg_stat_file			PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2249 "25" "{25,20,1184,1184,1184,1184,16}" "{i,o,o,o,o,o,o}" "{filename,size,access,modification,change,creation,isdir}" _null_ pg_stat_file _null_ _null_ _null_ ));
  DESCR("return file information");
! DATA(insert OID = 2624 ( pg_read_file			PGNSP PGUID 12 1 0 0 f f f t f v 3 0 25 "25 20 20" _null_ _null_ _null_ _null_ pg_read_file _null_ _null_ _null_ ));
  DESCR("read text from a file");
! DATA(insert OID = 2625 ( pg_ls_dir				PGNSP PGUID 12 1 1000 0 f f f t t v 1 0 25 "25" _null_ _null_ _null_ _null_ pg_ls_dir _null_ _null_ _null_ ));
  DESCR("list all files in a directory");
! DATA(insert OID = 2626 ( pg_sleep				PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "701" _null_ _null_ _null_ _null_ pg_sleep _null_ _null_ _null_ ));
  DESCR("sleep for the specified time in seconds");
+ DATA(insert OID = 3627 ( pg_execute_from_file	PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "25" _null_ _null_ _null_ _null_ pg_execute_from_file _null_ _null_ _null_ ));
+ DESCR("execute queries read from a file");
+ DATA(insert OID = 3928 ( pg_execute_from_file	PGNSP PGUID 12 1 0 25 f f f t f v 2 0 2278 "25 25" "{25,25}" "{i,v}" _null_ _null_ pg_execute_from_file _null_ _null_ _null_ ));
+ DESCR("execute queries read from a file");
  
  DATA(insert OID = 2971 (  text				PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "16" _null_ _null_ _null_ _null_ booltext _null_ _null_ _null_ ));
  DESCR("convert boolean to text");
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
***************
*** 442,447 **** extern Datum pg_relation_filepath(PG_FUNCTION_ARGS);
--- 442,448 ----
  extern Datum pg_stat_file(PG_FUNCTION_ARGS);
  extern Datum pg_read_file(PG_FUNCTION_ARGS);
  extern Datum pg_ls_dir(PG_FUNCTION_ARGS);
+ extern Datum pg_execute_from_file(PG_FUNCTION_ARGS);
  
  /* misc.c */
  extern Datum current_database(PG_FUNCTION_ARGS);
#20Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Dimitri Fontaine (#1)
3 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Dimitri Fontaine <dimitri@2ndQuadrant.fr> writes:

Please find attached v12 of the patch, which implements that idea.

And v13 now. v12 was intended to see what you think about the new
pg_execute_from_file placeholder API and replace_text usage, v13 fixes
the pg_dump support by adding dependencies.

Also, I've been changing the \dx output to show the schema where an
extension's objects are living rather than the custom_variable_classes
that most users won't care about, I think.

Then, I think the ALTER EXTENSION foo SET SCHEMA name still has a use
case, so I've prepared a simple patch to show the API usage before we
get to refactor it all following Tom's asking. So there's a initial
patch to see that in action. I had to rework AlterFunctionNamespace()
API so that I can call it from elsewhere in the backend where I have
Oids, so here's an updated set_schema.4.patch. We will have to extend
the APIs for relations and types the same way, but it's already possible
to test the patch with some extensions this way.

Producing those patches (the alter_extension patch is an incremental
patch that sits atop both the extension and the set_schema one) is made
easy enough with git, I'm impressed by this tool.

http://git.postgresql.org/gitweb?p=postgresql-extension.git;a=summary

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

extension.v13.patch.gzapplication/octet-streamDownload
�B��Lextension.v13.patch��y_�H�8����j���a��C�;�4w0zy���+ltcKnIaf�����T�������fz�-�^�N��<z�H�k�8���z����h��������p�euuU\O+��������l
�%�.���p��gB�n��e(�)���_�B�(����vq!�^�w�j%��y,�?_�O;�g����������v�:���������o�n8�q�iw�_�������g�/�_A��Mf=o����Ho�����u���]Z������k�d8�\�|��.6��������N���Ez,�*��sh@��eA��q�{�hD��+T L������L�^�R1�q��Mt�q���	��Z�B�P�9P\gIto��
(\j�{�-������v7S��n�d-����]1�>|�?�bG�������W��U�4�{~��@� ��e��L����������_\�����5��(H��WO���o�'��
E��OE:��$#��W)��8H��K�#�q0'�@)6�m�����N��vxvB�=���p���������n�T�A�����b!WS��Ioa�����T� p%����_���%�C����wzr={����E���-�.��O������%�G�=t�������I�=:����`����M��K��:�s����8���8�M�Q�X���AL{������\78��,�f�p��!}�	���������ZM�I
'r=���tT���[��Y8
���8������|Gg���N�*����AxS�L�Y7�c��:�	�jl�F�a����O{�S1����8����Ei\o���n�z@�@������?�<��L��������U���z:Y�����E�����t����:�%�c�����u�^w����}J��D�������Q���HEV�QJPE h�k��/��]���G��9GE��Q���O�,�VW����$:�/�I�_sVb��E���p�d
v�S*�����!^��x�����[^s���sUM�@��J��(+n�W����t�y��Lz�y��9�.X��B��8x���"X�����zk��#�*���wT���]�
h��ux|	K��v�?��+O��)�urTb��k#��N.�b�5/�B����A���}���������{��7�AG<���AD���z2q����S�+a�I��|F��#I0N8���0��h�(�)������>����B�Oz$�!�6&i����{���t�\���]�r�ig��N�uN�g^���a��JA{���Cl��\U��Pj����
�"��?�b��x�Q�� ����,'c_�q �����`�#�5\��$�H��S�������=z��v������s�]w�zF��G�S��(�V��8H�����bZ��?�����?!�@Bv
��Sv���4�Ak��WR���h�T���qViU�_
��MO��xE���,�;4x
�~��
h������,��x��e1������An~�R���T[�T4�eH��0 9�0��
�����w�P�g��B���8���h*N���e�k��G	U`�����^v��?@5,�M��4�����r�"_v�����}���s���4�1����8����eJ?��3]�,8]t����.�z�"��B����:�����z�>2����'�:���j�f������pA9�M� �� \�^������@e&@`:I~���lc�sc�i�rb�9*��uf7�iY�K�L�0�I0���6% ����_A����@��0�����&E���v�Sv�6�
&���=�f#?��Va��B�1�4I��6b��?����;���bv�
M����A
��j���X�j� �
����R8
�~fa�J1�7���R���N��U�Qa~T5��/�Po�(��P
�N?�&�
t������N^�W��������b!J����
��)�Ta��[7��)0������\���0A��U
�d���X��7k�<��p�Y��ki��M7n��5��~9��Vd����w�������d�c����`��7Y����FKb��'�Q���������UMh�z�ja�Q��0�������
��x>����.��O�a��`��?vo���6^JC*��z����#�Q?�"L�q$�x��gj\.��`���7���[8	�������:�E��,\�?��p��y[.��tz�����mo`k���
���6��6��������@3]h'	n`�����J�]�XE�BP.�=�����C�"�����8!���y��2=���i<Z�>����'�?m���(b�W�80n������U+(�E�Gu�����h�Q�i�	
�8�T�p���)���O��:�}g9?�<��������x8q�,C��q9��I.w�r�|t%���%�|�R/	�����E�G"�T�X�\S��4�$��}.�����|
TI�W_��%.��WFUt�r�8;c'q�#7���	��{k5h7��_.�����VD�f��i�(+����g��D�����D}^���p���������o�<��x��U'X��
0,�����:�#?�o0N��&g	s�K��TZ��?�f����`����j�� �$�/�������B���h���t���qx��
���P���~���]���u�iH��W�EMr��~5|^(��C/Mx�9�m�@E��{��7J���$��[��u��r��x��"s'E�; ����������|�����7��1���;�8A��'[����������(`�1r)|'K�c���W^shd�|�C[�8����-�8�\����B�sx 1�(
|�!A!�
���S��T3>�C�:P�2��T���\f��Lo�3�7�V����6MZ�9G^-�(���7p(� ��P�oT��.�#�A��L�P��7���4J$���W�"�5-L����j�l9��d�t�'A_pYA�@(���f��"����(�������O+%�P-�XE���/{�!��k>���r�8��
��H�~zO�T�b��*��X�*>M��}5x�Z��d���f�Q�TL@9Q{�y]_=M|����B(j�?!�r��C��N�:�}&e�3c:%��S����J�����Xj����\���6
r���&�R\[�|�[
-��%K����]�� ��v#�	{�>��t���E��"�g�V!���.���n�3QLZ	i�&�Pl�d���/d�������tYr3������]�L4�u+����K6�������h��|��h�����)��{�%A[Yr�g
<)`g*���`����
-�T
|�a��;�u�j;���������Ol!���+EO���C��6���f9�q��QMq;�{�������a|7�[�����`(#ck�Z��W�d'��}"��m��%����e�s���q3�x�[u�#U�� ��a=�B�/�+\���F�n|���e�Q^��(��p7��8��i�~���x�v*��S[��~������w���f
�T.1�~)�:[}���GK���X�k�7��3x0vP-L�o1Zj�bf�+�b�H��� D�F�Zu��_�>�]�T7�e��|X��St��|�M��Nz��]]�^�.n������c�?�b��5��0��/A���&��������H�m����s`���t�v������e5��`��(X,_gh�DoVIkm�h@G��V ���AI��R����#I��;"������%���}��Jd.
�o�Q%�!���>��,��>��� ��U���6z9'�J�y9����>�"���b\�y����>�!i�'0����j�Q��G���������r~lcW�����;L����>3������B��=�8����o�r
a���7������d0�		���C'6������$8����$>\�E
��5��O'�A�N�x�q=�����S,&#t�E8��g'��r����HM��;�r��2��Q�a?�#L��������X#����}<w~�vuLB���`r3��!�c��x��h
����Bn3GpV#6����i
��m���"3���^^���,���g����������"	�Ip����Z2G����`�R�/��c���!���#�4�����7}R�mw@�{�+
.�F�p(��A`�9��x�7�Y������&�B�CV
*��L�"6��QW����b ^n��oc\�zy�g����B@=kj������B2���!���j�����e�DG��Bp,�[	��������e.@A�Mw��#?���	���pZA�|s��9�P�X�����MR����l%��,���_$��zq��g� ��Z�!*�*e��s����f��T�*<���_��P���Ce�\��n�+J�k���$�KL��!��tNDK�� �
wcw�P���/�^+vy�@�QP�CE�)���"�J���(��c3���Ka��y�>�B:��MEs��Z�] 6���#_!����^1����0��F@�����f�&I��(@��D��%q
h���	���&����L)8?
�n��@C��a7��~�S�s�q��$Kad�@>��o>���9�w��4��@=���Ud���F��"+�6������1���C1����V��I�x$����W���L/���������I��I���m�=G���9���E�\&��U�mJ���S�����J[HF��J��bz>E,j�V��{o�0��*)9��F#�����S'��nccz�4~7b�*�J�h���NI,>4�=B'�@�I\�cJV�R���l������~o,���y�]�:��L��I��zAu.�����9nPU���Uk(w��/;�:����]@�p3_]���1r����Ak�k�p=��FV�/�}��bJ���i�����(^�=��WC��W_���V���j2S�1;6��b�%�7��Ay�NUYl~U���A��A���&_��eIKO����yf����T�2	����W>qX0o�n�����V���w�����$��z��^�|���a�F�pu�����?&���4��(IE
W/���q���6�.�8*�BP���CKO�����4��E��lpx7V2=�;����3��
5�R�S��UY��������~�t�"z��3S~?�Q)����?�*Aq���OD.��>�x�.��=�iX��5���g����q����{�%�J��sr9���f�n����k��G�����p
���
�%�2��3]��������0�����M�"��k)lC�������h�-�>�<��&p����XH<��l<�q��=xL��f�O��0fC]������qL�G<�&���SnpM��wp��60=��C�5bAI�R���[���y�L�D�� O��� o��^���!�rs� ��a*��E������\r��e�����a<������P�&�'c�a�lyS-4<�
���%�&���!���r�BGO��{��%0�U�.4�\U�(��A���<]3��Q���������-������*E4�a���"?���������jOD�X<=���/��"3@���3�Qb3$��kX���b���!�A\����?�n�����z�no���'�0m�l%��������=l#��M��a��2�sO���g�f�[����>��*M$H��CY�X�P�P���O�T��y���9cYa����_t�������T��'���7�*
�V�<����FD�B+te����vY�����m�mm����������3������Q���
�;������*����-�sr�Dj�qE�s1��iWK#��SG]h�*�����=-��cujZ�[��vs��5�[�=o���i�,r��5\[2��.FjTv�&4�P��T�H`K�,��)�In$�>�����XH��6>	��	i�E	�9n�r0,^���
?���C~;���p7y����s.�_M<�W�)�	I5!`/�5�`?���s�8�%����'�0i2�����m�����u������ ��F�>�r���A�i$���\��0��+��ezV�C`��q����	`�r4���3����9�������Rh�}���pB"���������B�D�b�EpX�]Q��,q�h�|�t_���66�v���k��j��Ls�s,����y>aV�QL�,�	p���|wz(��E�������n8i&(��{d@�(���D����\�Pg`��~/������?N����8�\H�m9G?����z���) ����"����C6g0�x��(=(.k�>��U!!i���-6L8)EBG�B��8��(U"�F
�ZTX)>?j�R������F��w.�~`VK������*����(C~�a_�sDchN)�h�H��e��:�{����:?\���/���Xp�@������Ao���/|c�GkA
K�4	h8���l��0H��	F������f*��xw��e)@��!���)i�c���#���R60��
�J��Sa�`��E��Mp/��m�P��c��{�;3W������i�{��� ���n�j�-�Z~�\��������$�4A����2�*$P�n-dx}���-h�y�VX�T����Fr'��_`����X��sQfJ7pTr�X~+���)d
�%�
�g����
�R�d�/��9��1+�����%���=8��Z�L<����|�r���K�S��(#��+��`D������8�����WQ���U�<���5��#gQ/�`��2q5�})"�F�����@m��� 7�G����*��Uhj��K��n|�k�9�����������jb`>s���9�ct=�'�[�~)���x:d���p��M����E@M�IW�^	�����Q��$�����Q~��4{�9���s���,��@+��l����?�-�g��z�h^�G���3e�(R���I�WQ�s	���q��:�����v&�z1�F}����';�������"�����;T���6��LTy~���y��v�<�.8&V�����YX�5��QN)����H;��w���wC������R��ZD|~MP��f��}>��������a��t+��M-'�l����&���L�C��_6��?�"B���8m8���b
H�1���Kt��o������fcwo�kn��K�q�f���_E�}�>�������h*�n���"�����K�D*��������l'�n6-�TAl��8��V����Y�����u8k����U����<6�O�Er������s�\!o�@L�$6��'���d���3Q�e�'3�s7�F�w�{]��������<����q�����_Z��y�j�T�R���R�����M�.W������I�,�\3�}Z&�J����RA7l�m�k����B�]S�hOW�N���
3�����M�����B"Q�� F����E�Z��-Q�.��A�q�tH�=�E�I�����,[�����$26�������Bk�Z'd�N�R&-iI�����[{��f�7a�q�]8����I�R~�Kf��(����������@�~r3�h�������Z5�����
�
���*dj���N���W��9o9�Ie+840�P
+���I��/�y������iU5+�V�V�I����\C�2�T�i�4
jQ�����:-\
��t�i��(�L�J���!%���E�D@���;������Q4����X$�J�O��J~jRq'��!��#RMI5f,��/'�Lg��ij�`�$�U)�P����%�YI��$�Sr_>���Y����_5I�� h1��G���RR>��%��z�.Z��R9'��J�l�Df�7|�6s�7�Y�q��e����	o��)[g �����~s&��`����p4�\�1N%�4�+��{�}dwA�8�.��Q�Jh��K��--k�-�c��.Cqk����6�����BN���	�z�L�Q	1�������4c�1G�J��N�p����nC`$���f���SS�j���-I�;����ME���k�B�I6���|���V���B�����n��QH��H�>V�o�����
��h�'O�~�����I���"2���q����0����29��$U
I���Cm�pY�;����'��<����a�m���JOfK����4�v��Y����7\�o��Q��(���J/nV����� �I��,���*�H��Q�)R��z!H,~:��A���o��l��������"��,��fd��*���vt&����h�:>���/�T�E\��>���y�F������<m\�I-��D&$������
CII�q�mt�~7
�(�����O�`�������p�b�G��sjtc��-Z�="�$�i�]�����x;�����s�!~�!��wC���$@Z?L{1p�t	��mf�8d�V��U�:�v3������H��P���V���������0�?��ao���7e�h����d��6L��~�R�-�t#�o��z+8Y��-f5->���1��+dH[$��n��is}geH�[�d�.)\��'�
���p+�
��WB�'�)�f!�Bu��nL��N3'�C���e�P�U,P��9D�kp(�2�R�].���X���s�a��Te;I��������1I���C��J��.�����t?��%�8�#�s�C��\��
�m�;'Y�)wQ��\�+S�u�������X5�����lNU�/���{��py�T7�0�c0
r*+�"��{��R5�	�����%���^�%}�D����W�aKXR�<B��	��U��o-�(T�X`
lP�9!��2��0�)p��-�(T-BE�c��n�c��tsS{O��$�������s��
uH��|pWW%��0!B'�-]e�Y����`1@�J��*���l�e��:p�����d�|��Z�C78��u���Uq�G7L���AS�wR�������'���o�����9Hz���'�8N���[��v$
��e�������
S5����(M��a���N��x��������?Jl���^]���&����G�������������E*�9����@���w1�����r{�������W���6=�6�����XXH��J�������*g�7�0RT�~i�"�S,�g��B��# ��e��)��
�1�T$���K�}���1�K|�"�\o���|E��'�7%K���;i[)�U�}�E=�,�/[1��<T�9d'�<�pR���x�����u����=?W`Uv��}����M�r�0v���F��!�$}����&������nks�jAQqX
`�m���k���A����#{D���KI�WaV+O���]��R>F�����m<�Z6�B���������:�z}���!R)���#��K���Kj�k��{����&�n��m��K�4=8!:'$KU:�	�'
��O7���������~�����A�pjZ�*�V�k���gkz�R���}�z��`��
�3e����XJ�.c�L��!/�����oY���h���32�+�����P" �[?�1���:��G�2�=T.;d��V2q6�Eg�����B��@�����`�t��)�Y���D/��������c�E�����3�������W���=j�<�:����%ph�������{����BX�1�hZ�������ib�MR�=�]�v]�E�/�GET�����`8�z���@m���/���>�e+n�Fqo�A�����"]+�����PJA6��t2'��<qL>��������1��&A���M���-�H�R8����WZA��T��*q�\�ZOc���;���v��}9*T�U������1���`��������$���<[#tx�N����s��%KE�tM-T���}�Y��b3O���]~~���^t1��kX�a�n�k��e��Ds
���9�g*�Q�����C�gGg������.8s�-6� ��R%�p9Y�(�R����SFf7'~E�{����eG�%L�������|:�t���Q[�[\�;�����^�T\-C�$�����3g��4�f^�s��6�>��r�GT�<'��U��G�fB2c��������=O��KN�[�j�4d���C����������6��h��-l�1X�q��I���a/D��X'���E��4���Z�m�d���'i�5*��\1F?�4uX>������6,e�J���q �}�i)D��y]b�b��<1�5�|~a����ac0^��G'�/c�f�S/gN�+s%�g�[e1f�Y_M^y�|�yI]��Tn�X��N�T1K8�I�z�F�H��iX
}_42���+���SR��m�z��
�hYY_x/9�))��+��l��k���M��Z7�d�D�O�����l,��X�LLK�Y>������b�n��mk�����4>����38I�Q�o����:�J��*���!6����v#o��# UH��l��?`���_	SE���r���w2&;G6%{�B&X
����z����z��u>
�*�`[�M(��Q�}k_F��U�������	N�b����[j�,vqy>���)����O��o���/��~����i���3+�U#����b���B�>*m�=9#��`IFc��t�{���������N�=�\cC�#�sDR���'����%��{W9.).��j�C�w��������9x��O�)�f(S9#��0\�M�����C	}io\���H�&��Fx���>�8���o��o��o|��u�^@��a��4]�?J��Vh���2��������,��������$�������]v�S��l��_'�p��y��q�uo ��*�
���W7_omz[��D��]�������^����'��3��8�N���"�4����{��AC��F}|�B^cp��(�j��S��~��0�\*}4Z�������L�%t��������w�rc>�Yzt&Q-x�����;&��#�g�!�IU�V�q[��jt�%�q(��u�����Q�0g����P�����,�]%���-@/	��'�����IsS4��x�t0ln��sDF�����I�Z*(���\��z2��a�8D��#��	L�U&f��S����B�!s3/�z���[�O���'�~U�8����M<���	��S���,�\���/��%��������~-��1z$G��@M��p������,_E�=�%X��!f�����EE��	�����C��A59,�UeB�R	D��t)�����������aF������W��?���Y�9��@��[t��iUVY���Q$/C�~�=�j������}^~��`hoh������j�H���*��J�G�t
,���r\�70�IK��?�������W���-����p�|�Ts����B�s��Sh�a=<w���b�4��+Q|cy������V�����a��j�d���gV�%���m�cg�x$�#4�o`��m�}y<�}������%#��/�>~<}�d��[���q@��� ����<��q7������R�����Y�����TUp���++�x��o�-�����x���<4j?�,`]bp���X����V��� ��)i'������C�@F":z�/��3 ��6����@I@����O�QF�fisM�1�@���g.����r��(��K�9*��:7pr��@6�����$�U	�������D��,��.�#�AN�P�s��u!���y���L7JI�N�^����$]�������-��'%���Jn���S��k��(Gk~�e���~�Q�R�}�6k�������-���s7���%����iy&�\�PA��^�Ynk�E�Yz}�a�������rjg��=o�S
����%������q�sA"�ok����c�7��&u�IR��'�7�>mjg�%������T�R��7Y��	D��6y�g�B�	Bh��T#t�����Ao�_C*�����iY/�}���7�/�&�_=���Z�<4���ssn��gE���6��<�j�����Y�\�)�phE��(`,Xe#���Y\mie�����"����^��hP�7[��M�C����V	I0*-�z]�X��8�{8��lH
h�z9X��eg�k6�Uf�"���1��9G�����`��c����$�cb�G?7B&��~�V�������b2[5�v�0�H�����@�h��%������`e�X�0a�s�VA*�W���I�����
�_�J�k���z�;�����Cqh�c�E�t����0��r���Bv\�`����W@vI?I7���8
x�:C������X�������+�������Q�F��*����/O^u�.�_��,��[__o�p��"	�2�}����m�����]��&����������>g����!���\]��66Km`���-�^�/�dvK�hA�!������S�v�-��� X�)0����	y��=�
y��>��8x�X���U����[�4C3���$�&��[��H�5��Uk��+�J��R�C��u	�9��CS\2��p�#ui�r�r�)Srv����x���'3:�������(��}\���nZ(�/�1���N�[-������,IA�sq���*����~���t:�%D�ZY�HF�0���G���/�~���*����F�������n�}�c�B�����5�7}�kO����9�PB%�?e\���0�cVA������}��Q/��`����*'��g
���8/,�����^'��i8~�I���d|=	P6��Q�����#�h*�u��}�A������G���_4�{���[�_H�*_*)��Q�4^$m�
��e��~D)�d����w���*���,�����f�B�&���a�6z����T4hY����������r�s=���H�-��1�,��)�����W{���dK;@M������@\�P���|���K��?��MTG��I;)P��	R�Q�*���g���X�4c��/�N�e�f8�%
�Q�2F(b]��R������d+�M�����2�p����	���=����u@��U�-K��y��@�)��$9d6t�5�
E��O
��!>{&x�.k��|#�s.�_���M�6w��@�"�����Aw]7�����d2h�q/���5��*���*�����H�xE=�W�]�aU�>6Z}�`h����s��f=<�g�N����-��\��t`�y��f�b�e��ww
�ak��/G~�Z����\3T��1KI�5�}��}8�\��]<.w�7� U�x=q�h%#Og����t.������fa1
��9�tk{�1��y�9������� �������[�<��vm[�Je��.\�O������/.�.<�P��o&c1�C��c�7Y�T�%Q��Q�C:��h��g�'��e��t�������<��9��������a[���"��!�*�����{���_��pxonz>z�O<�x��u�ung;?H�;��!.e�]N�|:�����O�]@��Q��7��Q�
����=f]9�Ww�`���d���(@�`2��H��]�#���S+��
!�W����p�I�4�"�B����$
�g8��Sq�:!
u,�5
�	NJM��E6���0�e?a����S|�C�A�a��j�-xq$�6�~�����!5es�����+�7�[C0�f��Y�e����|��.��Kb�^�"�k���'�O���z$G�;�o�@���\;����V]��R��Gy��291v�.���o���2d�5����`���#���<�CD�$x���B�o(�������
U��VD6����a�;�B���MB�C����2�����`�E�����X������"�5~,J	�W(}"���R���pk<����A�0]5h�:��/AVo�A��T�V��OGIl�c
}�e��
\P�~P�G���D�!l����S{d����N�hn�X�K��A�awP�gW�����J�hheU^�?n���1#8Zn��#-�=;c�yM��^�aS�]���~C�f��!y�TM������uwP��B�@z����`��cp���K9���4{�Mo�)oz>��D�)H�M�r)o ��^s��k�dPp��a�`}?�(��1�|�9��qD�tgX�xu��}��E�$����� ��0�����������C�EH��4�87G����/D���(�J�q�}�����d�eKl[�+��I��,!�
}����S����u�^��u�/���_��hu%�t�T����s�����.��q�B�v��p�a�5��q������5��d��%rv_��h�,��f(���]/%��O�Nuj��a���5�)����T��rF��u�P���s��l��x���y�����c���D}��v#��=�����"Q��D���rN]���5�dRy"���z�	b����|O�"�����Jg�6��9%I&�����,	��I��o�:c2��yE�3�h������^������OrBcK�!�<)�%q��4#_������E[��]J7�
�h^]t�lc�A�@E0-��5(���YT�^�,��!�t��s�F��|0;�'K���
cB[��8r��Q$��x��	#��47J�!�aL����e��F�^_rKC�AL!�d%�5�B*�t��
�nN%���B0A��X�E�ad��T"Tr~s��b���UAUm�x[-���E���(h!���&=�Cd�.��77ek�w����:��E!���&����d}0�2�H(z��`���SU����D�@�m��K�=)��;��	�'5��n��D�%i��������e]�^t�O�%�1$��JP��m��wg'������\no{��f�Zv'ZX!:�OYW,�S����=h���'���Qz�+�)��Q�k�:��
��mG�����V�aV����~
1�+:z�V�V�����P�?'�~��\��������m47��o�7�����j�dH�nW+���NM�(}�hB�������i�eK}<u������F�Gz���q��UC���1Vloly�*��|��S���y��7������"��sH>�%5�'�ar{?;>���j= 3#�+~���K-I9K]2������"i�����D��.�S�d
f���I�4��F�
:-�[���a�?w��U��}J�Z���~aV��B���E�QX��s��%j��)��#����0O�.G0�@B "���H�D3[�	tz���������~*$fQ�ye��fO�����*s���+���|*V���
��;j��N�]�6�����U`;\N���d��P>���"�U�(5����a�|g��p-�U$_�kn����<������aJ��r2����e�q]z��k�����,�!���3�Mh_?g�FR����Y��f�]]�M�nY)o>�����e��h���3X�%��-o���O~�H�rH
���V����06��������2��r��@�����aL���S@BMM��
��(|�����#����Y�n����L�E�����~;@��=�GSZt�u�w~|��T��	�qY��c)�`D�g���|B�?�fV��w"
�	�)J�$���s8����=Nb�w�X��]
�]���j��l#Z�d	����S��e���?T�3�)�`�&�Z�q���s�)c� ��#��#ChM�U������8�6Z�1P;r+�(}��%'k|�5�
�M/IG��Uh_����6�
<����XFz�j�<ND�P
���=P�h��#������4Va�l������.^�/;�W��wJc"����*'GS+����B�R�^����C�`��
:�*#%|�����5r�x|�U�<IF���D��~������*�!p��.�8��FV��=���<����7�������[!�6c�!�uZ+C��:u"2��O�yE�&��-�^]��&E�������h���P(�������w��>f]�fA�M��Z��0~�Tpy
��'a;W��N}[��Tk-��|����&���:�a;fNB��@z
���:V���*�����t����4H8gG6���J�^
T?A��T�C_��9�T���O��������D�<��k!fp�*e��Cb�s29���L�:%i���������1��L�����n�3�w�j��P���� ��ggws������|�"�Fu7�!�>
���8Q�Q�?/�O��O�J����HY�	�[�����?���3`�a I$���`t�t��E��gp�1������K@`���W�*�ds��V&@���O^�w�ph���m��-����������'��������h*='=�tl�2Nlz��??�����=���#?���4�]����"�l�Uam�� ���WA�(*@��B��x��S[������&Z<-9�K#_�\���hJ��Q��mxY�d����
�8=>qK4)�>���C�w���]J�~�A�T�����5u�s��~<n��V&lO�a��Y(��#�)
�,��>i^�������D�E����
��u�v���q[miUhK���w��h[\�y��f�8�y�	�������LE+�IL�=���Y���q�Lq.��S�tZ(�R�^mz��b�c��C(:��j�q3�����/���h�Y���?\K�����-��z��(�S1Qb��p|����E����oh"fN�{���k��op���V<2��lC��'�J�/�S~U4��I�Y�[��|"���I�Y��>��1������|c#�
������(M�|��O����?s7�G���i�1/�>����Q**�\fM��d�L<J�S��b��
� �I��jP3{xv����s�����q���{~q���I�U;��1n�(��-���:���1�HB�n���r�^_�t�\�t��r����R�����������3����Vg��i'���[6G'��8����N�����Z]a[Z�{C*�����������*����}�	x�%{Z���Lu�����Hs���Uy���~����>~A@�l��	%���b�z;����L���8.��>l���6����3K��ds�	1T��������Y+SF���eT`����
�0�������8��(i��:t"*�o��`w����2S7���E�4�G��|v|d�/�c����Pr�^n�q/�p��
��Z�������8�=Q�&�$$A(�������,si�O��2��#�*��@�������xg�8�2�O�(Xh��Y2��k'�OV���~$��Fh�K�,9,=n���z�,P[#�s��G:�.�"��v
eC������cz�#Yl���A�!\�	%����������Zo�{&<�"�Ja��xLH����jj����g+]�U�=�P��,N���G�m�py����p��)���-�,vt��J&�x�t�i�o�>���y:�!�O�i!o���e|���Z��%�Kq��;�T����,K*�"Qe�l��r��FV�I/_��L���.�����|8���e���v�"HA�����
�)�'}-�]���P�Uze:��/�7�����C`��g)(�EA\)ue����Q0�/��R��xn�O���+�@��5����?`��8����!Bd�����M���������I���]0"��b�
����C`X}Q����!c*W`
��,��k��*��f��I�Y&���,��s�~v���A��e�'����cK�
j����F�(��h\SE<��X�S�&i��H��R�("z^n��RW��
�+`��,��w���;��_��^Y+XWUYyk����_>1���Ai	Q���B5�?���5����!]$�&�����SwR�0$|��4�7���G)������k+u�d?�`/�Ul�e� UY�]�@`t0Y��hh�5�~����(�j��(+2�#*S�>y5���W�:�<"]aS��vri0�W!s�\@�i��d9��{�X
'����b��'p�V��,)A���w�3�8����@���Q�E.A�B�,M�/��g�-���d�����N�Z�w���0=��2������F���A���G�;��9�w�]�c[hA�gK��W�>k���]x
�f�����`b3t�I�],�����l!G�D��2��((�����(f�Ib*��4"���B�����1'�T��BO���J�]aZ����jM]h��B��� l@�c�	0ac�y)�^�V�J�'$=X./wU�2W�b��LKz��9�@w�XG��)�SY�!	3�[�t���"�I�fl(c�AQB&�����%s��$�+��j8g�Q����{�6*���p2���c����x"�S�����#c:7�%������?����\����#Q��2#��z�5[����|p�^$L�m�	��eXJ����q������/jQ��#���Pl�C���z��	����T#9z��F�9�����&���c"!El��^c�x���� ��I�pwK����1�����������{K]��af��i��jI6P(L|O�FV�Q�����M�o����.c�d|����gP)}��`J#&�;�%����I<hN�N���F���-+L9U�x
������O�@���zBn*�8Nq��
���}p`-��!������p�eu�M�2�k���N���=N����^u�F`�
0��A��X��y�T-�7��2Sn���$2��Z��������UG*��x@U��"��7H��G�NE�D��&] rK,W3�^���������:4"[+��x�_�&a������i�4v����8��r�$�p�j�y��{>kK�.���e�bY-��w����/+����Q������f81y�
���-8�%�r"���r&�p��q�������Y(��v~�0/��)U!�K���4b���"
��%�}D=������n����0}����k3��(�4~���5@��EAam#K?��2)�������O^�+d_�;�(�U �r2E$������!��@�WW�F����a���S@�I�W�������Z6����������'m"��NN:/!�jl���I����R���Rs�K�X�%W���z:mG�W�����.�0:Zuy���U���e���H!�g`8T��a0�stF�o��:9�*b�^��Q�1n����y-
Z����D�w��N@_���frzy!f�h.��~�R*�Lk=g9�lA����b��3��,�
:\�r	
��)�)�L!�1W����I��r����������_���Ml8��J{��h����i}�V�S�"�?��e<���V�mYf� ��D|72����`��hLNZ�LhL�G�A����Y������;��8K�VL����f�
���=.�R��[�f
"<��0�)�%�j����/���?�N�_�/���������EA>��\���P+���&�
����C�Y��%�Om<?��.�����	�����6�y�D��F��2�XW�2;d��T��j~~����������Q��V�F�Tu��K��C��4��G�gad�6�k ��\�PA�9��?#U�����$�i@�Kr@�����,�Z�<VU��e���c�iE#�@�)����\�B�����X]��{�#3+'���(IL��j���
�#���%�	Qd�����������#"
e:6H�W:8�}$z�&@R�S3���&��(���c+�%B{#���
w�����T�$���r��$#j<���
9���.!2��q�� ��`��_jR�b��2�:���eOX��-��t:D��"�h��F
S�a�g���	�����Z\\W�|�i���i��N�^�Ta��������p���L����_srj�i���3: q>i��L��Z
CyUbE�/�
.*�����E��U$yR+���2��SP�����t��P[~���$�QW*�q��b�< )�9+��*Hz46��Zf �JZ�V�u���}��&�f�_8h;M����v��/��,�*%�ObZd����������\�a�IN\~���r]��s�h����Uj-�tG���[�|l� i�U&�T�3���g���D�aTa�'���k��g�<�8��D�U�}��?+��+���2	r��:Np�Q����.��~�_�g��Q�e����%Y���`�)��%(EH+)M�zE�[�Y���E�����/S�;�
/q�&:W����Z���L�F���46Z.$W1q@�I5�@�CN�0�A��z�fE�p(�`�S=S��-�V�8�yA�G�]@�R%T��"dT����.�8p!MS��(<�ejF
�x��xh[�00���>�V��^��"�G��_��u9=&wS
��&�(0��r�8 p��
�F�@%�Y�:?�-��e_#�s
��j�Y����
WbF�����?������ 8`�h��p�0�����i}��
]�\�<���&�nms�Ju�{D�Q.i�a�*�K���6
�a����~Z+������9�\�O
"o6��F?����#��~�v��>0��8��]�9$�8�PM��u!�b�d�R
�R|ZE36	�[)>	��F-]�����/�\����+-\g��t-0/���f�k}�j����y�WC<��b�U���6��$��e����v���~o�3t	,��$-�X�i��ZNGSe����.Zy�p���g���)���JSBNx���g�?�.(�u(%����1ziy{��=s)L6�
���������xD-�8��q�qS&O@��1�3��������xM�)f�s����5U�;����SA��0������V�(��,��
V	�H����k�K���.����J�[(D#�5%������15sQw���Lk��%�2�4��K%A��]���V���.[q�y[^�DiS�w�2rAiD�#������O�����r~�f���eW�k-���q�!GW�'���.J15l�_��a��,0��"���,�[�q�"-��D�0!f&���\Ne�@>���Lcef�4$���R�����b�a0�h�2�HV���}��r{(�r�Z
����8�T�^�-.�B;	���a������c�6�u�k����Urw��u����<�3��(����n�C�a�Z	~��J��:O���}�L���K���O��'`�k�t�����G�(~���g����N����*��g��+����6�����q
@�Wj��
Df���Gu1$Y�l����Z�m ���%]%{7��E5�_N/~�R1��7v���������N
�[�T�YLS3����F���g������4��O���34���M!���Y1����O�Lp<�S�T������\gj����M���6�"��)T.���N�2���'��8(��F����0�
2�U)�J�����a����Jr��^.��9���p�5�0�A/�mXV_Y����ot">������,i]���fZb�+_�)�d.�e�&�N���BPYp$6�l����}�`WYh��r�,���j��JXy���p������<�Z]�f���p��*\l�R��iV(m�����{�����3u�����2��3�������|��V�A@?Tr�|"�������SZ��=�p�|�\���`GzMf�:S-�#�#���?��m�e��K��_b����xE��0:2�
D���K,����x�_��S��)�c�.�����s<E�B-�g������mN�Hu#�B�H3J��G���u��6H�K'4��Rq��yG-{*r�
3
��C-:����Fm���&N�K;#Y��q��	��l�:��G�.�����Y�f�����R�e�/�O��?6)QN�����0���|�9l$�y_,�sHU�1�I����������Z��k����n[	�5���SpT�c�������@5m��d��ml���4��H!!�CB�,rg
�8��}E�)n|��
��uZoa�w���Te1�LM��_���f��N�'�d�[XG����LZ�Z��C�N�Jx�p��q�#���]�]Y;��X�m2'�*����_ff�2���A����R);��#r��S���eV$�.���M�Zb���;�����!��[����X>fE��l�0�
39;+	,4�7)/M4Y7?���kZ��-��3��3����&������2NzL
�`j�Py*J�C��;����H�jsj���w��?�z� 7�*J�s��"_�'��3�8��x�B4��
��R\%�������7L#�?�}
<�9�������fp4|�`�]��$�IJ���z@@�=���HU+�
D�{�+�o���{�<�\n+	FS;$���]�fO�O�������Jq�;�0�g�k��D,��ku�i.�L�J�'R�f�z�����GS�e�[6�+�~Y����^g�:��L��u�a��iwr{�?����;��f����C���t��H���WI��"e8�o��"����V�$f�F�`������/����V��8^��$�9�������D�W=�$�e������%��������������N�]@�������m`!U3�@^�J�(���O�����Gj��\��7�7�7�7|���}E��Et��@e���b�R
3`[�i���3ui�^k�~�������]G:�E�.SXv�lV�����
��"�9"���"���F=���%��g�G�(�>��F��2'�����4��d�����o�L>tSngX���S1-�V�hw/�8��f��>=�O�u�m7�~�1�R��')N#��ZU�(�e����O�b�t�:x3�,G�r������b�\��V�~����i��Do���f�e�]2��z.�S5��k������4������,A�NRA[�TJvZ�H�(���EG��
�W����U����(��`�i&��0�qn��Q��04��;}��m��/n��t�%���k�O0�
-��B����V�>��r����lf������<S_Q�������6=0��sW�
�f��kn	�
o��}?��[�T�33�~�Z���H�.-�K�����0����~<��	�c���;��5���Yc��	��c��C����2�o����e$���M����b��4OB�|	rl*uP�D��9jA��)�A�Y=�e��a��2:Frs��d�i�'�H�
���#9���\N	�U�������L���)�\H'V 1�P���AA��,�H�;j�]tE�W�A<��
���O������+@���tO��!��-���W~w�A�>�%��^	����5+I���;e�TgR�u�H#?�Q`u�/''�z9��zS��bS6I�@���__W��&�VGI�76���{��o�+��o���UY�Q���]�������5�u$��%3���W<��H�K�P����0%/e���S�8�vt���I�%������������tOnn��t
J*��-J�H9K�S��c\%:v���$���"(�e�3
��
�;t(���q@=����a���O3`��7x�T��2��O�@"��K�����
l�d�u��B�����Y(��f�����"�R�PTN40���}#`�U�"�os���}�1�?�G�����7��c���x#y2��B*e{����1>gC�&��#�>�u�H��;�a{e�]����%��3�3�C��+�.i��8g���oQ5�<=��d2R�z)��V��C�L����g���_�LS��B�>���Sq'�������1���Dk^�O8�w���I����
�[
��GFHb���BYHS?�#�
�*5�3�	�`��v���f��o��Hg�� ����#�Y��#/E'2es�v���8��8;;���(xP"PQ-<j]rW�����^2�U�WW&�����]
��dz�>KV�0B�*pS0\C5����w��_�c��_��m��^!?n@G7A��h��F�4{�JC�Q����I��A^�N�P�a�y
��'d�%tn!u�H����-|����0��HVC��>W�<I�z�[�xaA-��V�|�<��f��9�pe���CMkP}*Pl�������x���c�q����fE���\���#��IH �n�T�/V�K���8P�������b�����%��������;��F�]'���k���k�F�mE�vRe�24�3�92"OK��V46�W5})��&�)���`J��A���hi�ZP��2�����-A���E>���9�������L�G��c*"!�i��90����29��dd�zuh�]�:�����K]���2�p�y*Y���fB�C��$@o�z�����r��:����2pr8�"�����x?��
^��]C����������y�Y�rPO�*B�������F��b��� ��g�V(T���}���sXa��T�l��#��|�k>��5{�
T��
i3��a���|�Ac������������3�l�����%��[������������t���S����w��7���}3K^b��N���������M�5(���o�k���!�2�9���A��+����v���[�/���d���Y[L��+t���zq��F\���a�M�9v����NTHc�>Y����[�"},Pl@�����X�[=�f��������J9L�����)�����E�����?Lso�<����Ri�+���t�,)u�@�n���<���F��5M�xmvFy[.���� ��H �;;[��
�<�.1���W7�^���T~(�f����[���#�	��sIf�����v����������65�;���&�IP�����w�/�/:��''5���5%�Pk���=�����x�����I���P����0@��>��&�KywP�J����e\�����~�E*���;��8�%rphK��e0c�R=���m.�_�H��\NM���
rYL[Gq�r�����bv}�6[F�x�Y�w�f7�D)���lA�?`��A�����7+4l`|��+!�&��7^�f�s��Hrf�O9r��'3	8���*����j^�2]�y���(�q@�<���i����Y�
��1R_�^+�m��'F,��M(��K}�����93t>fiMPH��X)3����
P����4����mm����!�N���\.���V�1X�k��m����N�����k�fkv��B�-�������0�]�
c{3<`�Yg����i���@���F:�rR��%�}lQ0xvY�HAjUF$����z�CpM�!�c�;��1
�U�v�1K7�_{��"n�j��������.���7�9�J/�JG��=��Z3F��9��ya�q�`c�6f���zm����8�,���VU`$�Bg���*w��*x7&���ApZD�^*==�o#���8�����H��:\�X�L��y�u.	7��7���{�2OE��*I�
�j7Be�/V%4|��E1�l�����	���z+�����E�:c8hg,�%�t���-U���yR��=c�y���e����N��i�$��}dW-� �%��xU/����>i^r�mOHE���������8{m��d���[�Q�����*_�
:�`���Q�$Cb��.�s*Y���e�8L��>������8�����tl&��������y?�L���44�~\�ls���73Y�������
��*^�,f	R-@����VQ7\n����h���6��3B@h�,{R2e��3����E)���7a�V��(���]��9������v�fc�<��:
��B<h�j5X��n��U#K�#ebad*���Xm�N�����m�g����gU��J`���)l&�?�g�!�N��)�v52����~Mj�d{X1%�>���N�]����;�8��(�7V�B��$�\�3��y(�G�	�L.���k�.��z�~������)���G=l���A?��������a�N��X�d�0]��@��n�����5�������x�����T��[{��f��m6�i��jx��D�������L/�w�S3Np���6[j��������67�����q��.g�}Q�>?�G�TO|�W�f��BG�6���%���s2I=��a��{!�)}��rsgw�oy�MkX=�cQ:�������v�����P����Yq7w�7������9F����M���`��k���[���p
m]���Q<��"Q�%���m�x{;-sm��2~��gn�����{����^3?%k��$�Y�!7�x_EX����>	�F��OF��_��W"iy�����������%�~ �-����_}#1���[h�����������$�fD>�#���wg�\�
�<*�����\w�G��k��;0q����C?�j����uv��]�w�������cX
���9A��K~���Dz�>avA'Yd�A������Mm�o{M��<��G��^�;���V��eBV%�l���?"�S���w�e=�2"�kRb�*DF�a��Gd�z=�����+��_������� cfU�������{vDi	�����X� �*�8�@�4?��P�������YW�8�a���tda�r�m�?�	~�>?�@'�~0�j�
��mn�3�=��vq�Vx|0�o��<���I��������e)���������������_����k�M���&�L1Db]v�w9����������cP�d���rO���E�]�D����2k{?N�������0���)P,��Z������/�QH$����^d@"��f~%�����?3���w��(@�R����F���_���mo���o�eG��fo�������7�3ho�9~������/~����=������BY��_����l��[�����57�{&�&�(+�H��ZHT���=iq��(��|�"��������kF����U[U�%���0�u@�8�>��E}��Y��\a�4�i/�J�V��D�}���8i<��6$0t��Q�g����f|���KrO\mk�@��D�v���}����5��x�N��#��
�rp��O���QN�����_������W�����#�k_�>E�t~�:��������#���s��+F�5_�{�lK��k�����B�6"fU���WZa��%cw�5�k"L8����Uxe��[w����M)���Y!U#������&����oL" .���v�OXs|��y������u�o��a�o����u%�R*
�a���-?v�\�zg�e�s�j���z�n8�\����u��m�����U�y�m�7�J^�`��
�
+?�|O�_K��[ni���b����N����K������>?�hO=�\b6�R�6��F>����<�8
U��)srnS����6��/�i%���Skg{�k���[��#1�&��������{{e��_�����g��������JP�M?'U@��YQ��l�p��Q�Dd����$��q�@B�{'��[��{�H ���?��	�l��%�����P5v"#�5f�0�`�Z ;��=J7�.��P&�=O���0�	�����'B���?��'��C����I�����$���Y���w�wH	|I�	2Yd|�_huR��R����R�(��F�WI<�
�0wi��� ��z���O|V�;��(�	�0�_m�0�PU�y5q�{f���<�$�����������_�A��d���4�-��7���p��q��$��C��W�K;��: R��	���m�>�{A�����"�H�����C�x�M�o��j^�[5�2�������P5hZw����
~_Y�V��*������&(3������p+'�����P����Y8�7���oN	�~J\���q��mti��t�W��N�����66>����=�+���p]���U��Y��^�������b�!���6 {��>/-�U�>][�:���|� [�xMV��@����Z�w��C��x�CL3�]z�b������o��d2�2c�s���1�-�J���������G]tw��r;�r��Moso����G��'up��8:��8iw��������<>=�Gg����k
]__���+Y���\ZQ���N[�Oes����#`����/���#�y����k���c�����%�|;�:�'��j�������}xEQ�`p�s~���}(~�/��r4/`$������'����K9C�����{vrr�v����������S��,�u�n������}<�����a���3u�'-1��B�i�����w5G
�6W����������4���q�]�?0��oaW1)��a��/���������6�����7������ ��^���3�����zT5'���������C����QK��$���4j���6��ZX���C�������W��_�XqZ�_),����*�+��6�N_O���U�}A�����
V�������g�����������gU=�����X������\nq[)Vg�=��*\]�lU�t�<��a>��c|����-:�a����PL�a+�.����P�Y�0�h��k�6=�m�n���#�~}~��x�&������d_�,v)��{���6�(�e�z��������	����U�^)@����G?���I8�������W�/���
G?���=u��nv_�P�_o����Z�y�;j�<�:�\�?e�t|>0��H�-mS4e ��T����,/����������8xR����@��Q��r���(��"��
��lV�~����6�C�K�	�Dj�	����}��oUN<�R���B�����'L�8h�K�
:�@ZShLr'g�DA��a��,^���������|��"Y-��rRQ�	��#}�����	7�Px��8����G�/��G���o�
�rz��h��/������O��� GN8<;��}A �oqrp�����<;o_\gB�%����Lh��7F�g'W��y���\���3��5m��\wt~p�������XY�.����0�����.x�O���E�U��'��M�����x�l���w�����;����^$Zb�gs�#����:\f��� /\������z������{�R���*�[Ep.�����������oT�}��`���kh�f�NC�B��;�k��~0H�Q��>�������5�w�@�#9T�"uz�������q�k�*���}��I�}�)o>2�� �~�P�U2�pIT���
��"��<�i�Q�lJQ����z��&O*��[^k}�����ZN3<%uyR|�|�j���~�5g���r�����[[���v������s�������U��v���14�KZ+l�<�������=��|?��<���X�k.;��=�g�s�`���2WP�����2����'�KD����)�\��-�G�v�Y���[�M������S�[�u��aJ3��5���m����I����-�7Y~��9���R��*kJ�K�����d�{X�����������6j�LZ`��Q����\����<l��,����oeg��L������n�#�:iW)�|���Ru/�cv�x|��7����������zs��q��$�t{5��Qx�;�)>(��
9��$���'� ���Rq>Nn���������i�����4��s[�{��,	��8�����'kE�L�>4�s���#���_37��Y�VS;�T�S���}�z!����k�"l��	Z:����xt������
�-\���1l���&�+	}���T��	�}���$�UO�oG���T�`�#�gGc�d�Zt�]����)U��}|zt|A�#��������V��"����/�Q	�,Thb�'7��,�:�5f}��ka��r�H<�
i����a{k�����7�����
������w�Sk&H�+�����#m��ooz-�|�va�AT	*��;��4U�>�h���@b������"Tp<o��)����c�f�q��X�8%A`�Y~����xpq|�����h�4
TKPH�+A���x�i#U��4��Qj�AF�N�y
k2�
���2n-4����n����D\�0n�<eV�{/Pc���p���Z���1�hb:���B5m	���������I��|��DazUzW,V�~�6�C�S��`�����tp���5�����J7��*��u�O��&��0���M�t���Y�o]�g23����1P$�=��0��}��C!c��K���'j�m�7�0�D^#gc�]���1/R���I�P�Y7�E����	�|��?4�����s>�LPSY��WN����=Ezl��?0�y��VWSL�����u=�S���n��������7Y������u�tf���	(�'�5��'4�5�K�1��"Y#��#<6���e�y���������(u�^��*����#��0�Hx����T�y�,0h����zt�vs�(��Bh�m��f�V�i5�`��
bL�Z0R�0`"
\`��x�\N\���~t
�5�Y+1Fj��PF|=��6�Y���l(�,�;����+pA���%SDn(~��v1���)��"�bz�s����FP�2��9@9cX`0.O
O1���+e xAb�\����yI\\��*�)�V�^���S�|�r���j����j�l�}�~�-��W��������F���K���g��QzW�3�����X�
�	�V������ha����ys�H�)C���Jq���sV��VY�s���t���s
`K0C��t�|�&����t�J�����](�-�?kYAJ�^	�%*�^|S;j��z���}�u����b��t���iDT�%T�A�(|^3�����z�A�77���A�!�7j��*$�8�)������E
��DyRR���4���������U�����
�iS�����g#a��k�b�x����D��0���r��<N��iFdr,&��
���ob�\�s��9�H^�Q#����|<���*�!�<<�����m��4�4�g;X����;m^z�������t���h���1	�`
G�$��s�����xrs��e���RM�
p�o�������}k�a*�QY��\�����<>9��E���+!���yf�D�X	Z�0,%��'Z�����X6j�1���]�XN�n�8rI3{���d�F�@�N���2��'k�
��40��V���b!�|i��?�
Q�����=F�YC�~�"�,�sr�{��c��8��r(*sA�a����(r�Mb �$�9�dn+���r^��X�'���
}�^3D@N�����
������#9o+^����G]�e�x/��J���AI<r3���7Qo��1��~��)9_������������O���?�v�����s�7��p>���P# ��,����x����2Hf���M����c�bL�d���_c����9�%��z���.�����x���aL9<���o�r�����uW��m-C��I8��Y�fU������M������'�:��3�z�����$V����:���^�w�Lz�n��X���@@��	�{�E�q��w
S�=�'{��������%���i�Rx���u���D�r��	��8�K�da��Z�C�����:
3��!2�
W��!�t��������z��
�l��]����V����s����M��Q*�����Fc0�Y��(Xb��%R
���I}�K�Z#qh�WL-Y&l���9��������1.|D���[��bXV�(�0���T�Ay8
���z��J���/S��������5������hj��U�AR]Io���LZ2�*BC�B�YA���J�V$����i�l+L`]*4z@����SO���
j�!��;hn�JoD�;W.�;�Q|BU�1�9���40	D���K8�����S����)��>E�KEze�;&��,R�=n�����;&|D�?�z�H'S����(^\a"�l
����}i�<�1�U`���z��l�P����I+^R��u ����6'�����3Q*=Z�c�cS�$� a�\*H9����A���:L%�C��'0�!�B��$�n���
������V�u2\S�StrTlt��%�YN�7�[%c�O�%�5&U����@��zA.��|�����Vb`Z^5�A��
���w�)q�Q]���� (����(M�2{����?��BU�x,�
�#k�M8&A�	�?�	#���^xKa?
�`�QR�{���/���cC�HZ�0M�ji!��i��TE��0�)�u|��n����#�.���W���-�����e�K+��l�����
���0��\h�����������y��g+XO��mE�����	���KF=�/pf�]��*��?&����V>'F[<)�&L�z�`_d_��p����"4����=����5�rRm��d{eE`��1��HXt7������R�����Y���O��-U\*������a�,����F��������C��c��&ev����u7,_]�s�����(�N���_������M����C���M��(7~r
4��7��8U;���(s���������o��4.V����9B/E������J����(���o{-��JcY8�6��������,T`	,�bF���~�D�l:�����j�V��qN^�maJ�5�����X��Z���I��@���J6�H��1�c��e�,����`90N�h"�;N�@���r"*)]3w
}X9M�#�Ua>�������K�PB�`H����Cyuz�~y|�>��+B=/�e��	��(�'��`�@��\���T�IF�/nb�NL�=����e��o\K2��_��%E�����Rl�*��� #dq��C�]�x�++��I��<�B�b�F:�^W��8:6I��:�KjMt�RH7�S�W�a�>�Vy��iC��YJ�5�B l����
�����n��t+h�$�����(1�A�����P{����������[>5 ���w>��%y!qZ�
��0f�EBX�;���5�~�O�d�����e������s�����~7�hK$�[-�w�gn�O�a_!����}#�K�Nx�t�`��T�!�N�k#��I���;�������]����ml��k��f�lW�h�]E�1G#t��L�����a���D������\��6���R������1�ZZ�#w������%�G��DI	K����T�����?cD�
!��^E0�s����fST@Fw�����O�PP��`�����SYPJ��K�x���R����PQ~:�$��R���_���%�����d��4 ]�YS
�k�0�4�����?�bY�Y�^�#CXu
a:
��=�)�
���&mN�\On�>���\p�)8�������N�ZN
�� $� ���w��B�>�H*���e��8
����*����@��
	���?���8�����*0�����	���h��F�����u����>D��.�	����a�t��w_���,\����e.B��	�a�(�7I0+��lvcjiU�A��V��~���O�$�?���Ij+��"��6�4�����S�O�s��D������7l���n�{�v�I�XQu��ZHE��R�"q������������5�wQG����x&l�P5u��bX�X��������]�}�c���*Do�$�H_�&],O��X�����MD����45��������e��U$�*�.�4��.��;Xup�^�/�z���]f���$>��A����r)G��E�$B��
`r�_������'�:�g��gd���7!Y6Eq<�-��J!:��h���e��'�����=9�\v�O��0��~������tsP���f�)1O�e��mK�&p�ec�����.o]�K��:X��D(���AB�2�4��7��i��"}�G�p�h$�D#*#��=�$�����rDl�M	<}������ L+�H����T��pfXH���-�AH�E��5>D�HU��|���2��~�f{����B��>�O�@p�P�!�����>38�%�����c������]���\������9�=R�X��@�3>�tw,���P��"��*���2�B�zWl}�S
��;��y����BS�)������
�������u�n�A�W4��@��Z� /mM�j���r������E��5AM�x.�zS��:����:�qi`����hm}'K0/���z���}���pMl2�;� +���/�'����\{���&������/��<�`2�5P�fRw�R/�`X�/Y�*��XT��&�,=���#������b8mW��f���>T����[r� ��R��+I ��O^d[^��;�E��QRyn����y6��j(�!���}��/�<j>G|w	�k�������(���-=�Tm��z��%%�<�Q�v�M�[�8��boIL��p�;�Psp��dY��K�������~��r��B��VPT8�|�;�,�����F	��[�O������|.h�E�/:������"�������,&����3l%��"�!oN�J���-]�� d��� �1�MPk��8y���p
�vZ�f�,1�1�~���E�D]�p���-+��t7��Qz��J��9Y�G��,����#f��+D��>���
h��7j�����:W���}�
����gx�����I��R�S����*��G�8}��G��)����,����]@�
�	ba���8��)�`��d����r?t7���e�����u����b+�����**�rQ�7�����H�1���7������=�&S6�FI3���-�������u���>-�t�������{����|�������(m��t���!��Z�EXpj���v��0�l����kn/��H�����L�YT�������8�l1]�}��m�c0zT����	��F�eH���e����v*�87*)���N���L��C�41�V�k4e�����i,�*��{�����[���F�h��.���U���2r��K�������W�.�T��)\��i�'=rO�)��J���66��XB_�����C)w���Uvj�~(<K����%�+?����aLO��H77��	C���)�dk1R�JId�f��P��g�?�e3��CH�D0e��NK]�1���bF�9neh�{��x G���1��ZP��YC���u���S`#��i.T>��6R>���s�m`4��
���a����D�72����.�����\��<n_t;��
����2��?]p�G�9cXB.�hK���i@���u
����������p�Afn�����q����������Ifr��B���`:���UN�|�eEn��N��������b�Y�K�����mH�b3�_�z�T�4�4��\%��?��m���V���������F��
�5�[�|�G"����hf]�
��;8��,�}�':��������\=�(��@��v�9#(���y[{��1�Sb�"�5MZH�J*��0=�AaF������B;(g!%+�+�;aB�%P_<A$I���_��yo'���Kl��1��~i����;�M>���-��d�������L�����	�v����3�����'h���Y[�}���g��4���$98�L�Q+�|�Y��tkf��n����vwc�����MK��D���e��8����%������+�(
4�QA%����O�;��#]v�����+����|��@R6�FC}�>���m�@qT�l�D��QO�a"
c���HT��A�FpC")J���RP���w ��dS��"��q���9r'�uc�H����������L�G6���� �*���,����lH����i1������i�b��d��g���%���e"-|��1���6Y����{�&������i��� ^e����r��gBy���_���]��u������]��f���R�|��ld���j�YG��0�s�{��(D��jSB,���Q��
][y
�CMM���1�7�����*�Y�����&��u�N��E����J������S��j_��{aD��&�1����1��]�������Q����8�(��u�Qz�D�(>f
��
�7��GP����� ���&�:�#���#8�T&=�����?\PL_h]�Eo�
J�777�iX��F??�n��0���������������D�����4�������t�V�Xu�������;8<�w}�7��+x��JzEXm����(<��H0 [�9,G7���h��fsg�5h67�f+7?������(����1�Ht�`,A�
��eY���VI�86���<�A��G�{ky��hFobZo1Zv��H����0����s6�N��<��{w(����*L��t������ao6���8CBo`��W|���]�D�&��%�&�Z;&��G��W/�`�, e*;��Ip�G����k�h,6c������
�n&�RSh��5�C��Xl��^��m`��bu|�5����/�4���;��fG�U��a�'����&�����C��h���~7~�8T!�mb(��P6]
+�������%����:~OT������H��>E����U�[Hr1n���GR�6�vk��u���2���&��0hha�E�@�'6FQ���*J�y�Jr/BK���&c�7����SD������������3���o����L�#+>��v[O�U�x�����F��`	��1�H��t�W�'���y@���7��
2�^_m���}�h�0�
�����b`�aI�"��]�$#��Y�y�i@X�XW��j;V�rY��
�����w�������8"�3%�Xb1c�;��$�.0��3�
�|#�C�����4��>-L'Y,w�'�\�]C������Q�]C�����0
	 V��g�m��w���>;>��2�]n���t��x�����$P�Th%��|�����	P7lt��R���d�v�o/������Vk /���)����;`���a��?��=�(��1�N�������]wD����o�5�9����Z9�U #n@�gY��h�eP_F�<�e�JRT�I��yR�b)��,)!�]X�4�3*r7�OWP@X..���Z�r��FAr���o ���y�a@���T���������~��m�*!9-�����\���f�c4q@�;������
Vt#O�����:j���&dAG+���n����L~���!��n�>�J�}���L�����R58�.���/�WyR !���gx���ij��H���q�\5�%'�������]�����y����>��'v�I��o��=}���}���;�}C��K�E|I]tD��"�|(�
�����u�����k-BZb��R�{^)D�o��^kkg����b6��|�L���(o�51�&%1���WJ�`��.FIq&�~t�������>:L�q:)�T�3��!���R�#%��Dw$>��"$����)e��T)��b����&7���)����$C�%����\��	�DV��lF�&�<Q
�����*����T
%�Y�]Df������S>@s� :B
y����|��D����C��m��3q+����?�~���88=��ml�T���z�$�j@E�����IzuVyf��$ �(�8�|�R��zus�8������N�.������}xu�9��-�A������y5�O��<=B�U�����cAh3-
���+��%�1�B��Sppr���A�7�`s���Q���&?c�}A��Z���{�N�3�7
��������95V\�:5C�c
��a�G���B�����5��v������dx���F9J���z�����\���h�X����O_������~�=���}FXQ��Wb�T��8��Y�
8�zQus�����
�����X�����z�c�K����N��|��L:�,��\c�d���\��8�[*y5
�s�1JN��������whG����b�dI����X�ceUE���nR����=�4���Y7
{�����20p��-����2��g�9�� �������$Y��$���V|�T�[������������ �e�?*l<����@��"'F~�����Hq���H�Qhk_Y�q[�.#E��~���������|N�::%S��P�1��.S����m9p='������a]6H�a���l�Ae�k{o��j|e��y�T4Hhk��$)1�10�v�F['�0����n���]�	��J��<��-��w�]�@�M{=-z����5��!��S�����ng����S�������AOd
����q1��z���^��\��0O�'OgCA��U&Y(�O� ���I0de��D�Z�EP����j��e4
�m��H$�b����H5A��/C,�[�9�#��\����q��<xU���::��tW�[�����������c>�j�D�gAy��X�~�ES�i�k7c�;i���U'Y�p�CX��f�SLN�xc�V�f�|�
��)����CZ��E�W��$'��EqW�������|��������;��,�8q,�|jc��-�����`����qC��gl�~^����,LMm`v�}�o7b�%�xa��r����p��=��M�A�����p��
1D��6���hn�z����C�*Nwo:���0D��������y���]��#�48?�C���G��/>�AY*[��`
\[`M�������m����#�ARLGJ������a��*h�����_��(�=��;�|6�g���<|��������^ll3�z�kpm����AdV
��lric��&�F��7����o��!��gj�����'7�l�J�m	���,����
e�%Cu(0���Fk�Z#�,@��
����|��y�
C0���5�R��+6����?���3Uwh������?�O�c-�5m�����y^B�����/C?���-�6�67�BG��}^L����4h�?z�U���<0���F3�3	2�'$q����]�i
�,�z�1�mGF?�d���\�}�c�D5�;;�����E%!�#�}5
=6�����$�@������J���Q������#���^#�8��^�$l}2��1jlc1{o�d,5��'H�'Z�����t�
�I;�qgs�����S�2d}�)�f`�Z
�!bB�Z����j2W�g�Z�b����e�@�=���O��,zNh����N�B�T`	G���He��~*C�������\���	�V?a&���$�g������>}�����"
����$t'��x�#��j�6�F*�~�Jxxn����*W\F $�I:-��'4��}]�7bv��6Y,C,�x)(�,�
������P�m��W�v�A����'Q�Y-3���wu�/���_�o]��zs^���j�k���JYc�o��m~��\~���Y���Z�6�p���7��h<jM�� ��yN�tJ�����s����
#���L���'"N�=�:)#��F���{��YX����������o�y�>����Q����U����z0��7W���?�%�^��u�/���_���8�Fw&��HR�������T�'@��~R�<���z "�6�\��h�&��	���[\�u[�[eVlk}o��j6�������K�44H��rY6N��M3�@_��,��Y���1����"�I�0F�e�����*�"'T�����`�0S7��`�(#�r:V�����=��G=N$�����#��<��4GP��3jn��t����p4�6d���T�;�{��L{�qUk{��j�~EfA���.X+����a�F���6FAv�+hT�n-�Dz�H��86��������qp�v����=���s�'i`�'_�Q�8I�,*�0�7),S�,~D�g�$t��C�Z����!�q���&�iwL+�����vw6�������il`�qC��w�Q���U���6�6V7�����F��:7X�F���c�fO0��.px���V��og���
��������B
��'��?�b�rS��RO�>#���f���"Y0�,��1�/���P0���L����1����W�+��Mo����_�K	������o�z��l�nc��UxR�g���C��S=���z��X����M8�;[;���s5q�~�����S�����a��{%�U�	k���T���ONo�ooy����_��fyo��`a{�
jTnQ��?����pe�f=�$M9J_��m!���2�������x����w��M����}O�<��`�� �_���jy����[��k�7NJ.����c�����������#8�~�4#g!kv��������rX��/��w�����9v�jg����J�����E������_j\B,/-)�Kb$���tV��1d��Y����,���x�h<���{������$k8i�cZ����W��7���������n��&�
����������_�K
]y%6�Y�(��/@��L���92���F���w�=E��_3t~(��n���
��noq��T����/��N������b��J��Rl@_t���E��8P�����)m��u�olnx�;_�~a��x�P�08'���'@���Y��kp��_*�������	�\�O��d��.�.��� �������;����j>0;����-o{wK;���Wzb��[}.3�Hs0��������	���q���<F����$��pZ�����v����������s��B�9��0u.��6\E[��`��67���������Z������*U�@XE ��?	8K�2U%_3�����$������j�lk�`�����'H�<����&��u��c�#�s1�����������LQe1=@�Y4��Y�T�T')[�aM�a�G�rI�����~�G������xtqv.4����}
������>�h\�����th�>���g����G����q�������)h�c>���(K���gL����I�)�k�_q0j�T���`����
f��
��\����.NO�C!;\d��j�0H����=��`�:i����q�8X2)�� �v�!����^��l]n����������C��M��sa����0U�g���;�-Y�V�ZZc��"����^og${�u���]oOzp#�]�4N�����C��	�t�����BT�8^u�����Gq?�s��0�"����8�q��(�LrQ�)9�n'Y����-��$�u�vS��L}���>9�O��m7Z^sc�9_@~Sq���
���S�/L	���������<����������Y�	��z\D`^:��)�����b��4�98�s3�~#3X<�0G�m����0�8��$%8����4��VSJTp�I��j�V��HG���Z��x�������e����[z�IU���q�@$p.�����=VC)33�����kf�3�j���"��QC����h/���<s���*�C�m�i�����&�@R0B�Q�Fq<�-c�l�Ka|��Z��X����a�wW�\�8a�T������[�����k�K�������M�g$^v�����cQ�����mo�5c���c��F�:l,������\oI������A�g(g8��������5|A�*������<:��v-�u��HQ6�Q_������!j�C�/S��
��ze���J���	L$��h�i�[���XN�GU8��=������~���/������"�[���5���F2�7������gH����2��[y�'\Z3Rr+�f����s�����~�HH����X�:N�����'�L���		#:�8��>�^������S�[���
��j�ub��M�/�%��������zB�q<jB2C����g�Py:�I����������.Oc.���R#�����3�SX�9�U����Aw�*9��?P�s6���>��gb\Ec�uf�(������z�������:Ow���������1�������I��`x��1����LM����4�vhG��4h�l��<����A)�5��x���UC($��d�3���U6�pJY�+_��R:W��5��n.Y�Q�b��KzL0��!`���@��p���9���u��\_#��'ej�0b���|��6���L���jw��~)9���P���0��}�h�0��!����}:��h2��9��p����,�����2���?��Ef��%?J�4���_A�������+D����������/I�@�:�0��KY�-\*9}%��N_���
�So7;���m�Y��WD�����X2@��v+gp�s�r/�yZ���+�����!�Jlh���pxt����;V�6����|����{^�%#����W��&�9G��X�B��<��/��mm�XSi�������������_�./���3a��").'������V&�B#�V�x8Oo+��6�T��xG5\
��u�0�4��?jCy��\8��t�-��:=D�Y5�d��)h���I����M�S�f�*����X6���LA�&/��<��u���`�����U(D8JA�H7�<�����E��{�>o��O���xp��3�N�'WM��_Ct3���h����~�"l�����E^���:��)������mlz�����"�E�P�EG����I))8^t�W�H���d���{.|�<�gM��(�L�?&!^�~�O���C(�^�i���R*?n.���c�!D��E�A4�x	US���=��R�����0F,{�	�2Q84U\^J��N�c�T�NN9�%4�Y����<�5U�;x@Jsw��
�:���3�P���8^�oq��c-�+ �%`��J�N��W+�����8�8
��?�y�q��Af�-�8XX�����tP����U���������������&�o#X��&�}����FN�.^C�F��Hp�a�oC�����)��
F��ml���'�[8>E4�&�[j�������)[f��pj�_q��pL�@J��=��%�+*+�pxO����U�C��-R�JC��~����&I����m0Yt�p@8���W����ji�	����^ss�qO�H�Oc��
�q;We��t:��g��W��N�������X��X�'��������������������*~�~ypx�I�!1�$y�bT|������GX ���_���ZJ���s)^�<�Tc
�X^��u���U�?$A/N�]FV]���k�v$q[qY"aIXk}�k5[F�r��Ez�f����J�-��
�VwY&&����+"������kc��k�r�<����r���Y4k��������[�n
c�Q|�G7A�<���%��y�l��X
)���Z����F:8�j
���L�5�F�����C�q!���F��������r��X#
�U���;T����0h�j�LnK��<N�065����<"�����������#?y���]Q�B���4�P$2�~6
�5R�R�Z�O\��W����j��y�����z�E�	P\�ac�z�}|����[{�[&`�5���RN*���#
`+�,Rg\6��`,UE��B�y��y�GC�n<����vb���6D����s;�j���HB+����p��a������]�_MboO�L���Y�f�R
E�$�@�9���Y����>%9�Z�cA)�1������1��D�������,Xz��������� ���`~���m�(�����N����Q`���|l
��s��y�#�U�mK6�3����<(�G�����.��m�u�e�kx��-���C��a<���65 2�{{������%��&	:�8���5P�G�[��MB�WI<�jj��
�1��^E!�����'���@E�o�l�����]�&������7ac<�P��z?e�e�DWC!L�
����:Z3S�|R��=4
����#��F����t$��0��8��i���TzA�x�0�!/�\��ee9%�=.-Y�9�,`�{��@��\:@���S�@�=;B�S�l�7�z�E�p!�p%`�m�!,���+�=|�5`�M��%e��D���8��%)���l���WQ
�e��O��Hf��G���a��������%���WX���	0�q�������Q��M��(�PwK��p�����h��8����G�!��T/��T&lv�#�@���d����a�9�.�lF����]	:P�9��������&dp�S�@^v�B�JT���Qd��0^�����D@��9
_F��'Xt�"��
��(W`��$����t�e�M�"�2�TZ�{���b6������2&x�Q6g�@!���'�9�3�5��[-Q�uKbD�]�zZZ:u�9�Y]A9`�p����/������m��,�������S�jTX���s���Mw�������rkkY,������Nsw����'�8�=������^|2����4���{�[yd<����&.���<��H�%�6�[��\�M��p���.�.[�*���g��j|�d�E@4����b�[<�!F^K��o������n���:�;������
|5�K���)���p9����@��+�w��3�O��1z.�WQ�lP���pD�`�����S��i�T3'�MhnO����gc|�#�*�O�4��2�T�P�t������U ���}���+�u���k��D��h'��Aj���!���'�XMN���9d�������2��2�%r�%���?�?������m�������E�4G�%�^�	��V�T��Zy�$�f7��
E���wu�rdz9x�w7`����1}U����uus�N>��������*�Q��x���2Wu�JS�4a�h�,jK�'/=����N��K������\`�4H=ib�i�J��3�ig�>#��~8�H��lm
���*�����<9���S�Z������l� _"Z
O��z�-�O4!t/���k"n����&-5d��b��hrANBs^KH����@��������+��7a���(!69e�������5��,�5�t~����9&l����-��`���m<���7�����F��N�s?����&�XD����m����Je�;KI���j �nx����O�P��Yz>���#�/k�_�q�f�?��������I0<%�l��P{����<;�\�\����<({�>��
�x0�C�UX�E��������m�����B�\����K�{�v9L4�M�;�RI@��Td�>+�S:I�T����T�N�V�KP����j����J����������D�����~���uC��U��\{�	�Dn�
"�4v�Y���4�)��JQ��4�V3^P���j��
�����I"�����3}Q
@!W�a�����t���+Ub��2��[��p�dwt�e��t���8��4�6�!��
%R7�p�%)Z������� ���t4���o���GF.�e�������f��+��'Yy	�Z{p��iQ�-2E�
..c&a�h�.��c����)�<��>��q�%��%�����=�4v�m�����F��U�XGU+���;�%3�1th����C�~�>���z
X��k��"2H��S���N���P	[�����5~&;�JH��kWr%��X5(p4U�L�+���:!��iV�<�Yv���P��HK�������`^+�3�Bo_mI��J�Bw����>L
J��d�?��*�e��!��<|R�w'����Y�yWk^��U�e���#2��r/��~3�B����o�����V"�42�rL�"�o����?���y\���r��2���O'	l�w*(�Z�������j]�7,��Ry���.��`��l��+����!L���zl�q�7���!�G���c�����z2�'�F{��W���B�\t������g���~���W.�Y�r
�Bng��M>�*������L��N�s}������g�R��O��|q�i[��^���'v�����O�O�N�|suJ��*f7��=��r��9���ns��51���f��<��B.-1<���A�:�H�m3P�(��f��������� :��2�!�d�rz��`$N*vt��(J�^�(
��,(�c�}]���$��|�_*:t�"".������x�H�b~��"�XV�OMN�4�j��C����/!s���m.��R���=����+�y��%� ��%��U���_~:�8B84����~><��������E����**c�P;�,�-�F���.+Z)V�1�T��s�����	����0����'�4��<.TR���0*�{�z���Y-�1o��88��=/��
/N:��9���>������f@I;��T�)3�ly��;����������*R������V�{p���4�����b;Z��/�J��|�Y��*��T��*rw��LO�oX
I�U���q��[x]nU,�8�EN�~W��V�7���W������=�$k���G��9z�M�4N*�N��!(�Y<�����}�-p3����b�E+Jb�]
=�M�/�O;9�:M��[�0Z�G������>c,�v���g)6�D>�" ��C�ub���k�����_�~a����Z>3���gQpej:L������Mp��_�s��_eg�����E��a�������� ���;���^"�HO���*�5�������i j�s�M��Z___8�@��G��W����'m��g�d�)��D@�=�&��?��T�/��/��)��*��h�S
b����Z��4�M!F��3�����^f89�*����:������������W�3��i�_,�m������B��$�|N��0�#�r�����%�"�P��������}h���������l��������K����gU��JDH�=��&�=@i�q%�r���������\	���
�'��.Q���(��=�R�hn{��YH�P��nyx��� ���5�������B?3O���8u�H�ON����$�	�B�U�A~1��'�'mIL&?�����(������k�D>C���bY9f,/�0����`�K�&��3@��5�|�jt�������K.Xa���������x��M���1u���F���E`��:,"�A��k��wic��@'�wNd��v%���uxNQ"��I�$$���'���5�P~���8`6����'X������k,���Kl��^�_v��l�d0�a�������?�=�����������������ux�%R����:��{��`}�8��S��/mVV����XB������{���+��Z��5p��	z^K�i���.tC���U��p�W{(Y�1���J��nJ���?D��5�[KG�V�����/�UN��N���+^/,�>�[���E������5`G.NN�:���R�+P�������5�_9�0>XY���th�t����a�"<6������O	9��t�����#���*G�
���p�Ql�x���
��I������#���XXS�s�� Q��9�l�^�����qt/;����x��B&	|��>oTJEwZ�^{F@�E�>-u��9{�s1��Mv�����)�'2����jj���?:��-tI��k�����!?��]}T�q��%�f�M1�jl����c�k��)�F������U�hk��m������]I=Y�����N{�~��f��G������x���L*�����$��#B��@~�",�$���e��>�w"�����"�U>���x��}�����0�$l�^�7�<K@�)"z������zr�������/*�X��?���UNm
alter_extension.0.patchtext/x-patchDownload
*** 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/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,48 ****
--- 38,51 ----
  #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 "funcapi.h"
***************
*** 1276,1278 **** pg_extension_objects(PG_FUNCTION_ARGS)
--- 1279,1369 ----
  	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;
+ 
+ 		/*
+ 		 * 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:
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 						 errmsg("Relations are not supported.")));
+ 				break;
+ 			case OCLASS_PROC:
+ 				AlterFunctionNamespace_oid(thisobj->objectId, nspOid);
+ 				break;
+ 			case OCLASS_TYPE:
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 						 errmsg("Types are not supported.")));
+ 				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/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
***************
*** 238,243 **** extern Oid	get_constraint_index(Oid constraintId);
--- 238,246 ----
  
  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 */
set_schema.4.patchtext/x-patchDownload
*** a/src/backend/catalog/pg_namespace.c
--- b/src/backend/catalog/pg_namespace.c
***************
*** 17,24 ****
--- 17,26 ----
  #include "access/heapam.h"
  #include "catalog/dependency.h"
  #include "catalog/indexing.h"
+ #include "catalog/namespace.h"
  #include "catalog/pg_namespace.h"
  #include "utils/builtins.h"
+ #include "utils/lsyscache.h"
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
***************
*** 77,79 **** NamespaceCreate(const char *nspName, Oid ownerId)
--- 79,117 ----
  
  	return nspoid;
  }
+ 
+ /*
+  * Check new namespace validity in ALTER OBJECT ... SET SCHEMA ... and
+  * ereport(ERROR, ...) in case of any problem.
+  */
+ void
+ CheckSetNamespace(Oid oldNspOid, Oid nspOid,
+ 				  const char *name, const char *objtype)
+ {
+ 	if (oldNspOid == nspOid)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s \"%s\" already exists in schema \"%s\"",
+ 						objtype, name, get_namespace_name(nspOid))));
+ 
+ 	/* disallow renaming into or out of temp schemas */
+ 	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 			errmsg("cannot move objects into or out of temporary schemas")));
+ 
+ 	/* same for TOAST schema */
+ 	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of TOAST schema")));
+ 
+ 	/* check for duplicate name (more friendly than unique-index failure) */
+ 	if (SearchSysCacheExists2(TYPENAMENSP,
+ 							  CStringGetDatum(name),
+ 							  ObjectIdGetDatum(nspOid)))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s \"%s\" already exists in schema \"%s\"",
+ 						objtype, name, get_namespace_name(nspOid))));
+ }
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 182,192 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 182,208 ----
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_CONVERSION:
+ 			AlterConversionNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_FUNCTION:
  			AlterFunctionNamespace(stmt->object, stmt->objarg, false,
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_OPERATOR:
+ 			AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPCLASS:
+ 			AlterOpClassNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPFAMILY:
+ 			AlterOpFamilyNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_SEQUENCE:
  		case OBJECT_TABLE:
  		case OBJECT_VIEW:
***************
*** 195,200 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 211,232 ----
  								stmt->objectType, AccessExclusiveLock);
  			break;
  
+ 		case OBJECT_TSPARSER:
+ 			AlterTSParserNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSDICTIONARY:
+ 			AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSTEMPLATE:
+ 			AlterTSTemplateNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSCONFIGURATION:
+ 			AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_TYPE:
  		case OBJECT_DOMAIN:
  			AlterTypeNamespace(stmt->object, stmt->newschema);
*** a/src/backend/commands/conversioncmds.c
--- b/src/backend/commands/conversioncmds.c
***************
*** 19,24 ****
--- 19,25 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_conversion.h"
  #include "catalog/pg_conversion_fn.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
  #include "commands/conversioncmds.h"
  #include "mb/pg_wchar.h"
***************
*** 326,328 **** AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId)
--- 327,412 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER CONVERSION SET SCHEMA
+  */
+ void
+ AlterConversionNamespace(List *name, const char *newschema)
+ {
+ 	Oid			conversionOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	conversionOid = get_conversion_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterConversionNamespace_internal(rel, conversionOid, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
+  * Change conversion owner, by oid
+  */
+ void
+ AlterConversionNamespace_oid(Oid conversionOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	AlterConversionNamespace_internal(rel, conversionOid, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterConversionNamespace_internal(Relation rel, Oid conversionOid, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 	Form_pg_conversion convForm;
+ 
+ 	Assert(RelationGetRelid(rel) == ConversionRelationId);
+ 
+ 	tup = SearchSysCacheCopy1(CONVOID, ObjectIdGetDatum(conversionOid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for conversion %u", conversionOid);
+ 
+ 	convForm = (Form_pg_conversion) GETSTRUCT(tup);
+ 	oldNspOid = convForm->connamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(convForm->conname), "conversion");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_conversion_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
+ 						   NameStr(convForm->conname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(convForm->connamespace,
+ 										  GetUserId(),
+ 										  ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(convForm->connamespace));
+ 	}
+ 
+ 	convForm->connamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(ConversionRelationId, conversionOid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
*** a/src/backend/commands/functioncmds.c
--- b/src/backend/commands/functioncmds.c
***************
*** 1870,1882 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema)
  {
  	Oid			procOid;
- 	Oid			oldNspOid;
  	Oid			nspOid;
- 	HeapTuple	tup;
- 	Relation	procRel;
- 	Form_pg_proc proc;
- 
- 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
  
  	/* get function OID */
  	if (isagg)
--- 1870,1876 ----
***************
*** 1889,1894 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
--- 1883,1903 ----
  		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
  					   NameListToString(name));
  
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterFunctionNamespace_oid(procOid, nspOid);
+ }
+ 
+ void
+ AlterFunctionNamespace_oid(Oid procOid, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 	Relation	procRel;
+ 	Form_pg_proc proc;
+ 
+ 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
+ 
  	tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid));
  	if (!HeapTupleIsValid(tup))
  		elog(ERROR, "cache lookup failed for function %u", procOid);
***************
*** 1896,1910 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  
  	oldNspOid = proc->pronamespace;
  
- 	/* get schema OID and check its permissions */
- 	nspOid = LookupCreationNamespace(newschema);
- 
  	if (oldNspOid == nspOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" is already in schema \"%s\"",
! 						NameListToString(name),
! 						newschema)));
  
  	/* disallow renaming into or out of temp schemas */
  	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
--- 1905,1916 ----
  
  	oldNspOid = proc->pronamespace;
  
  	if (oldNspOid == nspOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" is already in schema \"%s\"",
! 						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* disallow renaming into or out of temp schemas */
  	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
***************
*** 1927,1933 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						newschema)));
  
  	/* OK, modify the pg_proc row */
  
--- 1933,1939 ----
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* OK, modify the pg_proc row */
  
***************
*** 1941,1947 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameListToString(name));
  
  	heap_freetuple(tup);
  
--- 1947,1953 ----
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameStr(proc->proname));
  
  	heap_freetuple(tup);
  
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 1912,1917 **** AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
--- 1912,2007 ----
  }
  
  /*
+  * ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpClassNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup, origtup;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	/* Look up the opclass. */
+ 	origtup = OpClassCacheLookup(amOid, name, false);
+ 	tup = heap_copytuple(origtup);
+ 	ReleaseSysCache(origtup);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterOpClassNamespace_internal(rel, tup, nspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(CLAOID, ObjectIdGetDatum(opclassOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
+ 
+ 	AlterOpClassOwner_internal(rel, tup, newNspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpClassNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	Form_pg_opclass opcForm;
+ 
+ 	opcForm = (Form_pg_opclass) GETSTRUCT(tup);
+ 	oldNspOid = opcForm->opcnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(opcForm->opcname), "operator class");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_opclass_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
+ 						   NameStr(opcForm->opcname));
+ 
+ 		/* New owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(nspOid));
+ 	}
+ 
+ 	/* tup is a copy, so we can scribble directly on it */
+ 	opcForm->opcnamespace = nspOid;
+ 
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(OperatorClassRelationId, HeapTupleGetOid(tup),
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
+ 
+ /*
   * Change opfamily owner by name
   */
  void
***************
*** 2067,2069 **** get_am_oid(const char *amname, bool missing_ok)
--- 2157,2284 ----
  				 errmsg("access method \"%s\" does not exist", amname)));
  	return oid;
  }
+ 
+ /*
+  * ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpFamilyNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup;
+ 	char	   *opfname, *schemaname;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	/*
+ 	 * Look up the opfamily
+ 	 */
+ 	DeconstructQualifiedName(name, &schemaname, &opfname);
+ 
+ 	if (schemaname)
+ 	{
+ 		Oid			namespaceOid;
+ 
+ 		namespaceOid = LookupExplicitNamespace(schemaname);
+ 
+ 		tup = SearchSysCacheCopy3(OPFAMILYAMNAMENSP,
+ 								  ObjectIdGetDatum(amOid),
+ 								  PointerGetDatum(opfname),
+ 								  ObjectIdGetDatum(namespaceOid));
+ 		if (!HeapTupleIsValid(tup))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 	}
+ 	else
+ 	{
+ 		Oid			opfOid;
+ 
+ 		opfOid = OpfamilynameGetOpfid(amOid, opfname);
+ 		if (!OidIsValid(opfOid))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 
+ 		tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfOid));
+ 		if (!HeapTupleIsValid(tup))		/* should not happen */
+ 			elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
+ 	}
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterOpFamilyNamespace_internal(rel, tup, nspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
+ 
+ 	AlterOpFamilyOwner_internal(rel, tup, newNspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpFamilyNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	Form_pg_opfamily opfForm;
+ 
+ 	Assert(tup->t_tableOid == OperatorFamilyRelationId);
+ 	Assert(RelationGetRelid(rel) == OperatorFamilyRelationId);
+ 
+ 	opfForm = (Form_pg_opfamily) GETSTRUCT(tup);
+ 	oldNspOid = opfForm->opfnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(opfForm->opfname), "operator family");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_opfamily_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
+ 						   NameStr(opfForm->opfname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(nspOid));
+ 	}
+ 
+ 	/* tup is a copy, so we can scribble directly on it */
+ 	opfForm->opfnamespace = nspOid;
+ 
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(OperatorFamilyRelationId, HeapTupleGetOid(tup),
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
*** a/src/backend/commands/operatorcmds.c
--- b/src/backend/commands/operatorcmds.c
***************
*** 39,44 ****
--- 39,45 ----
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_operator.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
***************
*** 452,454 **** AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
--- 453,544 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER OPERATOR SET SCHEMA
+  */
+ void
+ AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	AlterOperatorOwner_internal(rel, operOid, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOperatorNamespace(List *names, List *argtypes, const char *newschema)
+ {
+ 	List	   *operatorName = names;
+ 	TypeName   *typeName1 = (TypeName *) linitial(argtypes);
+ 	TypeName   *typeName2 = (TypeName *) lsecond(argtypes);
+ 	Oid			operOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	Assert(list_length(argtypes) == 2);
+ 	operOid = LookupOperNameTypeNames(NULL, operatorName,
+ 									  typeName1, typeName2,
+ 									  false, -1);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterOperatorNamespace_internal(rel, operOid, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOperatorNamespace_internal(Relation rel, Oid operOid, Oid nspOid)
+ {
+ 	Form_pg_operator oprForm;
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 
+ 	Assert(RelationGetRelid(rel) == OperatorRelationId);
+ 
+ 	tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(operOid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for operator %u", operOid);
+ 
+ 	oprForm = (Form_pg_operator) GETSTRUCT(tup);
+ 	oldNspOid = oprForm->oprnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid, NameStr(oprForm->oprname), "operator");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_oper_ownercheck(operOid, GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
+ 						   NameStr(oprForm->oprname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oprForm->oprnamespace,
+ 										  GetUserId(),
+ 										  ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(oprForm->oprnamespace));
+ 	}
+ 
+ 	/* tup is a copy, so we can scribble directly on it */
+ 	oprForm->oprnamespace = nspOid;
+ 
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(OperatorRelationId, operOid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
*** a/src/backend/commands/tsearchcmds.c
--- b/src/backend/commands/tsearchcmds.c
***************
*** 393,398 **** RenameTSParser(List *oldname, const char *newname)
--- 393,465 ----
  	heap_freetuple(tup);
  }
  
+ /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSParserNamespace(List *name, const char *newschema)
+ {
+ 	Oid			prsId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	prsId = get_ts_parser_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSParserNamespace_internal(rel, prsId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	AlterTSParserNamespace_internal(rel, prsId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSParserNamespace_internal(Relation rel, Oid prsId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_parser prs;
+ 
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 				 errmsg("must be superuser to rename text search parsers")));
+ 
+ 	tup = SearchSysCacheCopy1(TSPARSEROID, ObjectIdGetDatum(prsId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search parser %u", prsId);
+ 
+ 	prs = (Form_pg_ts_parser) GETSTRUCT(tup);
+ 	oldNspOid = prs->prsnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(prs->prsname), "text search parser");
+ 
+ 	prs->prsnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSParserRelationId, prsId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
  /* ---------------------- TS Dictionary commands -----------------------*/
  
  /*
***************
*** 620,625 **** RenameTSDictionary(List *oldname, const char *newname)
--- 687,772 ----
  }
  
  /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSDictionaryNamespace(List *name, const char *newschema)
+ {
+ 	Oid			dictId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	dictId = get_ts_dict_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSDictionaryNamespace_internal(rel, dictId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	AlterTSDictionaryNamespace_internal(rel, dictId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSDictionaryNamespace_internal(Relation rel, Oid dictId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_dict dict;
+ 
+ 	tup = SearchSysCacheCopy1(TSDICTOID, ObjectIdGetDatum(dictId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search dictionary %u",
+ 			 dictId);
+ 
+ 	dict = ((Form_pg_ts_dict) GETSTRUCT(tup));
+ 	oldNspOid = dict->dictnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(dict->dictname), "text search dictionary");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_ts_dict_ownercheck(dictId, GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
+ 						   NameStr(dict->dictname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(oldNspOid));
+ 	}
+ 
+ 	dict->dictnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSDictionaryRelationId, dictId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
+ /*
   * DROP TEXT SEARCH DICTIONARY
   */
  void
***************
*** 1100,1105 **** RenameTSTemplate(List *oldname, const char *newname)
--- 1247,1321 ----
  }
  
  /*
+  * ALTER TEXT SEARCH TEMPLATE any_name SET SCHEMA name
+  */
+ void
+ AlterTSTemplateNamespace(List *name, const char *newschema)
+ {
+ 	Oid			tmplId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	tmplId = get_ts_template_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSTemplateNamespace_internal(rel, tmplId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	AlterTSTemplateNamespace_internal(rel, tmplId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSTemplateNamespace_internal(Relation rel, Oid tmplId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_template tmpl;
+ 
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 			   errmsg("must be superuser to rename text search templates")));
+ 
+ 	tup = SearchSysCacheCopy1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search template %u",
+ 			 tmplId);
+ 
+ 	tmpl = (Form_pg_ts_template) GETSTRUCT(tup);
+ 	oldNspOid = tmpl->tmplnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(tmpl->tmplname), "text search template");
+ 
+ 	tmpl->tmplnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSTemplateRelationId, tmplId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH TEMPLATE
   */
  void
***************
*** 1498,1503 **** RenameTSConfiguration(List *oldname, const char *newname)
--- 1714,1798 ----
  }
  
  /*
+  * ALTER TEXT SEARCH CONFIGURATION any_name SET SCHEMA name
+  */
+ void
+ AlterTSConfigurationNamespace(List *name, const char *newschema)
+ {
+ 	Oid			cfgId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	cfgId = get_ts_config_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSConfigurationNamespace_internal(rel, cfgId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	AlterTSConfigurationNamespace_internal(rel, cfgId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSConfigurationNamespace_internal(Relation rel, Oid cfgId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_config cfg;
+ 
+ 	tup = SearchSysCacheCopy1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search configuration %u",
+ 			 cfgId);
+ 
+ 	cfg = (Form_pg_ts_config) GETSTRUCT(tup);
+ 	oldNspOid = cfg->cfgnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  NameStr(cfg->cfgname), "text search configuration");
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_ts_config_ownercheck(cfgId, GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
+ 						   NameStr(cfg->cfgname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
+ 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 					   get_namespace_name(oldNspOid));
+ 	}
+ 
+ 	cfg->cfgnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSConfigRelationId, cfgId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
+ /*
   * DROP TEXT SEARCH CONFIGURATION
   */
  void
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 6040,6045 **** AlterObjectSchemaStmt:
--- 6040,6053 ----
  					n->newschema = $7;
  					$$ = (Node *)n;
  				}
+ 			| ALTER CONVERSION_P any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_CONVERSION;
+ 					n->object = $3;
+ 					n->newschema = $6;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER DOMAIN_P any_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6057,6062 **** AlterObjectSchemaStmt:
--- 6065,6097 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER OPERATOR any_operator oper_argtypes SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPERATOR;
+ 					n->object = $3;
+ 					n->objarg = $4;
+ 					n->newschema = $7;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPCLASS;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPFAMILY;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER TABLE relation_expr SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6065,6070 **** AlterObjectSchemaStmt:
--- 6100,6137 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSPARSER;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSDICTIONARY;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSTEMPLATE;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSCONFIGURATION;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER SEQUENCE qualified_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 1694,1702 **** CreateCommandTag(Node *parsetree)
--- 1694,1714 ----
  				case OBJECT_AGGREGATE:
  					tag = "ALTER AGGREGATE";
  					break;
+ 				case OBJECT_CONVERSION:
+ 					tag = "ALTER CONVERSION";
+ 					break;
  				case OBJECT_DOMAIN:
  					tag = "ALTER DOMAIN";
  					break;
+ 				case OBJECT_OPERATOR:
+ 					tag = "ALTER OPERATOR";
+ 					break;
+ 				case OBJECT_OPCLASS:
+ 					tag = "ALTER OPERATOR CLASS";
+ 					break;
+ 				case OBJECT_OPFAMILY:
+ 					tag = "ALTER OPERATOR FAMILY";
+ 					break;
  				case OBJECT_FUNCTION:
  					tag = "ALTER FUNCTION";
  					break;
*** a/src/include/catalog/pg_namespace.h
--- b/src/include/catalog/pg_namespace.h
***************
*** 78,82 **** DESCR("standard public schema");
--- 78,84 ----
   * prototypes for functions in pg_namespace.c
   */
  extern Oid	NamespaceCreate(const char *nspName, Oid ownerId);
+ extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid,
+ 							  const char *name, const char *objtype);
  
  #endif   /* PG_NAMESPACE_H */
*** a/src/include/commands/conversioncmds.h
--- b/src/include/commands/conversioncmds.h
***************
*** 16,26 ****
--- 16,31 ----
  #define CONVERSIONCMDS_H
  
  #include "nodes/parsenodes.h"
+ #include "utils/relcache.h"
  
  extern void CreateConversionCommand(CreateConversionStmt *parsetree);
  extern void DropConversionsCommand(DropStmt *drop);
  extern void RenameConversion(List *name, const char *newname);
  extern void AlterConversionOwner(List *name, Oid newOwnerId);
  extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
+ extern void AlterConversionNamespace(List *name, const char *newschema);
+ extern void AlterConversionNamespace_oid(Oid conversionOid, Oid newNspOid);
+ extern void AlterConversionNamespace_internal(Relation rel, Oid conversionOid, Oid nspOid);
+ 
  
  #endif   /* CONVERSIONCMDS_H */
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 14,20 ****
--- 14,22 ----
  #ifndef DEFREM_H
  #define DEFREM_H
  
+ #include "access/htup.h"
  #include "nodes/parsenodes.h"
+ #include "utils/relcache.h"
  
  
  /* commands/indexcmds.c */
***************
*** 66,71 **** extern void DropCast(DropCastStmt *stmt);
--- 68,74 ----
  extern void DropCastById(Oid castOid);
  extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema);
+ extern void AlterFunctionNamespace_oid(Oid procOid, Oid nspOid);
  extern void ExecuteDoStmt(DoStmt *stmt);
  extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
  
***************
*** 78,83 **** extern void AlterOperatorOwner(List *name, TypeName *typeName1,
--- 81,89 ----
  extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId);
  extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
  extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern void AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid);
+ extern void AlterOperatorNamespace(List *names, List *argtypes, const char *newschema);
+ extern void AlterOperatorNamespace_internal(Relation rel, Oid operoid, Oid nspOid);
  
  /* commands/aggregatecmds.c */
  extern void DefineAggregate(List *name, List *args, bool oldstyle,
***************
*** 100,114 **** extern void RenameOpClass(List *name, const char *access_method, const char *new
--- 106,129 ----
  extern void RenameOpFamily(List *name, const char *access_method, const char *newname);
  extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId);
+ extern void AlterOpClassNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid);
+ extern void AlterOpClassNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid);
  extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId);
  extern Oid get_am_oid(const char *amname, bool missing_ok);
+ extern void AlterOpFamilyNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid);
+ extern void AlterOpFamilyNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid);
  
  /* commands/tsearchcmds.c */
  extern void DefineTSParser(List *names, List *parameters);
  extern void RenameTSParser(List *oldname, const char *newname);
  extern void RemoveTSParsers(DropStmt *drop);
  extern void RemoveTSParserById(Oid prsId);
+ extern void AlterTSParserNamespace(List *name, const char *newschema);
+ extern void AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
+ extern void AlterTSParserNamespace_internal(Relation rel, Oid prsId, Oid nspOid);
  
  extern void DefineTSDictionary(List *names, List *parameters);
  extern void RenameTSDictionary(List *oldname, const char *newname);
***************
*** 116,129 **** extern void RemoveTSDictionaries(DropStmt *drop);
--- 131,153 ----
  extern void RemoveTSDictionaryById(Oid dictId);
  extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
  extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
+ extern void AlterTSDictionaryNamespace(List *name, const char *newschema);
+ extern void AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid);
+ extern void AlterTSDictionaryNamespace_internal(Relation rel, Oid dictId, Oid nspOid);
  
  extern void DefineTSTemplate(List *names, List *parameters);
  extern void RenameTSTemplate(List *oldname, const char *newname);
+ extern void AlterTSTemplateNamespace(List *name, const char *newschema);
+ extern void AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
+ extern void AlterTSTemplateNamespace_internal(Relation rel, Oid tmplId, Oid nspOid);
  extern void RemoveTSTemplates(DropStmt *stmt);
  extern void RemoveTSTemplateById(Oid tmplId);
  
  extern void DefineTSConfiguration(List *names, List *parameters);
  extern void RenameTSConfiguration(List *oldname, const char *newname);
+ extern void AlterTSConfigurationNamespace(List *name, const char *newschema);
+ extern void AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid);
+ extern void AlterTSConfigurationNamespace_internal(Relation rel, Oid cfgId, Oid nspOid);
  extern void RemoveTSConfigurations(DropStmt *stmt);
  extern void RemoveTSConfigurationById(Oid cfgId);
  extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
#21Alvaro Herrera
alvherre@alvh.no-ip.org
In reply to: Dimitri Fontaine (#20)
1 attachment(s)
Fwd: Re: ALTER OBJECT any_name SET SCHEMA name

Sorry, I messed up and emailed this only to Dimitri.

--- Begin forwarded message from Alvaro Herrera ---
From: Alvaro Herrera <alvherre@commandprompt.com>
To: Dimitri Fontaine <dimitri@2ndquadrant.fr>
Date: Wed, 03 Nov 2010 14:13:58 -0300
Subject: Re: [HACKERS] ALTER OBJECT any_name SET SCHEMA name

Excerpts from Dimitri Fontaine's message of mié nov 03 13:10:12 -0300 2010:

Then, I think the ALTER EXTENSION foo SET SCHEMA name still has a use
case, so I've prepared a simple patch to show the API usage before we
get to refactor it all following Tom's asking. So there's a initial
patch to see that in action. I had to rework AlterFunctionNamespace()
API so that I can call it from elsewhere in the backend where I have
Oids, so here's an updated set_schema.4.patch. We will have to extend
the APIs for relations and types the same way, but it's already possible
to test the patch with some extensions this way.

Before I noticed that you were going to rework this patch completely, I
cleaned it up a bit; attached (probably just for your amusement)

I was looking at this patch 'cause someone asked for the ability to do
CREATE TEMP <OBJECT> for objects that currently don't support it. I
thought this might be related.

--- End forwarded message ---

--
Álvaro Herrera <alvherre@alvh.no-ip.org>

Attachments:

0010-Clean-up-ALTER-OBJECT-SET-SCHEMA-patch.patchapplication/octet-stream; name=0010-Clean-up-ALTER-OBJECT-SET-SCHEMA-patch.patchDownload
From 29f8757ab3760a4cbabd701e2925eccb2733aa99 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Wed, 3 Nov 2010 14:10:10 -0300
Subject: [PATCH 10/10] Clean up ALTER <OBJECT> SET SCHEMA patch

---
 src/backend/catalog/namespace.c       |   36 +++++++++++++++++++++++++++++++
 src/backend/catalog/pg_namespace.c    |   38 ---------------------------------
 src/backend/commands/conversioncmds.c |    6 +++-
 src/backend/commands/opclasscmds.c    |    8 +++++-
 src/backend/commands/operatorcmds.c   |   25 +++++++++++----------
 src/backend/commands/tsearchcmds.c    |   10 +++++++-
 src/include/catalog/namespace.h       |    2 +
 src/include/catalog/pg_namespace.h    |    2 -
 src/include/commands/conversioncmds.h |    2 -
 src/include/commands/defrem.h         |    9 -------
 10 files changed, 70 insertions(+), 68 deletions(-)

diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 3727146..0a04f4d 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -2340,6 +2340,42 @@ LookupCreationNamespace(const char *nspname)
 }
 
 /*
+ * Check new namespace validity in ALTER OBJECT ... SET SCHEMA ... and
+ * ereport(ERROR, ...) in case of any problem.
+ */
+void
+CheckSetNamespace(Oid oldNspOid, Oid nspOid,
+				  const char *name, const char *objtype)
+{
+	if (oldNspOid == nspOid)
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("%s \"%s\" already exists in schema \"%s\"",
+						objtype, name, get_namespace_name(nspOid))));
+
+	/* disallow renaming into or out of temp schemas */
+	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("cannot move objects into or out of temporary schemas")));
+
+	/* same for TOAST schema */
+	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("cannot move objects into or out of TOAST schema")));
+
+	/* check for duplicate name (more friendly than unique-index failure) */
+	if (SearchSysCacheExists2(TYPENAMENSP,
+							  CStringGetDatum(name),
+							  ObjectIdGetDatum(nspOid)))
+		ereport(ERROR,
+				(errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("%s \"%s\" already exists in schema \"%s\"",
+						objtype, name, get_namespace_name(nspOid))));
+}
+
+/*
  * QualifiedNameGetCreationNamespace
  *		Given a possibly-qualified name for an object (in List-of-Values
  *		format), determine what namespace the object should be created in.
diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c
index eabb19d..71ebd7a 100644
--- a/src/backend/catalog/pg_namespace.c
+++ b/src/backend/catalog/pg_namespace.c
@@ -17,10 +17,8 @@
 #include "access/heapam.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
-#include "catalog/namespace.h"
 #include "catalog/pg_namespace.h"
 #include "utils/builtins.h"
-#include "utils/lsyscache.h"
 #include "utils/rel.h"
 #include "utils/syscache.h"
 
@@ -79,39 +77,3 @@ NamespaceCreate(const char *nspName, Oid ownerId)
 
 	return nspoid;
 }
-
-/*
- * Check new namespace validity in ALTER OBJECT ... SET SCHEMA ... and
- * ereport(ERROR, ...) in case of any problem.
- */
-void
-CheckSetNamespace(Oid oldNspOid, Oid nspOid,
-				  const char *name, const char *objtype)
-{
-	if (oldNspOid == nspOid)
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("%s \"%s\" already exists in schema \"%s\"",
-						objtype, name, get_namespace_name(nspOid))));
-
-	/* disallow renaming into or out of temp schemas */
-	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-			errmsg("cannot move objects into or out of temporary schemas")));
-
-	/* same for TOAST schema */
-	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("cannot move objects into or out of TOAST schema")));
-
-	/* check for duplicate name (more friendly than unique-index failure) */
-	if (SearchSysCacheExists2(TYPENAMENSP,
-							  CStringGetDatum(name),
-							  ObjectIdGetDatum(nspOid)))
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("%s \"%s\" already exists in schema \"%s\"",
-						objtype, name, get_namespace_name(nspOid))));
-}
diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c
index d989c07..75c06aa 100644
--- a/src/backend/commands/conversioncmds.c
+++ b/src/backend/commands/conversioncmds.c
@@ -33,6 +33,8 @@
 
 static void AlterConversionOwner_internal(Relation rel, Oid conversionOid,
 							  Oid newOwnerId);
+static void AlterConversionNamespace_internal(Relation rel, Oid conversionOid,
+								  Oid nspOid);
 
 /*
  * CREATE CONVERSION
@@ -350,7 +352,7 @@ AlterConversionNamespace(List *name, const char *newschema)
 }
 
 /*
- * Change conversion owner, by oid
+ * Change conversion schema, by oid
  */
 void
 AlterConversionNamespace_oid(Oid conversionOid, Oid newNspOid)
@@ -364,7 +366,7 @@ AlterConversionNamespace_oid(Oid conversionOid, Oid newNspOid)
 	heap_close(rel, NoLock);
 }
 
-void
+static void
 AlterConversionNamespace_internal(Relation rel, Oid conversionOid, Oid nspOid)
 {
 	Oid			oldNspOid;
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 596779c..bfda30c 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -81,6 +81,10 @@ static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple,
 						   Oid newOwnerId);
 static void AlterOpFamilyOwner_internal(Relation rel, HeapTuple tuple,
 							Oid newOwnerId);
+static void AlterOpClassNamespace_internal(Relation rel, HeapTuple tup,
+			   				   Oid nspOid);
+extern void AlterOpFamilyNamespace_internal(Relation rel, HeapTuple tup,
+								Oid nspOid);
 
 
 /*
@@ -1955,13 +1959,13 @@ AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
 	if (!HeapTupleIsValid(tup))
 		elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
 
-	AlterOpClassOwner_internal(rel, tup, newNspOid);
+	AlterOpClassNamespace_internal(rel, tup, newNspOid);
 
 	heap_freetuple(tup);
 	heap_close(rel, NoLock);
 }
 
-void
+static void
 AlterOpClassNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid)
 {
 	Oid			oldNspOid;
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 0a94c12..3868216 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -53,6 +53,7 @@
 
 
 static void AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId);
+static void AlterOperatorNamespace_internal(Relation rel, Oid operOid, Oid nspOid);
 
 /*
  * DefineOperator
@@ -458,18 +459,6 @@ AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
  * Execute ALTER OPERATOR SET SCHEMA
  */
 void
-AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)
-{
-	Relation	rel;
-
-	rel = heap_open(OperatorRelationId, RowExclusiveLock);
-
-	AlterOperatorOwner_internal(rel, operOid, newNspOid);
-
-	heap_close(rel, NoLock);
-}
-
-void
 AlterOperatorNamespace(List *names, List *argtypes, const char *newschema)
 {
 	List	   *operatorName = names;
@@ -494,6 +483,18 @@ AlterOperatorNamespace(List *names, List *argtypes, const char *newschema)
 }
 
 void
+AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)
+{
+	Relation	rel;
+
+	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+
+	AlterOperatorNamespace_internal(rel, operOid, newNspOid);
+
+	heap_close(rel, NoLock);
+}
+
+static void
 AlterOperatorNamespace_internal(Relation rel, Oid operOid, Oid nspOid)
 {
 	Form_pg_operator oprForm;
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index aa309be..e441038 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -52,6 +52,14 @@ static void MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
 						 HeapTuple tup, Relation relMap);
 static void DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
 						 HeapTuple tup, Relation relMap);
+static void AlterTSParserNamespace_internal(Relation rel, Oid prsId,
+								Oid nspOid);
+static void AlterTSDictionaryNamespace_internal(Relation rel, Oid dictId,
+									Oid nspOid);
+static void AlterTSTemplateNamespace_internal(Relation rel, Oid tmplId,
+								  Oid nspOid);
+static void AlterTSConfigurationNamespace_internal(Relation rel, Oid cfgId,
+									   Oid nspOid);
 
 
 /* --------------------- TS Parser commands ------------------------ */
@@ -426,7 +434,7 @@ AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
 	heap_close(rel, NoLock);
 }
 
-void
+static void
 AlterTSParserNamespace_internal(Relation rel, Oid prsId, Oid nspOid)
 {
 	HeapTuple	tup;
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index c6672e9..16d5763 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -94,6 +94,8 @@ extern Oid	LookupExplicitNamespace(const char *nspname);
 extern Oid	get_namespace_oid(const char *nspname, bool missing_ok);
 
 extern Oid	LookupCreationNamespace(const char *nspname);
+extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid,
+							  const char *name, const char *objtype);
 extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p);
 extern RangeVar *makeRangeVarFromNameList(List *names);
 extern char *NameListToString(List *names);
diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h
index b8bed97..1d866d4 100644
--- a/src/include/catalog/pg_namespace.h
+++ b/src/include/catalog/pg_namespace.h
@@ -78,7 +78,5 @@ DESCR("standard public schema");
  * prototypes for functions in pg_namespace.c
  */
 extern Oid	NamespaceCreate(const char *nspName, Oid ownerId);
-extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid,
-							  const char *name, const char *objtype);
 
 #endif   /* PG_NAMESPACE_H */
diff --git a/src/include/commands/conversioncmds.h b/src/include/commands/conversioncmds.h
index 7cd96fa..b315a54 100644
--- a/src/include/commands/conversioncmds.h
+++ b/src/include/commands/conversioncmds.h
@@ -16,7 +16,6 @@
 #define CONVERSIONCMDS_H
 
 #include "nodes/parsenodes.h"
-#include "utils/relcache.h"
 
 extern void CreateConversionCommand(CreateConversionStmt *parsetree);
 extern void DropConversionsCommand(DropStmt *drop);
@@ -25,7 +24,6 @@ extern void AlterConversionOwner(List *name, Oid newOwnerId);
 extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
 extern void AlterConversionNamespace(List *name, const char *newschema);
 extern void AlterConversionNamespace_oid(Oid conversionOid, Oid newNspOid);
-extern void AlterConversionNamespace_internal(Relation rel, Oid conversionOid, Oid nspOid);
 
 
 #endif   /* CONVERSIONCMDS_H */
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index e2153ba..584ef90 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -14,9 +14,7 @@
 #ifndef DEFREM_H
 #define DEFREM_H
 
-#include "access/htup.h"
 #include "nodes/parsenodes.h"
-#include "utils/relcache.h"
 
 
 /* commands/indexcmds.c */
@@ -83,7 +81,6 @@ extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
 extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
 extern void AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid);
 extern void AlterOperatorNamespace(List *names, List *argtypes, const char *newschema);
-extern void AlterOperatorNamespace_internal(Relation rel, Oid operoid, Oid nspOid);
 
 /* commands/aggregatecmds.c */
 extern void DefineAggregate(List *name, List *args, bool oldstyle,
@@ -108,13 +105,11 @@ extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwne
 extern void AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId);
 extern void AlterOpClassNamespace(List *name, List *argam, const char *newschema);
 extern void AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid);
-extern void AlterOpClassNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid);
 extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
 extern void AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId);
 extern Oid get_am_oid(const char *amname, bool missing_ok);
 extern void AlterOpFamilyNamespace(List *name, List *argam, const char *newschema);
 extern void AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid);
-extern void AlterOpFamilyNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid);
 
 /* commands/tsearchcmds.c */
 extern void DefineTSParser(List *names, List *parameters);
@@ -123,7 +118,6 @@ extern void RemoveTSParsers(DropStmt *drop);
 extern void RemoveTSParserById(Oid prsId);
 extern void AlterTSParserNamespace(List *name, const char *newschema);
 extern void AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
-extern void AlterTSParserNamespace_internal(Relation rel, Oid prsId, Oid nspOid);
 
 extern void DefineTSDictionary(List *names, List *parameters);
 extern void RenameTSDictionary(List *oldname, const char *newname);
@@ -133,13 +127,11 @@ extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
 extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
 extern void AlterTSDictionaryNamespace(List *name, const char *newschema);
 extern void AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid);
-extern void AlterTSDictionaryNamespace_internal(Relation rel, Oid dictId, Oid nspOid);
 
 extern void DefineTSTemplate(List *names, List *parameters);
 extern void RenameTSTemplate(List *oldname, const char *newname);
 extern void AlterTSTemplateNamespace(List *name, const char *newschema);
 extern void AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
-extern void AlterTSTemplateNamespace_internal(Relation rel, Oid tmplId, Oid nspOid);
 extern void RemoveTSTemplates(DropStmt *stmt);
 extern void RemoveTSTemplateById(Oid tmplId);
 
@@ -147,7 +139,6 @@ extern void DefineTSConfiguration(List *names, List *parameters);
 extern void RenameTSConfiguration(List *oldname, const char *newname);
 extern void AlterTSConfigurationNamespace(List *name, const char *newschema);
 extern void AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid);
-extern void AlterTSConfigurationNamespace_internal(Relation rel, Oid cfgId, Oid nspOid);
 extern void RemoveTSConfigurations(DropStmt *stmt);
 extern void RemoveTSConfigurationById(Oid cfgId);
 extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
-- 
1.7.1

#22Alvaro Herrera
alvherre@commandprompt.com
In reply to: Dimitri Fontaine (#20)
1 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Excerpts from Dimitri Fontaine's message of mié nov 03 13:10:12 -0300 2010:

Then, I think the ALTER EXTENSION foo SET SCHEMA name still has a use
case, so I've prepared a simple patch to show the API usage before we
get to refactor it all following Tom's asking. So there's a initial
patch to see that in action.

FWIW I think you should use getObjectDescription, as in the attached
patch. (Note the patch is incomplete and does not compile because only
one caller to CheckSetNamespace has been fixed).

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

Attachments:

0001-Use-getObjectDescription.patchapplication/octet-stream; name=0001-Use-getObjectDescription.patchDownload
From 7f8d244e954d1810982a727382c5ca4548f81837 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Wed, 3 Nov 2010 18:13:20 -0300
Subject: [PATCH] Use getObjectDescription

---
 src/backend/catalog/dependency.c      |   15 +++++++++++++++
 src/backend/catalog/namespace.c       |   12 ++++++------
 src/backend/commands/conversioncmds.c |    3 +--
 src/include/catalog/dependency.h      |    2 ++
 src/include/catalog/namespace.h       |    4 ++--
 5 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index bb14a43..f55d3f3 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -2706,6 +2706,21 @@ getObjectDescription(const ObjectAddress *object)
 }
 
 /*
+ * getObjectDescriptionOids: as above, except the object is specified by Oids
+ */
+char *
+getObjectDescriptionOids(Oid classid, Oid objid)
+{
+	ObjectAddress	address;
+
+	address.classId = classid;
+	address.objectId = objid;
+	address.objectSubId = 0;
+
+	return getObjectDescription(&address);
+}
+
+/*
  * subroutine for getObjectDescription: describe a relation
  */
 static void
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 0a04f4d..b7b1198 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -2344,14 +2344,13 @@ LookupCreationNamespace(const char *nspname)
  * ereport(ERROR, ...) in case of any problem.
  */
 void
-CheckSetNamespace(Oid oldNspOid, Oid nspOid,
-				  const char *name, const char *objtype)
+CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid);
 {
 	if (oldNspOid == nspOid)
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("%s \"%s\" already exists in schema \"%s\"",
-						objtype, name, get_namespace_name(nspOid))));
+				 errmsg("%s already exists in schema \"%s\"",
+						getObjectDescriptionOids(classid, objid), get_namespace_name(nspOid))));
 
 	/* disallow renaming into or out of temp schemas */
 	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
@@ -2371,8 +2370,9 @@ CheckSetNamespace(Oid oldNspOid, Oid nspOid,
 							  ObjectIdGetDatum(nspOid)))
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("%s \"%s\" already exists in schema \"%s\"",
-						objtype, name, get_namespace_name(nspOid))));
+				 errmsg("%s already exists in schema \"%s\"",
+						getObjectDescriptionOids(classid, objid),
+						get_namespace_name(nspOid))));
 }
 
 /*
diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c
index 75c06aa..7e29342 100644
--- a/src/backend/commands/conversioncmds.c
+++ b/src/backend/commands/conversioncmds.c
@@ -382,8 +382,7 @@ AlterConversionNamespace_internal(Relation rel, Oid conversionOid, Oid nspOid)
 	convForm = (Form_pg_conversion) GETSTRUCT(tup);
 	oldNspOid = convForm->connamespace;
 
-	CheckSetNamespace(oldNspOid, nspOid,
-					  NameStr(convForm->conname), "conversion");
+	CheckSetNamespace(oldNspOid, nspOid, ConversionRelationId, conversionOid);
 
 	/* Superusers can always do it */
 	if (!superuser())
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index ccde371..f56dd4a 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -166,6 +166,8 @@ extern ObjectClass getObjectClass(const ObjectAddress *object);
 
 extern char *getObjectDescription(const ObjectAddress *object);
 
+extern char *getObjectDescriptionOids(Oid classid, Oid objid);
+
 extern ObjectAddresses *new_object_addresses(void);
 
 extern void add_exact_object_address(const ObjectAddress *object,
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 16d5763..29c9a5d 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -94,8 +94,8 @@ extern Oid	LookupExplicitNamespace(const char *nspname);
 extern Oid	get_namespace_oid(const char *nspname, bool missing_ok);
 
 extern Oid	LookupCreationNamespace(const char *nspname);
-extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid,
-							  const char *name, const char *objtype);
+extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid,
+				  Oid objid);
 extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p);
 extern RangeVar *makeRangeVarFromNameList(List *names);
 extern char *NameListToString(List *names);
-- 
1.7.1

#23Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Alvaro Herrera (#22)
Re: ALTER OBJECT any_name SET SCHEMA name

Alvaro Herrera <alvherre@commandprompt.com> writes:

FWIW I think you should use getObjectDescription, as in the attached
patch. (Note the patch is incomplete and does not compile because only
one caller to CheckSetNamespace has been fixed).

That a very good idea, will apply (cherry-pick -n) and finish it
tomorrow, thanks!

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#24Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Alvaro Herrera (#22)
2 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Alvaro Herrera <alvherre@commandprompt.com> writes:

FWIW I think you should use getObjectDescription, as in the attached
patch. (Note the patch is incomplete and does not compile because only
one caller to CheckSetNamespace has been fixed).

I had to re-add the object name to the CheckSetNamespace prototype to
handle this particular check:

/* check for duplicate name (more friendly than unique-index failure) */
if (SearchSysCacheExists2(TYPENAMENSP,
CStringGetDatum(name),
ObjectIdGetDatum(nspOid)))

If you know how to get some struct attribute given a char * holding its
name, in C, I would adapt the patch and work on the refactoring asked
for by Tom.

Apart from that, it was just about adapting the call sites, which is
done in the attached set_schema.5.patch. Thanks!

Also attached, please find the complete version of ALTER EXTENSION ext
SET SCHEMA name; with support for all contrib extensions. That's the
example that allows to see the API (AlterFooNamespace_oid and _internal
functions) in action: that should help devising the best refactoring.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

set_schema.5.patchtext/x-patchDownload
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 2706,2711 **** getObjectDescription(const ObjectAddress *object)
--- 2706,2726 ----
  }
  
  /*
+  * getObjectDescriptionOids: as above, except the object is specified by Oids
+  */
+ char *
+ getObjectDescriptionOids(Oid classid, Oid objid)
+ {
+ 	ObjectAddress	address;
+ 
+ 	address.classId = classid;
+ 	address.objectId = objid;
+ 	address.objectSubId = 0;
+ 
+ 	return getObjectDescription(&address);
+ }
+ 
+ /*
   * subroutine for getObjectDescription: describe a relation
   */
  static void
*** a/src/backend/catalog/namespace.c
--- b/src/backend/catalog/namespace.c
***************
*** 2340,2345 **** LookupCreationNamespace(const char *nspname)
--- 2340,2383 ----
  }
  
  /*
+  * Check new namespace validity in ALTER OBJECT ... SET SCHEMA ... and
+  * ereport(ERROR, ...) in case of any problem.
+  */
+ void
+ CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid,
+ 				  const char *name)
+ {
+ 	if (oldNspOid == nspOid)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s already exists in schema \"%s\"",
+ 						getObjectDescriptionOids(classid, objid),
+ 						get_namespace_name(nspOid))));
+ 
+ 	/* disallow renaming into or out of temp schemas */
+ 	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of temporary schemas")));
+ 
+ 	/* same for TOAST schema */
+ 	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of TOAST schema")));
+ 
+ 	/* check for duplicate name (more friendly than unique-index failure) */
+ 	if (SearchSysCacheExists2(TYPENAMENSP,
+ 							  CStringGetDatum(name),
+ 							  ObjectIdGetDatum(nspOid)))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s already exists in schema \"%s\"",
+ 						getObjectDescriptionOids(classid, objid),
+ 						get_namespace_name(nspOid))));
+ }
+ 
+ /*
   * QualifiedNameGetCreationNamespace
   *		Given a possibly-qualified name for an object (in List-of-Values
   *		format), determine what namespace the object should be created in.
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 182,192 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 182,208 ----
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_CONVERSION:
+ 			AlterConversionNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_FUNCTION:
  			AlterFunctionNamespace(stmt->object, stmt->objarg, false,
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_OPERATOR:
+ 			AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPCLASS:
+ 			AlterOpClassNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPFAMILY:
+ 			AlterOpFamilyNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_SEQUENCE:
  		case OBJECT_TABLE:
  		case OBJECT_VIEW:
***************
*** 195,200 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 211,232 ----
  								stmt->objectType, AccessExclusiveLock);
  			break;
  
+ 		case OBJECT_TSPARSER:
+ 			AlterTSParserNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSDICTIONARY:
+ 			AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSTEMPLATE:
+ 			AlterTSTemplateNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSCONFIGURATION:
+ 			AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_TYPE:
  		case OBJECT_DOMAIN:
  			AlterTypeNamespace(stmt->object, stmt->newschema);
*** a/src/backend/commands/conversioncmds.c
--- b/src/backend/commands/conversioncmds.c
***************
*** 19,24 ****
--- 19,25 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_conversion.h"
  #include "catalog/pg_conversion_fn.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
  #include "commands/conversioncmds.h"
  #include "mb/pg_wchar.h"
***************
*** 30,37 ****
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
! static void AlterConversionOwner_internal(Relation rel, Oid conversionOid,
  							  Oid newOwnerId);
  
  /*
   * CREATE CONVERSION
--- 31,40 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
! static void AlterConversionOwner_internal(Relation rel, Oid convOid,
  							  Oid newOwnerId);
+ static void AlterConversionNamespace_internal(Relation rel, Oid convOid,
+ 								  Oid nspOid);
  
  /*
   * CREATE CONVERSION
***************
*** 326,328 **** AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId)
--- 329,414 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER CONVERSION SET SCHEMA
+  */
+ void
+ AlterConversionNamespace(List *name, const char *newschema)
+ {
+ 	Oid			convOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	convOid = get_conversion_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterConversionNamespace_internal(rel, convOid, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
+  * Change conversion schema, by oid
+  */
+ void
+ AlterConversionNamespace_oid(Oid convOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	AlterConversionNamespace_internal(rel, convOid, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ static void
+ AlterConversionNamespace_internal(Relation rel, Oid convOid, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 	Form_pg_conversion convForm;
+ 
+ 	Assert(RelationGetRelid(rel) == ConversionRelationId);
+ 
+ 	tup = SearchSysCacheCopy1(CONVOID, ObjectIdGetDatum(convOid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for conversion %u", convOid);
+ 
+ 	convForm = (Form_pg_conversion) GETSTRUCT(tup);
+ 	oldNspOid = convForm->connamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  ConversionRelationId, convOid, NameStr(convForm->conname));
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_conversion_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
+ 						   NameStr(convForm->conname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(convForm->connamespace,
+ 										  GetUserId(),
+ 										  ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(convForm->connamespace));
+ 	}
+ 
+ 	convForm->connamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(ConversionRelationId, convOid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
*** a/src/backend/commands/functioncmds.c
--- b/src/backend/commands/functioncmds.c
***************
*** 1870,1882 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema)
  {
  	Oid			procOid;
- 	Oid			oldNspOid;
  	Oid			nspOid;
- 	HeapTuple	tup;
- 	Relation	procRel;
- 	Form_pg_proc proc;
- 
- 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
  
  	/* get function OID */
  	if (isagg)
--- 1870,1876 ----
***************
*** 1889,1894 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
--- 1883,1903 ----
  		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
  					   NameListToString(name));
  
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterFunctionNamespace_oid(procOid, nspOid);
+ }
+ 
+ void
+ AlterFunctionNamespace_oid(Oid procOid, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 	Relation	procRel;
+ 	Form_pg_proc proc;
+ 
+ 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
+ 
  	tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid));
  	if (!HeapTupleIsValid(tup))
  		elog(ERROR, "cache lookup failed for function %u", procOid);
***************
*** 1896,1910 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  
  	oldNspOid = proc->pronamespace;
  
- 	/* get schema OID and check its permissions */
- 	nspOid = LookupCreationNamespace(newschema);
- 
  	if (oldNspOid == nspOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" is already in schema \"%s\"",
! 						NameListToString(name),
! 						newschema)));
  
  	/* disallow renaming into or out of temp schemas */
  	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
--- 1905,1916 ----
  
  	oldNspOid = proc->pronamespace;
  
  	if (oldNspOid == nspOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" is already in schema \"%s\"",
! 						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* disallow renaming into or out of temp schemas */
  	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
***************
*** 1927,1933 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						newschema)));
  
  	/* OK, modify the pg_proc row */
  
--- 1933,1939 ----
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* OK, modify the pg_proc row */
  
***************
*** 1941,1947 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameListToString(name));
  
  	heap_freetuple(tup);
  
--- 1947,1953 ----
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameStr(proc->proname));
  
  	heap_freetuple(tup);
  
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 81,86 **** static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple,
--- 81,90 ----
  						   Oid newOwnerId);
  static void AlterOpFamilyOwner_internal(Relation rel, HeapTuple tuple,
  							Oid newOwnerId);
+ static void AlterOpClassNamespace_internal(Relation rel, HeapTuple tup,
+ 			   				   Oid nspOid);
+ extern void AlterOpFamilyNamespace_internal(Relation rel, HeapTuple tup,
+ 								Oid nspOid);
  
  
  /*
***************
*** 1912,1917 **** AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
--- 1916,2012 ----
  }
  
  /*
+  * ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpClassNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup, origtup;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	/* Look up the opclass. */
+ 	origtup = OpClassCacheLookup(amOid, name, false);
+ 	tup = heap_copytuple(origtup);
+ 	ReleaseSysCache(origtup);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterOpClassNamespace_internal(rel, tup, nspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(CLAOID, ObjectIdGetDatum(opclassOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
+ 
+ 	AlterOpClassNamespace_internal(rel, tup, newNspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ static void
+ AlterOpClassNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	Form_pg_opclass opcForm;
+ 
+ 	opcForm = (Form_pg_opclass) GETSTRUCT(tup);
+ 	oldNspOid = opcForm->opcnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  OperatorClassRelationId, HeapTupleGetOid(tup),
+ 					  NameStr(opcForm->opcname));
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_opclass_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
+ 						   NameStr(opcForm->opcname));
+ 
+ 		/* New owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(nspOid));
+ 	}
+ 
+ 	/* tup is a copy, so we can scribble directly on it */
+ 	opcForm->opcnamespace = nspOid;
+ 
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(OperatorClassRelationId, HeapTupleGetOid(tup),
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
+ 
+ /*
   * Change opfamily owner by name
   */
  void
***************
*** 2067,2069 **** get_am_oid(const char *amname, bool missing_ok)
--- 2162,2290 ----
  				 errmsg("access method \"%s\" does not exist", amname)));
  	return oid;
  }
+ 
+ /*
+  * ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpFamilyNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup;
+ 	char	   *opfname, *schemaname;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	/*
+ 	 * Look up the opfamily
+ 	 */
+ 	DeconstructQualifiedName(name, &schemaname, &opfname);
+ 
+ 	if (schemaname)
+ 	{
+ 		Oid			namespaceOid;
+ 
+ 		namespaceOid = LookupExplicitNamespace(schemaname);
+ 
+ 		tup = SearchSysCacheCopy3(OPFAMILYAMNAMENSP,
+ 								  ObjectIdGetDatum(amOid),
+ 								  PointerGetDatum(opfname),
+ 								  ObjectIdGetDatum(namespaceOid));
+ 		if (!HeapTupleIsValid(tup))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 	}
+ 	else
+ 	{
+ 		Oid			opfOid;
+ 
+ 		opfOid = OpfamilynameGetOpfid(amOid, opfname);
+ 		if (!OidIsValid(opfOid))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 
+ 		tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfOid));
+ 		if (!HeapTupleIsValid(tup))		/* should not happen */
+ 			elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
+ 	}
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterOpFamilyNamespace_internal(rel, tup, nspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
+ 
+ 	AlterOpFamilyNamespace_internal(rel, tup, newNspOid);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpFamilyNamespace_internal(Relation rel, HeapTuple tup, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	Form_pg_opfamily opfForm;
+ 
+ 	Assert(tup->t_tableOid == OperatorFamilyRelationId);
+ 	Assert(RelationGetRelid(rel) == OperatorFamilyRelationId);
+ 
+ 	opfForm = (Form_pg_opfamily) GETSTRUCT(tup);
+ 	oldNspOid = opfForm->opfnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  OperatorFamilyRelationId, HeapTupleGetOid(tup),
+ 					  NameStr(opfForm->opfname));
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_opfamily_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
+ 						   NameStr(opfForm->opfname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(nspOid));
+ 	}
+ 
+ 	/* tup is a copy, so we can scribble directly on it */
+ 	opfForm->opfnamespace = nspOid;
+ 
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(OperatorFamilyRelationId, HeapTupleGetOid(tup),
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
*** a/src/backend/commands/operatorcmds.c
--- b/src/backend/commands/operatorcmds.c
***************
*** 39,44 ****
--- 39,45 ----
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_operator.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
***************
*** 52,57 ****
--- 53,59 ----
  
  
  static void AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId);
+ static void AlterOperatorNamespace_internal(Relation rel, Oid operOid, Oid nspOid);
  
  /*
   * DefineOperator
***************
*** 452,454 **** AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
--- 454,546 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER OPERATOR SET SCHEMA
+  */
+ void
+ AlterOperatorNamespace(List *names, List *argtypes, const char *newschema)
+ {
+ 	List	   *operatorName = names;
+ 	TypeName   *typeName1 = (TypeName *) linitial(argtypes);
+ 	TypeName   *typeName2 = (TypeName *) lsecond(argtypes);
+ 	Oid			operOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	Assert(list_length(argtypes) == 2);
+ 	operOid = LookupOperNameTypeNames(NULL, operatorName,
+ 									  typeName1, typeName2,
+ 									  false, -1);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterOperatorNamespace_internal(rel, operOid, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	AlterOperatorNamespace_internal(rel, operOid, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ static void
+ AlterOperatorNamespace_internal(Relation rel, Oid operOid, Oid nspOid)
+ {
+ 	Form_pg_operator oprForm;
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 
+ 	Assert(RelationGetRelid(rel) == OperatorRelationId);
+ 
+ 	tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(operOid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for operator %u", operOid);
+ 
+ 	oprForm = (Form_pg_operator) GETSTRUCT(tup);
+ 	oldNspOid = oprForm->oprnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  OperatorRelationId, operOid, NameStr(oprForm->oprname));
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_oper_ownercheck(operOid, GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
+ 						   NameStr(oprForm->oprname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oprForm->oprnamespace,
+ 										  GetUserId(),
+ 										  ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(oprForm->oprnamespace));
+ 	}
+ 
+ 	/* tup is a copy, so we can scribble directly on it */
+ 	oprForm->oprnamespace = nspOid;
+ 
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(OperatorRelationId, operOid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
*** a/src/backend/commands/tsearchcmds.c
--- b/src/backend/commands/tsearchcmds.c
***************
*** 52,57 **** static void MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
--- 52,65 ----
  						 HeapTuple tup, Relation relMap);
  static void DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
  						 HeapTuple tup, Relation relMap);
+ static void AlterTSParserNamespace_internal(Relation rel, Oid prsId,
+ 								Oid nspOid);
+ static void AlterTSDictionaryNamespace_internal(Relation rel, Oid dictId,
+ 									Oid nspOid);
+ static void AlterTSTemplateNamespace_internal(Relation rel, Oid tmplId,
+ 								  Oid nspOid);
+ static void AlterTSConfigurationNamespace_internal(Relation rel, Oid cfgId,
+ 									   Oid nspOid);
  
  
  /* --------------------- TS Parser commands ------------------------ */
***************
*** 393,398 **** RenameTSParser(List *oldname, const char *newname)
--- 401,473 ----
  	heap_freetuple(tup);
  }
  
+ /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSParserNamespace(List *name, const char *newschema)
+ {
+ 	Oid			prsId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	prsId = get_ts_parser_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSParserNamespace_internal(rel, prsId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	AlterTSParserNamespace_internal(rel, prsId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ static void
+ AlterTSParserNamespace_internal(Relation rel, Oid prsId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_parser prs;
+ 
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 				 errmsg("must be superuser to rename text search parsers")));
+ 
+ 	tup = SearchSysCacheCopy1(TSPARSEROID, ObjectIdGetDatum(prsId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search parser %u", prsId);
+ 
+ 	prs = (Form_pg_ts_parser) GETSTRUCT(tup);
+ 	oldNspOid = prs->prsnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  TSParserRelationId, prsId, NameStr(prs->prsname));
+ 
+ 	prs->prsnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSParserRelationId, prsId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
  /* ---------------------- TS Dictionary commands -----------------------*/
  
  /*
***************
*** 620,625 **** RenameTSDictionary(List *oldname, const char *newname)
--- 695,781 ----
  }
  
  /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSDictionaryNamespace(List *name, const char *newschema)
+ {
+ 	Oid			dictId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	dictId = get_ts_dict_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSDictionaryNamespace_internal(rel, dictId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	AlterTSDictionaryNamespace_internal(rel, dictId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSDictionaryNamespace_internal(Relation rel, Oid dictId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_dict dict;
+ 
+ 	tup = SearchSysCacheCopy1(TSDICTOID, ObjectIdGetDatum(dictId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search dictionary %u",
+ 			 dictId);
+ 
+ 	dict = ((Form_pg_ts_dict) GETSTRUCT(tup));
+ 	oldNspOid = dict->dictnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  TSDictionaryRelationId, dictId,
+ 					  NameStr(dict->dictname));
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_ts_dict_ownercheck(dictId, GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
+ 						   NameStr(dict->dictname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(oldNspOid));
+ 	}
+ 
+ 	dict->dictnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSDictionaryRelationId, dictId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
+ /*
   * DROP TEXT SEARCH DICTIONARY
   */
  void
***************
*** 1100,1105 **** RenameTSTemplate(List *oldname, const char *newname)
--- 1256,1330 ----
  }
  
  /*
+  * ALTER TEXT SEARCH TEMPLATE any_name SET SCHEMA name
+  */
+ void
+ AlterTSTemplateNamespace(List *name, const char *newschema)
+ {
+ 	Oid			tmplId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	tmplId = get_ts_template_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSTemplateNamespace_internal(rel, tmplId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	AlterTSTemplateNamespace_internal(rel, tmplId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSTemplateNamespace_internal(Relation rel, Oid tmplId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_template tmpl;
+ 
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 			   errmsg("must be superuser to rename text search templates")));
+ 
+ 	tup = SearchSysCacheCopy1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search template %u",
+ 			 tmplId);
+ 
+ 	tmpl = (Form_pg_ts_template) GETSTRUCT(tup);
+ 	oldNspOid = tmpl->tmplnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  TSTemplateRelationId, tmplId, NameStr(tmpl->tmplname));
+ 
+ 	tmpl->tmplnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSTemplateRelationId, tmplId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH TEMPLATE
   */
  void
***************
*** 1498,1503 **** RenameTSConfiguration(List *oldname, const char *newname)
--- 1723,1807 ----
  }
  
  /*
+  * ALTER TEXT SEARCH CONFIGURATION any_name SET SCHEMA name
+  */
+ void
+ AlterTSConfigurationNamespace(List *name, const char *newschema)
+ {
+ 	Oid			cfgId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	cfgId = get_ts_config_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterTSConfigurationNamespace_internal(rel, cfgId, nspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	AlterTSConfigurationNamespace_internal(rel, cfgId, newNspOid);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSConfigurationNamespace_internal(Relation rel, Oid cfgId, Oid nspOid)
+ {
+ 	HeapTuple	tup;
+ 	Oid			oldNspOid;
+ 	Form_pg_ts_config cfg;
+ 
+ 	tup = SearchSysCacheCopy1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
+ 
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for text search configuration %u",
+ 			 cfgId);
+ 
+ 	cfg = (Form_pg_ts_config) GETSTRUCT(tup);
+ 	oldNspOid = cfg->cfgnamespace;
+ 
+ 	CheckSetNamespace(oldNspOid, nspOid,
+ 					  TSConfigRelationId, cfgId, NameStr(cfg->cfgname));
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		AclResult	aclresult;
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		if (!pg_ts_config_ownercheck(cfgId, GetUserId()))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
+ 						   NameStr(cfg->cfgname));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
+ 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 					   get_namespace_name(oldNspOid));
+ 	}
+ 
+ 	cfg->cfgnamespace = nspOid;
+ 	simple_heap_update(rel, &tup->t_self, tup);
+ 	CatalogUpdateIndexes(rel, tup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(TSConfigRelationId, cfgId,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ 
+ 	heap_freetuple(tup);
+ }
+ 
+ /*
   * DROP TEXT SEARCH CONFIGURATION
   */
  void
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 6040,6045 **** AlterObjectSchemaStmt:
--- 6040,6053 ----
  					n->newschema = $7;
  					$$ = (Node *)n;
  				}
+ 			| ALTER CONVERSION_P any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_CONVERSION;
+ 					n->object = $3;
+ 					n->newschema = $6;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER DOMAIN_P any_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6057,6062 **** AlterObjectSchemaStmt:
--- 6065,6097 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER OPERATOR any_operator oper_argtypes SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPERATOR;
+ 					n->object = $3;
+ 					n->objarg = $4;
+ 					n->newschema = $7;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPCLASS;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPFAMILY;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER TABLE relation_expr SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6065,6070 **** AlterObjectSchemaStmt:
--- 6100,6137 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSPARSER;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSDICTIONARY;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSTEMPLATE;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSCONFIGURATION;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER SEQUENCE qualified_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 1694,1702 **** CreateCommandTag(Node *parsetree)
--- 1694,1714 ----
  				case OBJECT_AGGREGATE:
  					tag = "ALTER AGGREGATE";
  					break;
+ 				case OBJECT_CONVERSION:
+ 					tag = "ALTER CONVERSION";
+ 					break;
  				case OBJECT_DOMAIN:
  					tag = "ALTER DOMAIN";
  					break;
+ 				case OBJECT_OPERATOR:
+ 					tag = "ALTER OPERATOR";
+ 					break;
+ 				case OBJECT_OPCLASS:
+ 					tag = "ALTER OPERATOR CLASS";
+ 					break;
+ 				case OBJECT_OPFAMILY:
+ 					tag = "ALTER OPERATOR FAMILY";
+ 					break;
  				case OBJECT_FUNCTION:
  					tag = "ALTER FUNCTION";
  					break;
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
***************
*** 166,171 **** extern ObjectClass getObjectClass(const ObjectAddress *object);
--- 166,173 ----
  
  extern char *getObjectDescription(const ObjectAddress *object);
  
+ extern char *getObjectDescriptionOids(Oid classid, Oid objid);
+ 
  extern ObjectAddresses *new_object_addresses(void);
  
  extern void add_exact_object_address(const ObjectAddress *object,
*** a/src/include/catalog/namespace.h
--- b/src/include/catalog/namespace.h
***************
*** 94,99 **** extern Oid	LookupExplicitNamespace(const char *nspname);
--- 94,101 ----
  extern Oid	get_namespace_oid(const char *nspname, bool missing_ok);
  
  extern Oid	LookupCreationNamespace(const char *nspname);
+ extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid,
+ 							  Oid objid, const char *name);
  extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p);
  extern RangeVar *makeRangeVarFromNameList(List *names);
  extern char *NameListToString(List *names);
*** a/src/include/commands/conversioncmds.h
--- b/src/include/commands/conversioncmds.h
***************
*** 22,26 **** extern void DropConversionsCommand(DropStmt *drop);
--- 22,29 ----
  extern void RenameConversion(List *name, const char *newname);
  extern void AlterConversionOwner(List *name, Oid newOwnerId);
  extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
+ extern void AlterConversionNamespace(List *name, const char *newschema);
+ extern void AlterConversionNamespace_oid(Oid convOid, Oid newNspOid);
+ 
  
  #endif   /* CONVERSIONCMDS_H */
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 66,71 **** extern void DropCast(DropCastStmt *stmt);
--- 66,72 ----
  extern void DropCastById(Oid castOid);
  extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema);
+ extern void AlterFunctionNamespace_oid(Oid procOid, Oid nspOid);
  extern void ExecuteDoStmt(DoStmt *stmt);
  extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
  
***************
*** 78,83 **** extern void AlterOperatorOwner(List *name, TypeName *typeName1,
--- 79,86 ----
  extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId);
  extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
  extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern void AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid);
+ extern void AlterOperatorNamespace(List *names, List *argtypes, const char *newschema);
  
  /* commands/aggregatecmds.c */
  extern void DefineAggregate(List *name, List *args, bool oldstyle,
***************
*** 100,114 **** extern void RenameOpClass(List *name, const char *access_method, const char *new
--- 103,123 ----
  extern void RenameOpFamily(List *name, const char *access_method, const char *newname);
  extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId);
+ extern void AlterOpClassNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid);
  extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId);
  extern Oid get_am_oid(const char *amname, bool missing_ok);
+ extern void AlterOpFamilyNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid);
  
  /* commands/tsearchcmds.c */
  extern void DefineTSParser(List *names, List *parameters);
  extern void RenameTSParser(List *oldname, const char *newname);
  extern void RemoveTSParsers(DropStmt *drop);
  extern void RemoveTSParserById(Oid prsId);
+ extern void AlterTSParserNamespace(List *name, const char *newschema);
+ extern void AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
  
  extern void DefineTSDictionary(List *names, List *parameters);
  extern void RenameTSDictionary(List *oldname, const char *newname);
***************
*** 116,129 **** extern void RemoveTSDictionaries(DropStmt *drop);
--- 125,144 ----
  extern void RemoveTSDictionaryById(Oid dictId);
  extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
  extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
+ extern void AlterTSDictionaryNamespace(List *name, const char *newschema);
+ extern void AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid);
  
  extern void DefineTSTemplate(List *names, List *parameters);
  extern void RenameTSTemplate(List *oldname, const char *newname);
+ extern void AlterTSTemplateNamespace(List *name, const char *newschema);
+ extern void AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
  extern void RemoveTSTemplates(DropStmt *stmt);
  extern void RemoveTSTemplateById(Oid tmplId);
  
  extern void DefineTSConfiguration(List *names, List *parameters);
  extern void RenameTSConfiguration(List *oldname, const char *newname);
+ extern void AlterTSConfigurationNamespace(List *name, const char *newschema);
+ extern void AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid);
  extern void RemoveTSConfigurations(DropStmt *stmt);
  extern void RemoveTSConfigurationById(Oid cfgId);
  extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
alter_extension.1.patchtext/x-patchDownload
*** 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);
#25Alvaro Herrera
alvherre@commandprompt.com
In reply to: Dimitri Fontaine (#24)
Re: ALTER OBJECT any_name SET SCHEMA name

Excerpts from Dimitri Fontaine's message of jue nov 04 11:06:48 -0300 2010:

Alvaro Herrera <alvherre@commandprompt.com> writes:

FWIW I think you should use getObjectDescription, as in the attached
patch. (Note the patch is incomplete and does not compile because only
one caller to CheckSetNamespace has been fixed).

I had to re-add the object name to the CheckSetNamespace prototype to
handle this particular check:

/* check for duplicate name (more friendly than unique-index failure) */
if (SearchSysCacheExists2(TYPENAMENSP,
CStringGetDatum(name),
ObjectIdGetDatum(nspOid)))

Hmm, this check is wrong anyway, because you're looking in the pg_type
syscache for objects from an arbitrary catalog. That needs to be fixed
somehow, but perhaps it needs to be handled by the callers, not in this
routine. Otherwise you're going to need to pass the syscache ID, as
well as Datums identifying the object, and the number of Datums.

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#26Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Alvaro Herrera (#25)
Re: ALTER OBJECT any_name SET SCHEMA name

Alvaro Herrera <alvherre@commandprompt.com> writes:

/* check for duplicate name (more friendly than unique-index failure) */
if (SearchSysCacheExists2(TYPENAMENSP,
CStringGetDatum(name),
ObjectIdGetDatum(nspOid)))

Hmm, this check is wrong anyway, because you're looking in the pg_type
syscache for objects from an arbitrary catalog. That needs to be fixed
somehow, but perhaps it needs to be handled by the callers, not in this
routine. Otherwise you're going to need to pass the syscache ID, as
well as Datums identifying the object, and the number of Datums.

How embarrassing. I wonder why this works, too:

dim=# alter operator utils.@>(utils.ltree, utils.ltree) set schema public;
ALTER OPERATOR
dim=# alter operator @>(utils.ltree, utils.ltree) set schema utils;
ALTER OPERATOR

We have :

static void
AlterOperatorNamespace_internal(Relation rel, Oid operOid, Oid nspOid)
{
...
CheckSetNamespace(oldNspOid, nspOid,
OperatorRelationId, operOid, NameStr(oprForm->oprname));

Well, I'll go fix as you say, putting the check back into the
callers. That won't help a bit with the code duplication feeling we have
when reading the patch, though. Any idea on this front?

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#27Alvaro Herrera
alvherre@commandprompt.com
In reply to: Dimitri Fontaine (#24)
Re: ALTER OBJECT any_name SET SCHEMA name

Excerpts from Dimitri Fontaine's message of jue nov 04 11:06:48 -0300 2010:

Also attached, please find the complete version of ALTER EXTENSION ext
SET SCHEMA name; with support for all contrib extensions. That's the
example that allows to see the API (AlterFooNamespace_oid and _internal
functions) in action: that should help devising the best refactoring.

Three comments,

1. wouldn't it make more sense to save the extension namespace in the
extension catalog?

2. I think the guts of AlterExtensionNamespace (the large switch block)
should be elsewhere, probably in alter.c

3. Not this patch, but I think using "extension" as a global variable
name is a bad idea.

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#28Tom Lane
tgl@sss.pgh.pa.us
In reply to: Dimitri Fontaine (#26)
Re: ALTER OBJECT any_name SET SCHEMA name

Dimitri Fontaine <dimitri@2ndQuadrant.fr> writes:

Well, I'll go fix as you say, putting the check back into the
callers. That won't help a bit with the code duplication feeling we have
when reading the patch, though. Any idea on this front?

Not having read the patch, but ... the idea that was in the back of
my mind was to have a generic AlterObjectNamespace function that
would take parameters approximately like the following:

OID of catalog containing object
Column number of catalog's namespace column (Anum_xxx constant)
OID of intended new namespace

You could do a generic heap_open() on the catalog using the OID,
and then use heap_modify_tuple to apply the namespace column update.

It might be nice to include the "object already exists" check here
too, which could probably be done if in addition the column number
of the name column were passed in. Permission checks too, if the
owner column number were passed in. Etc.

Obviously this doesn't work for tables, but they're sufficiently
complex beasts that it's not unusual for them to need a different
code path. Doesn't help for functions/operators either, since their
collision check isn't just name and namespace. But that's OK IMO.
I'd be happy if we could unify the code paths for objects that have a
single catalog entry to update and a simple name/namespace collision
check to make.

regards, tom lane

#29Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Alvaro Herrera (#27)
Re: ALTER OBJECT any_name SET SCHEMA name

Alvaro Herrera <alvherre@commandprompt.com> writes:

1. wouldn't it make more sense to save the extension namespace in the
extension catalog?

I don't think so, because the extension itself is not schema
qualified. What lives in the namespace the extension depends on is not
the extension itself, but its objects.

2. I think the guts of AlterExtensionNamespace (the large switch block)
should be elsewhere, probably in alter.c

Makes sense, will move there.

3. Not this patch, but I think using "extension" as a global variable
name is a bad idea.

What about create_extension_extension instead? I'm not thinking of
something better, bikeshedding is opened.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#30Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#29)
Re: ALTER OBJECT any_name SET SCHEMA name

On Thu, Nov 4, 2010 at 7:52 AM, Dimitri Fontaine <dimitri@2ndquadrant.fr> wrote:

What about create_extension_extension instead? I'm not thinking of
something better, bikeshedding is opened.

That doesn't seem very clear... I'm always suspicious of names that
use the same word twice, and in this case I have no idea what this
variable would supposedly refer to.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#31Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Tom Lane (#28)
Re: ALTER OBJECT any_name SET SCHEMA name

Tom Lane <tgl@sss.pgh.pa.us> writes:

Not having read the patch, but ... the idea that was in the back of
my mind was to have a generic AlterObjectNamespace function that
would take parameters approximately like the following:

OID of catalog containing object
Column number of catalog's namespace column (Anum_xxx constant)
OID of intended new namespace

Ah, the trick is to use the Anum_xxx, of course. I couldn't get rid of
thinking how to dynamically access by name... will have a try at that,
thanks for the idea.

You could do a generic heap_open() on the catalog using the OID,
and then use heap_modify_tuple to apply the namespace column update.

Thanks for pointing me to the right APIs: finding them is where the time
is mostly spent as far as I'm concerned.

It might be nice to include the "object already exists" check here
too, which could probably be done if in addition the column number
of the name column were passed in. Permission checks too, if the
owner column number were passed in. Etc.

Well it seems that depending on the object, sometime only superusers are
allowed to edit things, and sometime the owner too. Will add a boolean
superuser_only in the prototype.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#32Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Robert Haas (#30)
Re: ALTER OBJECT any_name SET SCHEMA name

Robert Haas <robertmhaas@gmail.com> writes:

On Thu, Nov 4, 2010 at 7:52 AM, Dimitri Fontaine <dimitri@2ndquadrant.fr> wrote:

What about create_extension_extension instead? I'm not thinking of
something better, bikeshedding is opened.

That doesn't seem very clear... I'm always suspicious of names that
use the same word twice, and in this case I have no idea what this
variable would supposedly refer to.

The ObjectAddress of the extension currently being installed by the
CREATE EXTENSION command we're "in" (executing the script). The variable
create_extension is already a boolean only set to true if in the code
path.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#33Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#32)
Re: ALTER OBJECT any_name SET SCHEMA name

On Thu, Nov 4, 2010 at 8:18 AM, Dimitri Fontaine <dimitri@2ndquadrant.fr> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Thu, Nov 4, 2010 at 7:52 AM, Dimitri Fontaine <dimitri@2ndquadrant.fr> wrote:

What about create_extension_extension instead? I'm not thinking of
something better, bikeshedding is opened.

That doesn't seem very clear... I'm always suspicious of names that
use the same word twice, and in this case I have no idea what this
variable would supposedly refer to.

The ObjectAddress of the extension currently being installed by the
CREATE EXTENSION command we're "in" (executing the script). The variable
create_extension is already a boolean only set to true if in the code
path.

How about calling it CurrentExtensionObjectAddress or something like
that? And maybe you don't need a boolean: if
(OidIsValid(CurrentExtensionObjectAddress.objid)) ...

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#34Alvaro Herrera
alvherre@commandprompt.com
In reply to: Dimitri Fontaine (#26)
Re: ALTER OBJECT any_name SET SCHEMA name

Excerpts from Dimitri Fontaine's message of jue nov 04 11:37:37 -0300 2010:

Alvaro Herrera <alvherre@commandprompt.com> writes:

/* check for duplicate name (more friendly than unique-index failure) */
if (SearchSysCacheExists2(TYPENAMENSP,
CStringGetDatum(name),
ObjectIdGetDatum(nspOid)))

Hmm, this check is wrong anyway, because you're looking in the pg_type
syscache for objects from an arbitrary catalog. That needs to be fixed
somehow, but perhaps it needs to be handled by the callers, not in this
routine. Otherwise you're going to need to pass the syscache ID, as
well as Datums identifying the object, and the number of Datums.

How embarrassing. I wonder why this works, too:

dim=# alter operator utils.@>(utils.ltree, utils.ltree) set schema public;
ALTER OPERATOR

Well, I guess the operator doesn't exist in the pg_type syscache, so it
doesn't ereport(ERROR).

Well, I'll go fix as you say, putting the check back into the
callers. That won't help a bit with the code duplication feeling we have
when reading the patch, though. Any idea on this front?

I'm not really sure about the code duplication bits. There are plenty
of things you cannot factor into common routines because of the need to
handle different GETSTRUCT args, different number of syscache arguments,
etc. The ALTER OWNER implementation is already "duplicated" for each
database object. Your patch is already reducing duplication by moving
some common checks into namespace.c.

If there are more things that you could do by specifying a syscache ID
and datums to be passed to it, perhaps it would make sense to use them
as parameters to a function that does the whole bunch together. This
probably doesn't belong into namespace.c though.

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#35Alvaro Herrera
alvherre@commandprompt.com
In reply to: Dimitri Fontaine (#29)
Re: ALTER OBJECT any_name SET SCHEMA name

Excerpts from Dimitri Fontaine's message of jue nov 04 11:52:53 -0300 2010:

Alvaro Herrera <alvherre@commandprompt.com> writes:

3. Not this patch, but I think using "extension" as a global variable
name is a bad idea.

What about create_extension_extension instead? I'm not thinking of
something better, bikeshedding is opened.

CreateExtensionAddress? (I like CamelCase for this because it makes
these variables stand out more against local ones, named in
stuffed_lower_case).

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#36Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Tom Lane (#28)
1 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Tom Lane <tgl@sss.pgh.pa.us> writes:

Not having read the patch, but ... the idea that was in the back of
my mind was to have a generic AlterObjectNamespace function that
would take parameters approximately like the following:

Please find attached what I came up with, that's the set_schema patch
version 6.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

set_schema.6.patchtext/x-patchDownload
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 2706,2711 **** getObjectDescription(const ObjectAddress *object)
--- 2706,2726 ----
  }
  
  /*
+  * getObjectDescriptionOids: as above, except the object is specified by Oids
+  */
+ char *
+ getObjectDescriptionOids(Oid classid, Oid objid)
+ {
+ 	ObjectAddress	address;
+ 
+ 	address.classId = classid;
+ 	address.objectId = objid;
+ 	address.objectSubId = 0;
+ 
+ 	return getObjectDescription(&address);
+ }
+ 
+ /*
   * subroutine for getObjectDescription: describe a relation
   */
  static void
*** a/src/backend/catalog/namespace.c
--- b/src/backend/catalog/namespace.c
***************
*** 2340,2345 **** LookupCreationNamespace(const char *nspname)
--- 2340,2372 ----
  }
  
  /*
+  * Check new namespace validity in ALTER OBJECT ... SET SCHEMA ... and
+  * ereport(ERROR, ...) in case of any problem.
+  */
+ void
+ CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid)
+ {
+ 	if (oldNspOid == nspOid)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s already exists in schema \"%s\"",
+ 						getObjectDescriptionOids(classid, objid),
+ 						get_namespace_name(nspOid))));
+ 
+ 	/* disallow renaming into or out of temp schemas */
+ 	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of temporary schemas")));
+ 
+ 	/* same for TOAST schema */
+ 	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of TOAST schema")));
+ }
+ 
+ /*
   * QualifiedNameGetCreationNamespace
   *		Given a possibly-qualified name for an object (in List-of-Values
   *		format), determine what namespace the object should be created in.
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 14,21 ****
--- 14,23 ----
   */
  #include "postgres.h"
  
+ #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_largeobject.h"
+ #include "catalog/pg_namespace.h"
  #include "commands/alter.h"
  #include "commands/conversioncmds.h"
  #include "commands/dbcommands.h"
***************
*** 33,38 ****
--- 35,41 ----
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
+ #include "utils/syscache.h"
  
  
  /*
***************
*** 182,192 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 185,211 ----
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_CONVERSION:
+ 			AlterConversionNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_FUNCTION:
  			AlterFunctionNamespace(stmt->object, stmt->objarg, false,
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_OPERATOR:
+ 			AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPCLASS:
+ 			AlterOpClassNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPFAMILY:
+ 			AlterOpFamilyNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_SEQUENCE:
  		case OBJECT_TABLE:
  		case OBJECT_VIEW:
***************
*** 195,200 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 214,235 ----
  								stmt->objectType, AccessExclusiveLock);
  			break;
  
+ 		case OBJECT_TSPARSER:
+ 			AlterTSParserNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSDICTIONARY:
+ 			AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSTEMPLATE:
+ 			AlterTSTemplateNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSCONFIGURATION:
+ 			AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_TYPE:
  		case OBJECT_DOMAIN:
  			AlterTypeNamespace(stmt->object, stmt->newschema);
***************
*** 207,212 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 242,341 ----
  }
  
  /*
+  * Generic function to change the namespace of a given object, for simple
+  * cases (won't work for tables or functions, e.g.)
+  *
+  * The AlterFooNamespace() calls just above will call a function whose job
+  * is to lookup the arguments for the generic function here.
+  *
+  * Relation must already by open, it's the responsibility of the caller to
+  * close it.
+  */
+ void
+ AlterObjectNamespace(Relation rel, int cacheId,
+ 					 Oid classId, Oid objid, Oid nspOid,
+ 					 int Anum_name, int Anum_namespace, int Anum_owner,
+ 					 bool superuser_only)
+ {
+ 	Oid			oldNspOid, ownerId;
+ 	Datum       name, namespace, owner;
+ 	bool        isnull;
+ 	HeapTuple	tup, newtup = NULL;
+ 	Datum		values[rel->rd_att->natts];
+ 	bool		nulls[rel->rd_att->natts];
+ 	bool		replaces[rel->rd_att->natts];
+ 	int			i;
+ 
+ 	tup = SearchSysCacheCopy1(cacheId, ObjectIdGetDatum(objid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for object %u: %s",
+ 			 objid, getObjectDescriptionOids(classId, objid));
+ 
+ 	name = heap_getattr(tup, Anum_name, rel->rd_att, &isnull);
+ 	namespace = heap_getattr(tup, Anum_namespace, rel->rd_att, &isnull);
+ 	owner = heap_getattr(tup, Anum_owner, rel->rd_att, &isnull);
+ 
+ 	oldNspOid = DatumGetObjectId(namespace);
+ 	ownerId = DatumGetObjectId(owner);
+ 
+ 	/* Check basic namespace related issues */
+ 	CheckSetNamespace(oldNspOid, nspOid, classId, objid);
+ 
+ 	/* check for duplicate name (more friendly than unique-index failure) */
+ 	if (SearchSysCacheExists2(cacheId, name, ObjectIdGetDatum(nspOid)))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s already exists in schema \"%s\"",
+ 						getObjectDescriptionOids(classId, objid),
+ 						get_namespace_name(nspOid))));
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		Datum       owner;
+ 		Oid			ownerId;
+ 		AclResult	aclresult;
+ 
+ 		if (superuser_only)
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 					 (errmsg("must be superuser to SET SCHEMA of %s",
+ 							 getObjectDescriptionOids(classId, objid)))));
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		owner = heap_getattr(tup, Anum_owner, rel->rd_att, &isnull);
+ 		ownerId = DatumGetObjectId(owner);
+ 
+ 		if (!has_privs_of_role(GetUserId(), ownerId))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
+ 						   NameStr(*(DatumGetName(name))));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(oldNspOid));
+ 	}
+ 
+ 	/* prepare a new version of the tuple using nspId */
+ 	values[Anum_namespace - 1] = nspOid;
+ 	for (i = 0; i < rel->rd_att->natts; i++)
+ 	{
+ 		nulls[i]    = i != Anum_namespace - 1;
+ 		replaces[i] = i == Anum_namespace - 1;
+ 	}
+ 
+ 	newtup = heap_modify_tuple(tup, rel->rd_att, values, nulls, replaces);
+ 	simple_heap_update(rel, &tup->t_self, newtup);
+ 	CatalogUpdateIndexes(rel, newtup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(classId, objid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
+ 
+ 
+ /*
   * Executes an ALTER OBJECT / OWNER TO statement.  Based on the object
   * type, the function appropriate to that type is executed.
   */
*** a/src/backend/commands/conversioncmds.c
--- b/src/backend/commands/conversioncmds.c
***************
*** 19,25 ****
--- 19,27 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_conversion.h"
  #include "catalog/pg_conversion_fn.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/conversioncmds.h"
  #include "mb/pg_wchar.h"
  #include "miscadmin.h"
***************
*** 30,36 ****
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
! static void AlterConversionOwner_internal(Relation rel, Oid conversionOid,
  							  Oid newOwnerId);
  
  /*
--- 32,38 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
! static void AlterConversionOwner_internal(Relation rel, Oid convOid,
  							  Oid newOwnerId);
  
  /*
***************
*** 326,328 **** AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId)
--- 328,374 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER CONVERSION SET SCHEMA
+  */
+ void
+ AlterConversionNamespace(List *name, const char *newschema)
+ {
+ 	Oid			convOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	convOid = get_conversion_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, CONVOID, ConversionRelationId, convOid, nspOid,
+ 						 Anum_pg_conversion_conname,
+ 						 Anum_pg_conversion_connamespace,
+ 						 Anum_pg_conversion_conowner,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
+  * Change conversion schema, by oid
+  */
+ void
+ AlterConversionNamespace_oid(Oid convOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, CONVOID, ConversionRelationId, convOid, newNspOid,
+ 						 Anum_pg_conversion_conname,
+ 						 Anum_pg_conversion_connamespace,
+ 						 Anum_pg_conversion_conowner,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/functioncmds.c
--- b/src/backend/commands/functioncmds.c
***************
*** 1870,1882 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema)
  {
  	Oid			procOid;
- 	Oid			oldNspOid;
  	Oid			nspOid;
- 	HeapTuple	tup;
- 	Relation	procRel;
- 	Form_pg_proc proc;
- 
- 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
  
  	/* get function OID */
  	if (isagg)
--- 1870,1876 ----
***************
*** 1889,1894 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
--- 1883,1903 ----
  		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
  					   NameListToString(name));
  
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterFunctionNamespace_oid(procOid, nspOid);
+ }
+ 
+ void
+ AlterFunctionNamespace_oid(Oid procOid, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 	Relation	procRel;
+ 	Form_pg_proc proc;
+ 
+ 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
+ 
  	tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid));
  	if (!HeapTupleIsValid(tup))
  		elog(ERROR, "cache lookup failed for function %u", procOid);
***************
*** 1896,1910 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  
  	oldNspOid = proc->pronamespace;
  
- 	/* get schema OID and check its permissions */
- 	nspOid = LookupCreationNamespace(newschema);
- 
  	if (oldNspOid == nspOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" is already in schema \"%s\"",
! 						NameListToString(name),
! 						newschema)));
  
  	/* disallow renaming into or out of temp schemas */
  	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
--- 1905,1916 ----
  
  	oldNspOid = proc->pronamespace;
  
  	if (oldNspOid == nspOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" is already in schema \"%s\"",
! 						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* disallow renaming into or out of temp schemas */
  	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
***************
*** 1927,1933 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						newschema)));
  
  	/* OK, modify the pg_proc row */
  
--- 1933,1939 ----
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* OK, modify the pg_proc row */
  
***************
*** 1941,1947 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameListToString(name));
  
  	heap_freetuple(tup);
  
--- 1947,1953 ----
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameStr(proc->proname));
  
  	heap_freetuple(tup);
  
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 30,35 ****
--- 30,36 ----
  #include "catalog/pg_opfamily.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "parser/parse_func.h"
***************
*** 1912,1917 **** AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
--- 1913,1978 ----
  }
  
  /*
+  * ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpClassNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup, origtup;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	/* Look up the opclass. */
+ 	origtup = OpClassCacheLookup(amOid, name, false);
+ 	tup = heap_copytuple(origtup);
+ 	ReleaseSysCache(origtup);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, CLAOID, OperatorClassRelationId,
+ 						 HeapTupleGetOid(tup), nspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(CLAOID, ObjectIdGetDatum(opclassOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
+ 
+ 	AlterObjectNamespace(rel, CLAOID, OperatorClassRelationId,
+ 						 HeapTupleGetOid(tup), newNspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
   * Change opfamily owner by name
   */
  void
***************
*** 2067,2069 **** get_am_oid(const char *amname, bool missing_ok)
--- 2128,2222 ----
  				 errmsg("access method \"%s\" does not exist", amname)));
  	return oid;
  }
+ 
+ /*
+  * ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpFamilyNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup;
+ 	char	   *opfname, *schemaname;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	/*
+ 	 * Look up the opfamily
+ 	 */
+ 	DeconstructQualifiedName(name, &schemaname, &opfname);
+ 
+ 	if (schemaname)
+ 	{
+ 		Oid			namespaceOid;
+ 
+ 		namespaceOid = LookupExplicitNamespace(schemaname);
+ 
+ 		tup = SearchSysCacheCopy3(OPFAMILYAMNAMENSP,
+ 								  ObjectIdGetDatum(amOid),
+ 								  PointerGetDatum(opfname),
+ 								  ObjectIdGetDatum(namespaceOid));
+ 		if (!HeapTupleIsValid(tup))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 	}
+ 	else
+ 	{
+ 		Oid			opfOid;
+ 
+ 		opfOid = OpfamilynameGetOpfid(amOid, opfname);
+ 		if (!OidIsValid(opfOid))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 
+ 		tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfOid));
+ 		if (!HeapTupleIsValid(tup))		/* should not happen */
+ 			elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
+ 	}
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, OPFAMILYOID, OperatorFamilyRelationId,
+ 						 HeapTupleGetOid(tup), nspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
+ 
+ 	AlterObjectNamespace(rel, OPFAMILYOID, OperatorFamilyRelationId,
+ 						 opfamilyOid, newNspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/operatorcmds.c
--- b/src/backend/commands/operatorcmds.c
***************
*** 39,45 ****
--- 39,47 ----
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_operator.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "parser/parse_func.h"
***************
*** 452,454 **** AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
--- 454,503 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER OPERATOR SET SCHEMA
+  */
+ void
+ AlterOperatorNamespace(List *names, List *argtypes, const char *newschema)
+ {
+ 	List	   *operatorName = names;
+ 	TypeName   *typeName1 = (TypeName *) linitial(argtypes);
+ 	TypeName   *typeName2 = (TypeName *) lsecond(argtypes);
+ 	Oid			operOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	Assert(list_length(argtypes) == 2);
+ 	operOid = LookupOperNameTypeNames(NULL, operatorName,
+ 									  typeName1, typeName2,
+ 									  false, -1);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, OPEROID, OperatorRelationId, operOid, nspOid,
+ 						 Anum_pg_operator_oprname,
+ 						 Anum_pg_operator_oprnamespace,
+ 						 Anum_pg_operator_oprowner,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, OPEROID, OperatorRelationId, operOid, newNspOid,
+ 						 Anum_pg_operator_oprname,
+ 						 Anum_pg_operator_oprnamespace,
+ 						 Anum_pg_operator_oprowner,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/tsearchcmds.c
--- b/src/backend/commands/tsearchcmds.c
***************
*** 31,36 ****
--- 31,38 ----
  #include "catalog/pg_ts_parser.h"
  #include "catalog/pg_ts_template.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
+ #include "commands/extension.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "nodes/makefuncs.h"
***************
*** 393,398 **** RenameTSParser(List *oldname, const char *newname)
--- 395,441 ----
  	heap_freetuple(tup);
  }
  
+ /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSParserNamespace(List *name, const char *newschema)
+ {
+ 	Oid			prsId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	prsId = get_ts_parser_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSPARSEROID, TSParserRelationId, prsId, nspOid,
+ 						 Anum_pg_ts_parser_prsname,
+ 						 Anum_pg_ts_parser_prsnamespace,
+ 						 -1,
+ 						 true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSPARSEROID, TSParserRelationId, prsId, newNspOid,
+ 						 Anum_pg_ts_parser_prsname,
+ 						 Anum_pg_ts_parser_prsnamespace,
+ 						 -1,
+ 						 true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
  /* ---------------------- TS Dictionary commands -----------------------*/
  
  /*
***************
*** 620,625 **** RenameTSDictionary(List *oldname, const char *newname)
--- 663,709 ----
  }
  
  /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSDictionaryNamespace(List *name, const char *newschema)
+ {
+ 	Oid			dictId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	dictId = get_ts_dict_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSDICTOID, TSDictionaryRelationId, dictId, nspOid,
+ 						 Anum_pg_ts_dict_dictname,
+ 						 Anum_pg_ts_dict_dictnamespace,
+ 						 Anum_pg_ts_dict_dictowner,
+ 						 true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSDICTOID, TSDictionaryRelationId, dictId, newNspOid,
+ 						 Anum_pg_ts_dict_dictname,
+ 						 Anum_pg_ts_dict_dictnamespace,
+ 						 Anum_pg_ts_dict_dictowner,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
   * DROP TEXT SEARCH DICTIONARY
   */
  void
***************
*** 1100,1105 **** RenameTSTemplate(List *oldname, const char *newname)
--- 1184,1233 ----
  }
  
  /*
+  * ALTER TEXT SEARCH TEMPLATE any_name SET SCHEMA name
+  */
+ void
+ AlterTSTemplateNamespace(List *name, const char *newschema)
+ {
+ 	Oid			tmplId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	tmplId = get_ts_template_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSTEMPLATEOID, TSTemplateRelationId,
+ 						 tmplId, nspOid,
+ 						 Anum_pg_ts_template_tmplname,
+ 						 Anum_pg_ts_template_tmplnamespace,
+ 						 -1,
+ 						 true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSTEMPLATEOID, TSTemplateRelationId,
+ 						 tmplId, newNspOid,
+ 						 Anum_pg_ts_template_tmplname,
+ 						 Anum_pg_ts_template_tmplnamespace,
+ 						 -1,
+ 						 true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH TEMPLATE
   */
  void
***************
*** 1498,1503 **** RenameTSConfiguration(List *oldname, const char *newname)
--- 1626,1673 ----
  }
  
  /*
+  * ALTER TEXT SEARCH CONFIGURATION any_name SET SCHEMA name
+  */
+ void
+ AlterTSConfigurationNamespace(List *name, const char *newschema)
+ {
+ 	Oid			cfgId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	cfgId = get_ts_config_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSCONFIGOID, TSConfigRelationId, cfgId, nspOid,
+ 						 Anum_pg_ts_config_cfgname,
+ 						 Anum_pg_ts_config_cfgnamespace,
+ 						 Anum_pg_ts_config_cfgowner,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSCONFIGOID, TSConfigRelationId, cfgId, newNspOid,
+ 						 Anum_pg_ts_config_cfgname,
+ 						 Anum_pg_ts_config_cfgnamespace,
+ 						 Anum_pg_ts_config_cfgowner,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH CONFIGURATION
   */
  void
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 6040,6045 **** AlterObjectSchemaStmt:
--- 6040,6053 ----
  					n->newschema = $7;
  					$$ = (Node *)n;
  				}
+ 			| ALTER CONVERSION_P any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_CONVERSION;
+ 					n->object = $3;
+ 					n->newschema = $6;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER DOMAIN_P any_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6057,6062 **** AlterObjectSchemaStmt:
--- 6065,6097 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER OPERATOR any_operator oper_argtypes SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPERATOR;
+ 					n->object = $3;
+ 					n->objarg = $4;
+ 					n->newschema = $7;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPCLASS;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPFAMILY;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER TABLE relation_expr SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6065,6070 **** AlterObjectSchemaStmt:
--- 6100,6137 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSPARSER;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSDICTIONARY;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSTEMPLATE;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSCONFIGURATION;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER SEQUENCE qualified_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 1694,1702 **** CreateCommandTag(Node *parsetree)
--- 1694,1714 ----
  				case OBJECT_AGGREGATE:
  					tag = "ALTER AGGREGATE";
  					break;
+ 				case OBJECT_CONVERSION:
+ 					tag = "ALTER CONVERSION";
+ 					break;
  				case OBJECT_DOMAIN:
  					tag = "ALTER DOMAIN";
  					break;
+ 				case OBJECT_OPERATOR:
+ 					tag = "ALTER OPERATOR";
+ 					break;
+ 				case OBJECT_OPCLASS:
+ 					tag = "ALTER OPERATOR CLASS";
+ 					break;
+ 				case OBJECT_OPFAMILY:
+ 					tag = "ALTER OPERATOR FAMILY";
+ 					break;
  				case OBJECT_FUNCTION:
  					tag = "ALTER FUNCTION";
  					break;
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
***************
*** 166,171 **** extern ObjectClass getObjectClass(const ObjectAddress *object);
--- 166,173 ----
  
  extern char *getObjectDescription(const ObjectAddress *object);
  
+ extern char *getObjectDescriptionOids(Oid classid, Oid objid);
+ 
  extern ObjectAddresses *new_object_addresses(void);
  
  extern void add_exact_object_address(const ObjectAddress *object,
*** a/src/include/catalog/namespace.h
--- b/src/include/catalog/namespace.h
***************
*** 94,99 **** extern Oid	LookupExplicitNamespace(const char *nspname);
--- 94,101 ----
  extern Oid	get_namespace_oid(const char *nspname, bool missing_ok);
  
  extern Oid	LookupCreationNamespace(const char *nspname);
+ extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid,
+ 							  Oid objid);
  extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p);
  extern RangeVar *makeRangeVarFromNameList(List *names);
  extern char *NameListToString(List *names);
*** a/src/include/commands/alter.h
--- b/src/include/commands/alter.h
***************
*** 15,23 ****
--- 15,28 ----
  #define ALTER_H
  
  #include "nodes/parsenodes.h"
+ #include "utils/relcache.h"
  
  extern void ExecRenameStmt(RenameStmt *stmt);
  extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt);
+ extern void AlterObjectNamespace(Relation rel, int cacheId,
+ 								 Oid classId, Oid objid, Oid nspId,
+ 								 int Anum_name, int Anum_namespace, int Anum_owner,
+ 								 bool superuser_only);
  extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt);
  
  #endif   /* ALTER_H */
*** a/src/include/commands/conversioncmds.h
--- b/src/include/commands/conversioncmds.h
***************
*** 22,26 **** extern void DropConversionsCommand(DropStmt *drop);
--- 22,29 ----
  extern void RenameConversion(List *name, const char *newname);
  extern void AlterConversionOwner(List *name, Oid newOwnerId);
  extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
+ extern void AlterConversionNamespace(List *name, const char *newschema);
+ extern void AlterConversionNamespace_oid(Oid convOid, Oid newNspOid);
+ 
  
  #endif   /* CONVERSIONCMDS_H */
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 66,71 **** extern void DropCast(DropCastStmt *stmt);
--- 66,72 ----
  extern void DropCastById(Oid castOid);
  extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema);
+ extern void AlterFunctionNamespace_oid(Oid procOid, Oid nspOid);
  extern void ExecuteDoStmt(DoStmt *stmt);
  extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
  
***************
*** 78,83 **** extern void AlterOperatorOwner(List *name, TypeName *typeName1,
--- 79,86 ----
  extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId);
  extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
  extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern void AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid);
+ extern void AlterOperatorNamespace(List *names, List *argtypes, const char *newschema);
  
  /* commands/aggregatecmds.c */
  extern void DefineAggregate(List *name, List *args, bool oldstyle,
***************
*** 100,114 **** extern void RenameOpClass(List *name, const char *access_method, const char *new
--- 103,123 ----
  extern void RenameOpFamily(List *name, const char *access_method, const char *newname);
  extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId);
+ extern void AlterOpClassNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid);
  extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId);
  extern Oid get_am_oid(const char *amname, bool missing_ok);
+ extern void AlterOpFamilyNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid);
  
  /* commands/tsearchcmds.c */
  extern void DefineTSParser(List *names, List *parameters);
  extern void RenameTSParser(List *oldname, const char *newname);
  extern void RemoveTSParsers(DropStmt *drop);
  extern void RemoveTSParserById(Oid prsId);
+ extern void AlterTSParserNamespace(List *name, const char *newschema);
+ extern void AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
  
  extern void DefineTSDictionary(List *names, List *parameters);
  extern void RenameTSDictionary(List *oldname, const char *newname);
***************
*** 116,129 **** extern void RemoveTSDictionaries(DropStmt *drop);
--- 125,144 ----
  extern void RemoveTSDictionaryById(Oid dictId);
  extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
  extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
+ extern void AlterTSDictionaryNamespace(List *name, const char *newschema);
+ extern void AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid);
  
  extern void DefineTSTemplate(List *names, List *parameters);
  extern void RenameTSTemplate(List *oldname, const char *newname);
+ extern void AlterTSTemplateNamespace(List *name, const char *newschema);
+ extern void AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
  extern void RemoveTSTemplates(DropStmt *stmt);
  extern void RemoveTSTemplateById(Oid tmplId);
  
  extern void DefineTSConfiguration(List *names, List *parameters);
  extern void RenameTSConfiguration(List *oldname, const char *newname);
+ extern void AlterTSConfigurationNamespace(List *name, const char *newschema);
+ extern void AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid);
  extern void RemoveTSConfigurations(DropStmt *stmt);
  extern void RemoveTSConfigurationById(Oid cfgId);
  extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
#37Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Alvaro Herrera (#27)
1 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Alvaro Herrera <alvherre@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

Attachments:

alter_extension.2.patchtext/x-patchDownload
*** 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);
#38Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Alvaro Herrera (#35)
1 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Alvaro Herrera <alvherre@commandprompt.com> writes:

CreateExtensionAddress? (I like CamelCase for this because it makes
these variables stand out more against local ones, named in
stuffed_lower_case).

The version v14 of the extension main patch is there. It's still a
"cumulative" patch containing the pg_execute_from_file() and cfparser
patches so that it's self-consistent and you can test it, but it's not
containing the set_schema stuff nor the ALTER EXTENSION ... SET SCHEMA
stuff. I can produce a all-combined-patch for those interested, or they
could just use the git branch alter_extension from the repository:

http://git.postgresql.org/gitweb?p=postgresql-extension.git;a=shortlog;h=refs/heads/alter_extension

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

extension.v14.patch.gzapplication/octet-streamDownload
��Lextension.v14.patch��y_�H�8����j���a��C�;���`0��t��W�2����������?g�*UI%��}�7�cl��:u�����G�_��Q��Wk�`F��f���&���/����jV�G�?�-��fS�/qtpq�����L<�v#�cD-C�M_V�"�(�Fa�f�h���q����V+1<��c����}������ok�O�.��������~l����;����p�e��;{�s�������������z^�����	6�����%�0�����N_o���hT�n���]<j��s
�i�������X�U`g��h���(
�����8�p�W�@�f���o1�F�
�b'�,N��$���xj�
�����Z��s���� �]�QP8
�&�\��[��W��.n��k�<�Z����b8�}�Nv�8��;������hi���� ��A&�!|��w�x�'�?�qu���
�1��
kF�q������%��
O��^uND:�L�$#��W)��$H���#�I0'�@)6�m�����N��vxvB�=���p���������n�T�A�����b!WS��Ioa�W���T\#p%����_����C�M��wzz5
�����y���-N�����������G�=t�������I��<:����`����M��K��:�s���<?���8�M�Q�X���AL�7�����\78��<�f�p��!}�	���������ZM�I
'r=���lT�����Y8���$������|Gg��N�*��G�AxS�L�Y/�c���:�	�jl�F�a����O{�31����q���/����w��0���������X/~�y�3�c�6��o�L�4�Bt��������������$C
@%bu�O�&������n����5; ���}���_�E-�����n��.��@�
���@`��8,�>��s"��B��w�Y���.u��4:a �i�_sVb��E���h�dv�S*�����!^��x�����[^s���sUM�@��J��(+n�W����t�y��Lz�y��9�.X��B��8x���>"X�����zk��#�*r�������0d��  ���sK��u�?��+O��)�uzTb��k#��N.�b�5/�B����A���}�����W���{��7�AG<���AD���y2q����S�+a�I��|F��#I0I8���(�h�(�)�}�;Y�}4���q,U?���T����A�
��� _��Us���wA�5g��O:%�9}�y�?���*�����usU}C���{8/+����?�p�{�����\9�g9�����!$��4�(���N�0���6�����/|���;�����g�U���s����3�o="���Eq��N'A�G%������)�
h���	��3p����|�yZF��Z/���6NU^Lg��P�|����z����W��-��������1���&�(^���x�W^C�*	[�G-�I��KU�{���&���$�:��!�V�1�nj�,S����u���.��S�.`���-C�QB���,;��5E������P
��R:2�d:"b��\����]h��ex��s�\��0�j�.xO�l��2��|�����s�6�@��� \�+E��!n�ZXL�X�b����� ��^�����P�a/�=��{���?,��w�p%�a���������4�}BG���m.�efM��m��8�����e�.�2���'��������-�~�2�6e���`wb��s���O}���`6����w�����S��*
��H�$�����`d��&��F�DK��5+4��B_5d/�=�b-����6<;#�J�8�I��+���d�:�JY\N;k&NT�@��Q����Bi�
��&`@5�;=���$4p�+\�.~89x�^�V��+3���^�{QRl=l`�I��
����lO��_EUE�E����	���R�&�'�����Xk4�q�G�A��,P_K��n�q=���P���1�"[�������V��x�'3�W���[������7Z7=��:W����-L��jBs�kU���&����p�����W ���!���va|�R$�6��{��k�E�4��������\�1F�}
�!.��G�����1z�����{I��}����G�@L��6|��W����������.~9k����M�~��V������l�__W���[�����a�����]bh��$�5��4s9^)�+����C���'���Y��qHQ$q
��z'D�� �W�'��*�G@+�>�8�$��f��������0N�[��F��A��j�

g��Q���g0=�k�o��GB�':5�f}n����Nz�Y��4O��^�a�B
�
���e�!G��k�$�;x�e>���w���z����M���"V�#�V*^�W�)oJ�]��>����Dm�K���
�������+#�*�R
�R��1�L�x0����U��_W�{k5h7��_��Y?������'�\QV�5��:��p�}���,��	'��7�s&�����Cl�Y����GxW�`��+8��00�_X"������F�8���@�2$,|.y,�Si�Z�L��>���q3����F���h��c�
��������&S����6�*�������(�/�T���0�����:=�j��P<��^��s���-����.^�o���<M��4�>���8���_���������3��'�����s'fo�����M`(U��Y�	M<�Z����L$�-VGs�O�[H�;�[��t,���C#{�;�2�a^��o��!��_�0���q��DQ�C	
�mxLl������������J����jN�2����fvC�A��z���Y���9�j�Ea��-��C9I����x���l)a:XFe�����v��Q"1���a�ia*EV+e�I4 ��?	��
*,B�F5cq1snD�H�{�����R�����U�X�1��w�����O�)W��s/�H�t�����L�.�(�2k/����3����W���-N����l�Ua)A�������������BP�T��Z��O��g��8�3��g�I���N	$�Tf�A�������=,���,f�]QO�9��_V)��c>�-��l��%~�
b�.�OHP����}b�`����
����>�g�V!����
-��g���� L:�0��!���I_��g�K�y	���z<�������h�V:�q�.lJ���	M����<!��+���#S&�w�K����z�xR��U��a��'�q�Rq4�e������5�q�HS��Of#�O>�{���] (zZ\���]`���m6�q��L�[(Xh����_�_��]���a���$��h�#�[�$���z��'�8�m�x�{��ok�/����.���n����������#���(������Z}y8^���5zv������_,�@��U���b�A�&���� ��o�0�O��D�cj�t��;�"`$��(����2�K,�_���W�Es����8*�Z�
�~��TS�������� ���B��5��@�E8��-���:\��@3���T7�e��|X��	:uF>���S'��O//h/�A���s�--�����X�s��^�����f�	e��h���QdaT��6b����0S^s�b�T�kAP���sx0��M,��24n�7���6D4�@G��V ������f5�� %=�YG��oD�E�U������.ek%2��������DW�oe���>��� ��U���6z9'�J�y9����>�"���b\�E�����>�&i�'0����j�Q��G,��������rqlcW�����;L����>7������B�.<�8L���o�r
a���7������f0�>		���C'6�����$8����$>\�E
��50H��a�N�x�q=�����[,&#t�E8������r����HM�.:�9r��2��Q`?�#L\�������X#����]<�~�vuLC���`r3��!�c��x��h
������f���FlTg�A�����G�Df.�������	X����4a#��e�YS�E�������k��S��[�*��S�.��ga�O<�{Qq�'U�vD�������������=,>����MrF3.��b5�������U�J�C(�Eu����+��Q�~ ^n��oc\�zy��������z����3S1�d�=�C�
���a5�;0������{��n%����V�/p
�oz�$��]�Mp�������.6�y��3�a��X�9�$�������r��Aq������D\|�Y���N��p������Br�Z��o�b����DF(�K����B�^t�������n��%&���t����%Sg� �
wcw�{�g_��V:��"��&������S�;�E��R�YQ4?�*����/�
j$����
�8
�6��j�J�������
�o&8��Y������45Bg7~4s6M"�D�0�$Bg?�S@�W5Nx��hq7�d��gF��QPu#_���z�
j�Z�s���&Y
#����|���|/���y�)H3�?�S�^\E�2���X��b�&�x��9��s{(2��2�
�9i��{��*U�w#�����xf6���E0�I���G��A<o[x/�l�sN�~�}�\&��U�mJ�����*/��g����|��7j��|�X��-�r����b(�URr�9�F4�����6I�����=���������=PJE�<uJ��`���9�:���O��SXP����WLd��on'
�xc�,G��3���)e�6HM#���sQ���16�q��Z�-��ZCY�wzv�WA����o2]�����������.�Z\�����5���� ����
(�3Z�=�VVW�xu�}8�_
9�_}y(��[a���L5���8~�!����f�!;QTe��QTU_��UK��|ms�%-=�3��������M�.�p�
�}e�G�{���-8]|��O�����e��G���[�����P|���ua�W�,�~�c�p�J#���T�p�������h���=Ge#_��Q��pd�	��,4���t?DQ91��G�L�������L?p��#����?U�dv��26���1��p����/~TJu?)���JP���c����'��jwy��A��C�c%�h��3  ��g��R~�_,j;���f��� �S���z<Z����i���(�L��������6��9�hgS���Z
��|.C!=�'�.�g��8��	��a�9O�0��r�ad���������5.���P���0|��g3�O�IG�y��\�-��\��
L�)��XP��tm��r�m�=S7�"'��w�"��� �E��sb��� ��p��fu��!��� ���jY���sq���(-�>T�N��@y�>[�T
�o�~��I|������'���5�^|w�o��s�4W�8
�l���"O����t�0�������q�u"c���J��|X5����?�����`����9O��^����>3@���3�Qb3$��kX���b���!�A\����?�n�����z�^���'�0m�l%��������l#��M�`��2�sO���g�z�_����>��*M$H��CY�X�H�P���O�T��y���9gYa����_t�������T��'�����*
�Vo2	����FD�B+�d����vY�����m�mm����������3������Q���
�[����X�*����-�sr�Dj�qE����iWK#��3G]h�*�����=-��cujZ�[��vs��5�[�=o���i�,r��5\[���������Mh��4������Yj�S�5��H�}�7t�7��.N-l|j���%�U���xQ��6�87?���[�����{����45
�D_I�'$M���I��������g�����xRj2��@t��f|s�B��BrR�eO.�����������>q���}��*�G��Y��.���{V��7�?J��`�������?J���Q�6����B{���q4�s]&(��$2f{.������
f�+E�k��������g��c���.T�e���c�7�.��)���b�f�u�;�D��3�C��,�U=�dG�p�IsX0A@q��!2A��']�7�"��8>��I���w�q������B�l�9�Q����vH)��6)`�T^�9�Q��vJ�AqY�wi��
	I�o�a�I):�Be�aGD�5n������J��Q��Bt-f6�4���s���ZZ����Vy���E�s���#�Cs2H�C�G�,� ���g|�G�����}�9W�Kc�5)�
����r�������),��$������e,?� �&�7����Ho�)�Mr��-����~����1�����7cH�p��*7 �(q�#LQ�-��R=�7��x���B��W��N�``�d�\y��*fn0�M��8��?��$o�����	@7�j}�ar����7N����}�S*�����@���������w����YZaR1 ��
������{x}@p�j_��2W�������#X��%N!k�.�UH=���`a��$~at�	�Y�|��
-���7���p�I���d���,������L^�����GA~�Xa=#���x�XF���'��,����l�j�q6��9����`����Q�K��7�&d}jcn��I<6$lU��BS�X��������\���,_�jJ??�&�3k��C���t��/���OGKNc�w
;dn�Qr��PW;a�@5����B���h��"E�l%E�yk�-�H����|ui(p�&�_@��s��\��Y9-� +W`���"���}�%`��Z<���HeJ�-@�/TaGL���I�C:����H��&E�g\����g�hL�KR%�����3A������M���!1o^��o��Dq�C�m�;h����@��^��t
i�����cb�����uT^g�`������W�N���j�Bz���L���P-�xE\��y
��>��N���M�Q���)�/����	j6x�nl
Pj_�$��a�4��V���d
���t�67rQl���F��%na�
aK��i������57�����$N3p�����>n^�G����k4�z7�����k���s�P��x������}��Q
7��:� �K�~����b�svj-���t��z�5[0i�*�
�S�t�!���~jO�9��7^ �0���FIu2x{��(�UF�9���F�����.�O���]�oI�j���8TI[s�9�F��B59/�O�v�R�����u�.W��7�h�I�,�]35�Z��JA����T7l�m�;������]S��hOW�N���
3j�����M������h"!��3��b|^I9�G��9�A���T��1q�D��[-��e�����0�F�&6Xx��u������	��S�=��.��\Myk����L�-&l0��
G#��?����)a�*jD~<8�u
�'�S�(��
��Ts> ���Z���A�J�W��4��1�x���E�-�|�le�J�q���M��%<�22�`�USsm��f�A����j�,��sS��`D�����!A��u.��w;������6/�e.�e=sQ���;�D�����y~'4��=�9j��!��0��NYO��J~jRq'��!��#RMI5�,��/'�L��L�j�`�$�U)Q���%VXI��$�S�r����Y�e��_5I�� h1��G���RR���%��z�.Z��R9'��J�<�Df�7|�6sX
7�Y�q��e��-	o��[g ��*��Nx.��`����p4�\�~N%�4�+��;m~d�A�8�.���w�Jh,�K��--k�-�c���GqkW���6�����S���	'z�L5[	1�������4��1G����N�����oB`$��f��
Vt(��qE��$���g\��������NA4�$O��{d��z�X+HaT!���Czp����(�}Z�O+���FZa���H���'��?��A����Lj�r��W��d1I�RIs�
��ll�*��$R�JY��ji�,��:]
���KY���0����s�[��%�k~n&	�Pi_��y�M���7���(�ebDVeK`V����� �I��,��-,�H��Q�)R���4H,~�\� NN��\��h����eC��
qi���3�Js�J�Y;:�~_�_uN�o���I����'��4����s�73>���+?�����������a()�<���^8������p�B����U~�?�~������h�����s�!D+ u�H�5�nZw�m�����7�L��C�4@w��i�_�BAD�����PM*<	�6�~�:]B+t��7Y�n!C�����L�E+n��+��l���$6�U�!y1����7������������u;��`� ��
�8�[�4q�(����@���
Np�b�'�lC���1��+dH[$��n��is}geH�[�d�.)\��)'>��Gp+�
��WB�'���f!�Bu��nL��N3'�CT���L(�*����m�58�dMU)�.rz��{[���0F�P�2��LkA]��)J����$J��!p
p��q�lK��z�
��gwc�����!b�e~������.�����(WW���)��:����NU}\���n�Us6������������m�<���S�19��_�d���r����i[������mo�U��`"F�A���0�%,)T�!T���b�*���t*��,06����AM�pQ����T����e^B7��1�����=����,��cq��9���:$�V~�����z��������2���ffs� g�jT�X@[6[��s�~���h:~��t-�����:����8���)�����).>)��bl�n�K��L���y�d�$���&�d��s��fzT;������@���Y������tky�&�����q�wQ<I�T��T��%6hQ���LI��
�#F�w�
����Pq0��
�"���~} ~}���k��L��g������Q���"-�MO���k�2�R����k���'(����;�udZ����m;�a\)��d��mb�3��-��w�=�~���x��+h���_�� ��i#(_����I��M�$"�N��Jfg_������V"<�ly�I*O.�e�-n�A�vw1��z��X�"?�-��s�`S�:�%��Q0w"%I�@9���	���9���B��BPT���m[����!���on'7�1��)A�iz�iWa�,O���]-�R>F�����m<�Z6�B���������:�|}���!R)��������$�6��/��h�������[sy�8��$M�N��	�R�N�U�IC}������h.��e�_�5m�*~,��V�
�U�Z�$c@�����Fsr��^(7X4aC�L��**����<S�r�����2�[�Eo&8�&����T���:�!���O@�$$�6�Q���t������L��r���������1��$���;$2�(0/@Jd�� ���d���A���1���,�8;�Q��h���l����������X��<:���9���/j-���������������+��!�h�$E���l��Qk�����UD�:��*
������|�V�
��	|�GZ��f�+�������M�3��"�I�{^
�dc�H*s����37�������'j|��ya��z�t��10h�D��B�-?���
:_�
�T�����zc]�������kw��Q����8</pT������4.
7�L~$D���r���v$�^�;t�(Y2(��k�h����3��d��E������ ���`�a�_�
�w��^�ep/k.%ZP���. >S����g�v*<;:?=������3��b3\�,U�	����-%+�=edvs�WT���t/��-a:;8?x��h������C�?��������8�^|z�Sq����4o�l��e����yt���"h�4��*D����9y��e}?q�i&� 3���������Z������$�%��VHC�i�hY0�i��8��H�n���v.I����fL���k��AtN:�u�M*]T_K���E��J�0k~���FY�+.�G��%�g��;}`9�#t���l^�q(8v`�O1-��<��`H�S�s��G F��&��/��0l`��������E,�l�|����q���d��{�,��;����+/���"/�����-�p�Y�*f	g
�]o����?7
����F&��sePxJ�}��S�4Sa-+��%�a?%��~EN�
��w
2���5[���l��}�iq>����e�`���iI`>�gQ��w3]l����mm��=���G2��x'�*�����T�]g*n]V%�>=�&�q>z�n�-��*��
������l���+a�B��W�yp�N'd���d��vA������[�X��]����G�T�lk�	E66
���k�<S�*#=7P�z� ��[��rqKM����7�'�3�w6����I��-��Q��pp0ZI���v��� ;��5�h��-�p��,����F��3
�0e4v�L'.�G H���m��ze��/46492<G$���|�	[���'p�c�������J1�{�-Q�b��xII�������bn�2�3b�
�%���8�.1�����%���k��k��/�������&��&
��
^����f�J��,����a`�F_^-��9�[1tz~��Ox��
{.O�p��]O���e��	%Y����u��l���^��2�l�2�0�y�ye@������lI����0ihh�{@�E�-^r+k0S!�3����(zA#����C86�J<��+�5�!�o��( ��X?�a����)����
��4��d�uh,����E�����������3�j���w�	)/<��M�*�2��"�W��+.G�CI'���6���2��$���7��6eLe!�*ienozI�G=� �^��`N���)�l&3����T�� 2����7�Mr���PAoE��W��P�{�!��WLaR�2�03c��:����0��y���u�|"��}�������1�e
5h��,O�O���%g����	/^x4��5��&�h�~@��#9J�j������\�g�*����,���0�g��,/*��0LXW��V*���aid�*B�J �����K�P�h�<\��%�
3���?��:;��A<�:�
��|���~�H����*���:�"y�s���V�����^����x��C{C��el�V�F�%W�NU�<��+`y�� ����\G�l'-5���z&V~[_��������
��Se���:[�K�
S�S���������������D�
���
��?[�c{�;7�uBp���Q���Yq�$����i�i��|N��xR�M���7	���@��J~��7������������q;c>l
L�0�'i@��"���O���
�u����z�bH��@'�f�v�.�RU���j����L����pj$F�ab+����X��u��U~tc�S�Z]�s��wF�|��(�S������M��������F�%yg�k?�BU����5��8U;���(�������/�o��4.V����9B/`��f���0V	$|�k�F�CI^�������9�Cq�1�����?/��CO2�(%�;>}�;�c��t}��Sk��\�o��\sk(�-�N���]4�������o���G-J�������������O�����>��.k����\saB�r{f��}��;��������
��D��M��3�8���y���I��v/0Mg���;��9����_�R������A���'I�����8b?������O{�;�S�K���d!�'�Wo�����52$�y#R����#.������c*���e�,��"��������<��ku��N&�Y������`��\/�p�9����/p\fs5f����:���`���wonq���G��,��n{y�6�A�lM26������Z]$&���\�u�b��$���*�!)���A�`�^��m��\W�h��z������f���Q@��n2�����i��2��p��_��qJz�����W����\#i6:����M
���>z�s�U�mbY �0�]��[]�`\i��'���/>4�9:4g�I|p�����	sV���	(-��}&���l��o�Er(�q�����^y�%�$��oo�4� �:����c���g����;6��B����tx;j��<>x�;=����/��[__o�p��"	�2�}����m��������&����������>g����!���\^��66Km`T��-tN.��z2��F�����^������)A���JJ,����{�������y�<���A��o�,�}��F���-sj���p�T�F�q���!g$S�����5���k��?f)�!��������).�z������\{�.�� !h$�*���,0(�y,�b'�>mW�r7����KkL7����V�kn�*)#KR��\��*f��������{������@	�VV+�Q&�3�hY�B���O<tU�K�Y�(|z���:�u��?��e�K�_3}S����^���%T�S�%?���:f�}?<���W���-��o��r��{�PZ�����,��L��q��T��������T���ec	��z�:"����\����d���}r�>9�Ec�'|���������rk%L�E2p�����X��G��L��X�)�z��@������^�
q �n�($�a��)o������N���%
Q�)�������*G>���m�	�b�������h��k����y��\�O��C��~�+�����
�P��w!_i�T
�{��Du������L� ����HJz���A�5H3V����T[fm�c�_�+�a�"�%+)��a�K
H��$9��-�+��P<+�Q��mZ^^U����Pd���J�CfCW[��PDA��������g��'�����7B>0�������dis}
�*r+�ht��qS�n�@pN&�����3�q�UmV����DR�+�	����
�j����cC�U�%��CU7���"#uZ���my������kv��6[/����k��[;�|9�����0�����z]�YJZ����E���q�z���q��i4������G+y:�l��s1���om�6�i�,��[����������E@�_�'�|���\�������g��W�(Nu��|�,�u�}~~z��X����8~3�����������.������]�at�a\������������������D+�8V/��g�m	�R�k���F�s�8?��;|��[>y����������<�0�!J�i����� �3r������5|1���(��v��?yw�?FI����G1C(xb�����u�8"\��Qt�_�Y��"�����B 	Jv
��\CcN��Bxh*�_9"��	'=xdZ0��T�Z���(���JdN�I{,��(���4|'8)5����:>��x���y��2N�]Ma�1�g�e�L�������i��G���X��\g��g��T��o
�T���f��E���M�Oz8�/��z�������>�K�:��1�(��%R4r�38�����1`�li��2��eBg�<F].2]�(�L�d�0k��9����G,qSy���^I��k��v�P2MQ/��(�	��l����1v
��C�����/E�e�)Q77���(�����+����;�sE�k�X��P�D�;�5�(d�#��x\���a�j�fu�)=^���(N���(�,-����,�������6���3�vI!
��B���}����V�+A�������h� ,�������u�c��������:2���cu���eG$Z{v�
��Vk�p�f��d�����\eC����.��P����R9��4R��@�
y��T��\�S�r�U�i����^S��|
8 ���S��|�R�@Z��������:��t��/
��~�QF�c���s�ND�t�X�xu��]����E�$�{��� ��0�����������C�EH��4�87G����/D�O�8J�q�}�����d�eKl[�+O�I��,!�
}����S����wN�z����N���v����6Z]	2]*�8=�^�xp|�}�I_�����5���V�"���1�����v�,V�D�������%1���������N�^0l�f7��vW��QQ����n�7�s���m?��V5/W^��;cv�Y|!V�����nd������P$
u����P��k:���L*O�Ao�#A��6���������R�l���6�$��2|�=�%A�1
�
TgLf�R"��{��!qr`�X�z8�IN�cl	?D�'E�$N��f���<?��>o�����^�@������n��6f�T�b�Z�������F��%���N��<��>'t$�����N�d����&��	���H��E����'/�0��@���QZ��d���`R�}�Ht�H�iD�T��$�f�K��n���a8�����tS�3�'#��!���=��Lc��"@�J6p�R=�}B	�*H��o�e���H}V[��h�}��P����$��u�t*,���e�r��jQHR-���t6k � L���,R����X(�����'�E*1��m����lO
�Nzp��IM��[�>��GI4�Dm/��}x�C����C|�o�e�T9n:������)�>~�>���^k�Y���i��V��3������n{�4	�I�`q�^�
c~�^�����wF�}?BC��@��,�����+����B@����5����)?����_{�9�7>�~m�oz��2���������:Y�����
��S�6J�#�*s(6����q2��@���������^�.w]d�Ps�p���[���,7���E��C����mo{k������|I'���gX�|�O;G�X�t"kd��u!��;�Xo������#�t'�)��(�'�F���	�KDa�RYUM�`J���$�F��YTM������m�f��s��uu��������f�E.d�O���R�UN8�h��X`���@0���*<
��4�q8�
$��"b<P������@�'�Ui��Y�m�g2Kb��W�Hm��T`�m��������2y*��g�L��l��s@�*���uoc��a��]�����W���Ux-+�\5�l��o�0�wF���a^E�����������(Hjy�|���/��Q�*���Z6������8��v]�G|50�rL�>�9����s�}$���(��8���D���N��������8��a-�$���m�4f�!�c�A�J�R�J���v���\���7�6nf[���Z�3�)jsq
H��iP��\g��Z���z~���A:�2k���y9� lj���[��Lq���whq����n����R|���3K��,e����ud�\h	�P����V��
��EI��t{r�(�j��$�W�u��@�S������6��n�����;���_��pj�C�:��(Vj:��W��;���1>m`R1���!XPU9
�*��0:Q��*����c@XA������b�C�`U  iITz�B�������7qP��
O��2��Vd'��G5Dof�@�c<����rd��X�-2|&j���x���^�_^H�)m���Z��W-������J!x�*�I�&:6���l��I)�����.����d�$��s���{M&/o�U�Y�c�����d����������Y�����?�bXo^�	�����ZzwV���|B��(��������;)�gnN-����8c ���B�>.l��5)2�4:o����6���s����mp�>	C��Z������v�FY+c�\�NN4-G�UG����9��?��6�XE*A�=�2��1���������TkY(�z)��B��[�-}I��Tg=vjIy^���J��Q��p�q1��Wi��������@�=g6���Kc�O����N������������<Px!���eq~
�� �n�x�y���c��R��a��O�Y�i�m8I�T`�Kg��q�3Au)��S�q����ix�����p��}|���4_'=���#��p�������P[���U�J������
������'�].P�nny��m�ki>��o9<.l`����34
�$h��g/�j��F2D�������AY���,�|,�-����O�z2�{	����+��U�nm��6� �U!�
���%�dl�� m�v����0OJ���dX�jz7A���`�I�|����
I(���������[$����������6nS
$\
���ng�u����3-�c������A���TP�j�(��`>(���n��}x�.]�����:��Z,4�W��y�n'/�m���U�-�
p�{���rq\g
����4sg�k$f����3���l$1)
�G��a+���3���vN�YQ~Je�{�������1�����>����(��G9��o�59d��.pa�_�������.��_���N�[�G�1,R�������?����a�s�
�a�������a��X�P2�
�2���+���L�U�~�'Q�fE���G���_�&
<d1#^K,td�������"7!���:�C�q`StV`�4���.>�/�����q���g�����@��dG�\�(s�5����3�(�O�]�5�6lR�$	��A=���Q��������N���wv���s�~��YI;N�k�*��N���r�BEb�^e��\���g�@^}��Z]��I�t������g������>����6
�g��'��uy`�t'�����9��N����A�.��--���Q,���������I]�t�>�<������sfQsY~�dPk���jk�V?�?Ccc'!�)S�.�����d�w�Q����ad�m�(�c���6���	�X��%'C2g�`�xL�������������2��J����S���D��h9~
�~I�4��}����?0�Y0�[��h��I����[��$p>������rG19����h�)R'E��|;�Vy2&�#1�iO���I(	IJ~�,C�/�4����L�������/,[i3-�c���S�t�����������>-�I��1��R�L�x���R���4���������N�Ka��Gg���B��6����z�����H��;|F�{iB�3j��h��m������	����G�#����#����5����Jz�t�sr�C�[��(���q��.:�JP���\�����b��M'�0��H�WO�Q�f���s�)Z��Q���r�J]/P����e�}XR��O�C�A�Kh�����-2U&�f�,w�<e����B7V��"�e���9A9�L�s��P)H��3�����+�-��J�L�<��t\�)L����(��+�����P~1����V
�/,*����j������S6�m'w��O���W6��i�R����t1��F��\,�����n!	v���EQ�w���\Q�]�(�,��:�5���2�i�&e��h02��D�����M�wl&xL7;c�F�M,��*�MG���Q�X��IM��rc�N�H��#�;JU���y���J]��w4����+��^h�����~EV?x�`]UeE��)O�BZy|�����E'D&|��
���W��~�#���&���������I]���Q[;������`�p���������8��xV�i�e�lTe_P�
�]�Q�d�F����@d���*�C�`���"���HN���0u����P�(����]L�a`wg^����b�r+�AV��<
 ��b)X��?���Q?���[���5sK�`B�T�<�g���OD2��
�D&��U���t��j�Q��{�:=jq|�C��~��Tc�RkV.bM�A�5.g,���N�t��v
���^�<[r����Y�.�����S�4w�l�����c�N�7���L���e9bN"*�7EG)N��iD����S�]���!>BF�f�Q�j�z&�|�V"�
�B?6>Uk�BS(��a��<H0�����O���
WD!��Bz����������gZD����!����:��O����
I�y�����dN��C��?a���,����$�]����9s��M��Q�
'����0O��''����NN/��9�HF���-�7�	���O3�>�>�2���,��7���0��5���4&abo+�H8���(�R��>f���wn�;Q�b�� ������ WS^NX.���9���\L5r�)�|��4�4[{	)bk����#$���UL���"��v���j(���_48��� �����(�[��/;U$O%TK��Ba�x6�������f�h�}������s� {��5���9�J�31	��-)�X��M�A��v*���(B�/EoY�f�����S����aT}�*��TrSq�����W0�M���x�9�>F7
FC�(�#shJ��k_���t�no�p��~\��S�3$���@
������j��1����r��%��0eP�r������<�:
T���C�������A�|<�t*�'Z�5��[`��a���������z��������:��������W?\��6)h��O�rT���I�a�����|��'\�Dj��e�bY��w����/*���)�Q������f�2y�
���-�8�%��"���r3�p��q��GCE����a(��T}��0/��)%")O����c���"
�%��D=������n����0}�����6��(�t�~���5@��EA�
m�KY��#�����#�>y%���
�����\�9�T����20������^]�NJ����C�L5Ec$Y_s3��.j�|O�����^v��D(c��t^B(��D1���-�g� �
��.T����K�Bu
�t���/._5M�\2�at���l�G�D?��J��v��h���
�`4�(��Gs�r*W���Y�81b�p_�7!�Z������s%����I����B���\�	�T�n6��z�Bu��=��8�gb�YZ�����	
R�T��B�b��1��������W�����_z���Ml8��J����h�{��i����Sx$�s��i<���V�mYf!��D|76����`�iLNZ��kL�G�A�����������;��8K�VL����f����=.�U��[�f
"<��0�)�%�j����/���?.�;/;��^�}vp~pqz^��4�k,3�J�p�;�l�iv��uvI�m	�3���}[��ef�������6�y�D��F��2�YO�2;d��T��j~q+�������I���&,u#�:d��H�!�e�d�#��0�H���5p}�}���g�������Os���4 ��%9��djbB��y-c��*����QL������U@�S�Vr�r!}J�PE�.I������Sd�f�$�DQ5t���������(2��h�y����dTM���2m[��)���>�y ��)��Zy�V������I
���1\h����[@zF�j�n�z�k9�X��������Nh�����n�a��U�/5)Y1pifX|��'���fj��{y�aTGy������3�
����z�XV-.�+E��t�����eO������OE����J�A�~�}&t���99��4S�DL�8�4rd&�[�����*������e{�O���A�2�<
)��BS	��y�)(�ajl�=�Z�-�@�@���+��R�A�L.��,��s�$=�@0s�v%-H+�:��>�g�q3�/��&l`u�M��Pi��'1-2�\D�����_�h��0�$.�f�p����9e4Sm��*��R��J��-u>6z�4i�*�c*��Aq.�S\\��0��������A�3lS�Nu�c�*c�|�������}�9R�=�8�(|ijE�M
x?�/����(�2�q�������`�)X�%(_+)M�zE�[�Y���y�����/S�;�
/q�&:W����Z��������46Z.$q1q@�I5�@MBN
1�Q��z�fE�h$�`,!S=S��-�Vn9�yA�G�m@�R%T��BlTZ����.�8p!�R��(<�ejF�
�x��xh[�82�"�~�V��^#�G��_���9=&�TK��&�02��u�8 p��
�HF�@%�Y�:?�-��e_c�s
��j�Y�����wbF������������ 8`/j����0g���h}���\�<���(��ms�Ju�{D[R.i�a�*nL���6
�a����AZ+������9�\�O
"o>��F�.���C���v��>0��8��]�9$�8�QM��u!�bFf��R��R�ZE3�	�[)�	��F-]�����/�\����+-\g���30/���.�1�
�M >�8��<Fxt�D���
�m�wI�)��Q�"�(U���g�,Xv�IZ��r����)��)���V5]��(�@�T���8������He�dOi]P�PJ^�3p����G!^'z�R�l,��3��������ZJq�}����L,��^ucg����a?0
���T����u��k��wQO.-����a*�@G!���Q�/Y���2n�i��N�0�	]v1����P�F�kJ��a�?a
*��n1Y��(�K�e0i )�J���� '�����]��$72r��
���^oce����H�GTc��+��iOM��T�������Z|I1
�>\B�.���=�]�bj�(��J�%8x/�]Y`P/%P�Y����EZ���XaB:�LH;�����VY
�����iH:�9���9�*��p���e���8�1���A��P��L�0��)pn�t�[\�v`�	R��V����pm6,�������������Ky gp�S���?�h�.�����}��Mu��WY�FC��/$�N�9����-����(��e!�+��R^�N_ON�&"|��On1%���~�W�w��1l\a�S�����8"���������bD�l��S�C�0r�P���K�J�n	��8t9�8��G�\��T�Q:��L���:5�pmR�f1K�P�&��s���u�����f)�x~��g��A��h
����������~"�`����j����W�����:S���hVo,5�i��L�r��L:�xpJ��lf2���A�,7
����IV�Q�J�����'P6�
K����T����ro������K�������hC����2���}���!�5$@��fI�b�~�6��_�"�K	%s	�,�3Ivj���
mx@id�u��l�\�����=e�q������#���b(a�������gN����tTju������T�p�-Ku��Y��u�>3���Wk�O����������w�_�B�-�[�a�R�����n�[���ui�
���m�
r�����5������od(9��6�����e����C,���a+{B�1�z���0+9n�/���b��	�O�����g��#;�i��L�ZN�������F��$X�f���$e)5���m����Oh2�������Z�T�7�<�	f��Zt����6��)�M���0vNR���l�8��bu,��@]6(�ge����\����(��_J��C4jR��)��q�&9�Vs�HJ��
XR����c��O���]��%��M���s���ZhV��O�Q}�IX�j&����=��i���-��"�`�(	���5T����%E0���AZ*T��i�1��sp��#T���24�:K|��f��9_O8�.���%oy`]�*�~3i9jj
o8y+�-�qL����Ov�ve�b�c����l��C���@f���F���}v;��#��������e^������R�Zb�(�H=t@��jB��M7��a?F��l�1V3� �0��7	4M[Y?���k��-
�8��8����&�"���e���h�����rh�D�R�w�:��H�ss������c��� 7�*OK2����_z1��Z����B4��
��R,&���q��8L#�?��
<�9������	mp4|�3`�_��$�N����z@@-�}v��(Z+��
^�;�+�p4���7<�\�+�JS�$e��=�fO�O�'��W�yy�_��Q��r�V�'"D����4~&lF���s3$B�D��T�)��2�-��g���J���X�e�����0|���������G���~q3���Q���K�;��V�]�T	�O#e8��}#y�����$&�F�`������/����l[�B;^��$�9Y���}�X�Y}�$�����v���s	�2�)�MY"��0-��(�G�!UG�!��i�f������Q����"�i�l��7"��T3���o0#n�o�h�����%���-��S
��������+*;xg��zr����_�]]Gk�+�������]6�������)y�EWs�)��E����z��������#P���VB#,O�aj�\[l���br�|T�$�\&�)^�3������.k	���{?���T�[j��'�:��7� O�g)�������~�*[K�N�2��E��`�B�X��y|7Y�m�J��n����=4TH�����o���R���]�"�����~=U�|g���N1�1{E`"�&KP�T�E���m�2�:J��eR4�������l������,�{��n��14���a�T8F�_�����C���6�y��h�N���C�~_�ke>E+; �]9MbI�67=����v��(x������6=0��Y�$�f�]ln=�
o���Ez�['U�g��N�Z��)J�.��K*������U��~<��	'"����5���Yt0���J�����=!���
�b��wI�1�S�=�f��.-�'_��J��-tg������������2�(�l�#�$U��,��U�D�Aq��C�{.���*Ry}�ETR@��jwLJ.��+��f����O���T#l$�-5�n=���,�0�F���Fd�(LjE���&FtV�'�
�jo�l�+����h��|oO��gQ���$��U�2�
�@)z;b����)2;���3=#t����)�i�x���
��+hR
�{����x����T���U���m����(yQ��HY����F�����:�x���_�(-�Z�!��F�)t��������a��RlU;����$�:�2d[BY�t��e�N�\����7�Q�%"F�%��D��6��1;KSNbc
�GQ��������-
:�Rf�����p�`��wq��I��!\h�76x�T	�2�O�@"��������
l��u��B��}���y(��f�����"+��P$O4J���#�`���<�os�����@a�����?�����8f0�0�7�'�{*����?��.�36��a�<��7Z�Zu<����W��U
J�����0S~&}����R+���
����$O����L��yR�c��bSj=+?�\N��qrJ��p�U15�1�p�S"*?�pBn(#+�)�#��,N�F���|'I<�������� �~d�1��*��4������R]�1#�`Xm�P�;l&<����tN8	B������5<�RD#S6G:�������������%e���F�%w��,�
&�b��{eV-��h~@�5��LY@v��de#���=E�5�����w���=���}���������qt����a��H��4�AJQ�9��������u
��`�{JF]B''R'�������*8Z�on	�����d5$>Z1�s���$����5����AP�o%�G��P=m����Wf
<�����jP�,x�WPm�Q�(�W�%�l�VD?VJ�9�+���V�V�c�8���V����]1B���.�����ZA��{)Z~}��Nk��v�\���y�Vk��V4o�a��c��{fqG��Y�������}�f/Q%e��??.La�� (75�6-�C�/S*1���������\4[�]�&���h3sLE�$�&��8"&����&'����R����bH�����6��R�,(�a`L�,�}�����<	�s���L�"�(��`,��(N���g��:v���9NA7����k$�BxN>Fp������0/��4k�������+���V�����
U���fp`���V�:������'���iw�������BC��dv���2_e�]/���g�'���u}�L4[���Ev���Va53��wPF�S�Y��_�)��`��r�[@xb���'G1�X��XD}������f�-�VD��7��5B��
?�BU�������q�~;����N��Y2}����v��HoS�8��=F\��a�M,8vD���NTxd�>�����[#�5P�@i�O�Y��d=�y��Q�����J�L����H)�L�m��E�����?Js��<1��b%Ri�+������-uB���������F'�8Y�xevFy[.���� ��H �[;����<b/1�C���8�^���L>)�f����[�Q�#�	�
tI�������(�\������"�63�<��&SP ����u����������q��nyM	5�Z��z�����3�*��piof�U�Q�e�����;�ns)��YC������k��w��,�!���, =x��984�%��"O0���Am����/P��F.�&��D
�,����u���
���qmV�~�6[Fz�Y�Z���n��x���4��fa��5�
#oVh�2���IOB�L�o����v��������r�ec�hpf42�U�Ky�g���eH�4��`�#6rQ���fx��3�<����T�O+b��B�Vn���O��\�'�P^���"�p��7*�o�D�����x��Rf�|
 $����w�i���%�2�Fig�sBh�����\|�A�xc�d�H�� �����=���	�D��������[l�k� 4��!Y{&��f��P��.1�?��������#��JG��`��������J$�C��A[�������p�fc�����c�6n*3V��������'���3����.���`:��*]a*���z�#h�Ak����a(��5��9#��?���q"P��bv�lD��ZUA�,
��^R��j�����$��)Y�����
������N`�W��"0�rT�j
��W0y��?��$�X�X�����<���$!*��u��}�X����c�2s:B��'h����>"f����g��a�q
������ �TE�2N�HIPn�����
�1�>:=i��]�p���]�����PPHt�U�\j�n��}x�q�=!lR*OpLJC��������}�VnHw�^l3�e�|%7�p�Qr�G������\��d��
���0e�[�#������6��##����������n���2	�v����qe���Mn��e���S*��6X��x��A$Hm�X�BC�[E�pe����P��OK� �.a�]��n��=�N%|F��V�k���[I���B~w���b��'b_
�=��Q�|ng�(l7
�����`U���WW���������L�bi��:n�<r$*���M���U1.*����b.&���L;���$���\��z��5���Mb��L����:uv�J�V�<� 4��\�X������y���|��=z$�53������al��:��i����Z��#�����6v��v��.���E���Q4by���tm��]��	7���0���c��fNR}�o��s��������!K��%���J0�_"�R�����8��f��lm�)�Jw�~��;�pp+#Q�������E����MV=�}^y�Q

�3���(�"�i�$��3�Q���0���B��-�}z�b���4=���?1�������mog����.�b�9��vg}��in��]`���9�4ykV(���S�/�����]��Z�u�'�T1
A[�Z���oo�e.�%\��}�����yow���k��g
��d04����8�z�`��g���������>��?a'*q���@�vI�1jz��??��f�������Y��Q���V�mfO���V
Z}�";�8�?tn���S}�px����c�+�#O��}��8|X����f��k�@�:;M�J{��H���z��14��������q?���"W�7���R�����������6�����u��N^��pt'y$��.��'2�A�
?Dv�����*���;���yE�m*���+��R��	���` ����/���V����*�Lh�iV�H���.o��H8�R�d����L�Y��0�C=��C��?qs����$��G����Q�y,���1�/����8]M�P*}*��������(7����ZA4����N�H2�'�&Lzc���_�������;��:7r��2 ~hR_��7{�r�2��Yv������s�X[�^sk��s���6?92��k�Z[[^H�9��I��>�������@ ���i	����� ��|��B����n��z�67������e���I�����-��������8*'��"�ho{���Y������p��hog�����w*2ho�9~����:_�>4[�{^��������fm��W1z��h�7ksc}�kn4�L�OJkV�� 	��9�)�Z�J��q��EJeO�����X�����j��[���"�
(?g�-D���xc#7Z�8��&9����I)���;�����r'�P,�����?
��Mx�������I���m��x�(�������3�3��/���y�z�YBB�	�;�iL{xz�K�{q�9y�{�i��b���	Z��K����k�g��U���Q��K�\�T��:�;f[*u��v���k#�WE��h~�6\�mx�~�&���m�]�WF���U9������.l��c5"�H�lnoB����������i����n0��>Zk�},��Z��h�
F�Fj��]W�0�a1v
��cw���w�[<G��:0)�g�Q�����.�Z�*� ]?�Y�����z(�u	=�����#�������$�����?-��L<�����
�t>��Q��������S�%�#-e�ic,k��(�P`�s���P��17!�6N�_�ls����U��=�v�������ui<3�j�	h���](��W�O��\:��{�=�^�J�e���qR�9���A�����eLD����u��w$d�w���u��'���s��#J���V�^j<��P�Uc�6�c��*���4���D$���	e^��$|�����p�&*���2;D)�Y�d0�~O�L*���+~�z�������� �E&w��V� 5~(U�_�����b�Hb�y������0s���
�L�'\���g]�Q�KY�B���W����	e�Qe�&�)�����C���~}r����Q��+;�>����7?���A�$P�G~N�4N��Q �b$;�jpiG�^D��>�/S������z/�����RD�u���Q�h]2���
�>@=�~��Y&����A=���M�����H��� ���6^%>A���%]���q�n�8������8�wf�4��i��O�r4.���.mt������I�������GC"�Q8��E?_���>z�3+� ��?�	cW=,<b7���d��/���%�j���k�7F[z�"�b�>�j����WU���|�Op����Go�P�z��X����N�=f�xn�#8qc&��^�c�����LR�������Sn�S����m������Cn[����N���q�w������E���B�����)�|}}�9�/��������h� ����h����'��G����_�.�Gs������z;�������#�v|yDO�/��o�����}xI�ap]�sv����(~�/��r4/`$�������_�����|������==>>�	�yyz��?l�g�����KAm�����6���D�S����tY�&�L���IK��*���v���6��]�������"��a)���"�`?�#�]~�������F�ULJ/X�����d�=���M�I�������
k�1��,*�|�W�q��9�"��U��"�*��v7<��*o��h��?z"��v������=��������c��e���'V8Y�W��j'����
��������S�r�m�S�i�{��U�{�C�������*���s�hD��t�\U�>>��5�?��k��"`�V
Z}������W�[DF�#��o�����o���~��o�.z�E�9�7�b���K�_��TFa�8��D���MO|���C�3��H�_�]�"�	�/A#?������.�`5@��\�`��`�����n/{z��@�� �]�_������n��q�#�����*=����x������p���Y�S���������y���:.��Q���������AOK��c�<������6w��@AO�)x����: ���=
	����'%�,�
Da|E�,Wa�]���*�y���"g���j,Xms1d��T�`�%R�LXVN����O|�r�y������uI|l(����6�@��{v�5E�$�q|zx@��FDZ������JN�|X�w�6�qck/'�0_��`��?�'�XP-�<��q#	���`}�-y$��99j��mX��C|G+�9�??v�?�s��������9����������WX���}~p�	���w����A�Mt	s�_��V���os��-�Oq f�C�zp����9^���ce����q�+K�_v^]����.��W�����HQ�S7��Q�OY��|���<��->v�A)�H�����&pG��g�u��JY/	@^���'�
f)����\���F�|Y]U����\2�UE�5:�-rO����nC��O��R>����4����6��`����~��5����/j��(�2GrJ�*0!E��"$�'��7����U*�>����#���S�|d �%A��)�V�d����<)`��E.oy2���T���8^+E��J+M�T(I�����Wgojm8�����I����Z��V(X����8�Y3_"�blm�z[���'���Pp���|���&�[�Mok��.�i����|�������.��(�,b�c=����f���i�Y����\Aqx�_��xr�F�X.y�����r�������g}�kn57-wj��u�o�����)y��k@�������vK�&Y~�f��l�d�����"oK����)E��FS��!�a���k�n�B�6Z���3i�Q�Fq|��{�&~t��Uv4s�����b+;gNer�}��A�vD(�I�J9������{�H�x���$���D�_pl������8���:	0���Q|����xB�JIn����M�<�&����hz-�N���8��6I�U��`,���1�����pfI(^��D�(?�[+�c���1L�]v������07��Y�VS{�T�S����y�z!���Tk�k"l��	Z:����x|�n�#��
�-\���	l�s�&�_	}^�����������4�UO�o����T�m�c�g����Z�^����2U��}|z�9'����"���Cu��p�y�	�H`e����^*R����)A_�C���Ppj�0[I9�%���4�r����5���]��������}\�;N�5$��a����6�y��7����>J{�������Y���C��bp[���*1�avCAl*8�8����	&��3J��M^`hq���0qt?A��~<8��.(�*Z)�����S���&avK���"��v��e�Q>�@p:���C5�����a;���� W/�[ C	����������=�}��)�-&k2��N�bgzE��x�"�����ozR4'�CJQ�`���Ud��
�����2�/.2!)k>�Rb�4�w��bjD�Js���q[�d���Q��)�1R#4��V���L&���d� �d���a���y($6�|e��D�42:1�)&���` o����>�EjX64M9:���8�@��x�0���������8��FQ�qjj��	j*Y3���m1{��g�H������'�[���j�������gT��gtJ{Y���>�r8���&�w����.����9;�#�&3����~)�� ����5��:�c#�zX�������#�y��y�A�c��^WQ�?�)��1G�3(���/d�p�g�)I���]����,��@�|"��h�7��8�2j����UU�c����
�QeS��#��p
���w�+(_���Z�1p��2B8�����9��F�dCf)�Y�G\�"/��"rC�[L�Y&~H)N����a@v@�5����"������9{yjx���5_)9�s�B%�,�K�����T�M��"	c'����\(�����P3�l�T�f{���kl�F��dd��<j�  5:^&=*��=;��������7G��n�N8�������D����M�CG�M�!�mV������$������g�3�-�Q<]��Y�����5�M&��Vf@5�6C� h�E��Y�����J�-QY���Q�����>���[L
%+��+��M#��-�2b���������������9w�U���Q3�V!��YLq
�}'�^(R�'����>^�1��t�E$X�0���������mL��-�?�	��\!��� �_�&�oG��:�@��q�q�z"sa1���M�{%Uq�\��z����M��P���>E�����W9����t�:j��zC����I�`����
��}x���/;'��t���h���1
�`
��$��s�����xz}��%���RM�5p�o�������k�a*�A�{(�
����E��s����	WBv�F��\����aX�eeO���!�l��bF;������&q�:�f�`�C`�y)1;�V@.����H�!*��X���Z	�������u�S��7D�2�83��g
��e�4�X����y2�	���s����1h@���Jj@��U/��<���������u���j���?�n�o�s�*�#rjo7v`UTTf�m^��y[���<��?�i.K�{���VrO�.J���a�w��Q��x���=���O������^�^��}r���a���vtf4����Q��e�T$��G=����<d���0Y�u�n*�(0���c�)3+��
C��>��/Y��'ww9|U�����n
��������[%�������ok�M����:5��h\����o�T���<>x�O���N��-��X�Ro�,�:}��]�k2�7b��F���/I�:��i�i
�5L�����=_C��\��K�)�*�)(��N`�J
����/��a�j��JxK���4�/���g4\9������JJP�WG�����[(���A�v
s\�[=\7�^�Qv�k6%�F�����g���<f���`����H5`(3�-'��/UVj�L����1�d����N��#:�X��m��o�oy&V�aY��x�@&��S)��4pr�)Orm����L�*� K~[+������VnNS���5��Jz{�d��Q�[�BZ���
���U��" �>,�HCd[a�R������$�"���6�hP{�D��As�V�c
���pA������":���
���$�S.
���y��N��W�p��/�]����0o��HU���Go���� �,���#��Q+X�xq��p��5XXdSJFw����';T�i~J2�W? �B��R&�xI����(JRg��4�&2)�D�,�tPhQ�SL��Me�����sY� �$�rF�j:	�F�0��ez���F�

�H�
G�?$�:��cX�Z=�M�pM�L�I�Qa�y���f9�$Kl��yb?�����T=�.w5��P��e��kFZ��i1x���a+�GT�!��5Fu,Fvc��l��"H�4�<�1KK_�|�
U���"8\(����7���&0f<��:�P��{I�-��(D��FI!��>/�����
�"ie�4e��i�Tk0�U�S��8���W�:���8J�1�G�;\>�����[��]����V<-�&)*g��-��a����������%8+"��+�V�������#��	��S���z4_����$U�-LQ�#o�|N��xR�M���&��<�������%�=Dhd�W�{�q�ak��
��$e�����������:n�Qq=c�	�����o�Z;)��C[�*�TX���}%�TI���	L���11�\
Z��F���-L������E<�:nX����q+��P��HU��=�2���|!��A�R?�g���Q,���
hzC+n�q�vF8sQ>�%�+�G?_���Qi\�����s�^��7���g���9<�Q�)�Y��Z�����,p m��i_��U�&Y��X��r)&�����t�9��D���4�/������k|Y�}�,�����(��+����j�a�l�!��Ic$�0.)�^Y��
D7�r`��D(w�������W
Rzfb���r�hF6��|����U��������Li�S�������s�>��+B=/�e��	��(�'��m�@��\���T�IF�/�c�N�&>�����e��o\K2��_���!I��x�������U���AF����|����WV0�[�3|yd�����t:�����q�l��]v�� �����n����8���]���<p��*����k��@�^�
�G� ��q���V��I��Qbt���[�M}��0�"	uU�s
D�70|j@��|��K�B��t�a�������p�k��������C3���z/E��$c+@+G�^��H �Z��R?�� �|��B�K���F��q��V�H����4�C(�.�F�F��chw��MC���va���������i�]��I�9����73
��jO��al��yzDS6Rs��L��K5���oL��Xjia��A$��W?\�I42������1�._�j���B��^F0�3�����3T@Fw�����O�PP��`�����SYPJ��K�x���R�1��PQ~��4��R���_���%��o{�t��l!=�YS
�k�0�4�����?�bY�Y�^�#CXu
a6
��=�)�
���&mNa\M�{>���\�>Sp6xG����4�k9)�7��������6��d&������?�(�J_J��~�_��6$L�J����N��KUT`����	,r������w=%'�����}�=��/Q� �����L��i��W��4�f�
��Qz�`��;������H-�b5�^'�\�{�<I������V��Eb	mRi L/94�}��`�*;�S��M��o���)�w������0����o�zE��]osgC�G���k����2��w�L&���j�R���t�<gy�1��=�H������T$���I��@M�X��������/���MkGij\�����W?�i�H�U,�]�i*R)],D�w�����
_�����JkkI|H����C��R�^C����<������+`e�3�UO^v/N_�N���+o(B�l��xR[�5�Bt���((*2&Bq�JO��w��^�:'g�N@?����E[�9�uP`s�)1O�e��mK�&p�ec�����o=�Kz�:X��D(���AB�3�4��7��i��"};@�p�h$�D#*#��=�$�����rDl�u	<}������ �*�H����T��pfXH���-�AH�E��5>D�HU��|�����~�f�����B��>���@p�P�!�����>38�%����b������m���\������9�=R�X��@�3>�tw,���P��"��*���2�B�zWl}�S
��;��y����BS�)������
�������u�n�A�W4�@��Z� /mM�j���r������E��5AM�x.�zS��:����:�qi`����hm}'K0/���z���}���pMl2�;� +���/�'����\{���&������/��<�`2�5
P�fRw�R/�`X�/Y�*��XT��&�,=���#������b8mW������>T����r� ��R��+I �O^d[^��[�E��QRyn����y6��j(�!���}��/�<j>G|w	�k�������(���-=�Tm��z��%%�<�Q�v�M�[�8��boIL��p�;�Psp��dY��K�������}��r��B��VPT8�|;�,�����F	��[�O����1��|.h�E�/:�]����"�������,&����3l%��"�!oN�J���-]�� d��� F1�MPk��8y���p
�vZ�f�,1�1�~���E�D]�p���-+��t7��Qz��J��9Y�G��,����#f��+D��>���
h��7j�����:W���}�
����gx�����I��R�S����*��G�8}��G��)����,����m@�
�	ba���8��)�`��d�r��r?t7���e�����u����b+�����**�rQ�7�����H�1���7������=�&S6�FI3���-�������u���>-�t�������{����|�������(m��t���!��Z�EXpj���v��0�l����kn/��H�����L�YT���1���8�l1]�}��m�c0zT����	��F�eH���e����v*�87*)���N���L��C�41�V�k4e�����i,�*��{�����[���F�h��.���e���2r��K�������W�.�T��)\�Wi�'}rO�)��J���66��XB_�����C)w���Uvj�~(<K����!�+?����aLO��H77��	C���)�dk1R�JId�f��P��g�?�e3��CH�D0e��NK]�1���bF�9neh�{��x G���1��ZP��YC���U����S`#��i.T>��6R>���s�m`4��
���a����D�72����.�����\w^v���n���hk�����O�Q(F����%�.�r�iwc�Bo/�(�3���$�i�B��m;��s�.��g%2le0b���%����9�$���)d��&��~Y�0��)'0��be��Xb�R(��fh����W���;�0�6Md$W	#L'5�|��8���&G�g<�1������FE��6���H���s8�Y���s�:Q����D�!85���Z�c���e��H���n>g���=oko]2&J�Z$�fI�@]IE1�G4(�(z�Z�c�THc�,�d��z�t',B(���'(��$�y�k��>���dw�r���1f��/��vg���������[����r^��)���1���nwvqvFC�������3"kkX�OQ�L��4��$�	3j�O6K��nm�����=�`����n�z;�;�i	������L9C�������s�>>}����F?*����I|�}y���_4|�4��{�oH���h��G�=�-(�*�
���2��`>L�a� �:���*��$H�nD�"E	���R
�Q��5�l�*P�3<N2#b�G�$�nlI^���x�!v��v���Q��^E��w7��
�R��7-��`��z4-�Ul��"���D�;�,C����9�:Z�&�?TyO�Y��^W0�p�������T^n�L(/���k��������y�y���K�l��\J������,�Xm0�h?��|�r�?�����"Z�bJ����<J�S��k+O�E����=f���r5o��|*�C�.��.c�g�cd����Rt?!�����u����^Qp��xB�n�uL�{�k�}���n��wa-:�5���	J��H;����!|Q�@������
c�����K�y1��?�3Ke��,�����5�������1Q�����zsp}M��������Nt����
?w�����'��'���5�u�����[��pp���R������~}�����1�����X�K�T�+�j+�\/G�9,F����a1�8b�I�F��5�;�X�fs�k�r�c�Q>-mY@�B�z�D��������_���o����c�-I(�d�z�����
�f�&f���eWH��yO�
SO��z1g�q����S��w���������D	O7��W�(� �6`���S$$�&F��W���eL$l��\Bn"���t="��z�Ee)S���6H���=��#��^�Gc��-^�W�[7l@u3y��Bn�����b%�2�l����3���UV|������IUv0;���G
#?��M'��?�@w�$Q��x@{�������
�oC	F�B��iX�v��f-�|�����{�b����hd]E��w)���������B���q��&>����[��������&7q6�AC#-J-
<�1��uVQr��W�{Z"�p^6����F5W�"J�W�oF(�G%�������g2Y�q���z
`����WL�5�K�\���Ej������<	��T��C�|o���n����j�OE��+���@���VH�g�l�3
K�)d��$��'�2��M�j���=W���H���ehnd�v<���|
�h}t�0����)�������&�u�A���IoX���^�U�����ia�8�b��>����
|<�N��R�p�m/���,�qhH���<?}m�D�����i���8vL�9h�B�y����#V4�`H�R��|C�U/���'@�����K]PD�+��G�q��,>?�F[�Q��H
����J��Y��?F=>�(����8���������c�s�w���
���@��J�j�PW���m�e3��j�A}
!�x��+IQ&q3K�I������� wa��,���Q��?]Aa��|��jI2@�Y�5������=:5Ry:�Tv
c��,�/p��UBr(Z��Q�����o�h��DwH3u��
Vt#O�����:j���&dAG+���o����L~�g�!��n�>�J�}���L�����R58�.���/�WyR !���gx���ij��H�C-Q��jRKN�]o[�����3xE��
U}�{O<����]�T�{���/;����w�7���}����6
��8��$�KE��H�N't#(��sI�W
Z����{����R�L�j5�����a��lV5)�����Q��kbMJb
|����2�'��%�]���L
&��N���t�0�tRj�$�d��C�gi��GJ6B��nI|�iEH"N�CS�fy�R�k�r]IU;Ln>�QSh5+I��KG���`�S8�����jM)4x� ���*����T
%�Y�]D�������S>@� :B
y����|��D����C��m��3q+����?�~���889��ml�D�����4�j@E�����Izu^yf��$ �(�8�|�R��zus8�����E�f���s��8o^�w;?�e<���PP0/�F@��	��G����W��w,m����9u�Bp���]�xy�����c�4h���lN�{<�������y �PK6�y��{f�Fa83<V8�����+U��`hrLap1�����`�Rh���:��^�����������(�@	��Yo_��^������p�c���89����������g��Yz%�M5��>�NA��E���P��{�� �h����H�����8f�d��?M��-v���>�r,/4�OFO9��-�#���W��=��4*���y8z�v��J��-FO��Z�\��;VVU�������h��!I#x������j��/���Z��-C)�y���@�y*�\��M���M�)zj��O���[�	mmoiN��	�_����S�1h
$�*rb��*�����h�p�T����e�%�2R$K�W�n��p!\
I��4��S2�@[�	u��2%+��$����s�^k�M0�e��F)��VTva������W�.��JE����M�c�Qj�m�u�������M�������[,"����*y���
�����}o���&r5��|J�_���~�1ba|�����s5���!�36.F�\��p���y�+�F�i��	�l(��J�$E��$�A�5	F�,0��Y��
X��Y@�����!�-��dS�T{�&��eb��y�u"�x���kZ8t9�0��j�]G���
q�z���������n��V����,(�����a�5�v�f�w���b��$�.�c�|}���o�J��L�OQ��4;%b�_t���\��*���D��H"�*��)`"���Q��$�<�z�=�%�$�e�OmL�����v��L�:n�?��
����05�����
������F��"�9���>�)p� ��eO�trP��9r0�x�B�w�M��!6����Fs{���������!�%Qu��t������vz��c�H4
������:����:������	�����z8�-����}Q
����6�������)
g#���H�w����G�W������@���`��\>��3h
��z���d�`�}]/66��l������v�v� �+��R6����Go#x�������o��!��gj�����'��l�J�m	���<�����d�%Cu(0���������F/X�0��K�7��}�L�`+k:�j3Wl�[�P��g>���J�-=���:�Z�k.�BW�EO����9��B_F~t��Z�mlmn.���3�E1�Cw?4p��!���W5���@3C���$�X�<��]��>v���gxo�3��A=h;ro�cK���eh�����=�NT����ml*^Tr:�W��c��~���I��	d���M~���q4Gp�1-;"� �7�@���ukA�����0���6���FL'R��y�yB��)���H�0a����w67
*�O<�*C����l���p� &�E�!L�&Sqpyq���x(v��B6���7Pk�!�$������&���t�*$I��pT�X�T6y��2�[�*�)�U^:�R�k�f��8L���*O������J�i<-�P*I�OBwR���:20(�h��k���'�$�����)��r�%aB����2�xB�����x�'f�l���2�B������������
��FP�z%�a�����}EA��2���xW7��J�����������k/�q�F����5��F~������7x������uj��y�y������y	�>N��DK�4�����
����01�<���M�}"�����1��<`���'���;=?j��
-���������wN�z��?.�'�m�;�{�)���J��i���<<}}v��\�{����E�|���#Im�nnj�S�A�S8�I���o����$�s�����al&�j'oq����*�b[�{��V��������B���Az����q�F
h���:e�4��������yL�(�1B-��]f��T�9��~����{3u�����7�*��Q.��	�}���DR{{->r��C�JsE�>����{I�,IX�A��0oC��	L���������W��w����Wd��|
���
k-�j4
�Qjcd7���F�1����H�?������|O���g���mokk�p:���I�����b0IR%�J+�M
���T0����Y(	�����1s�d�G��*��l���
-jk����
okw�+2a��l���mT�)mU����������m8v�Q���
�{#������'�wv�qx���V��og���
��������B
��'��?�b��S��RO�>#�������"Y0���,��1�/���P0���L����1����W�+�Lo�t��_�K	��{��Y5�h���������wT�I����C�O���z���b���v6���l�h�B���������3O��r��'���W�'\��?gS�j�?9]�����m��n�n��������i7�Q�E{�������U����4�(}�n��|�F�@v�fv
���/����et'�<q\g�Tr�(���Qt�vs��m7w�n�g�Q�8)�\t���sn���r�ODTVl�����3�������i��r^�n�S��j�a���:��;JJJx��=x�u�EG�S*�ZO�
s��~�q	����/�� �K��Yd����QofA��j�g�������R��B��F���<�m�i��?v^C���C������Z�p+�v�"G3Xr��~�/4t��`��?(��EY�}2ogP6��� +����7��.����E �k���_�-����r���-���J�|����i���^��C	�Sj�
���N����{������{<�M��n���
o{c�+�/S�O�oBr����U:K�w
���KE�4�E��>a���������Y�P��.��� �������;����j>0;����-o{wK;���Wzb��[}.3�Hs0��������	���q���<F����$��pZ�����v����������s��B�9��0u.��6\E[��`��67���������Z������*U�PXE ��?	8K�2U%_3�����$������j�lk�`�����'H�<����&��u���#�s1�����������LQe1=@�i4��Y�T�T')[�a��a�G�rI������f�#�k��	��N<:?=��w�>QV}�hk��.�V}AY	��?�_���Sq�m�����A���������D���1����v�%w���3���������5��85}�G�z�b��]3�S�E���o���v�����.��n�\�r�	����Q0I�4S��	��8��,��pq�Y;����Rs/��@�J�.�@MOPF������u�&���0�q	]I�*�3�����,L�r-�c��"���9�^o�${�q���]oOzp#�]�4N��'��K��1�t�����BT�8^u������� �q��0�"��N8�I��(wLrQ�)9�^'Y����-��$�u�vS��L}���>>�O��m7Z^sc�9_@~Sq���
���S�/L	���������<����������Y�	��z\D`^:��)�����b��4�98�s3�~#3X<�0G�m����0�8��$%8����4��VSJTp�I��j�V�wHG���Z��x�������e����[z�IU���I��@$p.�����=VC)s3�����kn�3�j���"��QC����h/���<s���*�C�m�i�������@R0B�Q�Eq<�-c�l�Ka|��Z��X������wW�L�8a�T������[�����k�K�������M�g$^v�����cQf����mo�5g���c��F�:l�w���]�����i?	���P<�p�=	?W�!�k���U&~_o�C�yt~���'��Fp#E��F}�~rB�"Z��a��L%R7N��	N�*�C��'0�����gqnj`9\U����������n�t{C�z��P@n�'�������\|���n��K�!%HKB���n�I�pi�H��(N\�i�P�P&F��"E �o��`��8
��[#����2��Kx��$�����w���wy�����NTn�z*`v/����5w61���D8������	]��H�	����z��B��L�����k~����<��8��K�l��K���OaqW�7F#�������@!��$��>��	p�	|�����b3��6�y��;GB�<�������K[�l�*
�zb'�V��Q�]��\J��35�K`��T��1D�r�����r������������_W
��;��^�dz�V���ze�J�\��G�����n.Y�Q�b��KzL0��!`���@��p��������\_#��'ej�0b���|��6�������jw��~)9���P���0��}�h�0��!����}:��h:��9��p����,�F���2���?��Ef��%?J�4���_A�������+D����������/I�@�:��(��KY�-\*9}%��N_Nf�
73o7;���m�Y��WD�����X2@��v+gp�s�r/�EZ���+��q�;Cr����=�����*���w��M0���c��y7��VKFzKo.S�:�M#Ls���
�*D�N�y"�_����%���@��o��_����\\��O~g��ER\N�����L�F��$�h��V�m��W7��j�����a�h��
����2p~C�[zyyr�T�j�>�S���-�0-�s���p�0U�o��l"�;��nM^xky�!���,V�6{�k�P�&�p����ny�S�����Q��}�>9j������xp��3�N�'WM��_Ct3���h������"l�����E^���:��)������mlz�����"�E�P�EK����I))8^t�W�H���d���{.|�<
�gM��(�L�?�!^��`@����C(�^�i���R*?n.����!D��E�A4�x	US���}��R��x��0F,{�	�2Q84U\^J��N'�T�NN9�%4�Y����<�5U�;x@JswG�5�:���
3�P���8^�oq��c-�+ �%`��J�N�9P+�����8�8
��?�y�q��Af�-�8XX�����tP����U�����srp���n}}�����(�q�h8������������6�v��3�'cjJ�s���2e��6�)��:'���dvK������<��O<e�,wN��+��!��J����p���|Ee�t��#�t_��y��E*Ri���/ ����4I�_a��!&�g��������B-�;��#9�Bc�knn8�	�!�i��=n�������n������yu����l�{*�U�����
*\{���:'�tT\��0XDVV������cO

�)%�K���DG��u=��Y�0������R�������-�����k����
��{�����!	�q2�1�����=S�#����	K�Z��^��2B��}�.��4[<���U�(nY�T����2�0���]�gOx�4�]�`�(_����Q}@�X8�3�lO�y���������vkc��?����>�,�$���y����R���66,!�)�txh�
�����k��[�Ua���BC���9�wo
��$�7� F^���	�w���	/`��)��������IO165����<"�����������c?y���]R�B���4�P$2�~6
�5R�R�Z�O��{�'�\���<j�\Ch��!�(.�0��b=�>��X����-0�RYE)'�T����@�3.��0���"po!����<����!b/�`i���;����D}�X��[���E5t��1v$�G� ��hp����o�W����+��gk����TC��	9j�e1�GA��0vfCIN�V�XPJgfG#����;z�7?��(�'9?�>�$����aH���%��*~0J|q�9>�	u�]%�f����f��9�
�g=_���d�P>�������x�m^��J�bH�fY^����������p0�O��; �o2Q"������Zo�{P"������c�j_�{����$�������6=q\���e���/xr{DP���������l�\�z�z6&#	5H�RfxPIt5���@
(���50�'%���C��Z�99��j���MG"�������W9����8H�T�Wc�r�E�YV�S�����u�s�V�?������:	��cT?���xs��YD�^WV��a�����@���Z���^R�9K�KI��hZ������MY�p��Z&�����d�|�/��o����\���^��y{����#����,�|1����t��R	�q7$<'��lI�����S{���xT��I���Ne�f>b
����p:�3>g�%�m�(r\�U�'A�5���@����Y���}���NPhQ�*�7�%��:��0>��r���s�I=�{|C�y�{:	6��-"hEv3����;����������v�����	|��!P{��Ie���d���VK�p��QuO�����^�t�`V�PX�&���bH����o�ws[,/�uq�)��.����U�����������E�[p����=���Z��jmyh����,}l��B/��GO�'��!��><2+
����V���0�������!/�$Ry�������8�eSn+\��������h����;�_h�t�����������%������2��[��s���.0n���s��_@M�R��n���%\��`��0P���������S������@/�� ;��<�ud4�T�v�0�����z���g�<=���Y�����J�S"
���32�&]�o���Ct��+�t_;��
p�c�D6�Z;<�5��I��c������R���{�&'�h��|U�j���2��2�%r�%���?�?������m�������E�4G�%�^�
��V�T��Zy�$�f7��
E���wu�rdz9x�w7`����1{Un�h��t�N>��������*�Q��x���2Wu�JS�4a�h�,jK�'/=����N��K������\`�4H=ib�i�J��3�i��>#��~8�H��lm
���*���/�<9���S�Z������l� _"Z
O��z�-�O4!t/���k"�����&-5d��b��hrANB^KH���@�������+��7a���(!69c�������5��,�7�tq����&l����-��`���M<
��7�����F��N�{7��G�&�XD����m����Je�;KI���j nox������P��yz>���#�/k�_�q�f�?��������I0:!�l��P{����8=�^�\���d=({�>��
�x0�C�UX�E��������m�����B�\����K�{�v9L4�M�;�RI@��Td�>+�S:I�T����T���V�KP�v?]����U�UK�/;��&��P�5>k�$�����r��RS������:�D�i����si.S,4���	iZ�f2��xw
�����wA�D�
�)�g���B��'��[C;�[��
W��~5e�W�|����n����H�!q�oh�m�C&�
6J�n*�
�$KR�8�A���ANx��hH���0$����\��7�7wB�0"�W�eO����*��0����r[d���\\�L�����T>�W��+_.S��)(	u7�q�%��%��R�����w�m�������U��GU+\��U�?3�1��PJ_��*U}�����h���eGd�8���>�2�_��_�J��+��W
�j�L����zH���;��jP`o�v�"Y��uuB���LTy^��J���:�0)-��{_#������ls�}�%!�v(q
�a?{'�0�)=�n��xX{����B�3[+��fc��>K5�����Y�
�|��Df&Y�F:�a�qH������=����Jd�F6T�����m>�w��*��)(.�j-�(C�t���{��r��ml�8�O����b|*�go���z_�|������9���x����)G�3
(�2~�9v]�)��'C�qo4�>x�/O����y�-.��mqr
\��Qx9�z����*��*�������c����<n��������/��}�pz"�����������A���H>����/�~�~�F�����Ua=�������3��fdxv�{M���YTx6��f�zpi��a
7�� ��Kn��Aq�e0�v7�lT$�)=��
'+���`�cAp�P��S7EQ���Dip��gA�k���R�$	�w�X���R����Pt!���_xV���Gb���}8	���jr��qW����M&|!a��,fls1��:���a��-^��],��-��-	�g�zo���������H�e����e��c��'�m:VG��8B���`�D���>���h�X	��R�N������c��Q]a2��G5��i8{y\���.=axW,2<v����Y�Z�c7�u~px1^�,^w��3�wK}�a��<4����vG��S����67w,����'q	�X�a���M
��l���UW�
��]�v�n�U_8��z������U�q�lIo���; ��������6�w5��Y�����X�I����6h�Zohc��M����{<�N������s�(��&i�T����Cj��VcI����[�fN�[[���[Q��j�.`��h�~�9��d�,�oA�hy�_s������HC���1�E���������y��
Q0��M�W��O �;|I��%��j������F�1����Q��*���7�]o���7Q|�	�y������V���&oV>�|����.��pV=1	�H?�+���.���Y��o4eCTk}}���YR��?
�j����-02��b��h3��|�<DS��S��<��/�Sh�1,
�F8��7=7�*�i��A��[g�-oo��pr�Ux�G58{u�c�����T{����6��J'Y.�>������v�H�$���aGJ�nU�	{KFE���Q��%�!���%�5���6�9?Zm�A����UA���F��$��N|V�S�{����4J:�(�-o�i+M����/�O�7=�
��Q��|X�����6Z{��0�l��(��.���Avj2�#5���a�Af�x5�s����b�s{An���� (��dB__\M3����GJ3$l���)H+/PE%�b�|��;+�r�X^&ajy3�
����gvg�=k�����u��������>�`���7�hD��Y�c�0!~U��0����zuyXD(����&�������N�������J��e���BF��!�:IHT=O��okF�:���rq�l7��FO��������X�e��,��=<��]t��l�t8�a����������x}zty�����p�H�a�*���)hTp����k��q���)O��6+�PCbA,�Q�g����
��x���m-�'=����=�%�4�h��i��*�d���=����Y]E��h7��G�����������CR[����K�F����~������"���b���#��t@�o�����^���K������,�Ck:�`:r�B�0c�`n�c��g�����:cj��������j����F8p�(�w���W��4R��c���K�X��)/8NZ�(���\�n/L�Dd�8z��������!��
>pt�7*��;-X�=#��}�>-u�9{�s1��Nv�������)�'2����jj���?���������2��c�C~������K����b���*��;������S���#5j�
���^��X�3�!���z�����(�����?���������S�����TB5��NM�I��F����*V#DXPI*����}�D
9�A�E<�|>"!�0��8'"$�a3H����o"y��:$:HSD��	����z|�������/*�X��?{��O�o
#39Alvaro Herrera
alvherre@commandprompt.com
In reply to: Dimitri Fontaine (#36)
Re: ALTER OBJECT any_name SET SCHEMA name

Excerpts from Dimitri Fontaine's message of jue nov 04 16:39:31 -0300 2010:

Tom Lane <tgl@sss.pgh.pa.us> writes:

Not having read the patch, but ... the idea that was in the back of
my mind was to have a generic AlterObjectNamespace function that
would take parameters approximately like the following:

Please find attached what I came up with, that's the set_schema patch
version 6.

Neat.

The has_privs_of_role() call has the wrong ACL_KIND argument in the
error report.

(Nitpick: don't use "e.g." at the end of the phrase. It seems strange
to me.)

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#40Alvaro Herrera
alvherre@commandprompt.com
In reply to: Dimitri Fontaine (#37)
Re: ALTER OBJECT any_name SET SCHEMA name

Excerpts from Dimitri Fontaine's message of jue nov 04 16:42:53 -0300 2010:

Alvaro Herrera <alvherre@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.

Hmm, seeing the amount of new includes in extension.c, I wonder if it'd
be better to move AlterExtensionNamespace to alter.c.

(The problem with smaller patches is indeed the dependencies)

You can't please them all, I guess ...

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#41Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Alvaro Herrera (#39)
1 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Alvaro Herrera <alvherre@commandprompt.com> writes:

The has_privs_of_role() call has the wrong ACL_KIND argument in the
error report.

Ah yes, I missed the acl_kind. It's a parameter of the function in the
v7 patch, attached.

(Nitpick: don't use "e.g." at the end of the phrase. It seems strange
to me.)

Fixed too. I also added documentation of the new forms of the ALTER
commands, as it seems we're heading to something which needs it :)

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

set_schema.v7.patchtext/x-patchDownload
*** a/doc/src/sgml/ref/alter_conversion.sgml
--- b/doc/src/sgml/ref/alter_conversion.sgml
***************
*** 23,28 **** PostgreSQL documentation
--- 23,29 ----
  <synopsis>
  ALTER CONVERSION <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER CONVERSION <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER CONVERSION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 75,80 **** ALTER CONVERSION <replaceable>name</replaceable> OWNER TO <replaceable>new_owner
--- 76,90 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the conversion.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_opclass.sgml
--- b/doc/src/sgml/ref/alter_opclass.sgml
***************
*** 23,28 **** PostgreSQL documentation
--- 23,29 ----
  <synopsis>
  ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 85,90 **** ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="p
--- 86,100 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema for the operator class.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_operator.sgml
--- b/doc/src/sgml/ref/alter_operator.sgml
***************
*** 22,27 **** PostgreSQL documentation
--- 22,28 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } ) OWNER TO <replaceable>new_owner</replaceable>
+ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } ) SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 85,90 **** ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
--- 86,100 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the operator.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_opfamily.sgml
--- b/doc/src/sgml/ref/alter_opfamily.sgml
***************
*** 31,36 **** ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
--- 31,37 ----
    } [, ... ]
  ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 200,205 **** ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
--- 201,215 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema for the operator family.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
  
    <para>
*** a/doc/src/sgml/ref/alter_tsconfig.sgml
--- b/doc/src/sgml/ref/alter_tsconfig.sgml
***************
*** 33,38 **** ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable>
--- 33,39 ----
      DROP MAPPING [ IF EXISTS ] FOR <replaceable class="parameter">token_type</replaceable> [, ... ]
  ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 123,128 **** ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> OWNER TO <replac
--- 124,138 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema for the text search configuration.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
  
    <para>
*** a/doc/src/sgml/ref/alter_tsdictionary.sgml
--- b/doc/src/sgml/ref/alter_tsdictionary.sgml
***************
*** 26,31 **** ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> (
--- 26,32 ----
  )
  ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 96,101 **** ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> OWNER TO <replaceab
--- 97,111 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the text search dictionary.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
  
    <para>
*** a/doc/src/sgml/ref/alter_tsparser.sgml
--- b/doc/src/sgml/ref/alter_tsparser.sgml
***************
*** 22,27 **** PostgreSQL documentation
--- 22,28 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER TEXT SEARCH PARSER <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
+ ALTER TEXT SEARCH PARSER <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 60,65 **** ALTER TEXT SEARCH PARSER <replaceable>name</replaceable> RENAME TO <replaceable>
--- 61,75 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the text search parser.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_tstemplate.sgml
--- b/doc/src/sgml/ref/alter_tstemplate.sgml
***************
*** 22,27 **** PostgreSQL documentation
--- 22,28 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER TEXT SEARCH TEMPLATE <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
+ ALTER TEXT SEARCH TEMPLATE <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 60,65 **** ALTER TEXT SEARCH TEMPLATE <replaceable>name</replaceable> RENAME TO <replaceabl
--- 61,75 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the text search template.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
   </refsect1>
  
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 2706,2711 **** getObjectDescription(const ObjectAddress *object)
--- 2706,2726 ----
  }
  
  /*
+  * getObjectDescriptionOids: as above, except the object is specified by Oids
+  */
+ char *
+ getObjectDescriptionOids(Oid classid, Oid objid)
+ {
+ 	ObjectAddress	address;
+ 
+ 	address.classId = classid;
+ 	address.objectId = objid;
+ 	address.objectSubId = 0;
+ 
+ 	return getObjectDescription(&address);
+ }
+ 
+ /*
   * subroutine for getObjectDescription: describe a relation
   */
  static void
*** a/src/backend/catalog/namespace.c
--- b/src/backend/catalog/namespace.c
***************
*** 2340,2345 **** LookupCreationNamespace(const char *nspname)
--- 2340,2372 ----
  }
  
  /*
+  * Check new namespace validity in ALTER OBJECT ... SET SCHEMA ... and
+  * ereport(ERROR, ...) in case of any problem.
+  */
+ void
+ CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid)
+ {
+ 	if (oldNspOid == nspOid)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s already exists in schema \"%s\"",
+ 						getObjectDescriptionOids(classid, objid),
+ 						get_namespace_name(nspOid))));
+ 
+ 	/* disallow renaming into or out of temp schemas */
+ 	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of temporary schemas")));
+ 
+ 	/* same for TOAST schema */
+ 	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of TOAST schema")));
+ }
+ 
+ /*
   * QualifiedNameGetCreationNamespace
   *		Given a possibly-qualified name for an object (in List-of-Values
   *		format), determine what namespace the object should be created in.
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 14,21 ****
--- 14,23 ----
   */
  #include "postgres.h"
  
+ #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_largeobject.h"
+ #include "catalog/pg_namespace.h"
  #include "commands/alter.h"
  #include "commands/conversioncmds.h"
  #include "commands/dbcommands.h"
***************
*** 33,38 ****
--- 35,41 ----
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
+ #include "utils/syscache.h"
  
  
  /*
***************
*** 182,192 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 185,211 ----
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_CONVERSION:
+ 			AlterConversionNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_FUNCTION:
  			AlterFunctionNamespace(stmt->object, stmt->objarg, false,
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_OPERATOR:
+ 			AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPCLASS:
+ 			AlterOpClassNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPFAMILY:
+ 			AlterOpFamilyNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_SEQUENCE:
  		case OBJECT_TABLE:
  		case OBJECT_VIEW:
***************
*** 195,200 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 214,235 ----
  								stmt->objectType, AccessExclusiveLock);
  			break;
  
+ 		case OBJECT_TSPARSER:
+ 			AlterTSParserNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSDICTIONARY:
+ 			AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSTEMPLATE:
+ 			AlterTSTemplateNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSCONFIGURATION:
+ 			AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_TYPE:
  		case OBJECT_DOMAIN:
  			AlterTypeNamespace(stmt->object, stmt->newschema);
***************
*** 207,212 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 242,341 ----
  }
  
  /*
+  * Generic function to change the namespace of a given object, for simple
+  * cases (won't work for tables or functions, objects which have more than 2
+  * key-attributes to use when searching for their syscache entries --- we
+  * don't want nor need to get this generic here).
+  *
+  * The AlterFooNamespace() calls just above will call a function whose job
+  * is to lookup the arguments for the generic function here.
+  *
+  * Relation must already by open, it's the responsibility of the caller to
+  * close it.
+  */
+ void
+ AlterObjectNamespace(Relation rel, int cacheId,
+ 					 Oid classId, Oid objid, Oid nspOid,
+ 					 int Anum_name, int Anum_namespace, int Anum_owner,
+ 					 AclObjectKind acl_kind,
+ 					 bool superuser_only)
+ {
+ 	Oid			oldNspOid;
+ 	Datum       name, namespace;
+ 	bool        isnull;
+ 	HeapTuple	tup, newtup = NULL;
+ 	Datum		values[rel->rd_att->natts];
+ 	bool		nulls[rel->rd_att->natts];
+ 	bool		replaces[rel->rd_att->natts];
+ 	int			i;
+ 
+ 	tup = SearchSysCacheCopy1(cacheId, ObjectIdGetDatum(objid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for object %u: %s",
+ 			 objid, getObjectDescriptionOids(classId, objid));
+ 
+ 	name = heap_getattr(tup, Anum_name, rel->rd_att, &isnull);
+ 	namespace = heap_getattr(tup, Anum_namespace, rel->rd_att, &isnull);
+ 	oldNspOid = DatumGetObjectId(namespace);
+ 
+ 	/* Check basic namespace related issues */
+ 	CheckSetNamespace(oldNspOid, nspOid, classId, objid);
+ 
+ 	/* check for duplicate name (more friendly than unique-index failure) */
+ 	if (SearchSysCacheExists2(cacheId, name, ObjectIdGetDatum(nspOid)))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s already exists in schema \"%s\"",
+ 						getObjectDescriptionOids(classId, objid),
+ 						get_namespace_name(nspOid))));
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		Datum       owner;
+ 		Oid			ownerId;
+ 		AclResult	aclresult;
+ 
+ 		if (superuser_only)
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 					 (errmsg("must be superuser to SET SCHEMA of %s",
+ 							 getObjectDescriptionOids(classId, objid)))));
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		owner = heap_getattr(tup, Anum_owner, rel->rd_att, &isnull);
+ 		ownerId = DatumGetObjectId(owner);
+ 
+ 		if (!has_privs_of_role(GetUserId(), ownerId))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind,
+ 						   NameStr(*(DatumGetName(name))));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(oldNspOid));
+ 	}
+ 
+ 	/* prepare a new version of the tuple using nspId */
+ 	values[Anum_namespace - 1] = nspOid;
+ 	for (i = 0; i < rel->rd_att->natts; i++)
+ 	{
+ 		nulls[i]    = i != Anum_namespace - 1;
+ 		replaces[i] = i == Anum_namespace - 1;
+ 	}
+ 
+ 	newtup = heap_modify_tuple(tup, rel->rd_att, values, nulls, replaces);
+ 	simple_heap_update(rel, &tup->t_self, newtup);
+ 	CatalogUpdateIndexes(rel, newtup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(classId, objid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
+ 
+ 
+ /*
   * Executes an ALTER OBJECT / OWNER TO statement.  Based on the object
   * type, the function appropriate to that type is executed.
   */
*** a/src/backend/commands/conversioncmds.c
--- b/src/backend/commands/conversioncmds.c
***************
*** 19,25 ****
--- 19,27 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_conversion.h"
  #include "catalog/pg_conversion_fn.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/conversioncmds.h"
  #include "mb/pg_wchar.h"
  #include "miscadmin.h"
***************
*** 30,36 ****
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
! static void AlterConversionOwner_internal(Relation rel, Oid conversionOid,
  							  Oid newOwnerId);
  
  /*
--- 32,38 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
! static void AlterConversionOwner_internal(Relation rel, Oid convOid,
  							  Oid newOwnerId);
  
  /*
***************
*** 326,328 **** AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId)
--- 328,376 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER CONVERSION SET SCHEMA
+  */
+ void
+ AlterConversionNamespace(List *name, const char *newschema)
+ {
+ 	Oid			convOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	convOid = get_conversion_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, CONVOID, ConversionRelationId, convOid, nspOid,
+ 						 Anum_pg_conversion_conname,
+ 						 Anum_pg_conversion_connamespace,
+ 						 Anum_pg_conversion_conowner,
+ 						 ACL_KIND_CONVERSION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
+  * Change conversion schema, by oid
+  */
+ void
+ AlterConversionNamespace_oid(Oid convOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, CONVOID, ConversionRelationId, convOid, newNspOid,
+ 						 Anum_pg_conversion_conname,
+ 						 Anum_pg_conversion_connamespace,
+ 						 Anum_pg_conversion_conowner,
+ 						 ACL_KIND_CONVERSION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/functioncmds.c
--- b/src/backend/commands/functioncmds.c
***************
*** 1870,1882 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema)
  {
  	Oid			procOid;
- 	Oid			oldNspOid;
  	Oid			nspOid;
- 	HeapTuple	tup;
- 	Relation	procRel;
- 	Form_pg_proc proc;
- 
- 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
  
  	/* get function OID */
  	if (isagg)
--- 1870,1876 ----
***************
*** 1889,1894 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
--- 1883,1903 ----
  		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
  					   NameListToString(name));
  
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterFunctionNamespace_oid(procOid, nspOid);
+ }
+ 
+ void
+ AlterFunctionNamespace_oid(Oid procOid, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 	Relation	procRel;
+ 	Form_pg_proc proc;
+ 
+ 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
+ 
  	tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid));
  	if (!HeapTupleIsValid(tup))
  		elog(ERROR, "cache lookup failed for function %u", procOid);
***************
*** 1896,1910 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  
  	oldNspOid = proc->pronamespace;
  
- 	/* get schema OID and check its permissions */
- 	nspOid = LookupCreationNamespace(newschema);
- 
  	if (oldNspOid == nspOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" is already in schema \"%s\"",
! 						NameListToString(name),
! 						newschema)));
  
  	/* disallow renaming into or out of temp schemas */
  	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
--- 1905,1916 ----
  
  	oldNspOid = proc->pronamespace;
  
  	if (oldNspOid == nspOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" is already in schema \"%s\"",
! 						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* disallow renaming into or out of temp schemas */
  	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
***************
*** 1927,1933 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						newschema)));
  
  	/* OK, modify the pg_proc row */
  
--- 1933,1939 ----
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* OK, modify the pg_proc row */
  
***************
*** 1941,1947 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameListToString(name));
  
  	heap_freetuple(tup);
  
--- 1947,1953 ----
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameStr(proc->proname));
  
  	heap_freetuple(tup);
  
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 30,35 ****
--- 30,36 ----
  #include "catalog/pg_opfamily.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "parser/parse_func.h"
***************
*** 1912,1917 **** AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
--- 1913,1980 ----
  }
  
  /*
+  * ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpClassNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup, origtup;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	/* Look up the opclass. */
+ 	origtup = OpClassCacheLookup(amOid, name, false);
+ 	tup = heap_copytuple(origtup);
+ 	ReleaseSysCache(origtup);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, CLAOID, OperatorClassRelationId,
+ 						 HeapTupleGetOid(tup), nspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPCLASS,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(CLAOID, ObjectIdGetDatum(opclassOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
+ 
+ 	AlterObjectNamespace(rel, CLAOID, OperatorClassRelationId,
+ 						 HeapTupleGetOid(tup), newNspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPCLASS,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
   * Change opfamily owner by name
   */
  void
***************
*** 2067,2069 **** get_am_oid(const char *amname, bool missing_ok)
--- 2130,2226 ----
  				 errmsg("access method \"%s\" does not exist", amname)));
  	return oid;
  }
+ 
+ /*
+  * ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpFamilyNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup;
+ 	char	   *opfname, *schemaname;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	/*
+ 	 * Look up the opfamily
+ 	 */
+ 	DeconstructQualifiedName(name, &schemaname, &opfname);
+ 
+ 	if (schemaname)
+ 	{
+ 		Oid			namespaceOid;
+ 
+ 		namespaceOid = LookupExplicitNamespace(schemaname);
+ 
+ 		tup = SearchSysCacheCopy3(OPFAMILYAMNAMENSP,
+ 								  ObjectIdGetDatum(amOid),
+ 								  PointerGetDatum(opfname),
+ 								  ObjectIdGetDatum(namespaceOid));
+ 		if (!HeapTupleIsValid(tup))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 	}
+ 	else
+ 	{
+ 		Oid			opfOid;
+ 
+ 		opfOid = OpfamilynameGetOpfid(amOid, opfname);
+ 		if (!OidIsValid(opfOid))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 
+ 		tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfOid));
+ 		if (!HeapTupleIsValid(tup))		/* should not happen */
+ 			elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
+ 	}
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, OPFAMILYOID, OperatorFamilyRelationId,
+ 						 HeapTupleGetOid(tup), nspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPFAMILY,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
+ 
+ 	AlterObjectNamespace(rel, OPFAMILYOID, OperatorFamilyRelationId,
+ 						 opfamilyOid, newNspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPFAMILY,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/operatorcmds.c
--- b/src/backend/commands/operatorcmds.c
***************
*** 39,45 ****
--- 39,47 ----
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_operator.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "parser/parse_func.h"
***************
*** 452,454 **** AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
--- 454,505 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER OPERATOR SET SCHEMA
+  */
+ void
+ AlterOperatorNamespace(List *names, List *argtypes, const char *newschema)
+ {
+ 	List	   *operatorName = names;
+ 	TypeName   *typeName1 = (TypeName *) linitial(argtypes);
+ 	TypeName   *typeName2 = (TypeName *) lsecond(argtypes);
+ 	Oid			operOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	Assert(list_length(argtypes) == 2);
+ 	operOid = LookupOperNameTypeNames(NULL, operatorName,
+ 									  typeName1, typeName2,
+ 									  false, -1);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, OPEROID, OperatorRelationId, operOid, nspOid,
+ 						 Anum_pg_operator_oprname,
+ 						 Anum_pg_operator_oprnamespace,
+ 						 Anum_pg_operator_oprowner,
+ 						 ACL_KIND_OPER,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, OPEROID, OperatorRelationId, operOid, newNspOid,
+ 						 Anum_pg_operator_oprname,
+ 						 Anum_pg_operator_oprnamespace,
+ 						 Anum_pg_operator_oprowner,
+ 						 ACL_KIND_OPER,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/tsearchcmds.c
--- b/src/backend/commands/tsearchcmds.c
***************
*** 31,36 ****
--- 31,38 ----
  #include "catalog/pg_ts_parser.h"
  #include "catalog/pg_ts_template.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
+ #include "commands/extension.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "nodes/makefuncs.h"
***************
*** 393,398 **** RenameTSParser(List *oldname, const char *newname)
--- 395,439 ----
  	heap_freetuple(tup);
  }
  
+ /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSParserNamespace(List *name, const char *newschema)
+ {
+ 	Oid			prsId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	prsId = get_ts_parser_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSPARSEROID, TSParserRelationId, prsId, nspOid,
+ 						 Anum_pg_ts_parser_prsname,
+ 						 Anum_pg_ts_parser_prsnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSPARSEROID, TSParserRelationId, prsId, newNspOid,
+ 						 Anum_pg_ts_parser_prsname,
+ 						 Anum_pg_ts_parser_prsnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
  /* ---------------------- TS Dictionary commands -----------------------*/
  
  /*
***************
*** 620,625 **** RenameTSDictionary(List *oldname, const char *newname)
--- 661,709 ----
  }
  
  /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSDictionaryNamespace(List *name, const char *newschema)
+ {
+ 	Oid			dictId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	dictId = get_ts_dict_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSDICTOID, TSDictionaryRelationId, dictId, nspOid,
+ 						 Anum_pg_ts_dict_dictname,
+ 						 Anum_pg_ts_dict_dictnamespace,
+ 						 Anum_pg_ts_dict_dictowner,
+ 						 ACL_KIND_TSDICTIONARY,
+ 						 true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSDICTOID, TSDictionaryRelationId, dictId, newNspOid,
+ 						 Anum_pg_ts_dict_dictname,
+ 						 Anum_pg_ts_dict_dictnamespace,
+ 						 Anum_pg_ts_dict_dictowner,
+ 						 ACL_KIND_TSDICTIONARY,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
   * DROP TEXT SEARCH DICTIONARY
   */
  void
***************
*** 1100,1105 **** RenameTSTemplate(List *oldname, const char *newname)
--- 1184,1231 ----
  }
  
  /*
+  * ALTER TEXT SEARCH TEMPLATE any_name SET SCHEMA name
+  */
+ void
+ AlterTSTemplateNamespace(List *name, const char *newschema)
+ {
+ 	Oid			tmplId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	tmplId = get_ts_template_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSTEMPLATEOID, TSTemplateRelationId,
+ 						 tmplId, nspOid,
+ 						 Anum_pg_ts_template_tmplname,
+ 						 Anum_pg_ts_template_tmplnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSTEMPLATEOID, TSTemplateRelationId,
+ 						 tmplId, newNspOid,
+ 						 Anum_pg_ts_template_tmplname,
+ 						 Anum_pg_ts_template_tmplnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH TEMPLATE
   */
  void
***************
*** 1498,1503 **** RenameTSConfiguration(List *oldname, const char *newname)
--- 1624,1673 ----
  }
  
  /*
+  * ALTER TEXT SEARCH CONFIGURATION any_name SET SCHEMA name
+  */
+ void
+ AlterTSConfigurationNamespace(List *name, const char *newschema)
+ {
+ 	Oid			cfgId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	cfgId = get_ts_config_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSCONFIGOID, TSConfigRelationId, cfgId, nspOid,
+ 						 Anum_pg_ts_config_cfgname,
+ 						 Anum_pg_ts_config_cfgnamespace,
+ 						 Anum_pg_ts_config_cfgowner,
+ 						 ACL_KIND_TSCONFIGURATION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSCONFIGOID, TSConfigRelationId, cfgId, newNspOid,
+ 						 Anum_pg_ts_config_cfgname,
+ 						 Anum_pg_ts_config_cfgnamespace,
+ 						 Anum_pg_ts_config_cfgowner,
+ 						 ACL_KIND_TSCONFIGURATION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH CONFIGURATION
   */
  void
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 6040,6045 **** AlterObjectSchemaStmt:
--- 6040,6053 ----
  					n->newschema = $7;
  					$$ = (Node *)n;
  				}
+ 			| ALTER CONVERSION_P any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_CONVERSION;
+ 					n->object = $3;
+ 					n->newschema = $6;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER DOMAIN_P any_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6057,6062 **** AlterObjectSchemaStmt:
--- 6065,6097 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER OPERATOR any_operator oper_argtypes SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPERATOR;
+ 					n->object = $3;
+ 					n->objarg = $4;
+ 					n->newschema = $7;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPCLASS;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPFAMILY;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER TABLE relation_expr SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6065,6070 **** AlterObjectSchemaStmt:
--- 6100,6137 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSPARSER;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSDICTIONARY;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSTEMPLATE;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSCONFIGURATION;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER SEQUENCE qualified_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 1694,1702 **** CreateCommandTag(Node *parsetree)
--- 1694,1714 ----
  				case OBJECT_AGGREGATE:
  					tag = "ALTER AGGREGATE";
  					break;
+ 				case OBJECT_CONVERSION:
+ 					tag = "ALTER CONVERSION";
+ 					break;
  				case OBJECT_DOMAIN:
  					tag = "ALTER DOMAIN";
  					break;
+ 				case OBJECT_OPERATOR:
+ 					tag = "ALTER OPERATOR";
+ 					break;
+ 				case OBJECT_OPCLASS:
+ 					tag = "ALTER OPERATOR CLASS";
+ 					break;
+ 				case OBJECT_OPFAMILY:
+ 					tag = "ALTER OPERATOR FAMILY";
+ 					break;
  				case OBJECT_FUNCTION:
  					tag = "ALTER FUNCTION";
  					break;
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
***************
*** 166,171 **** extern ObjectClass getObjectClass(const ObjectAddress *object);
--- 166,173 ----
  
  extern char *getObjectDescription(const ObjectAddress *object);
  
+ extern char *getObjectDescriptionOids(Oid classid, Oid objid);
+ 
  extern ObjectAddresses *new_object_addresses(void);
  
  extern void add_exact_object_address(const ObjectAddress *object,
*** a/src/include/catalog/namespace.h
--- b/src/include/catalog/namespace.h
***************
*** 94,99 **** extern Oid	LookupExplicitNamespace(const char *nspname);
--- 94,101 ----
  extern Oid	get_namespace_oid(const char *nspname, bool missing_ok);
  
  extern Oid	LookupCreationNamespace(const char *nspname);
+ extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid,
+ 							  Oid objid);
  extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p);
  extern RangeVar *makeRangeVarFromNameList(List *names);
  extern char *NameListToString(List *names);
*** a/src/include/commands/alter.h
--- b/src/include/commands/alter.h
***************
*** 15,23 ****
--- 15,30 ----
  #define ALTER_H
  
  #include "nodes/parsenodes.h"
+ #include "utils/acl.h"
+ #include "utils/relcache.h"
  
  extern void ExecRenameStmt(RenameStmt *stmt);
  extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt);
+ extern void AlterObjectNamespace(Relation rel, int cacheId,
+ 								 Oid classId, Oid objid, Oid nspId,
+ 								 int Anum_name, int Anum_namespace, int Anum_owner,
+ 								 AclObjectKind acl_kind,
+ 								 bool superuser_only);
  extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt);
  
  #endif   /* ALTER_H */
*** a/src/include/commands/conversioncmds.h
--- b/src/include/commands/conversioncmds.h
***************
*** 22,26 **** extern void DropConversionsCommand(DropStmt *drop);
--- 22,29 ----
  extern void RenameConversion(List *name, const char *newname);
  extern void AlterConversionOwner(List *name, Oid newOwnerId);
  extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
+ extern void AlterConversionNamespace(List *name, const char *newschema);
+ extern void AlterConversionNamespace_oid(Oid convOid, Oid newNspOid);
+ 
  
  #endif   /* CONVERSIONCMDS_H */
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 66,71 **** extern void DropCast(DropCastStmt *stmt);
--- 66,72 ----
  extern void DropCastById(Oid castOid);
  extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema);
+ extern void AlterFunctionNamespace_oid(Oid procOid, Oid nspOid);
  extern void ExecuteDoStmt(DoStmt *stmt);
  extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
  
***************
*** 78,83 **** extern void AlterOperatorOwner(List *name, TypeName *typeName1,
--- 79,86 ----
  extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId);
  extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
  extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern void AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid);
+ extern void AlterOperatorNamespace(List *names, List *argtypes, const char *newschema);
  
  /* commands/aggregatecmds.c */
  extern void DefineAggregate(List *name, List *args, bool oldstyle,
***************
*** 100,114 **** extern void RenameOpClass(List *name, const char *access_method, const char *new
--- 103,123 ----
  extern void RenameOpFamily(List *name, const char *access_method, const char *newname);
  extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId);
+ extern void AlterOpClassNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid);
  extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId);
  extern Oid get_am_oid(const char *amname, bool missing_ok);
+ extern void AlterOpFamilyNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid);
  
  /* commands/tsearchcmds.c */
  extern void DefineTSParser(List *names, List *parameters);
  extern void RenameTSParser(List *oldname, const char *newname);
  extern void RemoveTSParsers(DropStmt *drop);
  extern void RemoveTSParserById(Oid prsId);
+ extern void AlterTSParserNamespace(List *name, const char *newschema);
+ extern void AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
  
  extern void DefineTSDictionary(List *names, List *parameters);
  extern void RenameTSDictionary(List *oldname, const char *newname);
***************
*** 116,129 **** extern void RemoveTSDictionaries(DropStmt *drop);
--- 125,144 ----
  extern void RemoveTSDictionaryById(Oid dictId);
  extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
  extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
+ extern void AlterTSDictionaryNamespace(List *name, const char *newschema);
+ extern void AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid);
  
  extern void DefineTSTemplate(List *names, List *parameters);
  extern void RenameTSTemplate(List *oldname, const char *newname);
+ extern void AlterTSTemplateNamespace(List *name, const char *newschema);
+ extern void AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
  extern void RemoveTSTemplates(DropStmt *stmt);
  extern void RemoveTSTemplateById(Oid tmplId);
  
  extern void DefineTSConfiguration(List *names, List *parameters);
  extern void RenameTSConfiguration(List *oldname, const char *newname);
+ extern void AlterTSConfigurationNamespace(List *name, const char *newschema);
+ extern void AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid);
  extern void RemoveTSConfigurations(DropStmt *stmt);
  extern void RemoveTSConfigurationById(Oid cfgId);
  extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
#42Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Alvaro Herrera (#40)
1 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Alvaro Herrera <alvherre@commandprompt.com> writes:

Hmm, seeing the amount of new includes in extension.c, I wonder if it'd
be better to move AlterExtensionNamespace to alter.c.

It was mainly missing includes cleanup. The guts of the function is now
so short I can inline it in this mail:

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);
}

So really, I don't think moving it to alter.c would do any better,
considering that you would then have this file include dependency
related function.

Please find attached v3 patch with #include cleanup.
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

alter_extension.v3.patchtext/x-patchDownload
*** 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/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
***************
*** 42,47 ****
--- 42,48 ----
  #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/extension.h"
  #include "funcapi.h"
***************
*** 1275,1277 **** pg_extension_objects(PG_FUNCTION_ARGS)
--- 1276,1322 ----
  	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/acl.h"
  #include "utils/relcache.h"
***************
*** 25,30 **** extern void AlterObjectNamespace(Relation rel, int cacheId,
--- 26,32 ----
  								 int Anum_name, int Anum_namespace, int Anum_owner,
  								 AclObjectKind acl_kind,
  								 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);
#43Alvaro Herrera
alvherre@commandprompt.com
In reply to: Dimitri Fontaine (#42)
Re: ALTER OBJECT any_name SET SCHEMA name

Excerpts from Dimitri Fontaine's message of vie nov 05 06:49:34 -0300 2010:

Alvaro Herrera <alvherre@commandprompt.com> writes:

Hmm, seeing the amount of new includes in extension.c, I wonder if it'd
be better to move AlterExtensionNamespace to alter.c.

It was mainly missing includes cleanup. The guts of the function is now
so short I can inline it in this mail:

Ah, good.

Please find attached v3 patch with #include cleanup.

Frankly, the get_extension_namespace bit still feels wrong to me. I
would have the namespace be present in the pg_extension catalog, even if
it's not part of the primary key. This would let you answer the
question: what schema did I install this extension in? (and display it
in \dx commands etc) If you don't know that, then the ability to change
it to another schema looks incomplete. Since we're now saying that
moving the extension to another schema is a first-class operation, I
think the data should be represented more explicitely in the catalog
rather than being derived from pg_depend contents.

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#44Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Alvaro Herrera (#43)
Re: ALTER OBJECT any_name SET SCHEMA name

Alvaro Herrera <alvherre@commandprompt.com> writes:

Frankly, the get_extension_namespace bit still feels wrong to me. I
would have the namespace be present in the pg_extension catalog, even if
it's not part of the primary key. This would let you answer the
question: what schema did I install this extension in? (and display it
in \dx commands etc)

dim=# \dx
List of extensions
Schema | Name | Version | Description
--------+--------------------+----------+--------------
utils | lo | 9.1devel | managing Larg
utils | unaccent | 9.1devel | text search d
utils | adminpack | 9.1devel | Administrativ
utils | moddatetime | 9.1devel | functions for
utils | isn | 9.1devel | data types fo
...

I've cut in there obviously, but you get the idea.

If you don't know that, then the ability to change
it to another schema looks incomplete. Since we're now saying that
moving the extension to another schema is a first-class operation, I
think the data should be represented more explicitely in the catalog
rather than being derived from pg_depend contents.

Well, I'm thinking that:

- namespace columns in the catalogs are actually all for objects that
live in a schema and extension do not

- pg_depend is a good source here, as it is for get_constraint_index
and some other functions

- maybe the problem is that parts of this patch should go into the main
extension's one, where there's already the with schema foo feature,
rather than be introduced in the alter extension set schema patch?

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#45Tom Lane
tgl@sss.pgh.pa.us
In reply to: Dimitri Fontaine (#44)
Re: ALTER OBJECT any_name SET SCHEMA name

Dimitri Fontaine <dimitri@2ndQuadrant.fr> writes:

Alvaro Herrera <alvherre@commandprompt.com> writes:

Frankly, the get_extension_namespace bit still feels wrong to me. I
would have the namespace be present in the pg_extension catalog, even if
it's not part of the primary key.

Well, I'm thinking that:
- namespace columns in the catalogs are actually all for objects that
live in a schema and extension do not

I'm with Alvaro on this. If we're going to have an ALTER EXTENSION SET
SCHEMA operation, then extensions must have a well-defined schema
property, and it would be good if that connection were explicitly
represented in the catalogs. Digging stuff out of pg_depend sucks;
we have to do it in some other cases where we didn't foresee the
connection in advance, but we can see it well enough here.

BTW, I'm not even 100% convinced that the schema shouldn't be part of
the extension's name, if we're going to make it work like this. Is
there a reason I shouldn't be able to have both public.myextension
and testing.myextension? If we're constraining all the objects owned by
the extension to live in a single schema, this seems perfectly feasible.

regards, tom lane

#46Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Tom Lane (#45)
Re: ALTER OBJECT any_name SET SCHEMA name

Tom Lane <tgl@sss.pgh.pa.us> writes:

I'm with Alvaro on this. If we're going to have an ALTER EXTENSION SET
SCHEMA operation, then extensions must have a well-defined schema
property, and it would be good if that connection were explicitly
represented in the catalogs. Digging stuff out of pg_depend sucks;
we have to do it in some other cases where we didn't foresee the
connection in advance, but we can see it well enough here.

Ok. So an extension using more than one schema is out, right? Not that I
can see a strong use case, just thinking out loud.

Also, do we keep the current notation or change it, or add to it:
CREATE EXTENSION foo WITH SCHEMA utils;
CREATE EXTENSION utils.foo;

I guess if you schema qualify the extension's name we could use that as
the schema name, but remember that the control file name would then be
different from the (qualified and given) extension's name. Surely we
would not try to find the utils.foo.control file, right?

The schema name is also used as a placeholder in the extension SQL
script, so it is somewhat weird to have it in the extension's name.

BTW, I'm not even 100% convinced that the schema shouldn't be part of
the extension's name, if we're going to make it work like this. Is
there a reason I shouldn't be able to have both public.myextension
and testing.myextension? If we're constraining all the objects owned by
the extension to live in a single schema, this seems perfectly feasible.

Are you proposing that an extension object is schema qualified? Would we
lower creating extension privileges to database owners, too, rather than
only superusers?

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#47Tom Lane
tgl@sss.pgh.pa.us
In reply to: Dimitri Fontaine (#46)
Re: ALTER OBJECT any_name SET SCHEMA name

Dimitri Fontaine <dimitri@2ndQuadrant.fr> writes:

Tom Lane <tgl@sss.pgh.pa.us> writes:

BTW, I'm not even 100% convinced that the schema shouldn't be part of
the extension's name, if we're going to make it work like this. Is
there a reason I shouldn't be able to have both public.myextension
and testing.myextension? If we're constraining all the objects owned by
the extension to live in a single schema, this seems perfectly feasible.

Are you proposing that an extension object is schema qualified?

Dunno, I'm just asking the question. If it isn't, why not?

Here's another question: if an extension's objects live (mostly or
entirely) in schema X, what happens if the possibly-unprivileged owner
of schema X decides to drop it? If the extension itself is considered
to live within the schema, then "the whole extension goes away" seems
like a natural answer. If not, you've got some problems.

Would we lower creating extension privileges to database owners, too,
rather than only superusers?

That seems like an orthogonal question. I can see people wanting both
behaviors though. Maybe an extension's config file should specify the
privs needed to install it?

regards, tom lane

#48Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Tom Lane (#47)
Re: ALTER OBJECT any_name SET SCHEMA name

Tom Lane <tgl@sss.pgh.pa.us> writes:

Are you proposing that an extension object is schema qualified?

Dunno, I'm just asking the question. If it isn't, why not?

Because extension are much like languages for stored procedure, on the
utility side rather than on the query side. The only queries that uses
language directly are utility statements, yet functions will depend on
them and live in some schema.

That's how I see extensions too, a new utility. Nothing I expect to be
visible in queries. They don't need schema, they are database globals.
The objects that are depending on the extension may or may not live in a
schema. A single extension script could create more than one schema and
have objects spread there.

So either we restrict an extension's to live in a single schema and we
have to forbid changing the schema of the objects in there on their own
(DEPENDENCY_INTERNAL should help), or we add a very simple check at
ALTER EXTENSION ... SET SCHEMA time to error out when the extension
depends on more than one schema. I'd do the later, obviously.

Here's another question: if an extension's objects live (mostly or
entirely) in schema X, what happens if the possibly-unprivileged owner
of schema X decides to drop it? If the extension itself is considered
to live within the schema, then "the whole extension goes away" seems
like a natural answer. If not, you've got some problems.

Currently, creating an extension is superuser only. So the owner of
those objects is a superuser. My understanding is that the drop schema
will then fail without any more code.

Would we lower creating extension privileges to database owners, too,
rather than only superusers?

That seems like an orthogonal question. I can see people wanting both
behaviors though. Maybe an extension's config file should specify the
privs needed to install it?

Orthogonal indeed, but it popped in my mind reading the previous mail,
and reading your previous question I guess you see why :)

I'm not for offering extension's author to control this behavior. As the
extension will more often than not come with a shared object lib, and as
the goal is to install SQL objects that will NOT be part of pg_dump
output, my feeling is that superuser only makes most sense.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#49Tom Lane
tgl@sss.pgh.pa.us
In reply to: Dimitri Fontaine (#48)
Re: ALTER OBJECT any_name SET SCHEMA name

Dimitri Fontaine <dimitri@2ndQuadrant.fr> writes:

Tom Lane <tgl@sss.pgh.pa.us> writes:

Here's another question: if an extension's objects live (mostly or
entirely) in schema X, what happens if the possibly-unprivileged owner
of schema X decides to drop it? If the extension itself is considered
to live within the schema, then "the whole extension goes away" seems
like a natural answer. If not, you've got some problems.

Currently, creating an extension is superuser only. So the owner of
those objects is a superuser. My understanding is that the drop schema
will then fail without any more code.

You're mistaken, and this case definitely does need more thought.
A schema owner is presumed to have the unconditional right to
drop anything in his schema, whether he owns it or not.

regards, tom lane

#50Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Tom Lane (#49)
Re: ALTER OBJECT any_name SET SCHEMA name

Tom Lane <tgl@sss.pgh.pa.us> writes:

You're mistaken, and this case definitely does need more thought.
A schema owner is presumed to have the unconditional right to
drop anything in his schema, whether he owns it or not.

Here a paste of how it works with current code.

dim=# create schema bob authorization bob;
CREATE SCHEMA

dim=# alter extension unaccent set schema bob;
ALTER EXTENSION

dim=# \c - bob
You are now connected to database "dim" as user "bob".

dim=> drop schema bob;
ERROR: cannot drop schema bob because other objects depend on it
DETAIL: extension unaccent depends on schema bob
HINT: Use DROP ... CASCADE to drop the dependent objects too.

dim=> drop schema bob cascade;
NOTICE: drop cascades to extension unaccent
DROP SCHEMA

dim=> \c - dim
You are now connected to database "dim" as user "dim".
dim=# select installed from pg_extensions where name = 'unaccent';
installed
-----------
f
(1 row)

Isn't that enough for you?
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#51Alvaro Herrera
alvherre@commandprompt.com
In reply to: Dimitri Fontaine (#50)
Re: ALTER OBJECT any_name SET SCHEMA name

Excerpts from Dimitri Fontaine's message of vie nov 05 16:58:00 -0300 2010:

dim=> drop schema bob cascade;
NOTICE: drop cascades to extension unaccent
DROP SCHEMA

dim=> \c - dim
You are now connected to database "dim" as user "dim".
dim=# select installed from pg_extensions where name = 'unaccent';
installed
-----------
f
(1 row)

Basically you're saying that the owner of the schema in which the
extension is installed can drop the extension ... even though, according
to your previous argument, the extension is not "in" said schema :-)

--
Álvaro Herrera <alvherre@commandprompt.com>
The PostgreSQL Company - Command Prompt, Inc.
PostgreSQL Replication, Consulting, Custom Development, 24x7 support

#52Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Alvaro Herrera (#51)
Re: ALTER OBJECT any_name SET SCHEMA name

Alvaro Herrera <alvherre@commandprompt.com> writes:

Basically you're saying that the owner of the schema in which the
extension is installed can drop the extension ... even though, according
to your previous argument, the extension is not "in" said schema :-)

Yeah it's a case of defining things. The extension is not in the schema,
it depends on it. So if you drop schema cascade, that cascades to drop
extension.

I'm not saying that the only way to do it sanely is the one I propose,
but I did consider some alternatives and I did not code the current
patch only by accident :)

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#53Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#36)
Re: ALTER OBJECT any_name SET SCHEMA name

On Thu, Nov 4, 2010 at 3:39 PM, Dimitri Fontaine <dimitri@2ndquadrant.fr> wrote:

Tom Lane <tgl@sss.pgh.pa.us> writes:

Not having read the patch, but ... the idea that was in the back of
my mind was to have a generic AlterObjectNamespace function that
would take parameters approximately like the following:

Please find attached what I came up with, that's the set_schema patch
version 6.

Looks good overall, but:

In AlterObjectNamespace(), you reference ACL_KIND_CONVERSION, which I
suspect actually needs to be yet another parameter to that function.
I've had the thought before that we have a deplorable number of
different ways of referring to object types in the back end:
ACL_KIND_*, OCLASS_*, OBJECT_*, and class IDs. We should maybe look
at unifying some or all of those.

getObjectDescriptionOids() needs a prototype somewhere.

And probably most significantly, you need to add docs and regression tests.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#54Robert Haas
robertmhaas@gmail.com
In reply to: Robert Haas (#53)
Re: ALTER OBJECT any_name SET SCHEMA name

On Sat, Nov 20, 2010 at 11:22 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Nov 4, 2010 at 3:39 PM, Dimitri Fontaine <dimitri@2ndquadrant.fr> wrote:

Tom Lane <tgl@sss.pgh.pa.us> writes:

Not having read the patch, but ... the idea that was in the back of
my mind was to have a generic AlterObjectNamespace function that
would take parameters approximately like the following:

Please find attached what I came up with, that's the set_schema patch
version 6.

Looks good overall, but:

In AlterObjectNamespace(), you reference ACL_KIND_CONVERSION, which I
suspect actually needs to be yet another parameter to that function.
I've had the thought before that we have a deplorable number of
different ways of referring to object types in the back end:
ACL_KIND_*, OCLASS_*, OBJECT_*, and class IDs.  We should maybe look
at unifying some or all of those.

getObjectDescriptionOids() needs a prototype somewhere.

And probably most significantly, you need to add docs and regression tests.

Ah, nuts. I see now there's a v7. Never mind...

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#55Robert Haas
robertmhaas@gmail.com
In reply to: Robert Haas (#54)
1 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

On Sat, Nov 20, 2010 at 11:23 PM, Robert Haas <robertmhaas@gmail.com> wrote:

Ah, nuts.  I see now there's a v7.  Never mind...

OK. I looked at the right version, now. Hopefully.

It seems we have no regression tests at all for any of the existing
SET SCHEMA commands. This seems like a good time to correct that
oversight, and also add some for the new commands you're adding here.
(It might be helpful to submit the regression tests for the existing
commands as a separate patch.) Also, you're missing psql tab
completion support, which would be nice to have.

In CheckSetNamespace() you have the message 'already exists in schema'
there where the existing, similar checks say 'is already in schema',
which is a bit confusing. But that code looks useful, and in fact I
think we should use it for the existing object types also to avoid
code duplication. This is technically a regression in terms of
translatability, since instead of a single string that says something
like 'function %s is already in schema %s', you'll have '%s is already
in schema %s', and where the first %s is provided by
getObjectDescription(). But that doesn't seem like a problem, because
(1) we're already doing it that way for dependency error messages
anyway and (2) as far as I can tell from a visual scan and some
hacking with Google Translate, all of the languages for which we have
backend translations put the object type next to the object name
anyway.

So, attached is a proposed patch that just adds CheckSetNamespace()
and makes the existing SET SCHEMA commands use it. Barring
objections, I'll go ahead and commit this part.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Attachments:

check_set_namespace.patchapplication/octet-stream; name=check_set_namespace.patchDownload
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index c4ccb5f..a912971 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -2685,6 +2685,21 @@ getObjectDescription(const ObjectAddress *object)
 }
 
 /*
+ * getObjectDescriptionOids: as above, except the object is specified by Oids
+ */
+char *
+getObjectDescriptionOids(Oid classid, Oid objid)
+{
+	ObjectAddress	address;
+
+	address.classId = classid;
+	address.objectId = objid;
+	address.objectSubId = 0;
+
+	return getObjectDescription(&address);
+}
+
+/*
  * subroutine for getObjectDescription: describe a relation
  */
 static void
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 3727146..653c9ad 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -2340,6 +2340,40 @@ LookupCreationNamespace(const char *nspname)
 }
 
 /*
+ * Common checks on switching namespaces.
+ *
+ * We complain if (1) the old and new namespaces are the same, (2) either the
+ * old or new namespaces is a temporary schema (or temporary toast schema), or
+ * (3) either the old or new namespaces is the TOAST schema.
+ */
+void
+CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid)
+{
+	if (oldNspOid == nspOid)
+		ereport(ERROR,
+				(classid == RelationRelationId ?
+					errcode(ERRCODE_DUPLICATE_TABLE) :
+				 classid == ProcedureRelationId ?
+					errcode(ERRCODE_DUPLICATE_FUNCTION) :
+					errcode(ERRCODE_DUPLICATE_OBJECT),
+				 errmsg("%s is already in schema \"%s\"",
+						getObjectDescriptionOids(classid, objid),
+						get_namespace_name(nspOid))));
+
+	/* disallow renaming into or out of temp schemas */
+	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("cannot move objects into or out of temporary schemas")));
+
+	/* same for TOAST schema */
+	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("cannot move objects into or out of TOAST schema")));
+}
+
+/*
  * QualifiedNameGetCreationNamespace
  *		Given a possibly-qualified name for an object (in List-of-Values
  *		format), determine what namespace the object should be created in.
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 4b6801a..62a2110 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1899,24 +1899,8 @@ AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
 	/* get schema OID and check its permissions */
 	nspOid = LookupCreationNamespace(newschema);
 
-	if (oldNspOid == nspOid)
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_FUNCTION),
-				 errmsg("function \"%s\" is already in schema \"%s\"",
-						NameListToString(name),
-						newschema)));
-
-	/* disallow renaming into or out of temp schemas */
-	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-			errmsg("cannot move objects into or out of temporary schemas")));
-
-	/* same for TOAST schema */
-	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("cannot move objects into or out of TOAST schema")));
+	/* common checks on switching namespaces */
+	CheckSetNamespace(oldNspOid, nspOid, ProcedureRelationId, procOid);
 
 	/* check for duplicate name (more friendly than unique-index failure) */
 	if (SearchSysCacheExists3(PROCNAMEARGSNSP,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b22bcf0..11171ea 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8114,24 +8114,8 @@ AlterTableNamespace(RangeVar *relation, const char *newschema,
 	/* get schema OID and check its permissions */
 	nspOid = LookupCreationNamespace(newschema);
 
-	if (oldNspOid == nspOid)
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_TABLE),
-				 errmsg("relation \"%s\" is already in schema \"%s\"",
-						RelationGetRelationName(rel),
-						newschema)));
-
-	/* disallow renaming into or out of temp schemas */
-	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-			errmsg("cannot move objects into or out of temporary schemas")));
-
-	/* same for TOAST schema */
-	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("cannot move objects into or out of TOAST schema")));
+	/* 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);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 2f21451..583bba3 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2828,24 +2828,8 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
 	oldNspOid = typform->typnamespace;
 	arrayOid = typform->typarray;
 
-	if (oldNspOid == nspOid)
-		ereport(ERROR,
-				(errcode(ERRCODE_DUPLICATE_OBJECT),
-				 errmsg("type %s is already in schema \"%s\"",
-						format_type_be(typeOid),
-						get_namespace_name(nspOid))));
-
-	/* disallow renaming into or out of temp schemas */
-	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-			errmsg("cannot move objects into or out of temporary schemas")));
-
-	/* same for TOAST schema */
-	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("cannot move objects into or out of TOAST schema")));
+	/* common checks on switching namespaces */
+	CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
 
 	/* check for duplicate name (more friendly than unique-index failure) */
 	if (SearchSysCacheExists2(TYPENAMENSP,
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index ccde371..87f853d 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -165,6 +165,7 @@ extern void recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
 extern ObjectClass getObjectClass(const ObjectAddress *object);
 
 extern char *getObjectDescription(const ObjectAddress *object);
+extern char *getObjectDescriptionOids(Oid classid, Oid objid);
 
 extern ObjectAddresses *new_object_addresses(void);
 
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index c6672e9..a842ea7 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -94,6 +94,8 @@ extern Oid	LookupExplicitNamespace(const char *nspname);
 extern Oid	get_namespace_oid(const char *nspname, bool missing_ok);
 
 extern Oid	LookupCreationNamespace(const char *nspname);
+extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid,
+							  Oid objid);
 extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p);
 extern RangeVar *makeRangeVarFromNameList(List *names);
 extern char *NameListToString(List *names);
#56David Fetter
david@fetter.org
In reply to: Robert Haas (#55)
Re: ALTER OBJECT any_name SET SCHEMA name

On Sun, Nov 21, 2010 at 07:53:57AM -0500, Robert Haas wrote:

On Sat, Nov 20, 2010 at 11:23 PM, Robert Haas <robertmhaas@gmail.com> wrote:

Ah, nuts. �I see now there's a v7. �Never mind...

OK. I looked at the right version, now. Hopefully.

It seems we have no regression tests at all for any of the existing
SET SCHEMA commands. This seems like a good time to correct that
oversight, and also add some for the new commands you're adding here.
(It might be helpful to submit the regression tests for the existing
commands as a separate patch.) Also, you're missing psql tab
completion support, which would be nice to have.

In CheckSetNamespace() you have the message 'already exists in schema'
there where the existing, similar checks say 'is already in schema',
which is a bit confusing. But that code looks useful, and in fact I
think we should use it for the existing object types also to avoid
code duplication.

Should this really error out? It's just a NOOP, so perhaps a NOTICE
would be more appropriate.

Cheers,
David.
--
David Fetter <david@fetter.org> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: david.fetter@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

#57Robert Haas
robertmhaas@gmail.com
In reply to: David Fetter (#56)
Re: ALTER OBJECT any_name SET SCHEMA name

On Nov 21, 2010, at 1:03 PM, David Fetter <david@fetter.org> wrote:

Should this really error out? It's just a NOOP, so perhaps a NOTICE
would be more appropriate.

Perhaps, but the purpose of this patch is to streamline the code, not change the behavior.

...Robert

#58Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Robert Haas (#55)
Re: ALTER OBJECT any_name SET SCHEMA name

Robert Haas <robertmhaas@gmail.com> writes:

So, attached is a proposed patch that just adds CheckSetNamespace()
and makes the existing SET SCHEMA commands use it. Barring
objections, I'll go ahead and commit this part.

Thank you for applying the new function to the existing code paths, that
was needed as soon as the new function would get acceptance! :)

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#59Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Robert Haas (#55)
1 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Robert Haas <robertmhaas@gmail.com> writes:

On Sat, Nov 20, 2010 at 11:23 PM, Robert Haas <robertmhaas@gmail.com> wrote:

Ah, nuts.  I see now there's a v7.  Never mind...

OK. I looked at the right version, now. Hopefully.

Yeah, that was the most recent one and I linked it in the commit fest
application. Given the very fast feedback I got, there has been a lot of
activity and patches versions produced, so that's easy to get confused.

It seems we have no regression tests at all for any of the existing
SET SCHEMA commands. This seems like a good time to correct that
oversight, and also add some for the new commands you're adding here.

Yeah, it's time for me to have a look at regression tests :)

Please find attached set_schema.v8.patch with tests for the added
commands in the patch.

(It might be helpful to submit the regression tests for the existing
commands as a separate patch.) Also, you're missing psql tab
completion support, which would be nice to have.

Do you still want me to prepare another patch for adding in the tests
the "set schema" variants that already existed but are not yet covered?
Which are the one you did spot, btw?

Completion support for psql. Isn't that stepping on David's toes? :)
I'll see about that later if needed, maybe sometime tomorrow…

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

set_schema.v8.patchtext/x-patchDownload
*** a/doc/src/sgml/ref/alter_conversion.sgml
--- b/doc/src/sgml/ref/alter_conversion.sgml
***************
*** 23,28 **** PostgreSQL documentation
--- 23,29 ----
  <synopsis>
  ALTER CONVERSION <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER CONVERSION <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER CONVERSION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 75,80 **** ALTER CONVERSION <replaceable>name</replaceable> OWNER TO <replaceable>new_owner
--- 76,90 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the conversion.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_opclass.sgml
--- b/doc/src/sgml/ref/alter_opclass.sgml
***************
*** 23,28 **** PostgreSQL documentation
--- 23,29 ----
  <synopsis>
  ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 85,90 **** ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="p
--- 86,100 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema for the operator class.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_operator.sgml
--- b/doc/src/sgml/ref/alter_operator.sgml
***************
*** 22,27 **** PostgreSQL documentation
--- 22,28 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } ) OWNER TO <replaceable>new_owner</replaceable>
+ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } ) SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 85,90 **** ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
--- 86,100 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the operator.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_opfamily.sgml
--- b/doc/src/sgml/ref/alter_opfamily.sgml
***************
*** 31,36 **** ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
--- 31,37 ----
    } [, ... ]
  ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 200,205 **** ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
--- 201,215 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema for the operator family.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
  
    <para>
*** a/doc/src/sgml/ref/alter_tsconfig.sgml
--- b/doc/src/sgml/ref/alter_tsconfig.sgml
***************
*** 33,38 **** ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable>
--- 33,39 ----
      DROP MAPPING [ IF EXISTS ] FOR <replaceable class="parameter">token_type</replaceable> [, ... ]
  ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 123,128 **** ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> OWNER TO <replac
--- 124,138 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema for the text search configuration.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
  
    <para>
*** a/doc/src/sgml/ref/alter_tsdictionary.sgml
--- b/doc/src/sgml/ref/alter_tsdictionary.sgml
***************
*** 26,31 **** ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> (
--- 26,32 ----
  )
  ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 96,101 **** ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> OWNER TO <replaceab
--- 97,111 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the text search dictionary.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
  
    <para>
*** a/doc/src/sgml/ref/alter_tsparser.sgml
--- b/doc/src/sgml/ref/alter_tsparser.sgml
***************
*** 22,27 **** PostgreSQL documentation
--- 22,28 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER TEXT SEARCH PARSER <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
+ ALTER TEXT SEARCH PARSER <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 60,65 **** ALTER TEXT SEARCH PARSER <replaceable>name</replaceable> RENAME TO <replaceable>
--- 61,75 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the text search parser.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_tstemplate.sgml
--- b/doc/src/sgml/ref/alter_tstemplate.sgml
***************
*** 22,27 **** PostgreSQL documentation
--- 22,28 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER TEXT SEARCH TEMPLATE <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
+ ALTER TEXT SEARCH TEMPLATE <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 60,65 **** ALTER TEXT SEARCH TEMPLATE <replaceable>name</replaceable> RENAME TO <replaceabl
--- 61,75 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the text search template.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
   </refsect1>
  
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 2706,2711 **** getObjectDescription(const ObjectAddress *object)
--- 2706,2726 ----
  }
  
  /*
+  * getObjectDescriptionOids: as above, except the object is specified by Oids
+  */
+ char *
+ getObjectDescriptionOids(Oid classid, Oid objid)
+ {
+ 	ObjectAddress	address;
+ 
+ 	address.classId = classid;
+ 	address.objectId = objid;
+ 	address.objectSubId = 0;
+ 
+ 	return getObjectDescription(&address);
+ }
+ 
+ /*
   * subroutine for getObjectDescription: describe a relation
   */
  static void
*** a/src/backend/catalog/namespace.c
--- b/src/backend/catalog/namespace.c
***************
*** 2340,2345 **** LookupCreationNamespace(const char *nspname)
--- 2340,2372 ----
  }
  
  /*
+  * Check new namespace validity in ALTER OBJECT ... SET SCHEMA ... and
+  * ereport(ERROR, ...) in case of any problem.
+  */
+ void
+ CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid, Oid objid)
+ {
+ 	if (oldNspOid == nspOid)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s already exists in schema \"%s\"",
+ 						getObjectDescriptionOids(classid, objid),
+ 						get_namespace_name(nspOid))));
+ 
+ 	/* disallow renaming into or out of temp schemas */
+ 	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of temporary schemas")));
+ 
+ 	/* same for TOAST schema */
+ 	if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of TOAST schema")));
+ }
+ 
+ /*
   * QualifiedNameGetCreationNamespace
   *		Given a possibly-qualified name for an object (in List-of-Values
   *		format), determine what namespace the object should be created in.
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 14,21 ****
--- 14,23 ----
   */
  #include "postgres.h"
  
+ #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_largeobject.h"
+ #include "catalog/pg_namespace.h"
  #include "commands/alter.h"
  #include "commands/conversioncmds.h"
  #include "commands/dbcommands.h"
***************
*** 33,38 ****
--- 35,41 ----
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
+ #include "utils/syscache.h"
  
  
  /*
***************
*** 182,192 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 185,211 ----
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_CONVERSION:
+ 			AlterConversionNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_FUNCTION:
  			AlterFunctionNamespace(stmt->object, stmt->objarg, false,
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_OPERATOR:
+ 			AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPCLASS:
+ 			AlterOpClassNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPFAMILY:
+ 			AlterOpFamilyNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_SEQUENCE:
  		case OBJECT_TABLE:
  		case OBJECT_VIEW:
***************
*** 195,200 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 214,235 ----
  								stmt->objectType, AccessExclusiveLock);
  			break;
  
+ 		case OBJECT_TSPARSER:
+ 			AlterTSParserNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSDICTIONARY:
+ 			AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSTEMPLATE:
+ 			AlterTSTemplateNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSCONFIGURATION:
+ 			AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_TYPE:
  		case OBJECT_DOMAIN:
  			AlterTypeNamespace(stmt->object, stmt->newschema);
***************
*** 207,212 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 242,341 ----
  }
  
  /*
+  * Generic function to change the namespace of a given object, for simple
+  * cases (won't work for tables or functions, objects which have more than 2
+  * key-attributes to use when searching for their syscache entries --- we
+  * don't want nor need to get this generic here).
+  *
+  * The AlterFooNamespace() calls just above will call a function whose job
+  * is to lookup the arguments for the generic function here.
+  *
+  * Relation must already by open, it's the responsibility of the caller to
+  * close it.
+  */
+ void
+ AlterObjectNamespace(Relation rel, int cacheId,
+ 					 Oid classId, Oid objid, Oid nspOid,
+ 					 int Anum_name, int Anum_namespace, int Anum_owner,
+ 					 AclObjectKind acl_kind,
+ 					 bool superuser_only)
+ {
+ 	Oid			oldNspOid;
+ 	Datum       name, namespace;
+ 	bool        isnull;
+ 	HeapTuple	tup, newtup = NULL;
+ 	Datum		values[rel->rd_att->natts];
+ 	bool		nulls[rel->rd_att->natts];
+ 	bool		replaces[rel->rd_att->natts];
+ 	int			i;
+ 
+ 	tup = SearchSysCacheCopy1(cacheId, ObjectIdGetDatum(objid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for object %u: %s",
+ 			 objid, getObjectDescriptionOids(classId, objid));
+ 
+ 	name = heap_getattr(tup, Anum_name, rel->rd_att, &isnull);
+ 	namespace = heap_getattr(tup, Anum_namespace, rel->rd_att, &isnull);
+ 	oldNspOid = DatumGetObjectId(namespace);
+ 
+ 	/* Check basic namespace related issues */
+ 	CheckSetNamespace(oldNspOid, nspOid, classId, objid);
+ 
+ 	/* check for duplicate name (more friendly than unique-index failure) */
+ 	if (SearchSysCacheExists2(cacheId, name, ObjectIdGetDatum(nspOid)))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s already exists in schema \"%s\"",
+ 						getObjectDescriptionOids(classId, objid),
+ 						get_namespace_name(nspOid))));
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		Datum       owner;
+ 		Oid			ownerId;
+ 		AclResult	aclresult;
+ 
+ 		if (superuser_only)
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 					 (errmsg("must be superuser to SET SCHEMA of %s",
+ 							 getObjectDescriptionOids(classId, objid)))));
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		owner = heap_getattr(tup, Anum_owner, rel->rd_att, &isnull);
+ 		ownerId = DatumGetObjectId(owner);
+ 
+ 		if (!has_privs_of_role(GetUserId(), ownerId))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind,
+ 						   NameStr(*(DatumGetName(name))));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(oldNspOid));
+ 	}
+ 
+ 	/* prepare a new version of the tuple using nspId */
+ 	values[Anum_namespace - 1] = nspOid;
+ 	for (i = 0; i < rel->rd_att->natts; i++)
+ 	{
+ 		nulls[i]    = i != Anum_namespace - 1;
+ 		replaces[i] = i == Anum_namespace - 1;
+ 	}
+ 
+ 	newtup = heap_modify_tuple(tup, rel->rd_att, values, nulls, replaces);
+ 	simple_heap_update(rel, &tup->t_self, newtup);
+ 	CatalogUpdateIndexes(rel, newtup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(classId, objid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
+ 
+ 
+ /*
   * Executes an ALTER OBJECT / OWNER TO statement.  Based on the object
   * type, the function appropriate to that type is executed.
   */
*** a/src/backend/commands/conversioncmds.c
--- b/src/backend/commands/conversioncmds.c
***************
*** 19,25 ****
--- 19,27 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_conversion.h"
  #include "catalog/pg_conversion_fn.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/conversioncmds.h"
  #include "mb/pg_wchar.h"
  #include "miscadmin.h"
***************
*** 30,36 ****
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
! static void AlterConversionOwner_internal(Relation rel, Oid conversionOid,
  							  Oid newOwnerId);
  
  /*
--- 32,38 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
! static void AlterConversionOwner_internal(Relation rel, Oid convOid,
  							  Oid newOwnerId);
  
  /*
***************
*** 326,328 **** AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId)
--- 328,376 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER CONVERSION SET SCHEMA
+  */
+ void
+ AlterConversionNamespace(List *name, const char *newschema)
+ {
+ 	Oid			convOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	convOid = get_conversion_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, CONVOID, ConversionRelationId, convOid, nspOid,
+ 						 Anum_pg_conversion_conname,
+ 						 Anum_pg_conversion_connamespace,
+ 						 Anum_pg_conversion_conowner,
+ 						 ACL_KIND_CONVERSION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
+  * Change conversion schema, by oid
+  */
+ void
+ AlterConversionNamespace_oid(Oid convOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, CONVOID, ConversionRelationId, convOid, newNspOid,
+ 						 Anum_pg_conversion_conname,
+ 						 Anum_pg_conversion_connamespace,
+ 						 Anum_pg_conversion_conowner,
+ 						 ACL_KIND_CONVERSION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/functioncmds.c
--- b/src/backend/commands/functioncmds.c
***************
*** 1870,1882 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema)
  {
  	Oid			procOid;
- 	Oid			oldNspOid;
  	Oid			nspOid;
- 	HeapTuple	tup;
- 	Relation	procRel;
- 	Form_pg_proc proc;
- 
- 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
  
  	/* get function OID */
  	if (isagg)
--- 1870,1876 ----
***************
*** 1889,1894 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
--- 1883,1903 ----
  		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
  					   NameListToString(name));
  
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterFunctionNamespace_oid(procOid, nspOid);
+ }
+ 
+ void
+ AlterFunctionNamespace_oid(Oid procOid, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 	Relation	procRel;
+ 	Form_pg_proc proc;
+ 
+ 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
+ 
  	tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid));
  	if (!HeapTupleIsValid(tup))
  		elog(ERROR, "cache lookup failed for function %u", procOid);
***************
*** 1896,1910 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  
  	oldNspOid = proc->pronamespace;
  
- 	/* get schema OID and check its permissions */
- 	nspOid = LookupCreationNamespace(newschema);
- 
  	if (oldNspOid == nspOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" is already in schema \"%s\"",
! 						NameListToString(name),
! 						newschema)));
  
  	/* disallow renaming into or out of temp schemas */
  	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
--- 1905,1916 ----
  
  	oldNspOid = proc->pronamespace;
  
  	if (oldNspOid == nspOid)
  		ereport(ERROR,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" is already in schema \"%s\"",
! 						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* disallow renaming into or out of temp schemas */
  	if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
***************
*** 1927,1933 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						newschema)));
  
  	/* OK, modify the pg_proc row */
  
--- 1933,1939 ----
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* OK, modify the pg_proc row */
  
***************
*** 1941,1947 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameListToString(name));
  
  	heap_freetuple(tup);
  
--- 1947,1953 ----
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameStr(proc->proname));
  
  	heap_freetuple(tup);
  
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 30,35 ****
--- 30,36 ----
  #include "catalog/pg_opfamily.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "parser/parse_func.h"
***************
*** 1912,1917 **** AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
--- 1913,1980 ----
  }
  
  /*
+  * ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpClassNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup, origtup;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	/* Look up the opclass. */
+ 	origtup = OpClassCacheLookup(amOid, name, false);
+ 	tup = heap_copytuple(origtup);
+ 	ReleaseSysCache(origtup);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, CLAOID, OperatorClassRelationId,
+ 						 HeapTupleGetOid(tup), nspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPCLASS,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(CLAOID, ObjectIdGetDatum(opclassOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
+ 
+ 	AlterObjectNamespace(rel, CLAOID, OperatorClassRelationId,
+ 						 HeapTupleGetOid(tup), newNspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPCLASS,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
   * Change opfamily owner by name
   */
  void
***************
*** 2067,2069 **** get_am_oid(const char *amname, bool missing_ok)
--- 2130,2226 ----
  				 errmsg("access method \"%s\" does not exist", amname)));
  	return oid;
  }
+ 
+ /*
+  * ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpFamilyNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup;
+ 	char	   *opfname, *schemaname;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	/*
+ 	 * Look up the opfamily
+ 	 */
+ 	DeconstructQualifiedName(name, &schemaname, &opfname);
+ 
+ 	if (schemaname)
+ 	{
+ 		Oid			namespaceOid;
+ 
+ 		namespaceOid = LookupExplicitNamespace(schemaname);
+ 
+ 		tup = SearchSysCacheCopy3(OPFAMILYAMNAMENSP,
+ 								  ObjectIdGetDatum(amOid),
+ 								  PointerGetDatum(opfname),
+ 								  ObjectIdGetDatum(namespaceOid));
+ 		if (!HeapTupleIsValid(tup))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 	}
+ 	else
+ 	{
+ 		Oid			opfOid;
+ 
+ 		opfOid = OpfamilynameGetOpfid(amOid, opfname);
+ 		if (!OidIsValid(opfOid))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 
+ 		tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfOid));
+ 		if (!HeapTupleIsValid(tup))		/* should not happen */
+ 			elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
+ 	}
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, OPFAMILYOID, OperatorFamilyRelationId,
+ 						 HeapTupleGetOid(tup), nspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPFAMILY,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
+ 
+ 	AlterObjectNamespace(rel, OPFAMILYOID, OperatorFamilyRelationId,
+ 						 opfamilyOid, newNspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPFAMILY,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/operatorcmds.c
--- b/src/backend/commands/operatorcmds.c
***************
*** 39,45 ****
--- 39,47 ----
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_operator.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "parser/parse_func.h"
***************
*** 452,454 **** AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
--- 454,505 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER OPERATOR SET SCHEMA
+  */
+ void
+ AlterOperatorNamespace(List *names, List *argtypes, const char *newschema)
+ {
+ 	List	   *operatorName = names;
+ 	TypeName   *typeName1 = (TypeName *) linitial(argtypes);
+ 	TypeName   *typeName2 = (TypeName *) lsecond(argtypes);
+ 	Oid			operOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	Assert(list_length(argtypes) == 2);
+ 	operOid = LookupOperNameTypeNames(NULL, operatorName,
+ 									  typeName1, typeName2,
+ 									  false, -1);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, OPEROID, OperatorRelationId, operOid, nspOid,
+ 						 Anum_pg_operator_oprname,
+ 						 Anum_pg_operator_oprnamespace,
+ 						 Anum_pg_operator_oprowner,
+ 						 ACL_KIND_OPER,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, OPEROID, OperatorRelationId, operOid, newNspOid,
+ 						 Anum_pg_operator_oprname,
+ 						 Anum_pg_operator_oprnamespace,
+ 						 Anum_pg_operator_oprowner,
+ 						 ACL_KIND_OPER,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/tsearchcmds.c
--- b/src/backend/commands/tsearchcmds.c
***************
*** 31,36 ****
--- 31,37 ----
  #include "catalog/pg_ts_parser.h"
  #include "catalog/pg_ts_template.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "nodes/makefuncs.h"
***************
*** 393,398 **** RenameTSParser(List *oldname, const char *newname)
--- 394,438 ----
  	heap_freetuple(tup);
  }
  
+ /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSParserNamespace(List *name, const char *newschema)
+ {
+ 	Oid			prsId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	prsId = get_ts_parser_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSPARSEROID, TSParserRelationId, prsId, nspOid,
+ 						 Anum_pg_ts_parser_prsname,
+ 						 Anum_pg_ts_parser_prsnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSPARSEROID, TSParserRelationId, prsId, newNspOid,
+ 						 Anum_pg_ts_parser_prsname,
+ 						 Anum_pg_ts_parser_prsnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
  /* ---------------------- TS Dictionary commands -----------------------*/
  
  /*
***************
*** 620,625 **** RenameTSDictionary(List *oldname, const char *newname)
--- 660,708 ----
  }
  
  /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSDictionaryNamespace(List *name, const char *newschema)
+ {
+ 	Oid			dictId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	dictId = get_ts_dict_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSDICTOID, TSDictionaryRelationId, dictId, nspOid,
+ 						 Anum_pg_ts_dict_dictname,
+ 						 Anum_pg_ts_dict_dictnamespace,
+ 						 Anum_pg_ts_dict_dictowner,
+ 						 ACL_KIND_TSDICTIONARY,
+ 						 true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSDICTOID, TSDictionaryRelationId, dictId, newNspOid,
+ 						 Anum_pg_ts_dict_dictname,
+ 						 Anum_pg_ts_dict_dictnamespace,
+ 						 Anum_pg_ts_dict_dictowner,
+ 						 ACL_KIND_TSDICTIONARY,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
   * DROP TEXT SEARCH DICTIONARY
   */
  void
***************
*** 1100,1105 **** RenameTSTemplate(List *oldname, const char *newname)
--- 1183,1230 ----
  }
  
  /*
+  * ALTER TEXT SEARCH TEMPLATE any_name SET SCHEMA name
+  */
+ void
+ AlterTSTemplateNamespace(List *name, const char *newschema)
+ {
+ 	Oid			tmplId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	tmplId = get_ts_template_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSTEMPLATEOID, TSTemplateRelationId,
+ 						 tmplId, nspOid,
+ 						 Anum_pg_ts_template_tmplname,
+ 						 Anum_pg_ts_template_tmplnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSTEMPLATEOID, TSTemplateRelationId,
+ 						 tmplId, newNspOid,
+ 						 Anum_pg_ts_template_tmplname,
+ 						 Anum_pg_ts_template_tmplnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH TEMPLATE
   */
  void
***************
*** 1498,1503 **** RenameTSConfiguration(List *oldname, const char *newname)
--- 1623,1672 ----
  }
  
  /*
+  * ALTER TEXT SEARCH CONFIGURATION any_name SET SCHEMA name
+  */
+ void
+ AlterTSConfigurationNamespace(List *name, const char *newschema)
+ {
+ 	Oid			cfgId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	cfgId = get_ts_config_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSCONFIGOID, TSConfigRelationId, cfgId, nspOid,
+ 						 Anum_pg_ts_config_cfgname,
+ 						 Anum_pg_ts_config_cfgnamespace,
+ 						 Anum_pg_ts_config_cfgowner,
+ 						 ACL_KIND_TSCONFIGURATION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSCONFIGOID, TSConfigRelationId, cfgId, newNspOid,
+ 						 Anum_pg_ts_config_cfgname,
+ 						 Anum_pg_ts_config_cfgnamespace,
+ 						 Anum_pg_ts_config_cfgowner,
+ 						 ACL_KIND_TSCONFIGURATION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH CONFIGURATION
   */
  void
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 6040,6045 **** AlterObjectSchemaStmt:
--- 6040,6053 ----
  					n->newschema = $7;
  					$$ = (Node *)n;
  				}
+ 			| ALTER CONVERSION_P any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_CONVERSION;
+ 					n->object = $3;
+ 					n->newschema = $6;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER DOMAIN_P any_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6057,6062 **** AlterObjectSchemaStmt:
--- 6065,6097 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER OPERATOR any_operator oper_argtypes SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPERATOR;
+ 					n->object = $3;
+ 					n->objarg = $4;
+ 					n->newschema = $7;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPCLASS;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPFAMILY;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER TABLE relation_expr SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6065,6070 **** AlterObjectSchemaStmt:
--- 6100,6137 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSPARSER;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSDICTIONARY;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSTEMPLATE;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSCONFIGURATION;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER SEQUENCE qualified_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 1694,1702 **** CreateCommandTag(Node *parsetree)
--- 1694,1714 ----
  				case OBJECT_AGGREGATE:
  					tag = "ALTER AGGREGATE";
  					break;
+ 				case OBJECT_CONVERSION:
+ 					tag = "ALTER CONVERSION";
+ 					break;
  				case OBJECT_DOMAIN:
  					tag = "ALTER DOMAIN";
  					break;
+ 				case OBJECT_OPERATOR:
+ 					tag = "ALTER OPERATOR";
+ 					break;
+ 				case OBJECT_OPCLASS:
+ 					tag = "ALTER OPERATOR CLASS";
+ 					break;
+ 				case OBJECT_OPFAMILY:
+ 					tag = "ALTER OPERATOR FAMILY";
+ 					break;
  				case OBJECT_FUNCTION:
  					tag = "ALTER FUNCTION";
  					break;
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
***************
*** 166,171 **** extern ObjectClass getObjectClass(const ObjectAddress *object);
--- 166,173 ----
  
  extern char *getObjectDescription(const ObjectAddress *object);
  
+ extern char *getObjectDescriptionOids(Oid classid, Oid objid);
+ 
  extern ObjectAddresses *new_object_addresses(void);
  
  extern void add_exact_object_address(const ObjectAddress *object,
*** a/src/include/catalog/namespace.h
--- b/src/include/catalog/namespace.h
***************
*** 94,99 **** extern Oid	LookupExplicitNamespace(const char *nspname);
--- 94,101 ----
  extern Oid	get_namespace_oid(const char *nspname, bool missing_ok);
  
  extern Oid	LookupCreationNamespace(const char *nspname);
+ extern void CheckSetNamespace(Oid oldNspOid, Oid nspOid, Oid classid,
+ 							  Oid objid);
  extern Oid	QualifiedNameGetCreationNamespace(List *names, char **objname_p);
  extern RangeVar *makeRangeVarFromNameList(List *names);
  extern char *NameListToString(List *names);
*** a/src/include/commands/alter.h
--- b/src/include/commands/alter.h
***************
*** 15,23 ****
--- 15,30 ----
  #define ALTER_H
  
  #include "nodes/parsenodes.h"
+ #include "utils/acl.h"
+ #include "utils/relcache.h"
  
  extern void ExecRenameStmt(RenameStmt *stmt);
  extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt);
+ extern void AlterObjectNamespace(Relation rel, int cacheId,
+ 								 Oid classId, Oid objid, Oid nspId,
+ 								 int Anum_name, int Anum_namespace, int Anum_owner,
+ 								 AclObjectKind acl_kind,
+ 								 bool superuser_only);
  extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt);
  
  #endif   /* ALTER_H */
*** a/src/include/commands/conversioncmds.h
--- b/src/include/commands/conversioncmds.h
***************
*** 22,26 **** extern void DropConversionsCommand(DropStmt *drop);
--- 22,29 ----
  extern void RenameConversion(List *name, const char *newname);
  extern void AlterConversionOwner(List *name, Oid newOwnerId);
  extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
+ extern void AlterConversionNamespace(List *name, const char *newschema);
+ extern void AlterConversionNamespace_oid(Oid convOid, Oid newNspOid);
+ 
  
  #endif   /* CONVERSIONCMDS_H */
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 66,71 **** extern void DropCast(DropCastStmt *stmt);
--- 66,72 ----
  extern void DropCastById(Oid castOid);
  extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema);
+ extern void AlterFunctionNamespace_oid(Oid procOid, Oid nspOid);
  extern void ExecuteDoStmt(DoStmt *stmt);
  extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
  
***************
*** 78,83 **** extern void AlterOperatorOwner(List *name, TypeName *typeName1,
--- 79,86 ----
  extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId);
  extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
  extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern void AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid);
+ extern void AlterOperatorNamespace(List *names, List *argtypes, const char *newschema);
  
  /* commands/aggregatecmds.c */
  extern void DefineAggregate(List *name, List *args, bool oldstyle,
***************
*** 100,114 **** extern void RenameOpClass(List *name, const char *access_method, const char *new
--- 103,123 ----
  extern void RenameOpFamily(List *name, const char *access_method, const char *newname);
  extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId);
+ extern void AlterOpClassNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid);
  extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId);
  extern Oid get_am_oid(const char *amname, bool missing_ok);
+ extern void AlterOpFamilyNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid);
  
  /* commands/tsearchcmds.c */
  extern void DefineTSParser(List *names, List *parameters);
  extern void RenameTSParser(List *oldname, const char *newname);
  extern void RemoveTSParsers(DropStmt *drop);
  extern void RemoveTSParserById(Oid prsId);
+ extern void AlterTSParserNamespace(List *name, const char *newschema);
+ extern void AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
  
  extern void DefineTSDictionary(List *names, List *parameters);
  extern void RenameTSDictionary(List *oldname, const char *newname);
***************
*** 116,129 **** extern void RemoveTSDictionaries(DropStmt *drop);
--- 125,144 ----
  extern void RemoveTSDictionaryById(Oid dictId);
  extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
  extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
+ extern void AlterTSDictionaryNamespace(List *name, const char *newschema);
+ extern void AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid);
  
  extern void DefineTSTemplate(List *names, List *parameters);
  extern void RenameTSTemplate(List *oldname, const char *newname);
+ extern void AlterTSTemplateNamespace(List *name, const char *newschema);
+ extern void AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
  extern void RemoveTSTemplates(DropStmt *stmt);
  extern void RemoveTSTemplateById(Oid tmplId);
  
  extern void DefineTSConfiguration(List *names, List *parameters);
  extern void RenameTSConfiguration(List *oldname, const char *newname);
+ extern void AlterTSConfigurationNamespace(List *name, const char *newschema);
+ extern void AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid);
  extern void RemoveTSConfigurations(DropStmt *stmt);
  extern void RemoveTSConfigurationById(Oid cfgId);
  extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
***************
*** 1645,1657 **** create view alter1.v1 as select * from alter1.t1;
--- 1645,1676 ----
  create function alter1.plus1(int) returns int as 'select $1+1' language sql;
  create domain alter1.posint integer check (value > 0);
  create type alter1.ctype as (f1 int, f2 text);
+ create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql 
+ as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
+ create operator alter1.=(procedure = alter1.same, leftarg  = alter1.ctype, rightarg = alter1.ctype);
+ create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
+   operator 1 alter1.=(alter1.ctype, alter1.ctype);
+ create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
+ create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ create text search configuration alter1.cfg(parser = alter1.prs);
+ create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize);
+ create text search dictionary alter1.dict(template = alter1.tmpl);
  insert into alter1.t1(f2) values(11);
  insert into alter1.t1(f2) values(12);
  alter table alter1.t1 set schema alter2;
  alter table alter1.v1 set schema alter2;
  alter function alter1.plus1(int) set schema alter2;
  alter domain alter1.posint set schema alter2;
+ alter operator class alter1.ctype_hash_ops using hash set schema alter2;
+ alter operator family alter1.ctype_hash_ops using hash set schema alter2;
+ alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
  alter type alter1.ctype set schema alter2;
+ alter conversion alter1.ascii_to_utf8 set schema alter2;
+ alter text search parser alter1.prs set schema alter2;
+ alter text search configuration alter1.cfg set schema alter2;
+ alter text search template alter1.tmpl set schema alter2;
+ alter text search dictionary alter1.dict set schema alter2;
  -- this should succeed because nothing is left in alter1
  drop schema alter1;
  insert into alter2.t1(f2) values(13);
***************
*** 1682,1693 **** select alter2.plus1(41);
  
  -- clean up
  drop schema alter2 cascade;
! NOTICE:  drop cascades to 5 other objects
  DETAIL:  drop cascades to table alter2.t1
  drop cascades to view alter2.v1
  drop cascades to function alter2.plus1(integer)
  drop cascades to type alter2.posint
  drop cascades to type alter2.ctype
  --
  -- composite types
  --
--- 1701,1720 ----
  
  -- clean up
  drop schema alter2 cascade;
! NOTICE:  drop cascades to 13 other objects
  DETAIL:  drop cascades to table alter2.t1
  drop cascades to view alter2.v1
  drop cascades to function alter2.plus1(integer)
  drop cascades to type alter2.posint
+ drop cascades to operator family alter2.ctype_hash_ops for access method hash
  drop cascades to type alter2.ctype
+ drop cascades to function alter2.same(alter2.ctype,alter2.ctype)
+ drop cascades to operator alter2.=(alter2.ctype,alter2.ctype)
+ drop cascades to conversion ascii_to_utf8
+ drop cascades to text search parser prs
+ drop cascades to text search configuration cfg
+ drop cascades to text search template tmpl
+ drop cascades to text search dictionary dict
  --
  -- composite types
  --
*** a/src/test/regress/sql/alter_table.sql
--- b/src/test/regress/sql/alter_table.sql
***************
*** 1206,1211 **** create domain alter1.posint integer check (value > 0);
--- 1206,1226 ----
  
  create type alter1.ctype as (f1 int, f2 text);
  
+ create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql 
+ as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
+ 
+ create operator alter1.=(procedure = alter1.same, leftarg  = alter1.ctype, rightarg = alter1.ctype);
+ 
+ create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
+   operator 1 alter1.=(alter1.ctype, alter1.ctype);
+ 
+ create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
+ 
+ create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ create text search configuration alter1.cfg(parser = alter1.prs);
+ create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize);
+ create text search dictionary alter1.dict(template = alter1.tmpl);
+ 
  insert into alter1.t1(f2) values(11);
  insert into alter1.t1(f2) values(12);
  
***************
*** 1213,1219 **** alter table alter1.t1 set schema alter2;
--- 1228,1243 ----
  alter table alter1.v1 set schema alter2;
  alter function alter1.plus1(int) set schema alter2;
  alter domain alter1.posint set schema alter2;
+ alter operator class alter1.ctype_hash_ops using hash set schema alter2;
+ alter operator family alter1.ctype_hash_ops using hash set schema alter2;
+ alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
  alter type alter1.ctype set schema alter2;
+ alter conversion alter1.ascii_to_utf8 set schema alter2;
+ alter text search parser alter1.prs set schema alter2;
+ alter text search configuration alter1.cfg set schema alter2;
+ alter text search template alter1.tmpl set schema alter2;
+ alter text search dictionary alter1.dict set schema alter2;
  
  -- this should succeed because nothing is left in alter1
  drop schema alter1;
#60Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#59)
Re: ALTER OBJECT any_name SET SCHEMA name

On Sun, Nov 21, 2010 at 4:47 PM, Dimitri Fontaine
<dimitri@2ndquadrant.fr> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Sat, Nov 20, 2010 at 11:23 PM, Robert Haas <robertmhaas@gmail.com> wrote:

Ah, nuts.  I see now there's a v7.  Never mind...

OK.  I looked at the right version, now.  Hopefully.

Yeah, that was the most recent one and I linked it in the commit fest
application. Given the very fast feedback I got, there has been a lot of
activity and patches versions produced, so that's easy to get confused.

Especially because you also posted some revs of the ALTER EXTENSION ..
SET SCHEMA patch on this thread....

It seems we have no regression tests at all for any of the existing
SET SCHEMA commands.  This seems like a good time to correct that
oversight, and also add some for the new commands you're adding here.

Yeah, it's time for me to have a look at regression tests :)

Please find attached set_schema.v8.patch with tests for the added
commands in the patch.

(It might be helpful to submit the regression tests for the existing
commands as a separate patch.) Also, you're missing psql tab
completion support, which would be nice to have.

Do you still want me to prepare another patch for adding in the tests
the "set schema" variants that already existed but are not yet covered?
Which are the one you did spot, btw?

[rhaas pgsql]$ git grep 'SET SCHEMA' src/test/regress/
[rhaas pgsql]$

Completion support for psql. Isn't that stepping on David's toes? :)
I'll see about that later if needed, maybe sometime tomorrow…

Please do. Tab completion support should really be included in the
patch - adding it as a separate patch is better than not having it, of
course.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#61Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Robert Haas (#60)
Re: ALTER OBJECT any_name SET SCHEMA name

Robert Haas <robertmhaas@gmail.com> writes:

Especially because you also posted some revs of the ALTER EXTENSION ..
SET SCHEMA patch on this thread....

Yes, I tried to answer where questions have been raised, and that's not
helping so much at review time. That's why I take the time to update the
commit fest application each time I send a new patch version.

Do you still want me to prepare another patch for adding in the tests
the "set schema" variants that already existed but are not yet covered?
Which are the one you did spot, btw?

[rhaas pgsql]$ git grep 'SET SCHEMA' src/test/regress/
[rhaas pgsql]$

The existing 'set schema' tests are in lower case, so I just did it the
same, try with git grep -i maybe :)

grep -c 'set schema' ../postgresql-extension-patches/set_schema.v8.patch
28

Please do. Tab completion support should really be included in the
patch - adding it as a separate patch is better than not having it, of
course.

Ok, will learn about this part of psql soon'ish, hopefully by today,
given a reasonable amount of other "distractions".

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#62Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Robert Haas (#60)
1 attachment(s)
Re: ALTER OBJECT any_name SET SCHEMA name

Robert Haas <robertmhaas@gmail.com> writes:

Please do. Tab completion support should really be included in the
patch - adding it as a separate patch is better than not having it, of
course.

Please find attached version 9 of the patch, which includes psql
completion support of the "SET SCHEMA" variant of already supported
ALTER commands.

That means I didn't add ALTER OPERATOR [CLASS,FAMILY] completion
support, my guess being there's no demand here, or the existing syntax
variants would be there already. And if there's demand, I don't feel
like it should be implemented as part of this very patch.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

Attachments:

set_schema.v9.patchtext/x-patchDownload
*** a/doc/src/sgml/ref/alter_conversion.sgml
--- b/doc/src/sgml/ref/alter_conversion.sgml
***************
*** 23,28 **** PostgreSQL documentation
--- 23,29 ----
  <synopsis>
  ALTER CONVERSION <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER CONVERSION <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER CONVERSION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 75,80 **** ALTER CONVERSION <replaceable>name</replaceable> OWNER TO <replaceable>new_owner
--- 76,90 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the conversion.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_opclass.sgml
--- b/doc/src/sgml/ref/alter_opclass.sgml
***************
*** 23,28 **** PostgreSQL documentation
--- 23,29 ----
  <synopsis>
  ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 85,90 **** ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="p
--- 86,100 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema for the operator class.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_operator.sgml
--- b/doc/src/sgml/ref/alter_operator.sgml
***************
*** 22,27 **** PostgreSQL documentation
--- 22,28 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } ) OWNER TO <replaceable>new_owner</replaceable>
+ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } ) SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 85,90 **** ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
--- 86,100 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the operator.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_opfamily.sgml
--- b/doc/src/sgml/ref/alter_opfamily.sgml
***************
*** 31,36 **** ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
--- 31,37 ----
    } [, ... ]
  ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 216,221 **** ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="
--- 217,231 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema for the operator family.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
  
    <para>
*** a/doc/src/sgml/ref/alter_tsconfig.sgml
--- b/doc/src/sgml/ref/alter_tsconfig.sgml
***************
*** 33,38 **** ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable>
--- 33,39 ----
      DROP MAPPING [ IF EXISTS ] FOR <replaceable class="parameter">token_type</replaceable> [, ... ]
  ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 123,128 **** ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> OWNER TO <replac
--- 124,138 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema for the text search configuration.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
  
    <para>
*** a/doc/src/sgml/ref/alter_tsdictionary.sgml
--- b/doc/src/sgml/ref/alter_tsdictionary.sgml
***************
*** 26,31 **** ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> (
--- 26,32 ----
  )
  ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
  ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 96,101 **** ALTER TEXT SEARCH DICTIONARY <replaceable>name</replaceable> OWNER TO <replaceab
--- 97,111 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the text search dictionary.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
  
    <para>
*** a/doc/src/sgml/ref/alter_tsparser.sgml
--- b/doc/src/sgml/ref/alter_tsparser.sgml
***************
*** 22,27 **** PostgreSQL documentation
--- 22,28 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER TEXT SEARCH PARSER <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
+ ALTER TEXT SEARCH PARSER <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 60,65 **** ALTER TEXT SEARCH PARSER <replaceable>name</replaceable> RENAME TO <replaceable>
--- 61,75 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the text search parser.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
   </refsect1>
  
*** a/doc/src/sgml/ref/alter_tstemplate.sgml
--- b/doc/src/sgml/ref/alter_tstemplate.sgml
***************
*** 22,27 **** PostgreSQL documentation
--- 22,28 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER TEXT SEARCH TEMPLATE <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
+ ALTER TEXT SEARCH TEMPLATE <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 60,65 **** ALTER TEXT SEARCH TEMPLATE <replaceable>name</replaceable> RENAME TO <replaceabl
--- 61,75 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">new_schema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the text search template.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
   </refsect1>
  
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 14,21 ****
--- 14,23 ----
   */
  #include "postgres.h"
  
+ #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_largeobject.h"
+ #include "catalog/pg_namespace.h"
  #include "commands/alter.h"
  #include "commands/conversioncmds.h"
  #include "commands/dbcommands.h"
***************
*** 33,38 ****
--- 35,41 ----
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
+ #include "utils/syscache.h"
  
  
  /*
***************
*** 178,188 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 181,207 ----
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_CONVERSION:
+ 			AlterConversionNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_FUNCTION:
  			AlterFunctionNamespace(stmt->object, stmt->objarg, false,
  								   stmt->newschema);
  			break;
  
+ 		case OBJECT_OPERATOR:
+ 			AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPCLASS:
+ 			AlterOpClassNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_OPFAMILY:
+ 			AlterOpFamilyNamespace(stmt->object, stmt->objarg, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_SEQUENCE:
  		case OBJECT_TABLE:
  		case OBJECT_VIEW:
***************
*** 191,196 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 210,231 ----
  								stmt->objectType, AccessExclusiveLock);
  			break;
  
+ 		case OBJECT_TSPARSER:
+ 			AlterTSParserNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSDICTIONARY:
+ 			AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSTEMPLATE:
+ 			AlterTSTemplateNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_TSCONFIGURATION:
+ 			AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		case OBJECT_TYPE:
  		case OBJECT_DOMAIN:
  			AlterTypeNamespace(stmt->object, stmt->newschema);
***************
*** 203,208 **** ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
--- 238,337 ----
  }
  
  /*
+  * Generic function to change the namespace of a given object, for simple
+  * cases (won't work for tables or functions, objects which have more than 2
+  * key-attributes to use when searching for their syscache entries --- we
+  * don't want nor need to get this generic here).
+  *
+  * The AlterFooNamespace() calls just above will call a function whose job
+  * is to lookup the arguments for the generic function here.
+  *
+  * Relation must already by open, it's the responsibility of the caller to
+  * close it.
+  */
+ void
+ AlterObjectNamespace(Relation rel, int cacheId,
+ 					 Oid classId, Oid objid, Oid nspOid,
+ 					 int Anum_name, int Anum_namespace, int Anum_owner,
+ 					 AclObjectKind acl_kind,
+ 					 bool superuser_only)
+ {
+ 	Oid			oldNspOid;
+ 	Datum       name, namespace;
+ 	bool        isnull;
+ 	HeapTuple	tup, newtup = NULL;
+ 	Datum		values[rel->rd_att->natts];
+ 	bool		nulls[rel->rd_att->natts];
+ 	bool		replaces[rel->rd_att->natts];
+ 	int			i;
+ 
+ 	tup = SearchSysCacheCopy1(cacheId, ObjectIdGetDatum(objid));
+ 	if (!HeapTupleIsValid(tup)) /* should not happen */
+ 		elog(ERROR, "cache lookup failed for object %u: %s",
+ 			 objid, getObjectDescriptionOids(classId, objid));
+ 
+ 	name = heap_getattr(tup, Anum_name, rel->rd_att, &isnull);
+ 	namespace = heap_getattr(tup, Anum_namespace, rel->rd_att, &isnull);
+ 	oldNspOid = DatumGetObjectId(namespace);
+ 
+ 	/* Check basic namespace related issues */
+ 	CheckSetNamespace(oldNspOid, nspOid, classId, objid);
+ 
+ 	/* check for duplicate name (more friendly than unique-index failure) */
+ 	if (SearchSysCacheExists2(cacheId, name, ObjectIdGetDatum(nspOid)))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("%s already exists in schema \"%s\"",
+ 						getObjectDescriptionOids(classId, objid),
+ 						get_namespace_name(nspOid))));
+ 
+ 	/* Superusers can always do it */
+ 	if (!superuser())
+ 	{
+ 		Datum       owner;
+ 		Oid			ownerId;
+ 		AclResult	aclresult;
+ 
+ 		if (superuser_only)
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 					 (errmsg("must be superuser to SET SCHEMA of %s",
+ 							 getObjectDescriptionOids(classId, objid)))));
+ 
+ 		/* Otherwise, must be owner of the existing object */
+ 		owner = heap_getattr(tup, Anum_owner, rel->rd_att, &isnull);
+ 		ownerId = DatumGetObjectId(owner);
+ 
+ 		if (!has_privs_of_role(GetUserId(), ownerId))
+ 			aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind,
+ 						   NameStr(*(DatumGetName(name))));
+ 
+ 		/* owner must have CREATE privilege on namespace */
+ 		aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(oldNspOid));
+ 	}
+ 
+ 	/* prepare a new version of the tuple using nspId */
+ 	values[Anum_namespace - 1] = nspOid;
+ 	for (i = 0; i < rel->rd_att->natts; i++)
+ 	{
+ 		nulls[i]    = i != Anum_namespace - 1;
+ 		replaces[i] = i == Anum_namespace - 1;
+ 	}
+ 
+ 	newtup = heap_modify_tuple(tup, rel->rd_att, values, nulls, replaces);
+ 	simple_heap_update(rel, &tup->t_self, newtup);
+ 	CatalogUpdateIndexes(rel, newtup);
+ 
+ 	/* update dependencies to point to the new schema */
+ 	changeDependencyFor(classId, objid,
+ 						NamespaceRelationId, oldNspOid, nspOid);
+ }
+ 
+ 
+ /*
   * Executes an ALTER OBJECT / OWNER TO statement.  Based on the object
   * type, the function appropriate to that type is executed.
   */
*** a/src/backend/commands/conversioncmds.c
--- b/src/backend/commands/conversioncmds.c
***************
*** 19,25 ****
--- 19,27 ----
  #include "catalog/indexing.h"
  #include "catalog/pg_conversion.h"
  #include "catalog/pg_conversion_fn.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/conversioncmds.h"
  #include "mb/pg_wchar.h"
  #include "miscadmin.h"
***************
*** 30,36 ****
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
! static void AlterConversionOwner_internal(Relation rel, Oid conversionOid,
  							  Oid newOwnerId);
  
  /*
--- 32,38 ----
  #include "utils/rel.h"
  #include "utils/syscache.h"
  
! static void AlterConversionOwner_internal(Relation rel, Oid convOid,
  							  Oid newOwnerId);
  
  /*
***************
*** 326,328 **** AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId)
--- 328,376 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER CONVERSION SET SCHEMA
+  */
+ void
+ AlterConversionNamespace(List *name, const char *newschema)
+ {
+ 	Oid			convOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	convOid = get_conversion_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, CONVOID, ConversionRelationId, convOid, nspOid,
+ 						 Anum_pg_conversion_conname,
+ 						 Anum_pg_conversion_connamespace,
+ 						 Anum_pg_conversion_conowner,
+ 						 ACL_KIND_CONVERSION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
+  * Change conversion schema, by oid
+  */
+ void
+ AlterConversionNamespace_oid(Oid convOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, CONVOID, ConversionRelationId, convOid, newNspOid,
+ 						 Anum_pg_conversion_conname,
+ 						 Anum_pg_conversion_connamespace,
+ 						 Anum_pg_conversion_conowner,
+ 						 ACL_KIND_CONVERSION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/functioncmds.c
--- b/src/backend/commands/functioncmds.c
***************
*** 1875,1887 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema)
  {
  	Oid			procOid;
- 	Oid			oldNspOid;
  	Oid			nspOid;
- 	HeapTuple	tup;
- 	Relation	procRel;
- 	Form_pg_proc proc;
- 
- 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
  
  	/* get function OID */
  	if (isagg)
--- 1875,1881 ----
***************
*** 1894,1899 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
--- 1888,1908 ----
  		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
  					   NameListToString(name));
  
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterFunctionNamespace_oid(procOid, nspOid);
+ }
+ 
+ void
+ AlterFunctionNamespace_oid(Oid procOid, Oid nspOid)
+ {
+ 	Oid			oldNspOid;
+ 	HeapTuple	tup;
+ 	Relation	procRel;
+ 	Form_pg_proc proc;
+ 
+ 	procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
+ 
  	tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid));
  	if (!HeapTupleIsValid(tup))
  		elog(ERROR, "cache lookup failed for function %u", procOid);
***************
*** 1901,1909 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  
  	oldNspOid = proc->pronamespace;
  
- 	/* get schema OID and check its permissions */
- 	nspOid = LookupCreationNamespace(newschema);
- 
  	/* common checks on switching namespaces */
  	CheckSetNamespace(oldNspOid, nspOid, ProcedureRelationId, procOid);
  
--- 1910,1915 ----
***************
*** 1916,1922 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						newschema)));
  
  	/* OK, modify the pg_proc row */
  
--- 1922,1928 ----
  				(errcode(ERRCODE_DUPLICATE_FUNCTION),
  				 errmsg("function \"%s\" already exists in schema \"%s\"",
  						NameStr(proc->proname),
! 						get_namespace_name(nspOid))));
  
  	/* OK, modify the pg_proc row */
  
***************
*** 1930,1936 **** AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameListToString(name));
  
  	heap_freetuple(tup);
  
--- 1936,1942 ----
  	if (changeDependencyFor(ProcedureRelationId, procOid,
  							NamespaceRelationId, oldNspOid, nspOid) != 1)
  		elog(ERROR, "failed to change schema dependency for function \"%s\"",
! 			 NameStr(proc->proname));
  
  	heap_freetuple(tup);
  
*** a/src/backend/commands/opclasscmds.c
--- b/src/backend/commands/opclasscmds.c
***************
*** 31,36 ****
--- 31,37 ----
  #include "catalog/pg_opfamily.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "parser/parse_func.h"
***************
*** 1989,1994 **** AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
--- 1990,2057 ----
  }
  
  /*
+  * ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpClassNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup, origtup;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	/* Look up the opclass. */
+ 	origtup = OpClassCacheLookup(amOid, name, false);
+ 	tup = heap_copytuple(origtup);
+ 	ReleaseSysCache(origtup);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, CLAOID, OperatorClassRelationId,
+ 						 HeapTupleGetOid(tup), nspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPCLASS,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(CLAOID, ObjectIdGetDatum(opclassOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
+ 
+ 	AlterObjectNamespace(rel, CLAOID, OperatorClassRelationId,
+ 						 HeapTupleGetOid(tup), newNspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPCLASS,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
   * Change opfamily owner by name
   */
  void
***************
*** 2144,2146 **** get_am_oid(const char *amname, bool missing_ok)
--- 2207,2303 ----
  				 errmsg("access method \"%s\" does not exist", amname)));
  	return oid;
  }
+ 
+ /*
+  * ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+  */
+ void
+ AlterOpFamilyNamespace(List *name, List *argam, const char *newschema)
+ {
+ 	Oid			amOid;
+ 	char       *access_method = linitial(argam);
+ 	Relation	rel;
+ 	HeapTuple	tup;
+ 	char	   *opfname, *schemaname;
+ 	Oid			nspOid;
+ 
+ 	Assert(list_length(argam) == 1);
+ 	amOid = get_am_oid(access_method, false);
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	/*
+ 	 * Look up the opfamily
+ 	 */
+ 	DeconstructQualifiedName(name, &schemaname, &opfname);
+ 
+ 	if (schemaname)
+ 	{
+ 		Oid			namespaceOid;
+ 
+ 		namespaceOid = LookupExplicitNamespace(schemaname);
+ 
+ 		tup = SearchSysCacheCopy3(OPFAMILYAMNAMENSP,
+ 								  ObjectIdGetDatum(amOid),
+ 								  PointerGetDatum(opfname),
+ 								  ObjectIdGetDatum(namespaceOid));
+ 		if (!HeapTupleIsValid(tup))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 	}
+ 	else
+ 	{
+ 		Oid			opfOid;
+ 
+ 		opfOid = OpfamilynameGetOpfid(amOid, opfname);
+ 		if (!OidIsValid(opfOid))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 					 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ 							opfname, access_method)));
+ 
+ 		tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfOid));
+ 		if (!HeapTupleIsValid(tup))		/* should not happen */
+ 			elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
+ 	}
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, OPFAMILYOID, OperatorFamilyRelationId,
+ 						 HeapTupleGetOid(tup), nspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPFAMILY,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
+ 
+ 	AlterObjectNamespace(rel, OPFAMILYOID, OperatorFamilyRelationId,
+ 						 opfamilyOid, newNspOid,
+ 						 Anum_pg_opfamily_opfname,
+ 						 Anum_pg_opfamily_opfnamespace,
+ 						 Anum_pg_opfamily_opfowner,
+ 						 ACL_KIND_OPFAMILY,
+ 						 false);
+ 
+ 	heap_freetuple(tup);
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/operatorcmds.c
--- b/src/backend/commands/operatorcmds.c
***************
*** 39,45 ****
--- 39,47 ----
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_operator.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "parser/parse_func.h"
***************
*** 452,454 **** AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
--- 454,505 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Execute ALTER OPERATOR SET SCHEMA
+  */
+ void
+ AlterOperatorNamespace(List *names, List *argtypes, const char *newschema)
+ {
+ 	List	   *operatorName = names;
+ 	TypeName   *typeName1 = (TypeName *) linitial(argtypes);
+ 	TypeName   *typeName2 = (TypeName *) lsecond(argtypes);
+ 	Oid			operOid, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	Assert(list_length(argtypes) == 2);
+ 	operOid = LookupOperNameTypeNames(NULL, operatorName,
+ 									  typeName1, typeName2,
+ 									  false, -1);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, OPEROID, OperatorRelationId, operOid, nspOid,
+ 						 Anum_pg_operator_oprname,
+ 						 Anum_pg_operator_oprnamespace,
+ 						 Anum_pg_operator_oprowner,
+ 						 ACL_KIND_OPER,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, OPEROID, OperatorRelationId, operOid, newNspOid,
+ 						 Anum_pg_operator_oprname,
+ 						 Anum_pg_operator_oprnamespace,
+ 						 Anum_pg_operator_oprowner,
+ 						 ACL_KIND_OPER,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
*** a/src/backend/commands/tsearchcmds.c
--- b/src/backend/commands/tsearchcmds.c
***************
*** 32,37 ****
--- 32,38 ----
  #include "catalog/pg_ts_parser.h"
  #include "catalog/pg_ts_template.h"
  #include "catalog/pg_type.h"
+ #include "commands/alter.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "nodes/makefuncs.h"
***************
*** 397,402 **** RenameTSParser(List *oldname, const char *newname)
--- 398,442 ----
  	heap_freetuple(tup);
  }
  
+ /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSParserNamespace(List *name, const char *newschema)
+ {
+ 	Oid			prsId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	prsId = get_ts_parser_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSPARSEROID, TSParserRelationId, prsId, nspOid,
+ 						 Anum_pg_ts_parser_prsname,
+ 						 Anum_pg_ts_parser_prsnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSParserRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSPARSEROID, TSParserRelationId, prsId, newNspOid,
+ 						 Anum_pg_ts_parser_prsname,
+ 						 Anum_pg_ts_parser_prsnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
  /* ---------------------- TS Dictionary commands -----------------------*/
  
  /*
***************
*** 628,633 **** RenameTSDictionary(List *oldname, const char *newname)
--- 668,716 ----
  }
  
  /*
+  * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
+  */
+ void
+ AlterTSDictionaryNamespace(List *name, const char *newschema)
+ {
+ 	Oid			dictId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	dictId = get_ts_dict_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSDICTOID, TSDictionaryRelationId, dictId, nspOid,
+ 						 Anum_pg_ts_dict_dictname,
+ 						 Anum_pg_ts_dict_dictnamespace,
+ 						 Anum_pg_ts_dict_dictowner,
+ 						 ACL_KIND_TSDICTIONARY,
+ 						 true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSDICTOID, TSDictionaryRelationId, dictId, newNspOid,
+ 						 Anum_pg_ts_dict_dictname,
+ 						 Anum_pg_ts_dict_dictnamespace,
+ 						 Anum_pg_ts_dict_dictowner,
+ 						 ACL_KIND_TSDICTIONARY,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ /*
   * DROP TEXT SEARCH DICTIONARY
   */
  void
***************
*** 1111,1116 **** RenameTSTemplate(List *oldname, const char *newname)
--- 1194,1241 ----
  }
  
  /*
+  * ALTER TEXT SEARCH TEMPLATE any_name SET SCHEMA name
+  */
+ void
+ AlterTSTemplateNamespace(List *name, const char *newschema)
+ {
+ 	Oid			tmplId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	tmplId = get_ts_template_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSTEMPLATEOID, TSTemplateRelationId,
+ 						 tmplId, nspOid,
+ 						 Anum_pg_ts_template_tmplname,
+ 						 Anum_pg_ts_template_tmplnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSTEMPLATEOID, TSTemplateRelationId,
+ 						 tmplId, newNspOid,
+ 						 Anum_pg_ts_template_tmplname,
+ 						 Anum_pg_ts_template_tmplnamespace,
+ 						 -1, -1, true);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH TEMPLATE
   */
  void
***************
*** 1512,1517 **** RenameTSConfiguration(List *oldname, const char *newname)
--- 1637,1686 ----
  }
  
  /*
+  * ALTER TEXT SEARCH CONFIGURATION any_name SET SCHEMA name
+  */
+ void
+ AlterTSConfigurationNamespace(List *name, const char *newschema)
+ {
+ 	Oid			cfgId, nspOid;
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	cfgId = get_ts_config_oid(name, false);
+ 
+ 	/* get schema OID */
+ 	nspOid = LookupCreationNamespace(newschema);
+ 
+ 	AlterObjectNamespace(rel, TSCONFIGOID, TSConfigRelationId, cfgId, nspOid,
+ 						 Anum_pg_ts_config_cfgname,
+ 						 Anum_pg_ts_config_cfgnamespace,
+ 						 Anum_pg_ts_config_cfgowner,
+ 						 ACL_KIND_TSCONFIGURATION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ void
+ AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid)
+ {
+ 	Relation	rel;
+ 
+ 	rel = heap_open(TSConfigRelationId, RowExclusiveLock);
+ 
+ 	AlterObjectNamespace(rel, TSCONFIGOID, TSConfigRelationId, cfgId, newNspOid,
+ 						 Anum_pg_ts_config_cfgname,
+ 						 Anum_pg_ts_config_cfgnamespace,
+ 						 Anum_pg_ts_config_cfgowner,
+ 						 ACL_KIND_TSCONFIGURATION,
+ 						 false);
+ 
+ 	heap_close(rel, NoLock);
+ }
+ 
+ 
+ /*
   * DROP TEXT SEARCH CONFIGURATION
   */
  void
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 6051,6056 **** AlterObjectSchemaStmt:
--- 6051,6064 ----
  					n->newschema = $7;
  					$$ = (Node *)n;
  				}
+ 			| ALTER CONVERSION_P any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_CONVERSION;
+ 					n->object = $3;
+ 					n->newschema = $6;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER DOMAIN_P any_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6068,6073 **** AlterObjectSchemaStmt:
--- 6076,6108 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER OPERATOR any_operator oper_argtypes SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPERATOR;
+ 					n->object = $3;
+ 					n->objarg = $4;
+ 					n->newschema = $7;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPCLASS;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_OPFAMILY;
+ 					n->object = $4;
+ 					n->objarg = list_make1($6);
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER TABLE relation_expr SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
***************
*** 6076,6081 **** AlterObjectSchemaStmt:
--- 6111,6148 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSPARSER;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSDICTIONARY;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSTEMPLATE;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
+ 			| ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TSCONFIGURATION;
+ 					n->object = $5;
+ 					n->newschema = $8;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER SEQUENCE qualified_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 1694,1702 **** CreateCommandTag(Node *parsetree)
--- 1694,1714 ----
  				case OBJECT_AGGREGATE:
  					tag = "ALTER AGGREGATE";
  					break;
+ 				case OBJECT_CONVERSION:
+ 					tag = "ALTER CONVERSION";
+ 					break;
  				case OBJECT_DOMAIN:
  					tag = "ALTER DOMAIN";
  					break;
+ 				case OBJECT_OPERATOR:
+ 					tag = "ALTER OPERATOR";
+ 					break;
+ 				case OBJECT_OPCLASS:
+ 					tag = "ALTER OPERATOR CLASS";
+ 					break;
+ 				case OBJECT_OPFAMILY:
+ 					tag = "ALTER OPERATOR FAMILY";
+ 					break;
  				case OBJECT_FUNCTION:
  					tag = "ALTER FUNCTION";
  					break;
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
***************
*** 741,750 **** psql_completion(char *text, int start, int end)
  		}
  	}
  
! 	/* ALTER CONVERSION,SCHEMA <name> */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
! 			 (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 ||
! 			  pg_strcasecmp(prev2_wd, "SCHEMA") == 0))
  	{
  		static const char *const list_ALTERGEN[] =
  		{"OWNER TO", "RENAME TO", NULL};
--- 741,749 ----
  		}
  	}
  
! 	/* ALTER SCHEMA <name> */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
! 			  pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
  	{
  		static const char *const list_ALTERGEN[] =
  		{"OWNER TO", "RENAME TO", NULL};
***************
*** 752,757 **** psql_completion(char *text, int start, int end)
--- 751,766 ----
  		COMPLETE_WITH_LIST(list_ALTERGEN);
  	}
  
+ 	/* ALTER CONVERSION <name> */
+ 	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ 			 pg_strcasecmp(prev2_wd, "CONVERSION") == 0)
+ 	{
+ 		static const char *const list_ALTERGEN[] =
+ 		{"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
+ 
+ 		COMPLETE_WITH_LIST(list_ALTERGEN);
+ 	}
+ 
  	/* ALTER DATABASE <name> */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
***************
*** 1237,1253 **** psql_completion(char *text, int start, int end)
  			 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
  			 (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
  			  pg_strcasecmp(prev2_wd, "PARSER") == 0))
! 		COMPLETE_WITH_CONST("RENAME TO");
  
  	else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
  			 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
  			 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
  	{
! 		static const char *const list_ALTERTEXTSEARCH2[] =
! 		{"OWNER TO", "RENAME TO", NULL};
  
! 		COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
  	}
  
  	else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
--- 1246,1267 ----
  			 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
  			 (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 ||
  			  pg_strcasecmp(prev2_wd, "PARSER") == 0))
! 	{
! 		static const char *const list_ALTERTEXTSEARCH2[] =
! 		{"RENAME TO", "SET SCHEMA", NULL};
! 
! 		COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2);
! 	}
  
  	else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
  			 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
  			 pg_strcasecmp(prev2_wd, "DICTIONARY") == 0)
  	{
! 		static const char *const list_ALTERTEXTSEARCH3[] =
! 		{"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
  
! 		COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
  	}
  
  	else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
***************
*** 1255,1264 **** psql_completion(char *text, int start, int end)
  			 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
  			 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
  	{
! 		static const char *const list_ALTERTEXTSEARCH3[] =
! 		{"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", NULL};
  
! 		COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3);
  	}
  
  	/* complete ALTER TYPE <foo> with actions */
--- 1269,1278 ----
  			 pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
  			 pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0)
  	{
! 		static const char *const list_ALTERTEXTSEARCH4[] =
! 		{"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
  
! 		COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4);
  	}
  
  	/* complete ALTER TYPE <foo> with actions */
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
***************
*** 167,172 **** extern ObjectClass getObjectClass(const ObjectAddress *object);
--- 167,174 ----
  extern char *getObjectDescription(const ObjectAddress *object);
  extern char *getObjectDescriptionOids(Oid classid, Oid objid);
  
+ extern char *getObjectDescriptionOids(Oid classid, Oid objid);
+ 
  extern ObjectAddresses *new_object_addresses(void);
  
  extern void add_exact_object_address(const ObjectAddress *object,
*** a/src/include/commands/alter.h
--- b/src/include/commands/alter.h
***************
*** 15,23 ****
--- 15,30 ----
  #define ALTER_H
  
  #include "nodes/parsenodes.h"
+ #include "utils/acl.h"
+ #include "utils/relcache.h"
  
  extern void ExecRenameStmt(RenameStmt *stmt);
  extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt);
+ extern void AlterObjectNamespace(Relation rel, int cacheId,
+ 								 Oid classId, Oid objid, Oid nspId,
+ 								 int Anum_name, int Anum_namespace, int Anum_owner,
+ 								 AclObjectKind acl_kind,
+ 								 bool superuser_only);
  extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt);
  
  #endif   /* ALTER_H */
*** a/src/include/commands/conversioncmds.h
--- b/src/include/commands/conversioncmds.h
***************
*** 22,26 **** extern void DropConversionsCommand(DropStmt *drop);
--- 22,29 ----
  extern void RenameConversion(List *name, const char *newname);
  extern void AlterConversionOwner(List *name, Oid newOwnerId);
  extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId);
+ extern void AlterConversionNamespace(List *name, const char *newschema);
+ extern void AlterConversionNamespace_oid(Oid convOid, Oid newNspOid);
+ 
  
  #endif   /* CONVERSIONCMDS_H */
*** a/src/include/commands/defrem.h
--- b/src/include/commands/defrem.h
***************
*** 66,71 **** extern void DropCast(DropCastStmt *stmt);
--- 66,72 ----
  extern void DropCastById(Oid castOid);
  extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
  					   const char *newschema);
+ extern void AlterFunctionNamespace_oid(Oid procOid, Oid nspOid);
  extern void ExecuteDoStmt(DoStmt *stmt);
  extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok);
  
***************
*** 78,83 **** extern void AlterOperatorOwner(List *name, TypeName *typeName1,
--- 79,86 ----
  extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId);
  extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok);
  extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok);
+ extern void AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid);
+ extern void AlterOperatorNamespace(List *names, List *argtypes, const char *newschema);
  
  /* commands/aggregatecmds.c */
  extern void DefineAggregate(List *name, List *args, bool oldstyle,
***************
*** 100,114 **** extern void RenameOpClass(List *name, const char *access_method, const char *new
--- 103,123 ----
  extern void RenameOpFamily(List *name, const char *access_method, const char *newname);
  extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId);
+ extern void AlterOpClassNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid);
  extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
  extern void AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId);
  extern Oid get_am_oid(const char *amname, bool missing_ok);
+ extern void AlterOpFamilyNamespace(List *name, List *argam, const char *newschema);
+ extern void AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid);
  
  /* commands/tsearchcmds.c */
  extern void DefineTSParser(List *names, List *parameters);
  extern void RenameTSParser(List *oldname, const char *newname);
  extern void RemoveTSParsers(DropStmt *drop);
  extern void RemoveTSParserById(Oid prsId);
+ extern void AlterTSParserNamespace(List *name, const char *newschema);
+ extern void AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid);
  
  extern void DefineTSDictionary(List *names, List *parameters);
  extern void RenameTSDictionary(List *oldname, const char *newname);
***************
*** 116,129 **** extern void RemoveTSDictionaries(DropStmt *drop);
--- 125,144 ----
  extern void RemoveTSDictionaryById(Oid dictId);
  extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt);
  extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId);
+ extern void AlterTSDictionaryNamespace(List *name, const char *newschema);
+ extern void AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid);
  
  extern void DefineTSTemplate(List *names, List *parameters);
  extern void RenameTSTemplate(List *oldname, const char *newname);
+ extern void AlterTSTemplateNamespace(List *name, const char *newschema);
+ extern void AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid);
  extern void RemoveTSTemplates(DropStmt *stmt);
  extern void RemoveTSTemplateById(Oid tmplId);
  
  extern void DefineTSConfiguration(List *names, List *parameters);
  extern void RenameTSConfiguration(List *oldname, const char *newname);
+ extern void AlterTSConfigurationNamespace(List *name, const char *newschema);
+ extern void AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid);
  extern void RemoveTSConfigurations(DropStmt *stmt);
  extern void RemoveTSConfigurationById(Oid cfgId);
  extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt);
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
***************
*** 1645,1657 **** create view alter1.v1 as select * from alter1.t1;
--- 1645,1676 ----
  create function alter1.plus1(int) returns int as 'select $1+1' language sql;
  create domain alter1.posint integer check (value > 0);
  create type alter1.ctype as (f1 int, f2 text);
+ create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql 
+ as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
+ create operator alter1.=(procedure = alter1.same, leftarg  = alter1.ctype, rightarg = alter1.ctype);
+ create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
+   operator 1 alter1.=(alter1.ctype, alter1.ctype);
+ create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
+ create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ create text search configuration alter1.cfg(parser = alter1.prs);
+ create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize);
+ create text search dictionary alter1.dict(template = alter1.tmpl);
  insert into alter1.t1(f2) values(11);
  insert into alter1.t1(f2) values(12);
  alter table alter1.t1 set schema alter2;
  alter table alter1.v1 set schema alter2;
  alter function alter1.plus1(int) set schema alter2;
  alter domain alter1.posint set schema alter2;
+ alter operator class alter1.ctype_hash_ops using hash set schema alter2;
+ alter operator family alter1.ctype_hash_ops using hash set schema alter2;
+ alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
  alter type alter1.ctype set schema alter2;
+ alter conversion alter1.ascii_to_utf8 set schema alter2;
+ alter text search parser alter1.prs set schema alter2;
+ alter text search configuration alter1.cfg set schema alter2;
+ alter text search template alter1.tmpl set schema alter2;
+ alter text search dictionary alter1.dict set schema alter2;
  -- this should succeed because nothing is left in alter1
  drop schema alter1;
  insert into alter2.t1(f2) values(13);
***************
*** 1682,1693 **** select alter2.plus1(41);
  
  -- clean up
  drop schema alter2 cascade;
! NOTICE:  drop cascades to 5 other objects
  DETAIL:  drop cascades to table alter2.t1
  drop cascades to view alter2.v1
  drop cascades to function alter2.plus1(integer)
  drop cascades to type alter2.posint
  drop cascades to type alter2.ctype
  --
  -- composite types
  --
--- 1701,1720 ----
  
  -- clean up
  drop schema alter2 cascade;
! NOTICE:  drop cascades to 13 other objects
  DETAIL:  drop cascades to table alter2.t1
  drop cascades to view alter2.v1
  drop cascades to function alter2.plus1(integer)
  drop cascades to type alter2.posint
+ drop cascades to operator family alter2.ctype_hash_ops for access method hash
  drop cascades to type alter2.ctype
+ drop cascades to function alter2.same(alter2.ctype,alter2.ctype)
+ drop cascades to operator alter2.=(alter2.ctype,alter2.ctype)
+ drop cascades to conversion ascii_to_utf8
+ drop cascades to text search parser prs
+ drop cascades to text search configuration cfg
+ drop cascades to text search template tmpl
+ drop cascades to text search dictionary dict
  --
  -- composite types
  --
*** a/src/test/regress/sql/alter_table.sql
--- b/src/test/regress/sql/alter_table.sql
***************
*** 1206,1211 **** create domain alter1.posint integer check (value > 0);
--- 1206,1226 ----
  
  create type alter1.ctype as (f1 int, f2 text);
  
+ create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql 
+ as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2';
+ 
+ create operator alter1.=(procedure = alter1.same, leftarg  = alter1.ctype, rightarg = alter1.ctype);
+ 
+ create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as
+   operator 1 alter1.=(alter1.ctype, alter1.ctype);
+ 
+ create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8;
+ 
+ create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype);
+ create text search configuration alter1.cfg(parser = alter1.prs);
+ create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize);
+ create text search dictionary alter1.dict(template = alter1.tmpl);
+ 
  insert into alter1.t1(f2) values(11);
  insert into alter1.t1(f2) values(12);
  
***************
*** 1213,1219 **** alter table alter1.t1 set schema alter2;
--- 1228,1243 ----
  alter table alter1.v1 set schema alter2;
  alter function alter1.plus1(int) set schema alter2;
  alter domain alter1.posint set schema alter2;
+ alter operator class alter1.ctype_hash_ops using hash set schema alter2;
+ alter operator family alter1.ctype_hash_ops using hash set schema alter2;
+ alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2;
+ alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2;
  alter type alter1.ctype set schema alter2;
+ alter conversion alter1.ascii_to_utf8 set schema alter2;
+ alter text search parser alter1.prs set schema alter2;
+ alter text search configuration alter1.cfg set schema alter2;
+ alter text search template alter1.tmpl set schema alter2;
+ alter text search dictionary alter1.dict set schema alter2;
  
  -- this should succeed because nothing is left in alter1
  drop schema alter1;
#63Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#62)
Re: ALTER OBJECT any_name SET SCHEMA name

On Thu, Nov 25, 2010 at 5:00 PM, Dimitri Fontaine
<dimitri@2ndquadrant.fr> wrote:

Robert Haas <robertmhaas@gmail.com> writes:

Please do.  Tab completion support should really be included in the
patch - adding it as a separate patch is better than not having it, of
course.

Please find attached version 9 of the patch, which includes psql
completion support of the "SET SCHEMA" variant of already supported
ALTER commands.

That means I didn't add ALTER OPERATOR [CLASS,FAMILY] completion
support, my guess being there's no demand here, or the existing syntax
variants would be there already. And if there's demand, I don't feel
like it should be implemented as part of this very patch.

Committed, after various changes and corrections. One noteworthy one
is that I removed the _oid variants, since those would be dead code at
the moment.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#64Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Robert Haas (#63)
Re: ALTER OBJECT any_name SET SCHEMA name

Robert Haas <robertmhaas@gmail.com> writes:

Committed, after various changes and corrections. One noteworthy one
is that I removed the _oid variants, since those would be dead code at
the moment.

Thanks!

The _oid variants will have to re-appear in the "alter extension set
schema" patch, which is the last of the series. Meanwhile, I will have
to merge head with the current extension patch (already overdue for a
new version, waiting on purpose) so that it no longer includes the
cfparser and execute from file patches too (which have changed a lot
underneath it already).

I'm not sure there's lots of precedent for dealing with in-commitfest
patches dependencies, so here's a summary of what I think would ideally
happen next (ordering counts):

1. cfparser
https://commitfest.postgresql.org/action/patch_view?id=413
ready for commiter

2. pg_execute_from_file
https://commitfest.postgresql.org/action/patch_view?id=414
needs another review and maybe some more documentation

3. extensions
https://commitfest.postgresql.org/action/patch_view?id=404
needs review and minor updating
will need another version after merging the two previous patches

4. alter extension set schema
https://commitfest.postgresql.org/action/patch_view?id=416
needs review and a reviewer
will need bitrot fix (and adding in the _oid variants)
would be better to adjust once the 3 previous are in

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

#65Robert Haas
robertmhaas@gmail.com
In reply to: Dimitri Fontaine (#64)
Re: ALTER OBJECT any_name SET SCHEMA name

On Sat, Nov 27, 2010 at 2:17 PM, Dimitri Fontaine
<dimitri@2ndquadrant.fr> wrote:

Thanks!

The _oid variants will have to re-appear in the "alter extension set
schema" patch, which is the last of the series. Meanwhile, I will have
to merge head with the current extension patch (already overdue for a
new version, waiting on purpose) so that it no longer includes the
cfparser and execute from file patches too (which have changed a lot
underneath it already).

I expected as much, but at least at that point it will be possible to
test that code.

I'm not sure there's lots of precedent for dealing with in-commitfest
patches dependencies, so here's a summary of what I think would ideally
happen next (ordering counts):

 1. cfparser
   https://commitfest.postgresql.org/action/patch_view?id=413
   ready for commiter

 2. pg_execute_from_file
   https://commitfest.postgresql.org/action/patch_view?id=414
   needs another review and maybe some more documentation

 3. extensions
   https://commitfest.postgresql.org/action/patch_view?id=404
   needs review and minor updating
   will need another version after merging the two previous patches

 4. alter extension set schema
   https://commitfest.postgresql.org/action/patch_view?id=416
   needs review and a reviewer
   will need bitrot fix (and adding in the _oid variants)
   would be better to adjust once the 3 previous are in

Thanks, that's very helpful.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company