Here is an updated version of your patch.  Would you supply SGML
documentation updates to match the code changes?  Thanks.

---------------------------------------------------------------------------

Bernd Helmle wrote:
> Here's my current patch for ALTER OBJECT SET SCHEMA: the attached patch 
> file implements
> schema "move" for FUNCTION, SEQUENCE, TYPE, DOMAIN and TABLE with all 
> improvements discussed on -hackers recently. Altering OPERATOR, OPERATOR 
> CLASS, AGGREGATE and CONVERSION are currently not implemented (since i ran 
> out of time) :(
> 
> Supported syntax is
> 
> ALTER TABLE name SET SCHEMA name;
> ALTER SEQUENCE name SET SCHEMA name;
> ALTER FUNCTION name SET SCHEMA name;
> ALTER TYPE name SET SCHEMA name;
> ALTER DOMAIN name SET SCHEMA name;
> 
> TIA
> 
> -- 
>   Bernd

[ Attachment, skipping... ]

> 
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
> 
>                http://www.postgresql.org/docs/faq

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: src/backend/catalog/pg_depend.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/pg_depend.c,v
retrieving revision 1.13
diff -c -c -r1.13 pg_depend.c
*** src/backend/catalog/pg_depend.c     14 Apr 2005 20:03:23 -0000      1.13
--- src/backend/catalog/pg_depend.c     29 Jul 2005 03:11:17 -0000
***************
*** 211,213 ****
--- 211,273 ----
  
        return ret;
  }
+ 
+ bool
+ changeDependencyFor(Oid classId, Oid objectId, Oid oldrefobjectId,
+                                       Oid newrefobjectId)
+ {
+       ScanKeyData key[2];
+       SysScanDesc scan;
+       HeapTuple       tup;
+       Relation        depRel;
+       bool            result = false; /* nothing changed */
+ 
+       Assert(OidIsValid(classId) && OidIsValid(objectId) &&
+                  OidIsValid(oldrefobjectId) && OidIsValid(newrefobjectId));
+ 
+       depRel = heap_open(DependRelationId, RowExclusiveLock);
+ 
+       ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, 
F_OIDEQ,
+                               ObjectIdGetDatum(classId));
+       ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, 
F_OIDEQ,
+                               ObjectIdGetDatum(objectId));
+ 
+       scan = systable_beginscan(depRel, DependDependerIndexId, true,
+                                 SnapshotNow, 2, key);
+ 
+       while (HeapTupleIsValid((tup = systable_getnext(scan))))
+       {
+               Form_pg_depend depend_class = (Form_pg_depend) GETSTRUCT(tup);
+       
+               if (depend_class->refobjid == oldrefobjectId)
+               {
+                       ObjectAddress objAddr;
+               
+                       objAddr.classId = classId;
+                       objAddr.objectId = oldrefobjectId;
+                       objAddr.objectSubId = 0;
+               
+                       if (isObjectPinned(&objAddr, depRel))
+                               elog(ERROR, "attempt to change dependency on a 
system object!");
+               
+                       tup = heap_copytuple(tup);
+                       depend_class = (Form_pg_depend) GETSTRUCT(tup);
+               
+                       depend_class->refobjid = newrefobjectId;
+                       simple_heap_update(depRel, &tup->t_self, tup);
+                       CatalogUpdateIndexes(depRel, tup);
+               
+                       /*
+                        * Assume that the specified object/classId couldn't 
reference the
+                        * changed object twice, so exit the loop immediately.
+                        */
+                       result = true;
+                       break;
+               }
+       }
+ 
+       systable_endscan(scan);
+       heap_close(depRel, RowExclusiveLock);
+ 
+       return result;
+ }
Index: src/backend/commands/alter.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/alter.c,v
retrieving revision 1.13
diff -c -c -r1.13 alter.c
*** src/backend/commands/alter.c        28 Jun 2005 05:08:53 -0000      1.13
--- src/backend/commands/alter.c        29 Jul 2005 03:11:17 -0000
***************
*** 38,43 ****
--- 38,75 ----
  
  
  /*
+  * Executes an ALTER OBJECT / SET SCHEMA statement
+  */
+ void
+ ExecRenameObjSchemaStmt(RenameObjSchemaStmt *stmt)
+ {
+       Oid relid;
+     
+       switch (stmt->renameType)
+       {
+               case OBJECT_TYPE:
+               case OBJECT_DOMAIN:
+                       AlterDomainNamespace(stmt->object, stmt->newname);
+                       break;
+                   
+               case OBJECT_FUNCTION:
+                       AlterFunctionNamespace(stmt->object, stmt->objarg, 
stmt->newname);
+                       break;
+                   
+               case OBJECT_SEQUENCE:
+               case OBJECT_TABLE:
+                       CheckRelationOwnership(stmt->relation, true);
+                       relid = RangeVarGetRelid(stmt->relation, false);
+                       AlterTableNamespace(relid, stmt->newname);
+                       break;
+                   
+               default:
+                       elog(ERROR, "unrecognized rename schema stmt type: %d",
+                                (int) stmt->renameType);
+       }
+ }
+ 
+ /*
   * Executes an ALTER OBJECT / RENAME TO statement.    Based on the object
   * type, the function appropriate to that type is executed.
   */
Index: src/backend/commands/functioncmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v
retrieving revision 1.64
diff -c -c -r1.64 functioncmds.c
*** src/backend/commands/functioncmds.c 14 Jul 2005 21:46:29 -0000      1.64
--- src/backend/commands/functioncmds.c 29 Jul 2005 03:11:18 -0000
***************
*** 1427,1429 ****
--- 1427,1493 ----
        systable_endscan(scan);
        heap_close(relation, RowExclusiveLock);
  }
