object kinds (tables, functions, types). Documentation is not here yet.
Original code by Bernd Helmle, extensive rework by Bruce Momjian and
Tom Lane.
* 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 $
*
*-------------------------------------------------------------------------
*/
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.
*/
errmsg("no schema has been selected to create in")));
}
- /* Note: callers will check for CREATE rights when appropriate */
-
*objname_p = objname;
return 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? */
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.
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
+}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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()
*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
}
}
+/*
+ * 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.
*
*
* 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
#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"
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);
+}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
}
+/*
+ * 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 }
*
*
* 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
#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"
/* 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);
+}
* 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 $
*
*-------------------------------------------------------------------------
*/
{
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;
}
{
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;
}
case T_RenameStmt:
retval = _copyRenameStmt(from);
break;
+ case T_AlterObjectSchemaStmt:
+ retval = _copyAlterObjectSchemaStmt(from);
+ break;
case T_AlterOwnerStmt:
retval = _copyAlterOwnerStmt(from);
break;
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
}
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;
}
case T_RenameStmt:
retval = _equalRenameStmt(a, b);
break;
+ case T_AlterObjectSchemaStmt:
+ retval = _equalAlterObjectSchemaStmt(a, b);
+ break;
case T_AlterOwnerStmt:
retval = _equalAlterOwnerStmt(a, b);
break;
*
*
* 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
%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
| AlterDomainStmt
| AlterFunctionStmt
| AlterGroupStmt
+ | AlterObjectSchemaStmt
| AlterOwnerStmt
| AlterSeqStmt
| AlterTableStmt
| 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
| /*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
*
*****************************************************************************/
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
case T_AlterFunctionStmt:
case T_AlterRoleStmt:
case T_AlterRoleSetStmt:
+ case T_AlterObjectSchemaStmt:
case T_AlterOwnerStmt:
case T_AlterSeqStmt:
case T_AlterTableStmt:
ExecRenameStmt((RenameStmt *) parsetree);
break;
+ case T_AlterObjectSchemaStmt:
+ ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree);
+ break;
+
case T_AlterOwnerStmt:
ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
break;
case OBJECT_SCHEMA:
tag = "ALTER SCHEMA";
break;
+ case OBJECT_COLUMN:
+ case OBJECT_TABLE:
+ tag = "ALTER TABLE";
+ break;
case OBJECT_TABLESPACE:
tag = "ALTER TABLESPACE";
break;
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)
{
tag = "ALTER TYPE";
break;
default:
- tag = "ALTER TABLE";
+ tag = "???";
+ break;
}
break;
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
* 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
extern char *GetConstraintNameForTrigger(Oid triggerId);
+extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
+ Oid newNspId, bool isType);
+
#endif /* PG_CONSTRAINT_H */
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "nodes/parsenodes.h"
extern void ExecRenameStmt(RenameStmt *stmt);
-
+extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt);
extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt);
#endif /* ALTER_H */
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
#define TABLECMDS_H
#include "nodes/parsenodes.h"
+#include "utils/rel.h"
extern Oid DefineRelation(CreateStmt *stmt, char relkind);
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,
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
T_DeclareCursorStmt,
T_CreateTableSpaceStmt,
T_DropTableSpaceStmt,
+ T_AlterObjectSchemaStmt,
T_AlterOwnerStmt,
T_A_Expr = 800,
* 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 $
*
*-------------------------------------------------------------------------
*/
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
* ----------------------
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;
(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
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;