Index: doc/src/sgml/ref/alter_conversion.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/alter_conversion.sgml,v
retrieving revision 1.7
diff -c -r1.7 alter_conversion.sgml
*** doc/src/sgml/ref/alter_conversion.sgml	13 Oct 2005 22:44:51 -0000	1.7
--- doc/src/sgml/ref/alter_conversion.sgml	1 Jun 2006 21:54:14 -0000
***************
*** 22,27 ****
--- 22,28 ----
  <synopsis>
  ALTER CONVERSION <replaceable>name</replaceable> RENAME TO <replaceable>newname</replaceable>
  ALTER CONVERSION <replaceable>name</replaceable> OWNER TO <replaceable>newowner</replaceable>
+ ALTER CONVERSION <replaceable>name</replaceable> SET SCHEMA <replaceable>newschema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 74,79 ****
--- 75,89 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">newschema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the conversion.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </refsect1>
  
***************
*** 95,100 ****
--- 105,118 ----
  ALTER CONVERSION iso_8859_1_to_utf8 OWNER TO joe;
  </programlisting>
    </para>
+ 
+   <para>
+    To move the conversion <literal>iso_8859_1_to_utf8</literal> to
+    another schema:
+ <programlisting>
+ ALTER CONVERSION iso_8859_1_to_utf8 SET SCHEMA customers;
+ </programlisting>
+   </para>
   </refsect1>
  
   <refsect1>
Index: doc/src/sgml/ref/alter_opclass.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/alter_opclass.sgml,v
retrieving revision 1.6
diff -c -r1.6 alter_opclass.sgml
*** doc/src/sgml/ref/alter_opclass.sgml	13 Oct 2005 22:44:51 -0000	1.6
--- doc/src/sgml/ref/alter_opclass.sgml	1 Jun 2006 21:54:15 -0000
***************
*** 22,27 ****
--- 22,28 ----
  <synopsis>
  ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> RENAME TO <replaceable>newname</replaceable>
  ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> OWNER TO <replaceable>newowner</replaceable>
+ ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> SET SCHEMA <replaceable>newschema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 84,93 ****
--- 85,114 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">newschema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the operator class.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
   </refsect1>
  
   <refsect1>
+   <title>Examples</title>
+ 
+   <para>
+    Change the schema of a custom operator class <literal>custom_op</literal> for index method <literal>btree</literal>:
+ <programlisting>
+ ALTER OPERATOR CLASS custom_op USING btree SET SCHEMA customers;
+ </programlisting>
+   </para>
+  </refsect1>
+ 
+  <refsect1>
    <title>Compatibility</title>
  
    <para>
Index: doc/src/sgml/ref/alter_operator.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/alter_operator.sgml,v
retrieving revision 1.2
diff -c -r1.2 alter_operator.sgml
*** doc/src/sgml/ref/alter_operator.sgml	13 Oct 2005 22:44:51 -0000	1.2
--- doc/src/sgml/ref/alter_operator.sgml	1 Jun 2006 21:54:15 -0000
***************
*** 21,26 ****
--- 21,27 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>lefttype</replaceable> | NONE } , { <replaceable>righttype</replaceable> | NONE } ) OWNER TO <replaceable>newowner</replaceable>
+ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>lefttype</replaceable> | NONE } , { <replaceable>righttype</replaceable> | NONE } ) SET SCHEMA <replaceable>newschema</replaceable>
  </synopsis>
   </refsynopsisdiv>
    
***************
*** 29,36 ****
  
    <para>
     <command>ALTER OPERATOR</command> changes the definition of
!    an operator.  The only currently available functionality is to change the
!    owner of the operator.
    </para>
  
    <para>
--- 30,37 ----
  
    <para>
     <command>ALTER OPERATOR</command> changes the definition of
!    an operator. Currently you can change the owner and the schema of an
!    existing operator only.
    </para>
  
    <para>