+ 
+ void
+ AlterFunctionNamespace(List *name, List *argtypes, const char *newnpname)
+ {
+       Oid                     procOid;
+       Oid                     oldnpOid;
+       Oid                     newnpOid;
+       HeapTuple               tup;
+       HeapTuple               nptup;
+       Relation                rel;
+       Form_pg_proc            proc;
+       AclResult               aclrc;
+     
+       Assert(newnpname != NULL && name != NIL);
+     
+       rel = heap_open(ProcedureRelationId, RowExclusiveLock);
+       procOid = LookupFuncNameTypeNames(name, argtypes, false);
+     
+       tup = SearchSysCacheCopy(PROCOID, ObjectIdGetDatum(procOid), 0, 0, 0);
+     
+       if (!HeapTupleIsValid(tup))
+               elog(ERROR, "cache lookup failed for function %u", procOid);
+     
+       nptup = SearchSysCacheCopy(NAMESPACENAME, CStringGetDatum(newnpname),
+                               0, 0, 0);
+       if (!HeapTupleIsValid(nptup))
+               ereport(ERROR,
+                        (errcode(ERRCODE_UNDEFINED_SCHEMA),
+                         errmsg("schema \"%s\" doesn't exists", newnpname)));
+     
+       newnpOid = HeapTupleGetOid(nptup);
+       if ((aclrc = pg_namespace_aclcheck(newnpOid, GetUserId(), ACL_CREATE))
+                       != ACLCHECK_OK)
+               aclcheck_error(aclrc, ACL_KIND_NAMESPACE, newnpname);
+     
+       proc = (Form_pg_proc) GETSTRUCT(tup);
+       oldnpOid = proc->pronamespace;
+     
+       if ((aclrc = pg_namespace_aclcheck(oldnpOid, GetUserId(), ACL_CREATE))
+                       != ACLCHECK_OK)
+               aclcheck_error(aclrc, ACL_KIND_NAMESPACE, 
get_namespace_name(oldnpOid));
+     
+       if (!pg_proc_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, 
NameListToString(name));
+     
+       if (SearchSysCacheExists(PROCNAMEARGSNSP,
+               CStringGetDatum(NameStr(proc->proname)),
+               PointerGetDatum(&proc->proargtypes), 
ObjectIdGetDatum(newnpOid), 0))
+               ereport(ERROR,
+                        (errcode(ERRCODE_DUPLICATE_FUNCTION),
+                         errmsg("function \"%s\" already exists in schema 
\"%s\"", 
+                                NameStr(proc->proname), 
get_namespace_name(newnpOid))));
+     
+       proc->pronamespace = newnpOid;
+       simple_heap_update(rel, &tup->t_self, tup);
+     
+       CatalogUpdateIndexes(rel, tup);
+     
+       if (changeDependencyFor(ProcedureRelationId, procOid, oldnpOid, 
newnpOid))
+               elog(NOTICE, "changed dependency to new schema \"%s\"", 
newnpname);
+     
+       heap_freetuple(tup);    
+       heap_close(rel, RowExclusiveLock);
+ }
Index: src/backend/commands/tablecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v
retrieving revision 1.164
diff -c -c -r1.164 tablecmds.c
*** src/backend/commands/tablecmds.c    14 Jul 2005 21:46:29 -0000      1.164
--- src/backend/commands/tablecmds.c    29 Jul 2005 03:11:22 -0000
***************
*** 15,20 ****
--- 15,21 ----
  #include "postgres.h"
  
  #include "access/genam.h"
+ #include "access/heapam.h"
  #include "access/tuptoaster.h"
  #include "catalog/catalog.h"
  #include "catalog/dependency.h"
***************
*** 22,27 ****
--- 23,29 ----
  #include "catalog/index.h"
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
+ #include "catalog/pg_attrdef.h"
  #include "catalog/pg_constraint.h"
  #include "catalog/pg_depend.h"
  #include "catalog/pg_inherits.h"
***************
*** 6198,6200 ****
--- 6200,6639 ----
                }
        }
  }
