Add ALTER object SET SCHEMA capability for a limited but useful set of

object kinds (tables, functions, types).  Documentation is not here yet.
Original code by Bernd Helmle, extensive rework by Bruce Momjian and
Tom Lane.
REL8_1_STABLE
Tom Lane 20 years ago
parent a85e5d1b1b
commit 35508d1cca
  1. 60
      src/backend/catalog/namespace.c
  2. 68
      src/backend/catalog/pg_constraint.c
  3. 101
      src/backend/catalog/pg_depend.c
  4. 34
      src/backend/commands/alter.c
  5. 88
      src/backend/commands/functioncmds.c
  6. 296
      src/backend/commands/tablecmds.c
  7. 171
      src/backend/commands/typecmds.c
  8. 24
      src/backend/nodes/copyfuncs.c
  9. 22
      src/backend/nodes/equalfuncs.c
  10. 67
      src/backend/parser/gram.y
  11. 44
      src/backend/tcop/utility.c
  12. 6
      src/include/catalog/dependency.h
  13. 4
      src/include/catalog/namespace.h
  14. 5
      src/include/catalog/pg_constraint.h
  15. 4
      src/include/commands/alter.h
  16. 4
      src/include/commands/defrem.h
  17. 9
      src/include/commands/tablecmds.h
  18. 5
      src/include/commands/typecmds.h
  19. 3
      src/include/nodes/nodes.h
  20. 21
      src/include/nodes/parsenodes.h
  21. 59
      src/test/regress/expected/alter_table.out
  22. 41
      src/test/regress/sql/alter_table.sql