***************
*** 84,89 ****
--- 85,99 ----
       </para>
      </listitem>
     </varlistentry>
+ 
+    <varlistentry>
+     <term><replaceable class="parameter">newschema</replaceable></term>
+     <listitem>
+      <para>
+       The new schema of the operator.
+      </para>
+     </listitem>
+    </varlistentry>
    </variablelist>
   </refsect1>
  
***************
*** 96,101 ****
--- 106,118 ----
  ALTER OPERATOR @@ (text, text) OWNER TO joe;
  </programlisting>
    </para>
+ 
+   <para>
+    Change the schema of a custom operator <literal>a @@ b</literal> for type <type>text</type>:
+ <programlisting>
+ ALTER OPERATOR @@ (text, text) SET SCHEMA customers;
+ </programlisting>
+   </para>
   </refsect1>
   
   <refsect1>
Index: src/backend/commands/alter.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/alter.c,v
retrieving revision 1.19
diff -c -r1.19 alter.c
*** src/backend/commands/alter.c	15 Apr 2006 17:45:34 -0000	1.19
--- src/backend/commands/alter.c	1 Jun 2006 21:54:17 -0000
***************
*** 170,175 ****
--- 170,188 ----
  			AlterTypeNamespace(stmt->object, stmt->newschema);
  			break;
  
+ 		case OBJECT_OPERATOR:
+ 			AlterOperatorNamespace(stmt->object, stmt->objarg, 
+ 								   stmt->newschema);
+ 			break;
+         case OBJECT_OPCLASS:
+ 			AlterOperatorClassNamespace(stmt->object, stmt->objarg,
+ 										stmt->newschema);
+ 			break;
+ 
+ 		case OBJECT_CONVERSION:
+ 			AlterConversionNamespace(stmt->object, stmt->newschema);
+ 			break;
+ 
  		default:
  			elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
  				 (int) stmt->objectType);
Index: src/backend/commands/conversioncmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/conversioncmds.c,v
retrieving revision 1.27
diff -c -r1.27 conversioncmds.c
*** src/backend/commands/conversioncmds.c	5 Mar 2006 15:58:23 -0000	1.27
--- src/backend/commands/conversioncmds.c	1 Jun 2006 21:54:20 -0000
***************
*** 20,25 ****
--- 20,26 ----
  #include "catalog/dependency.h"
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_type.h"
  #include "mb/pg_wchar.h"
  #include "commands/conversioncmds.h"