+ 
+ /*
+  * Rebuilds the default expression on a SERIAL column, identified
+  * by relid and attnum. The caller has to make sure, that attnum is really
+  * a SERIAL column, no further checks are done by 
+  * RebuildSequenceDefaultExpr().
+  */
+ static void
+ RebuildSequenceDefaultExpr(Oid relid, AttrNumber attnum, char *seqname,
+                                                       char *nspname)
+ {
+       ScanKeyData keys[2];
+       SysScanDesc scan;
+       HeapTuple       tup;
+       bool            isnull;
+       Datum           value;
+       text            *adbin;
+       Expr            *expr;
+       char *quoted_name = palloc(strlen(nspname) + strlen(seqname) + 2 /* dot 
*/);
+       /*
+        * Open the table we need to check for default expressions. Please
+        * note that we don't need to acquire a lock here, since we assume any
+        * interface function (such as AlterTableNamespace()) have locked the
+        * relation already.
+        */
+       Relation table_relation = heap_open(relid, NoLock);
+       Relation attr_default_rel = heap_open(AttrDefaultRelationId, 
RowExclusiveLock);
+ 
+       TupleDesc attrDesc = table_relation->rd_att;
+ 
+       MemSet(quoted_name, 0, strlen(nspname) + strlen(seqname) + 2);
+       strncpy(quoted_name, nspname, strlen(nspname));
+       strncat(quoted_name, ".", 1);
+       strncat(quoted_name, seqname, strlen(seqname));
+ 
+       /*
+        * Check that there is really a default expressions. Since we assume we 
are
+        * called from AlterSeqNamespacesForRel() there *must* be a default
+        * expression that calls nextval()...
+        */
+       if (!attrDesc->constr && attrDesc->constr->num_defval > 0)
+               elog(ERROR, "expected column defaults, but table %u has none 
defined",
+                         relid);
+ 
+       ScanKeyInit(&keys[0], Anum_pg_attrdef_adrelid, BTEqualStrategyNumber, 
F_OIDEQ,
+                               ObjectIdGetDatum(relid));
+       ScanKeyInit(&keys[1], Anum_pg_attrdef_adnum, BTEqualStrategyNumber, 
F_INT2EQ,
+                               Int16GetDatum(attnum));
+ 
+       scan = systable_beginscan(attr_default_rel, AttrDefaultIndexId, true,
+                                                          SnapshotNow, 2, 
keys);
+       if (!HeapTupleIsValid(tup = systable_getnext(scan)))
+               elog(ERROR, "could not found pg_attrdef attribute for column 
%d",
+                         attnum + 1);
+ 
+       isnull = false;
+       value = heap_getattr(tup, Anum_pg_attrdef_adbin,
+                                                
RelationGetDescr(attr_default_rel), &isnull);
+       if (isnull)
+               elog(ERROR, "null value in adbin default expression for column 
%d",
+                         attnum + 1);
+ 
+       adbin = DatumGetTextP(value);
+ 
+       /* Get executable expression node */
+ 
+       expr = stringToNode(VARDATA(adbin));
+ 
+       if IsA(expr, FuncExpr)
+       {
+               FuncExpr                *func;
+               Const                   *cval;
+               Expr                    *arg_expr;
+ 
+               func = (FuncExpr *) expr;
+               arg_expr = linitial(func->args);
+               if IsA(arg_expr, FuncExpr)
+               {
+                       Expr            *const_expr;
+                       Datum           values[ Natts_pg_attrdef ];
+                       char            replaces[ Natts_pg_attrdef ];
+                       char            nulls[4] = { ' ', ' ', ' ', ' ' };
+                       char            *func_expr_str;
+                       char            *adsrc;
+                       HeapTuple       newtup;
+ 
+                       func = (FuncExpr *)arg_expr;
+                       const_expr = linitial(func->args);
+ 
+                       if IsA(const_expr, Const)
+                       {
+                               /* modify argument to nextval() */
+                               func->args = list_delete_first(func->args);
+                               cval = makeNode(Const);
+                               cval->consttype = ((Const 
*)const_expr)->consttype;
+                               cval->constlen  = ((Const 
*)const_expr)->constlen;
+                               cval->constisnull = ((Const 
*)const_expr)->constisnull;
+                               cval->constbyval  = ((Const 
*)const_expr)->constbyval;
+                               cval->constvalue = 
PointerGetDatum(DirectFunctionCall1(textin,
+                                                                               
                   CStringGetDatum(quoted_name)));
+                               func->args = lappend(func->args, cval);
+ 
+                               /* update expressions in pg_attrdef */
+                               func_expr_str = nodeToString(expr); 
+                               values[ Anum_pg_attrdef_adbin - 1 ] = 
DirectFunctionCall1(textin,
+                                                                               
                   CStringGetDatum(func_expr_str));
+                               adsrc = deparse_expression((Node *)expr, 
deparse_context_for(
+                                                                       
RelationGetRelationName(table_relation), relid),
+                                                                       false, 
false);
+                               values[ Anum_pg_attrdef_adsrc - 1 ] = 
DirectFunctionCall1(textin,
+                                                                               
                                   CStringGetDatum(adsrc));
+                               MemSet(replaces, ' ', sizeof(replaces));
+                               replaces[ Anum_pg_attrdef_adbin - 1 ] = 'r';
+                               replaces[ Anum_pg_attrdef_adsrc - 1 ] = 'r';
+                               newtup = heap_modifytuple(tup, 
attr_default_rel->rd_att,
+                                                                               
   values, nulls, replaces);
+                               simple_heap_update(attr_default_rel, 
&newtup->t_self, newtup);
+                               CatalogUpdateIndexes(attr_default_rel, newtup);
+                       }
+               }
+       }
+ 
+       systable_endscan(scan);
+       heap_close(table_relation, NoLock);
+       heap_close(attr_default_rel, RowExclusiveLock);
+ }
+ 
+ /*
+  * Moves all sequences, based on a SERIAL column type of the
+  * specified relation to a new schema. Please note that we only move
+  * sequences to the new schema, that have tracked dependencies in
+  * pg_depend, because only those could be created via a SERIAL
+  * column type.
+  */
+ static void
+ AlterSeqNamespacesForTable (Oid relOid,
+                                Oid newnspOid)
+ {
+       Relation                dependRel;
+       Relation                classRel;
+       HeapTuple               depTup;
+       ScanKeyData             key[2];
+       SysScanDesc             scan;
+ 
+       Assert(OidIsValid(relOid) && OidIsValid(newnspOid));
+ 
+       /* Open pg_depend and grab a row share lock. */
+       dependRel = heap_open(DependRelationId, RowShareLock);
+ 
+       ScanKeyInit(&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, 
F_OIDEQ,
+                               ObjectIdGetDatum(RelationRelationId));
+ 
+       ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, 
F_OIDEQ,
+                               ObjectIdGetDatum(relOid));
+ 
+       scan = systable_beginscan(dependRel, DependReferenceIndexId, true,
+                                                               SnapshotNow, 2, 
key);
+ 
+       classRel = heap_open(RelationRelationId, RowExclusiveLock);
+ 
+       while (HeapTupleIsValid((depTup = systable_getnext(scan))))
+       {
+               /*
+                * The dependent object is examined wether it is a attached 
sequence
+                * or not. If true, we need to pull out the pg_class tuple of
+                * the dependent sequence and modify the relnamespace to reflect
+                * the new table schema.
+                */
+               Form_pg_depend          dependent = (Form_pg_depend) 
GETSTRUCT(depTup);
+               Form_pg_class           myclass;
+               HeapTuple                       seqTup;
+ 
+               seqTup = SearchSysCacheCopy(RELOID, 
ObjectIdGetDatum(dependent->objid),
+                                                                       0, 0, 
0);
+               if (!HeapTupleIsValid(seqTup))
+                       /*
+                        *      Don't stop on a cache lookup failure, since this
+                        *      only means that the dependent object is _not_ 
in pg_class
+                        */
+                       continue;
+ 
+               myclass = (Form_pg_class) GETSTRUCT(seqTup);
+ 
+               if (myclass->relkind == RELKIND_SEQUENCE)
+               {
+                       TypeName                *seqName;
+                       Relation                seqRel;
+                       char                    *nspname = 
get_namespace_name(newnspOid);
+ 
+                       myclass->relnamespace = newnspOid;
+ 
+                       elog(DEBUG1, "moving sequence OID %u to new schema OID 
%u",
+                                HeapTupleGetOid(seqTup), newnspOid);
+ 
+                       simple_heap_update(classRel, &seqTup->t_self, seqTup);
+                       CatalogUpdateIndexes(classRel, seqTup);
+ 
+                       /*
+                        * Sequences have entries in pg_type. We need to be 
careful
+                        * to move them to the new namespace, too.
+                        */
+                       seqName = makeNode(TypeName);
+                       seqName->names = NIL;
+                       seqName->typeid = myclass->reltype;
+                       seqName->typmod = -1;
+                       seqName->arrayBounds = NIL;
+ 
+                       seqRel = heap_open(TypeRelationId, RowExclusiveLock);
+                       AlterTypeNamespace(myclass->reltype, seqRel, nspname, 
seqName, false);
+                       heap_close(seqRel, RowExclusiveLock);
+ 
+                       /*
+                        * At least we need to rebuild all column default 
expressions that
+                        * rely on this sequence.
+                        */
+                       if (dependent->refobjsubid > 0)
+                       {
+                               AttrNumber attnum = dependent->refobjsubid;
+                               RebuildSequenceDefaultExpr(relOid, attnum,
+                                                                               
  NameStr(myclass->relname), nspname);
+                       }
+               }
+       }
+ 
+       systable_endscan(scan);
+       heap_close(classRel, RowExclusiveLock);
+       heap_close(dependRel, RowShareLock);
+ 
+ }
+ 
+ /*
+  * Moves all constraints for the specified relation to another
+  * namespace, specified by newnspOid. The function supports 'moving'
+  * constraints that are defined on tables and domains. Other relkinds
+  * causes the function to trap an error.
+  *
+  * NOTE: AlterConstraintNamespacesForRel() doesn't check itself for
+  * access permissions, this should be done by the caller.
+  */
+ void
+ AlterConstraintNamespacesForRel(Oid relOid, Oid newnspOid, const char relkind)
+ {
+ 
+       Relation                conRel;
+       HeapTuple               tup;
+       SysScanDesc     scan = NULL;
+       ScanKeyData     key[1];
+ 
+       Assert(OidIsValid(relOid) && OidIsValid(newnspOid));
+ 
+       conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
+ 
+       /* Initialize index scan */
+       switch (relkind)
+       {
+               case RELKIND_RELATION:
+                       ScanKeyInit(&key[0], Anum_pg_constraint_conrelid,
+                                               BTEqualStrategyNumber, F_OIDEQ, 
ObjectIdGetDatum(relOid));
+                       scan = systable_beginscan(conRel, 
ConstraintRelidIndexId, true,
+                                                  SnapshotNow, 1, key);
+                       break;
+ 
+               case RELKIND_COMPOSITE_TYPE:
+                       ScanKeyInit(&key[0], Anum_pg_constraint_contypid,
+                                               BTEqualStrategyNumber, F_OIDEQ, 
ObjectIdGetDatum(relOid));
+                       scan = systable_beginscan(conRel, 
ConstraintTypidIndexId, true,
+                                                  SnapshotNow, 1, key);
+                       break;
+ 
+               default:
+                       elog(ERROR, "altering constraint namespace only 
supported for tables and types");
+                       break;
+       }
+ 
+       while(HeapTupleIsValid((tup = systable_getnext(scan))))
+       {
+               Form_pg_constraint      constraint;
+               HeapTuple                       newtuple = NULL;
+ 
+               newtuple = heap_copytuple(tup);
+               constraint = (Form_pg_constraint) GETSTRUCT(newtuple);
+               constraint->connamespace = newnspOid;
+ 
+               simple_heap_update(conRel, &newtuple->t_self, newtuple);
+               CatalogUpdateIndexes(conRel, newtuple);
+       }
+ 
+       systable_endscan(scan);
+       heap_close(conRel, RowExclusiveLock);
+ }
+ 
+ /*
+  * Moves all indexes for the specified relation to another namespace.
+  *
+  * NOTE: AlterIndexNamespacesForTable() assumes that the caller checks wether
+  * there are enough permissions on the source and target namespace and
+  * locks to "move" the index to the new namespace. This is should be
+  * no problem, since this function is intended to be a small helper function 
to
+  * AlterTableNamespace() only. That's also the reason why it lives here.
+  */
+ static void
+ AlterIndexNamespacesForTable(Oid relOid, Oid newnspOid)
+ {
+       Relation                        indexRel;
+       Relation                        classRel;
+       HeapTuple                       tup;
+       ScanKeyData                     key[1];
+       SysScanDesc                     scan;
+ 
+       Assert(OidIsValid(relOid) && OidIsValid(newnspOid));
+ 
+       indexRel = heap_open(IndexRelationId, RowShareLock);
+ 
+       classRel = heap_open(RelationRelationId, RowExclusiveLock);
+ 
+       ScanKeyInit(&key[0], Anum_pg_index_indrelid, BTEqualStrategyNumber, 
F_OIDEQ,
+                               ObjectIdGetDatum(relOid));
+ 
+       scan = systable_beginscan(indexRel, IndexIndrelidIndexId, true, 
SnapshotNow, 1, key);
+ 
+       while (HeapTupleIsValid((tup = systable_getnext(scan))))
+       {
+               Form_pg_index           index = (Form_pg_index) GETSTRUCT(tup);
+               Form_pg_class           indexClass;
+               HeapTuple                       classTup = NULL;
+ 
+               classTup = SearchSysCacheCopy(RELOID, 
ObjectIdGetDatum(index->indexrelid),
+                                                                         0, 0, 
0);
+ 
+               if (!HeapTupleIsValid(classTup))
+                       elog(ERROR, "cache lookup failed for index relation OID 
%u",
+                                 index->indexrelid);
+ 
+               indexClass = (Form_pg_class) GETSTRUCT(classTup);
+               indexClass->relnamespace = newnspOid;
+ 
+               simple_heap_update(classRel, &classTup->t_self, classTup);
+               CatalogUpdateIndexes(classRel, classTup);
+       }
+ 
+       systable_endscan(scan);
+       heap_close(classRel, RowExclusiveLock);
+       heap_close(indexRel, RowShareLock);
+ 
+ }
+ 
+ /*
+  * Changes the namespace of the specified table
+  * Ownership of the specified relation (relid) should be checked
+  * by the caller.
+  */
+ void
+ AlterTableNamespace(Oid relid, const char *newnpname)
+ {
+       HeapTuple                       tup;
+       Relation                        rel;
+       Relation                        relRel;
+       char                            *relname;
+       Oid                             oldnpOid;
+       Oid                             newnpOid;
+       Relation                        relType;
+       TypeName                        *typename;
+       Form_pg_class           class;
+       AclResult                       aclrc;
+ 
+       rel = relation_open(relid, AccessExclusiveLock);
+ 
+       tup = SearchSysCacheCopy(NAMESPACENAME, CStringGetDatum(newnpname),
+                                                        0, 0, 0);
+       if (!HeapTupleIsValid(tup))
+               ereport(ERROR,
+                        (errcode(ERRCODE_UNDEFINED_SCHEMA),
+                         errmsg("schema \"%s\" doesn't exists", newnpname)));
+ 
+       newnpOid = HeapTupleGetOid(tup);
+ 
+       if ((aclrc = pg_namespace_aclcheck(HeapTupleGetOid(tup), GetUserId(),
+               ACL_CREATE)) != ACLCHECK_OK)
+               aclcheck_error(aclrc, ACL_KIND_NAMESPACE, newnpname);
+ 
+       oldnpOid = get_rel_namespace(relid);
+ 
+       if ((aclrc = pg_namespace_aclcheck(oldnpOid, GetUserId(), ACL_CREATE))
+               != ACLCHECK_OK)
+               aclcheck_error(aclrc, ACL_KIND_NAMESPACE, 
get_namespace_name(oldnpOid));
+ 
+       if (oldnpOid == newnpOid)
+               elog(ERROR, "relation %u already in schema %s", relid, 
newnpname);
+ 
+       relname = get_rel_name(relid);
+       if (get_relname_relid(relname, newnpOid) != InvalidOid)
+               ereport(ERROR,
+                       (errcode(ERRCODE_DUPLICATE_TABLE),
+                         errmsg("relation \"%s\" already exists in schema 
\"%s\"",
+                                        relname, newnpname)));
+       
+       relRel = heap_open(RelationRelationId, RowExclusiveLock);
+ 
+       tup = SearchSysCacheCopy(RELOID, PointerGetDatum(relid), 0, 0, 0);
+ 
+       if (!HeapTupleIsValid(tup))
+               elog(ERROR, "cache lookup failed for relation %u", relid);
+ 
+       class = (Form_pg_class) GETSTRUCT(tup);
+       class->relnamespace = newnpOid;
+       simple_heap_update(relRel, &tup->t_self, tup);
+ 
+       relType = heap_open(TypeRelationId, RowExclusiveLock);
+ 
+       typename = makeNode(TypeName);
+       typename->names  = NIL;
+       typename->typeid = class->reltype;
+       typename->typmod = -1;
+       typename->arrayBounds = NIL;
+ 
+       AlterTypeNamespace(class->reltype, relType, newnpname, typename, false);
+ 
+       heap_close(relType, NoLock);
+ 
+       if (class->relkind == RELKIND_RELATION)
+       {
+               AlterIndexNamespacesForTable(relid, newnpOid);
+               AlterConstraintNamespacesForRel(relid, newnpOid, 
RELKIND_RELATION);
+               AlterSeqNamespacesForTable(relid, newnpOid);
+       }
+ 
+ 
+       if (changeDependencyFor(RelationRelationId, relid, oldnpOid, newnpOid))
+               elog(DEBUG1, "changed dependency to new schema \"%s\"", 
newnpname);
+ 
+       CatalogUpdateIndexes(relRel, tup);
+ 
+       heap_freetuple(tup);
+       heap_close(relRel, RowExclusiveLock);
+ 
+       relation_close(rel, NoLock);
+ }
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.76
diff -c -c -r1.76 typecmds.c
*** src/backend/commands/typecmds.c     14 Jul 2005 21:46:29 -0000      1.76
--- src/backend/commands/typecmds.c     29 Jul 2005 03:11:24 -0000
***************
*** 2097,2102 ****
                changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
        }
  