@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.76 2005/06/28 05:08:52 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.77 2005/08/01 04:03:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1235,12 +1235,43 @@ LookupExplicitNamespace(const char *nspname)
return namespaceId;
}
/*
* LookupCreationNamespace
* Look up the schema and verify we have CREATE rights on it.
*
* This is just like LookupExplicitNamespace except for the permission check.
*/
Oid
LookupCreationNamespace(const char *nspname)
{
Oid namespaceId;
AclResult aclresult;
namespaceId = GetSysCacheOid(NAMESPACENAME,
CStringGetDatum(nspname),
0, 0, 0);
if (!OidIsValid(namespaceId))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_SCHEMA),
errmsg("schema \"%s\" does not exist", nspname)));
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
nspname);
return namespaceId;
}
/*
* QualifiedNameGetCreationNamespace
* Given a possibly-qualified name for an object (in List-of-Values
* format), determine what namespace the object should be created in.
* Also extract and return the object name (last component of list).
*
* Note: this does not apply any permissions check. Callers must check
* for CREATE rights on the selected namespace when appropriate.
*
* This is *not* used for tables. Hence, the TEMP table namespace is
* never selected as the creation target.
*/
@ -1277,8 +1308,6 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
errmsg("no schema has been selected to create in")));
}
/* Note: callers will check for CREATE rights when appropriate */
*objname_p = objname;
return namespaceId;
}
@ -1379,19 +1408,16 @@ isTempNamespace(Oid namespaceId)
}
/*
* isOtherTempNamespace - is the given namespace some other backend's
* temporary-table namespace?
* isAnyTempNamespace - is the given namespace a temporary-table namespace
* (either my own, or another backend's)?
*/
bool
isOtherTempNamespace(Oid namespaceId)
isAnyTempNamespace(Oid namespaceId)
{
bool result;
char *nspname;
/* If it's my own temp namespace, say "false" */
if (isTempNamespace(namespaceId))
return false;
/* Else, if the namespace name starts with "pg_temp_", say "true" */
/* If the namespace name starts with "pg_temp_", say "true" */
nspname = get_namespace_name(namespaceId);
if (!nspname)
return false; /* no such namespace? */
@ -1400,6 +1426,20 @@ isOtherTempNamespace(Oid namespaceId)
return result;
}
/*
* isOtherTempNamespace - is the given namespace some other backend's
* temporary-table namespace?
*/
bool
isOtherTempNamespace(Oid namespaceId)
{
/* If it's my own temp namespace, say "false" */
if (isTempNamespace(namespaceId))
return false;
/* Else, if the namespace name starts with "pg_temp_", say "true" */
return isAnyTempNamespace(namespaceId);
}
/*
* PushSpecialNamespace - push a "special" namespace onto the front of the
* search path.

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.25 2005/04/14 20:03:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_constraint.c,v 1.26 2005/08/01 04:03:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -599,3 +599,69 @@ GetConstraintNameForTrigger(Oid triggerId)
return result;
}
/*
* AlterConstraintNamespaces
* Find any constraints belonging to the specified object,
* and move them to the specified new namespace.
*
* isType indicates whether the owning object is a type or a relation.
*/
void
AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
Oid newNspId, bool isType)
{
Relation conRel;
ScanKeyData key[1];
SysScanDesc scan;
HeapTuple tup;
conRel = heap_open(ConstraintRelationId, RowExclusiveLock);
if (isType)
{
ScanKeyInit(&key[0],
Anum_pg_constraint_contypid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(ownerId));
scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
SnapshotNow, 1, key);
}
else
{
ScanKeyInit(&key[0],
Anum_pg_constraint_conrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(ownerId));
scan = systable_beginscan(conRel, ConstraintRelidIndexId, true,
SnapshotNow, 1, key);
}
while (HeapTupleIsValid((tup = systable_getnext(scan))))
{
Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup);
if (conform->connamespace == oldNspId)
{
tup = heap_copytuple(tup);
conform = (Form_pg_constraint) GETSTRUCT(tup);
conform->connamespace = newNspId;
simple_heap_update(conRel, &tup->t_self, tup);
CatalogUpdateIndexes(conRel, tup);
/*
* Note: currently, the constraint will not have its own
* dependency on the namespace, so we don't need to do
* changeDependencyFor().
*/
}
}
systable_endscan(scan);
heap_close(conRel, RowExclusiveLock);
}

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.13 2005/04/14 20:03:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.14 2005/08/01 04:03:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -162,6 +162,105 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId)
return count;
}
/*
* Adjust dependency record(s) to point to a different object of the same type
*
* classId/objectId specify the referencing object.
* refClassId/oldRefObjectId specify the old referenced object.
* newRefObjectId is the new referenced object (must be of class refClassId).
*
* Note the lack of objsubid parameters. If there are subobject references
* they will all be readjusted.
*
* Returns the number of records updated.
*/
long
changeDependencyFor(Oid classId, Oid objectId,
Oid refClassId, Oid oldRefObjectId,
Oid newRefObjectId)
{
long count = 0;
Relation depRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup;
ObjectAddress objAddr;
bool newIsPinned;
depRel = heap_open(DependRelationId, RowExclusiveLock);
/*
* If oldRefObjectId is pinned, there won't be any dependency entries
* on it --- we can't cope in that case. (This isn't really worth
* expending code to fix, in current usage; it just means you can't
* rename stuff out of pg_catalog, which would likely be a bad move
* anyway.)
*/
objAddr.classId = refClassId;
objAddr.objectId = oldRefObjectId;
objAddr.objectSubId = 0;
if (isObjectPinned(&objAddr, depRel))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot remove dependency on %s because it is a system object",
getObjectDescription(&objAddr))));
/*
* We can handle adding a dependency on something pinned, though,
* since that just means deleting the dependency entry.
*/
objAddr.objectId = newRefObjectId;
newIsPinned = isObjectPinned(&objAddr, depRel);
/* Now search for dependency records */
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 depform = (Form_pg_depend) GETSTRUCT(tup);
if (depform->refclassid == refClassId &&
depform->refobjid == oldRefObjectId)
{
if (newIsPinned)
simple_heap_delete(depRel, &tup->t_self);
else
{
/* make a modifiable copy */
tup = heap_copytuple(tup);
depform = (Form_pg_depend) GETSTRUCT(tup);
depform->refobjid = newRefObjectId;
simple_heap_update(depRel, &tup->t_self, tup);
CatalogUpdateIndexes(depRel, tup);
heap_freetuple(tup);
}
count++;
}
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
return count;
}
/*
* isObjectPinned()
*

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.13 2005/06/28 05:08:53 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.14 2005/08/01 04:03:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -142,6 +142,38 @@ ExecRenameStmt(RenameStmt *stmt)
}
}
/*
* Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object
* type, the function appropriate to that type is executed.
*/
void
ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
{
switch (stmt->objectType)
{
case OBJECT_AGGREGATE:
case OBJECT_FUNCTION:
AlterFunctionNamespace(stmt->object, stmt->objarg,
stmt->newschema);
break;
case OBJECT_SEQUENCE:
case OBJECT_TABLE:
CheckRelationOwnership(stmt->relation, true);
AlterTableNamespace(stmt->relation, stmt->newschema);
break;
case OBJECT_TYPE:
case OBJECT_DOMAIN:
AlterTypeNamespace(stmt->object, stmt->newschema);
break;
default:
elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
(int) stmt->objectType);
}
}
/*
* Executes an ALTER OBJECT / OWNER TO statement. Based on the object
* type, the function appropriate to that type is executed.

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.64 2005/07/14 21:46:29 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.65 2005/08/01 04:03:55 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@ -40,6 +40,7 @@
#include "catalog/pg_aggregate.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
@ -1427,3 +1428,88 @@ DropCastById(Oid castOid)
systable_endscan(scan);
heap_close(relation, RowExclusiveLock);
}
/*
* Execute ALTER FUNCTION SET SCHEMA
*/
void
AlterFunctionNamespace(List *name, List *argtypes, 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 */
procOid = LookupFuncNameTypeNames(name, argtypes, false);
/* check permissions on function */
if (!pg_proc_ownercheck(procOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(name));
tup = SearchSysCacheCopy(PROCOID,
ObjectIdGetDatum(procOid),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for function %u", procOid);
proc = (Form_pg_proc) GETSTRUCT(tup);
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))
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 (SearchSysCacheExists(PROCNAMEARGSNSP,
CStringGetDatum(NameStr(proc->proname)),
PointerGetDatum(&proc->proargtypes),
ObjectIdGetDatum(nspOid),
0))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_FUNCTION),
errmsg("function \"%s\" already exists in schema \"%s\"",
NameStr(proc->proname),
newschema)));
/* OK, modify the pg_proc row */
/* tup is a copy, so we can scribble directly on it */
proc->pronamespace = nspOid;
simple_heap_update(procRel, &tup->t_self, tup);
CatalogUpdateIndexes(procRel, tup);
/* Update dependency on schema */
if (changeDependencyFor(ProcedureRelationId, procOid,
NamespaceRelationId, oldNspOid, nspOid) != 1)
elog(ERROR, "failed to change schema dependency for function \"%s\"",
NameListToString(name));
heap_freetuple(tup);
heap_close(procRel, RowExclusiveLock);
}

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.164 2005/07/14 21:46:29 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.165 2005/08/01 04:03:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -163,6 +163,13 @@ static void StoreCatalogInheritance(Oid relationId, List *supers);
static int findAttrByName(const char *attributeName, List *schema);
static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
static bool needs_toast_table(Relation rel);
static void AlterIndexNamespaces(Relation classRel, Relation rel,
Oid oldNspOid, Oid newNspOid);
static void AlterSeqNamespaces(Relation classRel, Relation rel,
Oid oldNspOid, Oid newNspOid,
const char *newNspName);
static void RebuildSerialDefaultExpr(Relation rel, AttrNumber attnum,
const char *seqname, const char *nspname);
static int transformColumnNameList(Oid relId, List *colList,
int16 *attnums, Oid *atttypids);
static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
@ -5998,6 +6005,293 @@ needs_toast_table(Relation rel)
}
/*
* Execute ALTER TABLE SET SCHEMA
*
* Note: caller must have checked ownership of the relation already
*/
void
AlterTableNamespace(RangeVar *relation, const char *newschema)
{
Relation rel;
Oid relid;
Oid oldNspOid;
Oid nspOid;
Relation classRel;
rel = heap_openrv(relation, AccessExclusiveLock);
/* heap_openrv allows TOAST, but we don't want to */
if (rel->rd_rel->relkind == RELKIND_TOASTVALUE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is a TOAST relation",
RelationGetRelationName(rel))));
relid = RelationGetRelid(rel);
oldNspOid = RelationGetNamespace(rel);
/* 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")));
/* OK, modify the pg_class row and pg_depend entry */
classRel = heap_open(RelationRelationId, RowExclusiveLock);
AlterRelationNamespaceInternal(classRel, relid, oldNspOid, nspOid, true);
/* Fix the table's rowtype too */
AlterTypeNamespaceInternal(rel->rd_rel->reltype, nspOid, false);
/* Fix other dependent stuff */
if (rel->rd_rel->relkind == RELKIND_RELATION)
{
AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid);
AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid, newschema);
AlterConstraintNamespaces(relid, oldNspOid, nspOid, false);
}
heap_close(classRel, RowExclusiveLock);
/* close rel, but keep lock until commit */
relation_close(rel, NoLock);
}
/*
* The guts of relocating a relation to another namespace: fix the pg_class
* entry, and the pg_depend entry if any. Caller must already have
* opened and write-locked pg_class.
*/
void
AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
Oid oldNspOid, Oid newNspOid,
bool hasDependEntry)
{
HeapTuple classTup;
Form_pg_class classForm;
classTup = SearchSysCacheCopy(RELOID,
ObjectIdGetDatum(relOid),
0, 0, 0);
if (!HeapTupleIsValid(classTup))
elog(ERROR, "cache lookup failed for relation %u", relOid);
classForm = (Form_pg_class) GETSTRUCT(classTup);
Assert(classForm->relnamespace == oldNspOid);
/* check for duplicate name (more friendly than unique-index failure) */
if (get_relname_relid(NameStr(classForm->relname),
newNspOid) != InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_TABLE),
errmsg("relation \"%s\" already exists in schema \"%s\"",
NameStr(classForm->relname),
get_namespace_name(newNspOid))));
/* classTup is a copy, so OK to scribble on */
classForm->relnamespace = newNspOid;
simple_heap_update(classRel, &classTup->t_self, classTup);
CatalogUpdateIndexes(classRel, classTup);
/* Update dependency on schema if caller said so */
if (hasDependEntry &&
changeDependencyFor(RelationRelationId, relOid,
NamespaceRelationId, oldNspOid, newNspOid) != 1)
elog(ERROR, "failed to change schema dependency for relation \"%s\"",
NameStr(classForm->relname));
heap_freetuple(classTup);
}
/*
* Move all indexes for the specified relation to another namespace.
*
* Note: we assume adequate permission checking was done by the caller,
* and that the caller has a suitable lock on the owning relation.
*/
static void
AlterIndexNamespaces(Relation classRel, Relation rel,
Oid oldNspOid, Oid newNspOid)
{
List *indexList;
ListCell *l;
indexList = RelationGetIndexList(rel);
foreach(l, indexList)
{
Oid indexOid = lfirst_oid(l);
/*
* Note: currently, the index will not have its own dependency
* on the namespace, so we don't need to do changeDependencyFor().
* There's no rowtype in pg_type, either.
*/
AlterRelationNamespaceInternal(classRel, indexOid,
oldNspOid, newNspOid,
false);
}
list_free(indexList);
}
/*
* Move all SERIAL-column sequences of the specified relation to another
* namespace.
*
* Note: we assume adequate permission checking was done by the caller,
* and that the caller has a suitable lock on the owning relation.
*/
static void
AlterSeqNamespaces(Relation classRel, Relation rel,
Oid oldNspOid, Oid newNspOid, const char *newNspName)
{
Relation depRel;
SysScanDesc scan;
ScanKeyData key[2];
HeapTuple tup;
/*
* SERIAL sequences are those having an internal dependency on one
* of the table's columns (we don't care *which* column, exactly).
*/
depRel = heap_open(DependRelationId, AccessShareLock);
ScanKeyInit(&key[0],
Anum_pg_depend_refclassid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationRelationId));
ScanKeyInit(&key[1],
Anum_pg_depend_refobjid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(rel)));
/* we leave refobjsubid unspecified */
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_depend depForm = (Form_pg_depend) GETSTRUCT(tup);
Relation seqRel;
/* skip dependencies other than internal dependencies on columns */
if (depForm->refobjsubid == 0 ||
depForm->classid != RelationRelationId ||
depForm->objsubid != 0 ||
depForm->deptype != DEPENDENCY_INTERNAL)
continue;
/* Use relation_open just in case it's an index */
seqRel = relation_open(depForm->objid, AccessExclusiveLock);
/* skip non-sequence relations */
if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
{
/* No need to keep the lock */
relation_close(seqRel, AccessExclusiveLock);
continue;
}
/* Fix the pg_class and pg_depend entries */
AlterRelationNamespaceInternal(classRel, depForm->objid,
oldNspOid, newNspOid,
true);
/*
* Sequences have entries in pg_type. We need to be careful
* to move them to the new namespace, too.
*/
AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype,
newNspOid, false);
/*
* And we need to rebuild the column default expression that
* relies on this sequence.
*/
if (depForm->refobjsubid > 0)
RebuildSerialDefaultExpr(rel,
depForm->refobjsubid,
RelationGetRelationName(seqRel),
newNspName);
/* Now we can close it. Keep the lock till end of transaction. */
relation_close(seqRel, NoLock);
}
systable_endscan(scan);
relation_close(depRel, AccessShareLock);
}
/*
* Rebuild the default expression for a SERIAL column identified by rel
* and attnum. This is annoying, but we have to do it because the
* stored expression has the schema name as a text constant.
*
* The caller must be sure the specified column is really a SERIAL column,
* because no further checks are done here.
*/
static void
RebuildSerialDefaultExpr(Relation rel, AttrNumber attnum,
const char *seqname, const char *nspname)
{
char *qstring;
A_Const *snamenode;
FuncCall *funccallnode;
RawColumnDefault *rawEnt;
/*
* Create raw parse tree for the updated column default expression.
* This should match transformColumnDefinition() in parser/analyze.c.
*/
qstring = quote_qualified_identifier(nspname, seqname);
snamenode = makeNode(A_Const);
snamenode->val.type = T_String;
snamenode->val.val.str = qstring;
funccallnode = makeNode(FuncCall);
funccallnode->funcname = SystemFuncName("nextval");
funccallnode->args = list_make1(snamenode);
funccallnode->agg_star = false;
funccallnode->agg_distinct = false;
/*
* Remove any old default for the column. We use RESTRICT here for
* safety, but at present we do not expect anything to depend on the
* default.
*/
RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false);
/* Do the equivalent of ALTER TABLE ... SET DEFAULT */
rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
rawEnt->attnum = attnum;
rawEnt->raw_default = (Node *) funccallnode;
/*
* This function is intended for CREATE TABLE, so it processes a
* _list_ of defaults, but we just do one.
*/
AddRelationRawConstraints(rel, list_make1(rawEnt), NIL);
}
/*
* This code supports
* CREATE TEMP TABLE ... ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.76 2005/07/14 21:46:29 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.77 2005/08/01 04:03:55 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@ -39,6 +39,7 @@
#include "catalog/namespace.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
@ -2100,3 +2101,171 @@ AlterTypeOwner(List *names, Oid newOwnerId)
/* Clean up */
heap_close(rel, RowExclusiveLock);
}
/*
* Execute ALTER TYPE SET SCHEMA
*/
void
AlterTypeNamespace(List *names, const char *newschema)
{
TypeName *typename;
Oid typeOid;
Oid nspOid;
/* get type OID */
typename = makeNode(TypeName);
typename->names = names;
typename->typmod = -1;
typename->arrayBounds = NIL;
typeOid = LookupTypeName(typename);
if (!OidIsValid(typeOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type \"%s\" does not exist",
TypeNameToString(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);
/* and do the work */
AlterTypeNamespaceInternal(typeOid, nspOid, true);
}
/*
* Move specified type to new namespace.
*
* Caller must have already checked privileges.
*
* If errorOnTableType is TRUE, the function errors out if the type is
* a table type. ALTER TABLE has to be used to move a table to a new
* namespace.
*/
void
AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
bool errorOnTableType)
{
Relation rel;
HeapTuple tup;
Form_pg_type typform;
Oid oldNspOid;
bool isCompositeType;
rel = heap_open(TypeRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy(TYPEOID,
ObjectIdGetDatum(typeOid),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for type %u", typeOid);
typform = (Form_pg_type) GETSTRUCT(tup);
oldNspOid = typform->typnamespace;
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")));
/* check for duplicate name (more friendly than unique-index failure) */
if (SearchSysCacheExists(TYPENAMENSP,
CStringGetDatum(NameStr(typform->typname)),
ObjectIdGetDatum(nspOid),
0, 0))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("type \"%s\" already exists in schema \"%s\"",
NameStr(typform->typname),
get_namespace_name(nspOid))));
/* Detect whether type is a composite type (but not a table rowtype) */
isCompositeType =
(typform->typtype == 'c' &&
get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
/* Enforce not-table-type if requested */
if (typform->typtype == 'c' && !isCompositeType && errorOnTableType)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("%s is a table's row type",
format_type_be(typeOid)),
errhint("Use ALTER TABLE SET SCHEMA instead.")));
/* OK, modify the pg_type row */
/* tup is a copy, so we can scribble directly on it */
typform->typnamespace = nspOid;
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
/*
* Composite types have pg_class entries.
*
* We need to modify the pg_class tuple as well to
* reflect the change of schema.
*/
if (isCompositeType)
{
Relation classRel;
classRel = heap_open(RelationRelationId, RowExclusiveLock);
/*
* The dependency on the schema is listed under the pg_class entry,
* so tell AlterRelationNamespaceInternal to fix it.
*/
AlterRelationNamespaceInternal(classRel, typform->typrelid,
oldNspOid, nspOid,
true);
heap_close(classRel, RowExclusiveLock);
/*
* Check for constraints associated with the composite type
* (we don't currently support this, but probably will someday).
*/
AlterConstraintNamespaces(typform->typrelid, oldNspOid,
nspOid, false);
}
else
{
/* If it's a domain, it might have constraints */
if (typform->typtype == 'd')
AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
/*
* Update dependency on schema, if any --- a table rowtype has not
* got one.
*/
if (typform->typtype != 'c')
if (changeDependencyFor(TypeRelationId, typeOid,
NamespaceRelationId, oldNspOid, nspOid) != 1)
elog(ERROR, "failed to change schema dependency for type %s",
format_type_be(typeOid));
}
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
}

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.313 2005/07/31 17:19:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.314 2005/08/01 04:03:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -2035,12 +2035,27 @@ _copyRenameStmt(RenameStmt *from)
{
RenameStmt *newnode = makeNode(RenameStmt);
COPY_SCALAR_FIELD(renameType);
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(object);
COPY_NODE_FIELD(objarg);
COPY_STRING_FIELD(subname);
COPY_STRING_FIELD(newname);
COPY_SCALAR_FIELD(renameType);
return newnode;
}
static AlterObjectSchemaStmt *
_copyAlterObjectSchemaStmt(AlterObjectSchemaStmt *from)
{
AlterObjectSchemaStmt *newnode = makeNode(AlterObjectSchemaStmt);
COPY_SCALAR_FIELD(objectType);
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(object);
COPY_NODE_FIELD(objarg);
COPY_STRING_FIELD(addname);
COPY_STRING_FIELD(newschema);
return newnode;
}
@ -2050,12 +2065,12 @@ _copyAlterOwnerStmt(AlterOwnerStmt *from)
{
AlterOwnerStmt *newnode = makeNode(AlterOwnerStmt);
COPY_SCALAR_FIELD(objectType);
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(object);
COPY_NODE_FIELD(objarg);
COPY_STRING_FIELD(addname);
COPY_STRING_FIELD(newowner);
COPY_SCALAR_FIELD(objectType);
return newnode;
}
@ -2983,6 +2998,9 @@ copyObject(void *from)
case T_RenameStmt:
retval = _copyRenameStmt(from);
break;
case T_AlterObjectSchemaStmt:
retval = _copyAlterObjectSchemaStmt(from);
break;
case T_AlterOwnerStmt:
retval = _copyAlterOwnerStmt(from);
break;