***************
*** 290,292 ****
--- 291,428 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Do the work for ALTER CONVERSION SET SCHEMA
+  */
+ static void
+ AlterConversionNamespace_internal(Relation convRel, Oid convOid, 
+ 								  const char *newnspname)
+ {
+ 
+ 	HeapTuple tup;
+ 	Form_pg_conversion convForm;
+ 	Oid oldNspOid;
+ 	Oid newNspOid;
+ 
+ 	Assert((convRel != NULL)
+ 		   && (convOid != InvalidOid)
+ 		   && PointerIsValid(newnspname));
+ 
+ 	tup = SearchSysCacheCopy(CONOID,
+ 							 ObjectIdGetDatum(convOid),
+ 							 0, 0, 0);
+ 
+ 	if (!HeapTupleIsValid(tup))
+ 	{
+ 		elog(ERROR, "cache lookup failed for conversion %u", convOid);
+ 	}
+ 
+ 	convForm = (Form_pg_conversion) GETSTRUCT(tup);
+ 
+ 	/*
+ 	 * Get OID of current namespace and look wether the
+ 	 * requested conversion already lives in newNspOid
+ 	 */
+ 	newNspOid = LookupCreationNamespace(newnspname);
+ 	oldNspOid = convForm->connamespace;
+ 
+ 	Assert((newNspOid != InvalidOid)
+ 		   && (oldNspOid != InvalidOid));
+ 
+ 	/* 
+ 	 * disallow renaming into or out of temp schemas
+ 	 */
+ 	if (isAnyTempNamespace(newNspOid) || isAnyTempNamespace(oldNspOid))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of temporary schemas")));	
+ 
+ 	/*
+ 	 * Be careful with TOAST schemas as well...
+ 	 */
+ 	if (newNspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of TOAST schema")));	
+ 
+ 	if (oldNspOid == newNspOid)
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("conversion %s is already in schema \"%s\"",
+ 						NameStr(convForm->conname),
+ 						newnspname)));
+ 	}	
+ 
+ 	/*
+ 	 * Do a lookup of newnspname if a conversion with the
+ 	 * given name already exists there. This looks much better
+ 	 * than an ugly duplicate index violation.
+ 	 */
+ 	if (SearchSysCacheExists(CONNAMENSP,
+ 							 CStringGetDatum(NameStr(convForm->conname)),
+ 							 CStringGetDatum(newnspname), 0, 0)) 
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("conversion %s is already in schema \"%s\"",
+ 						NameStr(convForm->conname),
+ 						newnspname)));
+ 	}
+ 
+ 	/*
+ 	 * All seems okay, do the stuff. It's okay to scribble
+ 	 * on convForm since it is copied before.
+ 	 */	
+ 	convForm->connamespace = newNspOid;
+ 
+ 	simple_heap_update(convRel, &tup->t_self, tup);
+ 
+ 	if (changeDependencyFor(ConversionRelationId, convOid,
+ 							NamespaceRelationId, oldNspOid, newNspOid) != 1)
+ 		elog(ERROR, "failed to change schema dependency for conversion %s",
+ 			 NameStr(convForm->conname));
+ 
+ 	CatalogUpdateIndexes(convRel, tup);	
+ 	heap_freetuple(tup);
+ 
+ }
+ 
+ /*
+  * Executes ALTER CONVERSION SET SCHEMA
+  */
+ void AlterConversionNamespace(List *convname, const char *newnspname)
+ {
+ 
+ 	Oid convOid;
+ 	Relation convRel;
+ 
+ 	Assert(convname != NIL);
+ 	
+ 	convRel = heap_open(ConversionRelationId, RowExclusiveLock);
+ 
+ 	/*
+ 	 * Get OID of given conversion object
+ 	 */
+ 	convOid = FindConversionByName(convname);
+ 
+ 	if (convOid == InvalidOid)
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 				 errmsg("conversion \"%s\" does not exist",
+ 						NameListToString(convname))));		
+ 	}
+ 
+ 	/*
+ 	 * Check if we own the specified conversion
+ 	 */   
+ 	if (!pg_conversion_ownercheck(convOid, GetUserId()))
+ 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
+ 					   NameListToString(convname));	
+ 
+ 	AlterConversionNamespace_internal(convRel, convOid, newnspname);
+ 
+ 	heap_close(convRel, RowExclusiveLock);
+ }
Index: src/backend/commands/opclasscmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/opclasscmds.c,v
retrieving revision 1.45
diff -c -r1.45 opclasscmds.c
*** src/backend/commands/opclasscmds.c	2 May 2006 22:25:10 -0000	1.45
--- src/backend/commands/opclasscmds.c	1 Jun 2006 21:54:28 -0000
***************
*** 60,65 ****
--- 60,68 ----
  static void storeProcedures(Oid opclassoid, List *procedures);
  static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple,
  						   Oid newOwnerId);