-       /* Clean up */
        heap_close(rel, RowExclusiveLock);
  }
--- 2097,2262 ----
                changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
        }
  
        heap_close(rel, RowExclusiveLock);
  }
+ 
+ /*
+  * Apply new namespace to specified type. Assume TypeRelationId
+  * is already opened by the caller.
+  *
+  * Specifying errorOnTableType to TRUE causes the function
+  * to error out if an attempt to rename a table type namespace occurs.
+  * This is necessary, since we want users to use ALTER TABLE to rename
+  * the table type's namespace.
+  */
+ void
+ AlterTypeNamespace(Oid typeOid, Relation rel, const char *newnpname,
+                       const TypeName *typename, const bool errorOnTableType)
+ {
+       HeapTuple                       tup;
+       HeapTuple                       nsptup;
+       Form_pg_type            mytype;
+       AclResult                       aclrc;
+       Oid                                     oldnpOid;
+       Oid                                     relTypeOid;
+       Oid                                     classId;
+   
+       Assert(OidIsValid(typeOid) && typename != NULL && rel != NULL && 
newnpname != NULL);
+   
+       tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0);
+   
+       if (!HeapTupleIsValid(tup))
+               elog(ERROR, "cache lookup failed for type %u", typeOid);
+   
+       mytype = (Form_pg_type) GETSTRUCT(tup);
+   
+       if (!pg_type_ownercheck(typeOid, GetUserId()))
+               aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, 
TypeNameToString(typename));   
+   
+       if ((aclrc = pg_namespace_aclcheck(mytype->typnamespace, GetUserId(),
+                       ACL_CREATE)) != ACLCHECK_OK)
+               aclcheck_error(aclrc, ACL_KIND_NAMESPACE, 
get_namespace_name(mytype->typnamespace));
+   
+       nsptup = SearchSysCacheCopy(NAMESPACENAME, CStringGetDatum(newnpname), 
0, 0, 0);
+   
+       if (!HeapTupleIsValid(nsptup))
+               ereport(ERROR,
+                        (errcode(ERRCODE_UNDEFINED_SCHEMA),
+                         errmsg("schema \"%s\" doesn't exists", newnpname)));  
  
