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.
This commit is contained in:
Tom Lane 2005-08-01 04:03:59 +00:00
parent a85e5d1b1b
commit 35508d1cca
22 changed files with 1095 additions and 41 deletions

View File

@ -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.

View File

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

View File

@ -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()
*

View File

@ -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.

View File

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

View File

@ -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 }

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -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
*
*****************************************************************************/

View File

@ -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;

View File

@ -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,

View File

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

View File

@ -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 */

View File

@ -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 */

View File

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

View File

@ -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,

View File

@ -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 */

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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;