+ static void
+ AlterOperatorClassNamespace_internal(Relation opClassRel, Oid opClassOid, 
+ 									 const char *newnspname);
  
  
  /*
***************
*** 1053,1055 ****
--- 1056,1222 ----
  								newOwnerId);
  	}
  }
+ 
+ static void
+ AlterOperatorClassNamespace_internal(Relation opClassRel, Oid opClassOid, 
+ 									 const char *newnspname)
+ {
+ 
+ 	Oid             newNspOid = InvalidOid;
+ 	Oid             oldNspOid = InvalidOid;
+ 	HeapTuple       tup;
+ 	HeapTuple       newtup;
+ 	Form_pg_opclass oprClassForm;
+ 	Datum           values[Natts_pg_opclass];
+ 	char            nulls[Natts_pg_opclass];
+ 	char            replaces[Natts_pg_opclass];
+ 
+ 	Assert((opClassOid != InvalidOid)
+ 		   && (PointerIsValid(newnspname)));
+ 
+ 	tup = SearchSysCache(CLAOID,
+ 						 ObjectIdGetDatum(opClassOid),
+ 						 0, 0, 0);
+ 
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for operator class %u", opClassOid);
+ 
+ 	oprClassForm = (Form_pg_opclass) GETSTRUCT(tup);
+ 	oldNspOid    = oprClassForm->opcnamespace;
+ 	newNspOid    = LookupCreationNamespace(newnspname);
+ 	
+ 	/* 
+ 	 * disallow renaming into or out of temp schemas
+ 	 */
+ 	if (isAnyTempNamespace(newNspOid) || isAnyTempNamespace(oldNspOid))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of temporary schemas")));
+ 
+ 	/*
+ 	 * Be careful with TOAST schemas as well...
+ 	 */
+ 	if (newNspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of TOAST schema")));	
+ 
+ 	/*
+ 	 * Checkout if we already live in newnspschema
+ 	 */
+ 	if (oldNspOid == newNspOid)
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("operator %s is already in schema \"%s\"",
+ 						NameStr(oprClassForm->opcname),
+ 						newnspname)));
+ 	}	
+ 
+ 	/*
+ 	 * Now look if there is already the same operator class in
+ 	 * newnspschema.
+ 	 * This is much cleaner than a duplicate index violation...
+ 	 */
+ 	if (SearchSysCacheExists(CLAAMNAMENSP,
+ 							 ObjectIdGetDatum(oprClassForm->opcamid),
+ 							 PointerGetDatum(NameStr(oprClassForm->opcname)),
+ 							 ObjectIdGetDatum(newNspOid),
+ 							 0))
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("operator class %s is already in schema \"%s\"",
+ 						NameStr(oprClassForm->opcname),
+ 						get_namespace_name(newNspOid))));		
+ 	}
+ 
+ 	/*
+ 	 * Seems like everything is ok, so create a new tuple, set
+ 	 * the new namespace and do the update then.
+ 	 */
+ 
+ 	MemSet(values, (Datum) 0, sizeof(values));
+ 	MemSet(nulls, ' ', sizeof(nulls));
+ 	MemSet(replaces, ' ', sizeof(replaces));
+ 
+ 	values[Anum_pg_opclass_opcnamespace - 1] = newNspOid;
+ 	replaces[Anum_pg_opclass_opcnamespace - 1] = 'r';
+ 
+ 	newtup = heap_modifytuple(tup, RelationGetDescr(opClassRel),
+ 							  values, nulls, replaces);
+ 	simple_heap_update(opClassRel, &tup->t_self, newtup);
+ 	CatalogUpdateIndexes(opClassRel, newtup);
+ 
+ 	if (changeDependencyFor(OperatorClassRelationId, opClassOid,
+ 							NamespaceRelationId, oldNspOid, newNspOid) != 1)
+ 		elog(ERROR, "failed to change schema dependency for operator class %s",
+ 			 NameStr(oprClassForm->opcname));
+ 
+ 	/* Clean up */
+ 	ReleaseSysCache(tup);
+ 	heap_freetuple(newtup);
+ 	
+ }
+ 
+ void
+ AlterOperatorClassNamespace(List *opclass,
+ 							List *opclass_am,
+ 							const char *newschema)
+ {
+ 	Oid opClassOid = InvalidOid;
+ 	Oid amOid      = InvalidOid;
+ 	Oid newNspOid  = InvalidOid;
+ 	Name access_method;
+ 	Name opcname;
+ 	Relation opClassRel;
+ 
+ 	Assert( (opclass != NIL)
+ 			&& (opclass_am != NIL)
+ 			&& (PointerIsValid(newschema)) );
+ 
+ 	opClassRel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ 
+ 	/*
+ 	 * We need to get the access_method OID first to lookup
+ 	 * for the opclass OID
+ 	 */
+ 	opcname       = linitial(opclass);
+ 	access_method = linitial(opclass_am);
+ 	
+ 	amOid = GetSysCacheOid(AMNAME,
+ 						   CStringGetDatum(NameListToString(opclass_am)),
+ 						   0, 0, 0);
+ 	newNspOid = LookupCreationNamespace(newschema);
+ 
+ 	/*
+ 	 * Let's get the operator class OID
+ 	 */
+ 	opClassOid = OpclassnameGetOpcid(amOid, NameListToString(opclass));
+ 
+ 	/*
+ 	 * Check if we own this operator class
+ 	 */
+ 	if (!pg_opclass_ownercheck(opClassOid, GetUserId()))
+ 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
+ 					   NameListToString(opclass));
+ 
+ 	if (newNspOid == InvalidOid)
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_SCHEMA),
+ 				 errmsg("schema \"%s\" does not exist",
+ 						newschema)));
+ 	}
+ 
+ 	/*
+ 	 * Do the work...
+ 	 */
+ 	AlterOperatorClassNamespace_internal(opClassRel, opClassOid, newschema);
+ 
+ 	/*
+ 	 * Finish stuff...
+ 	 */
+ 	heap_close(opClassRel, RowExclusiveLock);
+ 	
+ }
Index: src/backend/commands/operatorcmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/operatorcmds.c,v
retrieving revision 1.30
diff -c -r1.30 operatorcmds.c
*** src/backend/commands/operatorcmds.c	15 Apr 2006 17:45:34 -0000	1.30
--- src/backend/commands/operatorcmds.c	1 Jun 2006 21:54:30 -0000
***************
*** 38,53 ****
  #include "catalog/dependency.h"
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_operator.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "parser/parse_oper.h"
  #include "parser/parse_type.h"
  #include "utils/acl.h"
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
  