+   
+       if ((aclrc = pg_namespace_aclcheck(HeapTupleGetOid(nsptup), GetUserId(),
+                                       ACL_CREATE)) != ACLCHECK_OK)
+               aclcheck_error(aclrc, ACL_KIND_NAMESPACE, newnpname);           
  
+   
+       /*
+        * if errorOnTableType is requested, we don't want to allow renaming
+        * the namespace of a table type. If such an attempt occurs, we error
+        * out....
+        */
+       if (mytype->typtype == RELKIND_COMPOSITE_TYPE && errorOnTableType &&
+               get_rel_relkind(mytype->typrelid) != RELKIND_COMPOSITE_TYPE)
+               ereport(ERROR,
+                       (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                        errmsg("\"%s\" is a table's row type",
+                               TypeNameToString(typename))));    
+ 
+       if (mytype->typnamespace == HeapTupleGetOid(nsptup))
+               ereport(ERROR,
+                       (errcode(ERRCODE_DUPLICATE_OBJECT),
+                        errmsg("type \"%s\" already in schema \"%s\"",
+                               TypeNameToString(typename), newnpname))); 
+   
+       oldnpOid = mytype->typnamespace; /* save for dependency refactoring */
+       mytype->typnamespace = HeapTupleGetOid(nsptup);
+       simple_heap_update(rel, &tup->t_self, tup);
+   
+       CatalogUpdateIndexes(rel, tup);
+         
+       /*
+        * Composite types has pg_class entries.
+        * We need to modify the pg_class tuple as well to
+        * reflect the changes of its schema.
+        */
+       if (mytype->typtype == 'c' && get_rel_relkind(mytype->typrelid) == 'c')
+       {
+               Form_pg_class pg_class;
+               Relation  relClass = heap_open(RelationRelationId, 
RowExclusiveLock);
+               HeapTuple relTup   = SearchSysCacheCopy(RELOID,
+                                                                       
ObjectIdGetDatum(mytype->typrelid), 0, 0, 0);
+         
+               if (!HeapTupleIsValid(relTup))
+                       elog(ERROR, "cache lookup for relation \"%s\" failed",
+                         TypeNameToString(typename));
+         
+               pg_class = (Form_pg_class) GETSTRUCT(relTup);
+               pg_class->relnamespace = HeapTupleGetOid(nsptup);
+         
+               simple_heap_update(relClass, &relTup->t_self, relTup);
+               CatalogUpdateIndexes(relClass, relTup);
+         
+               heap_close(relClass, RowExclusiveLock);
+               heap_freetuple(relTup);
+         
+               relTypeOid = mytype->typrelid;
+               classId = RelationRelationId;
+       }
+       else
+       {
+               relTypeOid = typeOid;
+               classId = TypeRelationId;
+       }
+         
+       if (changeDependencyFor(classId, relTypeOid, oldnpOid, 
HeapTupleGetOid(nsptup)))
+               elog(DEBUG1, "changed dependency to new schema \"%s\"", 
newnpname);
+   
+       heap_freetuple(tup);
+       heap_freetuple(nsptup);
+ }
+ 
+ void
+ AlterDomainNamespace(List *names, const char *newnpname)
+ {
+       Oid                                     typeOid;
+       Oid                                     nspOid;
+       TypeName                        *typename;
+       Relation                        rel;
+       HeapTuple                       nspTup;
+   
+       Assert(names != NIL && newnpname != NULL);
+   
+       /*
+        * As usual, create the type stuff so we can use
+        * standard type functions.
+        */
+   
+       typename = makeNode(TypeName);
+       typename->names = names;
+       typename->typmod = -1;
+       typename->arrayBounds = NIL;
+   
+       rel = heap_open(TypeRelationId, RowExclusiveLock);
+   
+       /* get type OID */
+       typeOid = LookupTypeName(typename);
+   
+       if (!OidIsValid(typeOid))
+               ereport(ERROR,
+                       (errcode(ERRCODE_UNDEFINED_OBJECT),
+                        errmsg("type \"%s\" does not exist",
+                               TypeNameToString(typename))));
+   
+       AlterTypeNamespace(typeOid, rel, newnpname, typename, true);
+ 
+       nspTup = SearchSysCacheCopy(NAMESPACENAME, CStringGetDatum(newnpname), 
0, 0, 0);
+ 
+       if (!HeapTupleIsValid(nspTup))
+               elog(ERROR, "cache lookup failure for schema %s", newnpname);
+ 
+       nspOid = HeapTupleGetOid(nspTup);
+ 
+       AlterConstraintNamespacesForRel(typeOid, nspOid, 
RELKIND_COMPOSITE_TYPE);
+   
+       heap_close(rel, RowExclusiveLock);
+ }
+ 
+ 
Index: src/backend/parser/gram.y
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.504
diff -c -c -r2.504 gram.y
*** src/backend/parser/gram.y   26 Jul 2005 22:37:50 -0000      2.504
--- src/backend/parser/gram.y   29 Jul 2005 03:11:27 -0000
***************
*** 132,138 ****
  
  %type <node>  stmt schema_stmt
                AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt 