@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.250 2005/07/31 17:19:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.251 2005/08/01 04:03:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1008,12 +1008,25 @@ _equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
static bool
_equalRenameStmt(RenameStmt *a, RenameStmt *b)
{
COMPARE_SCALAR_FIELD(renameType);
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(object);
COMPARE_NODE_FIELD(objarg);
COMPARE_STRING_FIELD(subname);
COMPARE_STRING_FIELD(newname);
COMPARE_SCALAR_FIELD(renameType);
return true;
}
static bool
_equalAlterObjectSchemaStmt(AlterObjectSchemaStmt *a, AlterObjectSchemaStmt *b)
{
COMPARE_SCALAR_FIELD(objectType);
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(object);
COMPARE_NODE_FIELD(objarg);
COMPARE_STRING_FIELD(addname);
COMPARE_STRING_FIELD(newschema);
return true;
}
@ -1021,12 +1034,12 @@ _equalRenameStmt(RenameStmt *a, RenameStmt *b)
static bool
_equalAlterOwnerStmt(AlterOwnerStmt *a, AlterOwnerStmt *b)
{
COMPARE_SCALAR_FIELD(objectType);
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(object);
COMPARE_NODE_FIELD(objarg);
COMPARE_STRING_FIELD(addname);
COMPARE_STRING_FIELD(newowner);
COMPARE_SCALAR_FIELD(objectType);
return true;
}
@ -2029,6 +2042,9 @@ equal(void *a, void *b)
case T_RenameStmt:
retval = _equalRenameStmt(a, b);
break;
case T_AlterObjectSchemaStmt:
retval = _equalAlterObjectSchemaStmt(a, b);
break;
case T_AlterOwnerStmt:
retval = _equalAlterOwnerStmt(a, b);
break;

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.505 2005/07/31 17:19:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.506 2005/08/01 04:03:56 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -132,7 +132,7 @@ static void doNegateFloat(Value *v);
%type <node> stmt schema_stmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt
AlterOwnerStmt AlterSeqStmt AlterTableStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
@ -493,6 +493,7 @@ stmt :
| AlterDomainStmt
| AlterFunctionStmt
| AlterGroupStmt
| AlterObjectSchemaStmt
| AlterOwnerStmt
| AlterSeqStmt
| AlterTableStmt
@ -3954,10 +3955,10 @@ RenameStmt: ALTER AGGREGATE func_name '(' aggr_argtype ')' RENAME TO name
| ALTER TRIGGER name ON relation_expr RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_TRIGGER;
n->relation = $5;
n->subname = $3;
n->newname = $8;
n->renameType = OBJECT_TRIGGER;
$$ = (Node *)n;
}
| ALTER ROLE RoleId RENAME TO RoleId
@ -3990,10 +3991,68 @@ opt_column: COLUMN { $$ = COLUMN; }
| /*EMPTY*/ { $$ = 0; }
;
/*****************************************************************************
*
* ALTER THING name SET SCHEMA name
*
*****************************************************************************/
AlterObjectSchemaStmt:
ALTER AGGREGATE func_name '(' aggr_argtype ')' SET SCHEMA name
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
n->objectType = OBJECT_AGGREGATE;
n->object = $3;
n->objarg = list_make1($5);
n->newschema = $9;
$$ = (Node *)n;
}
| ALTER DOMAIN_P any_name SET SCHEMA name
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
n->objectType = OBJECT_DOMAIN;
n->object = $3;
n->newschema = $6;
$$ = (Node *)n;
}
| ALTER FUNCTION func_name func_args SET SCHEMA name
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
n->objectType = OBJECT_FUNCTION;
n->object = $3;
n->objarg = extractArgTypes($4);
n->newschema = $7;
$$ = (Node *)n;
}
| ALTER SEQUENCE relation_expr SET SCHEMA name
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
n->objectType = OBJECT_SEQUENCE;
n->relation = $3;
n->newschema = $6;
$$ = (Node *)n;
}
| ALTER TABLE relation_expr SET SCHEMA name
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
n->objectType = OBJECT_TABLE;
n->relation = $3;
n->newschema = $6;
$$ = (Node *)n;
}
| ALTER TYPE_P any_name SET SCHEMA name
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
n->objectType = OBJECT_TYPE;
n->object = $3;
n->newschema = $6;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* ALTER THING name OWNER TO newname.
* ALTER THING name OWNER TO newname
*
*****************************************************************************/

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.242 2005/07/31 17:19:19 tgl Exp $
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.243 2005/08/01 04:03:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -281,6 +281,7 @@ check_xact_readonly(Node *parsetree)
case T_AlterFunctionStmt:
case T_AlterRoleStmt:
case T_AlterRoleSetStmt:
case T_AlterObjectSchemaStmt:
case T_AlterOwnerStmt:
case T_AlterSeqStmt:
case T_AlterTableStmt:
@ -625,6 +626,10 @@ ProcessUtility(Node *parsetree,
ExecRenameStmt((RenameStmt *) parsetree);
break;
case T_AlterObjectSchemaStmt:
ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree);
break;
case T_AlterOwnerStmt:
ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
break;
@ -1358,6 +1363,10 @@ CreateCommandTag(Node *parsetree)
case OBJECT_SCHEMA:
tag = "ALTER SCHEMA";
break;
case OBJECT_COLUMN:
case OBJECT_TABLE:
tag = "ALTER TABLE";
break;
case OBJECT_TABLESPACE:
tag = "ALTER TABLESPACE";
break;
@ -1365,10 +1374,38 @@ CreateCommandTag(Node *parsetree)
tag = "ALTER TRIGGER";
break;
default:
tag = "ALTER TABLE";
tag = "???";
break;
}
break;
case T_AlterObjectSchemaStmt:
switch (((AlterObjectSchemaStmt *) parsetree)->objectType)
{
case OBJECT_AGGREGATE:
tag = "ALTER AGGREGATE";
break;
case OBJECT_DOMAIN:
tag = "ALTER DOMAIN";
break;
case OBJECT_FUNCTION:
tag = "ALTER FUNCTION";
break;
case OBJECT_SEQUENCE:
tag = "ALTER SEQUENCE";
break;
case OBJECT_TABLE:
tag = "ALTER TABLE";
break;
case OBJECT_TYPE:
tag = "ALTER TYPE";
break;
default:
tag = "???";
break;
}
break;
case T_AlterOwnerStmt:
switch (((AlterOwnerStmt *) parsetree)->objectType)
{
@ -1403,7 +1440,8 @@ CreateCommandTag(Node *parsetree)
tag = "ALTER TYPE";
break;
default:
tag = "ALTER TABLE";
tag = "???";
break;
}
break;

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.15 2005/07/07 20:39:59 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.16 2005/08/01 04:03:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -174,6 +174,10 @@ extern void recordMultipleDependencies(const ObjectAddress *depender,
extern long deleteDependencyRecordsFor(Oid classId, Oid objectId);
extern long changeDependencyFor(Oid classId, Oid objectId,
Oid refClassId, Oid oldRefObjectId,
Oid newRefObjectId);
/* in pg_shdepend.c */
extern void recordSharedDependencyOn(ObjectAddress *depender,

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.35 2004/12/31 22:03:24 pgsql Exp $
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.36 2005/08/01 04:03:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -74,12 +74,14 @@ extern void DeconstructQualifiedName(List *names,
char **objname_p);
extern Oid LookupExplicitNamespace(const char *nspname);
extern Oid LookupCreationNamespace(const char *nspname);
extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p);
extern RangeVar *makeRangeVarFromNameList(List *names);
extern char *NameListToString(List *names);
extern char *NameListToQuotedString(List *names);
extern bool isTempNamespace(Oid namespaceId);
extern bool isAnyTempNamespace(Oid namespaceId);
extern bool isOtherTempNamespace(Oid namespaceId);
extern void PushSpecialNamespace(Oid namespaceId);

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.16 2005/04/14 01:38:20 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_constraint.h,v 1.17 2005/08/01 04:03:57 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -185,4 +185,7 @@ extern char *ChooseConstraintName(const char *name1, const char *name2,
extern char *GetConstraintNameForTrigger(Oid triggerId);
extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
Oid newNspId, bool isType);
#endif /* PG_CONSTRAINT_H */

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/commands/alter.h,v 1.6 2004/12/31 22:03:28 pgsql Exp $
* $PostgreSQL: pgsql/src/include/commands/alter.h,v 1.7 2005/08/01 04:03:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -17,7 +17,7 @@
#include "nodes/parsenodes.h"
extern void ExecRenameStmt(RenameStmt *stmt);
extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt);
extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt);
#endif /* ALTER_H */

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.66 2005/06/28 05:09:12 tgl Exp $
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.67 2005/08/01 04:03:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -55,6 +55,8 @@ extern void AlterFunction(AlterFunctionStmt *stmt);
extern void CreateCast(CreateCastStmt *stmt);
extern void DropCast(DropCastStmt *stmt);
extern void DropCastById(Oid castOid);
extern void AlterFunctionNamespace(List *name, List *argtypes,
const char *newschema);
/* commands/operatorcmds.c */
extern void DefineOperator(List *names, List *parameters);

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.22 2005/01/27 03:18:24 tgl Exp $
* $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.23 2005/08/01 04:03:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -15,6 +15,7 @@
#define TABLECMDS_H
#include "nodes/parsenodes.h"
#include "utils/rel.h"
extern Oid DefineRelation(CreateStmt *stmt, char relkind);
@ -27,6 +28,12 @@ extern void AlterTableInternal(Oid relid, List *cmds, bool recurse);
extern void AlterTableCreateToastTable(Oid relOid, bool silent);
extern void AlterTableNamespace(RangeVar *relation, const char *newschema);
extern void AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
Oid oldNspOid, Oid newNspOid,
bool hasDependEntry);
extern void ExecuteTruncate(List *relations);
extern void renameatt(Oid myrelid,

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.11 2005/06/28 05:09:12 tgl Exp $
* $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.12 2005/08/01 04:03:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -35,5 +35,8 @@ extern void AlterDomainDropConstraint(List *names, const char *constrName,
extern List *GetDomainConstraints(Oid typeOid);
extern void AlterTypeOwner(List *names, Oid newOwnerId);
extern void AlterTypeNamespace(List *names, const char *newschema);
extern void AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
bool errorOnTableType);
#endif /* TYPECMDS_H */

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.173 2005/07/31 17:19:21 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.174 2005/08/01 04:03:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -284,6 +284,7 @@ typedef enum NodeTag
T_DeclareCursorStmt,
T_CreateTableSpaceStmt,
T_DropTableSpaceStmt,
T_AlterObjectSchemaStmt,
T_AlterOwnerStmt,
T_A_Expr = 800,

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.287 2005/07/31 17:19:21 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.288 2005/08/01 04:03:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1477,15 +1477,30 @@ typedef struct RemoveOpClassStmt
typedef struct RenameStmt
{
NodeTag type;
ObjectType renameType; /* OBJECT_TABLE, OBJECT_COLUMN, etc */
RangeVar *relation; /* in case it's a table */
List *object; /* in case it's some other object */
List *objarg; /* argument types, if applicable */
char *subname; /* name of contained object (column, rule,
* trigger, etc) */
char *newname; /* the new name */
ObjectType renameType; /* OBJECT_TABLE, OBJECT_COLUMN, etc */
} RenameStmt;
/* ----------------------
* ALTER object SET SCHEMA Statement
* ----------------------
*/
typedef struct AlterObjectSchemaStmt
{
NodeTag type;
ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */
RangeVar *relation; /* in case it's a table */
List *object; /* in case it's some other object */
List *objarg; /* argument types, if applicable */
char *addname; /* additional name if needed */
char *newschema; /* the new schema */
} AlterObjectSchemaStmt;
/* ----------------------
* Alter Object Owner Statement
* ----------------------
@ -1493,12 +1508,12 @@ typedef struct RenameStmt
typedef struct AlterOwnerStmt
{
NodeTag type;
ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */
RangeVar *relation; /* in case it's a table */
List *object; /* in case it's some other object */
List *objarg; /* argument types, if applicable */
char *addname; /* additional name if needed */
char *newowner; /* the new owner */
ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */
} AlterOwnerStmt;