! 
  static void AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId);
  
  /*
--- 38,56 ----
  #include "catalog/dependency.h"
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
+ #include "catalog/pg_namespace.h"
  #include "catalog/pg_operator.h"
  #include "commands/defrem.h"
  #include "miscadmin.h"
  #include "parser/parse_oper.h"
  #include "parser/parse_type.h"
  #include "utils/acl.h"
+ #include "utils/builtins.h"
  #include "utils/lsyscache.h"
  #include "utils/syscache.h"
  
! static void AlterOperatorNamespace_internal(Relation oprRel, Oid oprOid, 
! 											const char *newnsp);
  static void AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId);
  
  /*
***************
*** 355,357 ****
--- 358,518 ----
  
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Do the stuff for ALTER OPERATOR SET SCHEMA.
+  * 
+  * The caller is assumed to hold proper locks and performed
+  * any owner checks of the given operator.
+  */
+ static void
+ AlterOperatorNamespace_internal(Relation oprRel, Oid oprOid, const char *newnsp)
+ {
+ 
+ 	Oid oldNspOid  = InvalidOid;
+ 	Oid newNspOid  = InvalidOid;
+ 	Form_pg_operator oprForm;
+ 	char		     nulls[Natts_pg_operator];
+ 	char		     replaces[Natts_pg_operator];
+ 	Datum		     values[Natts_pg_operator];
+ 	HeapTuple        tup;
+ 	HeapTuple        newtup;
+ 
+ 	Assert(oprOid != InvalidOid);
+ 
+ 	/*
+ 	 * Lookup operator
+ 	 */
+ 
+ 	tup = SearchSysCache(OPEROID,
+ 						 ObjectIdGetDatum(oprOid), 0, 0, 0);
+ 
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for operator %u", oprOid);
+ 
+ 	oprForm = (Form_pg_operator) GETSTRUCT(tup);
+ 
+ 	/* 
+ 	 * disallow renaming into or out of temp schemas
+ 	 */
+ 	if (isAnyTempNamespace(newNspOid) || isAnyTempNamespace(oldNspOid))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of temporary schemas")));
+ 	
+ 	/*
+ 	 * Be careful with TOAST schemas as well...
+ 	 */
+ 	if (newNspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot move objects into or out of TOAST schema")));
+ 
+ 	/*
+ 	 * Get OID of current namespace and look wether the
+ 	 * requested operator already lives in newNspOid
+ 	 */
+ 	newNspOid = LookupCreationNamespace(newnsp);
+ 	oldNspOid = oprForm->oprnamespace;	
+ 
+ 	if (oldNspOid == newNspOid)
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("operator %s is already in schema \"%s\"",
+ 						format_operator(oprOid),
+ 						get_namespace_name(newNspOid))));
+ 	}
+ 
+ 	/*
+ 	 * Look if the same operator already lives in
+ 	 * the new namespace.
+ 	 */
+ 	if (SearchSysCacheExists(OPERNAMENSP,
+ 							 PointerGetDatum(NameStr(oprForm->oprname)),
+ 							 ObjectIdGetDatum(oprForm->oprleft),
+ 							 ObjectIdGetDatum(oprForm->oprright),
+ 							 ObjectIdGetDatum(newNspOid)))
+ 	{
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DUPLICATE_OBJECT),
+ 				 errmsg("operator %s is already in schema \"%s\"",
+ 						format_operator(oprOid),
+ 						get_namespace_name(newNspOid))));
+ 	}
+ 
+ 	/* Setup new tuple */
+ 	MemSet(values, (Datum) 0, sizeof(values));
+ 	MemSet(nulls, ' ', sizeof(nulls));
+ 	MemSet(replaces, ' ', sizeof(replaces));
+ 	
+ 	values[Anum_pg_operator_oprnamespace - 1]   = newNspOid;
+ 	replaces[Anum_pg_operator_oprnamespace - 1] = 'r';
+ 
+ 	newtup = heap_modifytuple(tup, RelationGetDescr(oprRel),
+ 							  values, nulls, replaces);
+ 							  
+ 
+ 	simple_heap_update(oprRel, &tup->t_self, newtup);
+ 
+ 	/* adjust dependencies on schema */
+ 	if (changeDependencyFor(OperatorRelationId, oprOid, 
+ 							NamespaceRelationId, oldNspOid, newNspOid) != 1)
+ 		elog(ERROR, "failed to change schema dependency for operator \"%s\"",
+ 			 format_operator(oprOid));
+ 
+ 	/* update system indexes */
+ 	CatalogUpdateIndexes(oprRel, newtup);
+ 
+ 	/* clean up */
+ 	ReleaseSysCache(tup);
+ 	//heap_freetuple(tup);
+ 	heap_freetuple(newtup);
+ 
+ }
+ 
+ /*
+  * Executes ALTER OPERATOR SET SCHEMA
+  */
+ void AlterOperatorNamespace(List *operator, List *oprtypes, char *newschema)
+ {
+ 
+ 	Oid oprOid = InvalidOid;
+ 	TypeName *typeName1 = (TypeName *) linitial(oprtypes);
+ 	TypeName *typeName2 = (TypeName *) lsecond(oprtypes);
+ 	Relation oprRel;
+ 
+ 	Assert(PointerIsValid(newschema));
+ 
+ 	oprRel = heap_open(OperatorRelationId, RowExclusiveLock);
+ 	oprOid = LookupOperNameTypeNames(NULL, operator,
+ 									 typeName1, typeName2,
+ 									 false, -1);
+ 	if (oprOid == InvalidOid) {
+ 
+ 		/*
+ 		 * Shouldn't happen...
+ 		 */
+ 		elog(ERROR, "cache lookup failed for operator %u", oprOid);
+ 
+ 	}
+ 
+ 	/*
+ 	 * Check if we own this operator class
+ 	 */
+ 	if (!pg_oper_ownercheck(oprOid, GetUserId()))
+ 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
+ 					   NameListToString(operator));
+ 
+ 	/*
+ 	 * Finally do the work...
+ 	 */
+ 	AlterOperatorNamespace_internal(oprRel, oprOid, newschema);
+ 
+ 	/*
+ 	 * Finish
+ 	 */
+ 
+ 	heap_close(oprRel, RowExclusiveLock);
+ 
+ }
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.545
diff -c -r2.545 gram.y
*** src/backend/parser/gram.y	27 May 2006 17:38:45 -0000	2.545
--- src/backend/parser/gram.y	1 Jun 2006 21:55:13 -0000
***************
*** 4256,4261 ****
--- 4256,4288 ----
  					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 = $5;