AlterOwnerStmt
!               AlterSeqStmt AlterTableStmt AlterUserStmt AlterUserSetStmt
                AlterRoleStmt AlterRoleSetStmt
                AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
                ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
--- 132,138 ----
  
  %type <node>  stmt schema_stmt
                AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt 
AlterOwnerStmt
!               AlterSeqStmt AlterTableStmt AlterUserStmt AlterUserSetStmt 
AlterObjectSchemaStmt
                AlterRoleStmt AlterRoleSetStmt
                AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
                ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
***************
*** 487,492 ****
--- 487,493 ----
  
  stmt :
                        AlterDatabaseSetStmt
+                       | AlterObjectSchemaStmt
                        | AlterDomainStmt
                        | AlterFunctionStmt
                        | AlterGroupStmt
***************
*** 3997,4002 ****
--- 3998,4060 ----
                        | /*EMPTY*/                                             
                { $$ = 0; }
                ;
  
+ /*****************************************************************************
+  *
+  * ALTER THING name SET SCHEMA name
+  *
+  
*****************************************************************************/
+ 
+ AlterObjectSchemaStmt: ALTER TABLE relation_expr SET SCHEMA name
+                               {
+                                       RenameObjSchemaStmt *n = 
makeNode(RenameObjSchemaStmt);
+                                       n->renameType = OBJECT_TABLE;
+                                       n->relation = $3;
+                                       n->object = NIL;
+                                       n->objarg = NIL;
+                                       n->newname = $6;
+                                       $$ = (Node *)n;
+                               }
+                  | ALTER SEQUENCE relation_expr SET SCHEMA name
+                               {
+                                       RenameObjSchemaStmt *n = 
makeNode(RenameObjSchemaStmt);
+                                       n->renameType = OBJECT_SEQUENCE;
+                                       n->relation = $3;
+                                       n->object = NIL;
+                                       n->objarg = NIL;
+                                       n->newname = $6;
+                                       $$ = (Node *)n;
+                               }
+                  | ALTER FUNCTION func_name func_args SET SCHEMA name
+                          {
+                                       RenameObjSchemaStmt *n = 
makeNode(RenameObjSchemaStmt);
+                                       n->renameType = OBJECT_FUNCTION;
+                                       n->relation = NULL;
+                                       n->object = $3;
+                                       n->objarg = extractArgTypes($4);
+                                       n->newname = $7;
+                                       $$ = (Node *)n;
+                          }
+                  | ALTER DOMAIN_P any_name SET SCHEMA name
+                          {
+                                       RenameObjSchemaStmt *n = 
makeNode(RenameObjSchemaStmt);
+                                       n->renameType = OBJECT_DOMAIN;
+                                       n->relation = NULL;
+                                       n->object = $3;
+                                       n->objarg = NIL;
+                                       n->newname = $6;
+                                       $$ = (Node *)n;
+                               }
+                  | ALTER TYPE_P any_name SET SCHEMA name
+                          {
+                                       RenameObjSchemaStmt *n = 
makeNode(RenameObjSchemaStmt);
+                                       n->renameType = OBJECT_TYPE;
+                                       n->relation = NULL;
+                                       n->object = $3;
+                                       n->objarg = NIL;
+                                       n->newname = $6;
+                                       $$ = (Node *)n;
+                          }
+               ;
  
  /*****************************************************************************
   *
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.241
diff -c -c -r1.241 utility.c
*** src/backend/tcop/utility.c  14 Jul 2005 05:13:41 -0000      1.241
--- src/backend/tcop/utility.c  29 Jul 2005 03:11:29 -0000
***************
*** 284,289 ****
--- 284,290 ----
                case T_AlterSeqStmt:
                case T_AlterTableStmt:
                case T_RenameStmt:
+               case T_RenameObjSchemaStmt:
                case T_CommentStmt:
                case T_DefineStmt:
                case T_CreateCastStmt:
***************
*** 624,629 ****
--- 625,634 ----
                        ExecRenameStmt((RenameStmt *) parsetree);
                        break;
  
+               case T_RenameObjSchemaStmt:
+                       ExecRenameObjSchemaStmt((RenameObjSchemaStmt 
*)parsetree);
+                       break;
+                   
                case T_AlterOwnerStmt:
                        ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
                        break;
***************
*** 1323,1328 ****
--- 1328,1360 ----
                        tag = "COPY";
                        break;
  
+               case T_RenameObjSchemaStmt:
+                   switch(((RenameObjSchemaStmt *) parsetree)->renameType)
+                   {
+                               case OBJECT_AGGREGATE:
+                                   tag = "ALTER AGGREGATE";
+                                   break;
+                                   
+                               case OBJECT_CONVERSION:
+                                   tag = "ALTER CONVERSION";
+                                   
+                               case OBJECT_DOMAIN:
+                                   tag = "ALTER DOMAIN";
+                                   break;
+                                   
+                               case OBJECT_FUNCTION:
+                                   tag = "ALTER FUNCTION";
+                                   break;
+                                   
+                               case OBJECT_SEQUENCE:
+                                   tag = "ALTER SEQUENCE";
+                                   break;
+                                   
+                               default:
+                                   tag = "ALTER TABLE";
+                                   break;
+                   }
+ 
                case T_RenameStmt:
                        switch (((RenameStmt *) parsetree)->renameType)
                        {
Index: src/include/catalog/dependency.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/catalog/dependency.h,v
retrieving revision 1.15
diff -c -c -r1.15 dependency.h
*** src/include/catalog/dependency.h    7 Jul 2005 20:39:59 -0000       1.15
--- src/include/catalog/dependency.h    29 Jul 2005 03:11:30 -0000
***************
*** 198,201 ****
--- 198,206 ----
  
  extern void dropDatabaseDependencies(Oid databaseId);
  
+ extern bool changeDependencyFor(Oid classId, 
+                                                                Oid objectId,
+                                                                Oid 
oldrefobjectId,
+                                                                Oid 
newrefobjectId);
+ 
  #endif   /* DEPENDENCY_H */