@ -1274,3 +1274,62 @@ select non_strict(NULL);
(1 row)
--
-- alter object set schema
--
create schema alter1;
create schema alter2;
create table alter1.t1(f1 serial primary key, f2 int check (f2 > 0));
NOTICE: CREATE TABLE will create implicit sequence "t1_f1_seq" for serial column "t1.f1"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "t1_pkey" for table "t1"
create view alter1.v1 as select * from alter1.t1;
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);
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 type alter1.ctype set schema alter2;
-- this should succeed because nothing is left in alter1
drop schema alter1;
insert into alter2.t1(f2) values(13);
insert into alter2.t1(f2) values(14);
select * from alter2.t1;
f1 | f2
----+----
1 | 11
2 | 12
3 | 13
4 | 14
(4 rows)
select * from alter2.v1;
f1 | f2
----+----
1 | 11
2 | 12
3 | 13
4 | 14
(4 rows)
select alter2.plus1(41);
plus1
-------
42
(1 row)
-- clean up
drop schema alter2 cascade;
NOTICE: drop cascades to composite type alter2.ctype
NOTICE: drop cascades to type alter2.ctype
NOTICE: drop cascades to type alter2.posint
NOTICE: drop cascades to function alter2.plus1(integer)
NOTICE: drop cascades to view alter2.v1
NOTICE: drop cascades to rule _RETURN on view alter2.v1
NOTICE: drop cascades to sequence alter2.t1_f1_seq
NOTICE: drop cascades to table alter2.t1 column f1
NOTICE: drop cascades to table alter2.t1
NOTICE: drop cascades to constraint t1_f2_check on table alter2.t1

@ -998,3 +998,44 @@ create function non_strict(text) returns text as
select non_strict(NULL);
alter function non_strict(text) returns null on null input;
select non_strict(NULL);
--
-- alter object set schema
--
create schema alter1;
create schema alter2;
create table alter1.t1(f1 serial primary key, f2 int check (f2 > 0));
create view alter1.v1 as select * from alter1.t1;
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);
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 type alter1.ctype set schema alter2;
-- this should succeed because nothing is left in alter1
drop schema alter1;
insert into alter2.t1(f2) values(13);
insert into alter2.t1(f2) values(14);
select * from alter2.t1;
select * from alter2.v1;
select alter2.plus1(41);
-- clean up
drop schema alter2 cascade;

Loading…
Cancel
Save