+ 					n->newschema = $9;
+ 					$$ = (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(makeString($6));
+ 					n->newschema = $9;
+ 					$$ = (Node *)n;					
+ 				}
+             | ALTER CONVERSION_P any_name SET SCHEMA name
+                 {
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_CONVERSION;
+ 					n->object = $3;
+ 					n->objarg = NIL;
+ 					n->newschema = $6;
+ 					$$ = (Node *)n;					
+ 				}
  		;
  
  /*****************************************************************************
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.257
diff -c -r1.257 utility.c
*** src/backend/tcop/utility.c	30 Apr 2006 18:30:40 -0000	1.257
--- src/backend/tcop/utility.c	1 Jun 2006 21:55:20 -0000
***************
*** 1457,1462 ****
--- 1457,1471 ----
  				case OBJECT_TYPE:
  					tag = "ALTER TYPE";
  					break;
+ 				case OBJECT_OPERATOR:
+ 					tag = "ALTER OPERATOR";
+ 					break;
+ 				case OBJECT_OPCLASS:
+ 					tag = "ALTER OPERATOR CLASS";
+ 					break;
+ 				case OBJECT_CONVERSION:
+ 					tag = "ALTER CONVERSION";
+ 					break;
  				default:
  					tag = "???";
  					break;
Index: src/include/commands/conversioncmds.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/conversioncmds.h,v
retrieving revision 1.14
diff -c -r1.14 conversioncmds.h
*** src/include/commands/conversioncmds.h	5 Mar 2006 15:58:55 -0000	1.14
--- src/include/commands/conversioncmds.h	1 Jun 2006 21:55:22 -0000
***************
*** 23,27 ****
--- 23,28 ----
  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 *convname, const char *newnspname);
  
  #endif   /* CONVERSIONCMDS_H */