Index: src/include/commands/alter.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/commands/alter.h,v
retrieving revision 1.6
diff -c -c -r1.6 alter.h
*** src/include/commands/alter.h        31 Dec 2004 22:03:28 -0000      1.6
--- src/include/commands/alter.h        29 Jul 2005 03:11:30 -0000
***************
*** 16,21 ****
--- 16,23 ----
  
  #include "nodes/parsenodes.h"
  
+ extern void ExecRenameObjSchemaStmt(RenameObjSchemaStmt *stmt);
+ 
  extern void ExecRenameStmt(RenameStmt *stmt);
  
  extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt);
Index: src/include/commands/defrem.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/commands/defrem.h,v
retrieving revision 1.66
diff -c -c -r1.66 defrem.h
*** src/include/commands/defrem.h       28 Jun 2005 05:09:12 -0000      1.66
--- src/include/commands/defrem.h       29 Jul 2005 03:11:30 -0000
***************
*** 55,60 ****
--- 55,62 ----
  extern void CreateCast(CreateCastStmt *stmt);
  extern void DropCast(DropCastStmt *stmt);
  extern void DropCastById(Oid castOid);
+ extern void AlterFunctionNamespace(List *name, List *argtypes, 
+                                   const char *newnpname);
  
  /* commands/operatorcmds.c */
  extern void DefineOperator(List *names, List *parameters);
Index: src/include/commands/tablecmds.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/commands/tablecmds.h,v
retrieving revision 1.22
diff -c -c -r1.22 tablecmds.h
*** src/include/commands/tablecmds.h    27 Jan 2005 03:18:24 -0000      1.22
--- src/include/commands/tablecmds.h    29 Jul 2005 03:11:30 -0000
***************
*** 16,21 ****
--- 16,26 ----
  
  #include "nodes/parsenodes.h"
  
+ extern void AlterConstraintNamespacesForRel(Oid relOid,
+                                            Oid newnspOid,
+                                            const char relkind);
+ extern void AlterTableNamespace(Oid relid,
+                                 const char *newnpname);
  
  extern Oid    DefineRelation(CreateStmt *stmt, char relkind);
  
Index: src/include/commands/typecmds.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/commands/typecmds.h,v
retrieving revision 1.11
diff -c -c -r1.11 typecmds.h
*** src/include/commands/typecmds.h     28 Jun 2005 05:09:12 -0000      1.11
--- src/include/commands/typecmds.h     29 Jul 2005 03:11:30 -0000
***************
*** 19,24 ****
--- 19,27 ----
  
  #define DEFAULT_TYPDELIM              ','
  
+ extern void AlterTypeNamespace(Oid typeOid, Relation rel, const char 
*newnpname,
+                               const TypeName *typename, const bool 
errorOnTableType);
+ extern void AlterDomainNamespace(List *names, const char *newnpname);
  extern void DefineType(List *names, List *parameters);
  extern void RemoveType(List *names, DropBehavior behavior);
  extern void RemoveTypeById(Oid typeOid);
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.172
diff -c -c -r1.172 nodes.h
*** src/include/nodes/nodes.h   28 Jun 2005 05:09:13 -0000      1.172
--- src/include/nodes/nodes.h   29 Jul 2005 03:11:30 -0000
***************
*** 284,289 ****
--- 284,290 ----
        T_CreateTableSpaceStmt,
        T_DropTableSpaceStmt,
        T_AlterOwnerStmt,
+       T_RenameObjSchemaStmt,
  
        T_A_Expr = 800,
        T_ColumnRef,
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.286
diff -c -c -r1.286 parsenodes.h
*** src/include/nodes/parsenodes.h      26 Jul 2005 16:38:28 -0000      1.286
--- src/include/nodes/parsenodes.h      29 Jul 2005 03:11:34 -0000
***************
*** 1471,1476 ****
--- 1471,1491 ----
  } RemoveOpClassStmt;
  
  /* ----------------------
+  *            Alter Object Rename Schema
+  * ----------------------
+  */
+ typedef struct RenameObjSchemaStmt
+ {
+       NodeTag    type;
+       RangeVar   *relation;
+       List       *object;
+       List       *objarg;
+       
+       char       *newname;
+       ObjectType renameType;
+ } RenameObjSchemaStmt;
+ 
+ /* ----------------------
   *            Alter Object Rename Statement
   * ----------------------
   */
---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

               http://archives.postgresql.org

Reply via email to