Index: src/include/commands/defrem.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/defrem.h,v
retrieving revision 1.72
diff -c -r1.72 defrem.h
*** src/include/commands/defrem.h	15 Apr 2006 17:45:41 -0000	1.72
--- src/include/commands/defrem.h	1 Jun 2006 21:55:23 -0000
***************
*** 67,72 ****
--- 67,75 ----
  extern void AlterOperatorOwner(List *name, TypeName *typeName1,
  				   TypeName *typename2, Oid newOwnerId);
  extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId);
+ extern void AlterOperatorNamespace(List *operator, 
+ 								   List *oprtypes, 
+ 								   char *newschema);
  
  /* commands/aggregatecmds.c */
  extern void DefineAggregate(List *name, List *args, bool oldstyle,
***************
*** 82,87 ****
--- 85,93 ----
  extern void RenameOpClass(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 opcOid, Oid newOwnerId);
+ extern void AlterOperatorClassNamespace(List *opclass,
+ 										List *opclass_am,
+ 										const char *newschema);
  
  /* support routines in commands/define.c */
  
Index: src/test/regress/expected/alter_table.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/alter_table.out,v
retrieving revision 1.94
diff -c -r1.94 alter_table.out
*** src/test/regress/expected/alter_table.out	23 Mar 2006 00:19:30 -0000	1.94
--- src/test/regress/expected/alter_table.out	1 Jun 2006 21:55:33 -0000
***************
*** 1347,1352 ****
--- 1347,1356 ----
  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 conversion alter1.myconv for 'LATIN1' to 'UTF8' from iso8859_1_to_utf8;
+ create default conversion alter1.myconv_def for 'LATIN1' to 'UTF8' from iso8859_1_to_utf8;
+ create function alter1.incrementor(int) returns int as 'select $1 + 1' language sql;
+ create operator @+ (PROCEDURE=alter1.incrementor, RIGHTARG=int);
  insert into alter1.t1(f2) values(11);
  insert into alter1.t1(f2) values(12);
  alter table alter1.t1 set schema alter2;
***************
*** 1354,1361 ****
--- 1358,1374 ----
  alter function alter1.plus1(int) set schema alter2;
  alter domain alter1.posint set schema alter2;
  alter type alter1.ctype set schema alter2;
+ alter conversion myconv set schema alter2;
+ ERROR:  conversion "myconv" does not exist
+ alter operator @+ (NONE, int) set schema alter2;
  -- this should succeed because nothing is left in alter1
  drop schema alter1;
+ NOTICE:  function alter1.incrementor(integer) depends on schema alter1
+ NOTICE:  operator alter2.@+(NONE,integer) depends on function alter1.incrementor(integer)
+ NOTICE:  conversion myconv_def depends on schema alter1
+ NOTICE:  conversion myconv depends on schema alter1
+ ERROR:  cannot drop schema alter1 because other objects depend on it
+ HINT:  Use DROP ... CASCADE to drop the dependent objects too.
  insert into alter2.t1(f2) values(13);
  insert into alter2.t1(f2) values(14);
  select * from alter2.t1;
***************
*** 1384,1389 ****
--- 1397,1403 ----
  
  -- clean up
  drop schema alter2 cascade;
+ NOTICE:  drop cascades to operator alter2.@+(NONE,integer)
  NOTICE:  drop cascades to composite type alter2.ctype
  NOTICE:  drop cascades to type alter2.ctype
  NOTICE:  drop cascades to type alter2.posint
Index: src/test/regress/sql/alter_table.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/alter_table.sql,v
retrieving revision 1.54
diff -c -r1.54 alter_table.sql
*** src/test/regress/sql/alter_table.sql	12 Feb 2006 19:11:01 -0000	1.54
--- src/test/regress/sql/alter_table.sql	1 Jun 2006 21:55:40 -0000
***************
*** 1016,1021 ****
--- 1016,1027 ----
  
  create type alter1.ctype as (f1 int, f2 text);
  
+ create conversion alter1.myconv for 'LATIN1' to 'UTF8' from iso8859_1_to_utf8;
+ create default conversion alter1.myconv_def for 'LATIN1' to 'UTF8' from iso8859_1_to_utf8;
+ 
+ create function alter1.incrementor(int) returns int as 'select $1 + 1' language sql;
+ create operator @+ (PROCEDURE=alter1.incrementor, RIGHTARG=int);
+ 
  insert into alter1.t1(f2) values(11);
  insert into alter1.t1(f2) values(12);
  
***************
*** 1024,1029 ****
--- 1030,1037 ----
  alter function alter1.plus1(int) set schema alter2;
  alter domain alter1.posint set schema alter2;
  alter type alter1.ctype set schema alter2;
+ alter conversion myconv set schema alter2;
+ alter operator @+ (NONE, int) set schema alter2;
  
  -- this should succeed because nothing is left in alter1
  drop schema alter1;
