2003-06-27 14:45:32 +00:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* alter.c
|
|
|
|
* Drivers for generic alter commands
|
|
|
|
*
|
2004-12-31 22:04:05 +00:00
|
|
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
2003-06-27 14:45:32 +00:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2006-02-11 22:17:19 +00:00
|
|
|
* $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.16 2006/02/11 22:17:18 momjian Exp $
|
2003-06-27 14:45:32 +00:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "access/htup.h"
|
|
|
|
#include "catalog/catalog.h"
|
2006-02-11 22:17:19 +00:00
|
|
|
#include "catalog/dependency.h"
|
2003-06-27 14:45:32 +00:00
|
|
|
#include "catalog/namespace.h"
|
|
|
|
#include "catalog/pg_class.h"
|
2006-02-11 22:17:19 +00:00
|
|
|
#include "catalog/pg_constraint.h"
|
2003-06-27 14:45:32 +00:00
|
|
|
#include "commands/alter.h"
|
|
|
|
#include "commands/conversioncmds.h"
|
|
|
|
#include "commands/dbcommands.h"
|
|
|
|
#include "commands/defrem.h"
|
|
|
|
#include "commands/proclang.h"
|
|
|
|
#include "commands/schemacmds.h"
|
|
|
|
#include "commands/tablecmds.h"
|
2004-06-25 21:55:59 +00:00
|
|
|
#include "commands/tablespace.h"
|
2003-06-27 14:45:32 +00:00
|
|
|
#include "commands/trigger.h"
|
2004-06-25 21:55:59 +00:00
|
|
|
#include "commands/typecmds.h"
|
2003-06-27 14:45:32 +00:00
|
|
|
#include "commands/user.h"
|
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "parser/parse_clause.h"
|
2003-07-22 19:00:12 +00:00
|
|
|
#include "tcop/utility.h"
|
2003-06-27 14:45:32 +00:00
|
|
|
#include "utils/acl.h"
|
|
|
|
#include "utils/lsyscache.h"
|
|
|
|
#include "utils/syscache.h"
|
|
|
|
|
|
|
|
|
2004-06-25 21:55:59 +00:00
|
|
|
/*
|
2004-08-29 05:07:03 +00:00
|
|
|
* Executes an ALTER OBJECT / RENAME TO statement. Based on the object
|
2004-06-25 21:55:59 +00:00
|
|
|
* type, the function appropriate to that type is executed.
|
|
|
|
*/
|
2003-06-27 14:45:32 +00:00
|
|
|
void
|
|
|
|
ExecRenameStmt(RenameStmt *stmt)
|
|
|
|
{
|
|
|
|
switch (stmt->renameType)
|
|
|
|
{
|
|
|
|
case OBJECT_AGGREGATE:
|
2004-05-26 04:41:50 +00:00
|
|
|
RenameAggregate(stmt->object,
|
|
|
|
(TypeName *) linitial(stmt->objarg),
|
|
|
|
stmt->newname);
|
2003-06-27 14:45:32 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_CONVERSION:
|
|
|
|
RenameConversion(stmt->object, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_DATABASE:
|
|
|
|
RenameDatabase(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_FUNCTION:
|
|
|
|
RenameFunction(stmt->object, stmt->objarg, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_LANGUAGE:
|
|
|
|
RenameLanguage(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_OPCLASS:
|
|
|
|
RenameOpClass(stmt->object, stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2005-06-28 05:09:14 +00:00
|
|
|
case OBJECT_ROLE:
|
|
|
|
RenameRole(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2003-06-27 14:45:32 +00:00
|
|
|
case OBJECT_SCHEMA:
|
|
|
|
RenameSchema(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2004-06-25 21:55:59 +00:00
|
|
|
case OBJECT_TABLESPACE:
|
|
|
|
RenameTableSpace(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2003-06-27 14:45:32 +00:00
|
|
|
case OBJECT_TABLE:
|
2004-08-22 00:08:28 +00:00
|
|
|
case OBJECT_INDEX:
|
2003-06-27 14:45:32 +00:00
|
|
|
case OBJECT_COLUMN:
|
|
|
|
case OBJECT_TRIGGER:
|
2006-02-11 22:17:19 +00:00
|
|
|
case OBJECT_CONSTRAINT:
|
2003-08-04 00:43:34 +00:00
|
|
|
{
|
|
|
|
Oid relid;
|
2003-06-27 14:45:32 +00:00
|
|
|
|
2003-08-04 00:43:34 +00:00
|
|
|
CheckRelationOwnership(stmt->relation, true);
|
2003-06-27 14:45:32 +00:00
|
|
|
|
2003-08-04 00:43:34 +00:00
|
|
|
relid = RangeVarGetRelid(stmt->relation, false);
|
2003-06-27 14:45:32 +00:00
|
|
|
|
2003-08-04 00:43:34 +00:00
|
|
|
switch (stmt->renameType)
|
2003-06-27 14:45:32 +00:00
|
|
|
{
|
2003-08-04 00:43:34 +00:00
|
|
|
case OBJECT_TABLE:
|
2004-08-22 00:08:28 +00:00
|
|
|
case OBJECT_INDEX:
|
2003-08-04 00:43:34 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* RENAME TABLE requires that we (still) hold
|
2005-10-15 02:49:52 +00:00
|
|
|
* CREATE rights on the containing namespace, as
|
|
|
|
* well as ownership of the table.
|
2003-08-04 00:43:34 +00:00
|
|
|
*/
|
|
|
|
Oid namespaceId = get_rel_namespace(relid);
|
|
|
|
AclResult aclresult;
|
|
|
|
|
|
|
|
aclresult = pg_namespace_aclcheck(namespaceId,
|
2006-02-11 22:17:19 +00:00
|
|
|
GetUserId(), ACL_CREATE);
|
2003-08-04 00:43:34 +00:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
|
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
2005-10-15 02:49:52 +00:00
|
|
|
get_namespace_name(namespaceId));
|
2003-08-04 00:43:34 +00:00
|
|
|
|
2006-02-11 22:17:19 +00:00
|
|
|
/*
|
|
|
|
* Do NOT refer to stmt->renameType here because
|
|
|
|
* you can also rename an index with ALTER TABLE
|
|
|
|
*/
|
|
|
|
if (get_rel_relkind(relid) == RELKIND_INDEX)
|
|
|
|
{
|
|
|
|
/* see if we depend on a constraint */
|
|
|
|
List* depOids = getDependentOids(
|
|
|
|
RelationRelationId, relid,
|
|
|
|
ConstraintRelationId,
|
|
|
|
DEPENDENCY_INTERNAL);
|
|
|
|
|
|
|
|
/* there should only be one constraint */
|
|
|
|
Assert(list_length(depOids) <= 1);
|
|
|
|
if (list_length(depOids) == 1)
|
|
|
|
{
|
|
|
|
Oid conRelId = linitial_oid(depOids);
|
|
|
|
/*
|
|
|
|
* Apply the same name to the
|
|
|
|
* constraint and tell it that this
|
|
|
|
* is an implicit rename triggered
|
|
|
|
* by an "ALTER INDEX" command.
|
|
|
|
*/
|
|
|
|
RenameConstraint(conRelId,
|
|
|
|
stmt->newname, true, "ALTER INDEX");
|
|
|
|
}
|
|
|
|
}
|
2003-08-04 00:43:34 +00:00
|
|
|
renamerel(relid, stmt->newname);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case OBJECT_COLUMN:
|
|
|
|
renameatt(relid,
|
|
|
|
stmt->subname, /* old att name */
|
|
|
|
stmt->newname, /* new att name */
|
2005-10-15 02:49:52 +00:00
|
|
|
interpretInhOption(stmt->relation->inhOpt), /* recursive? */
|
2003-08-04 00:43:34 +00:00
|
|
|
false); /* recursing already? */
|
|
|
|
break;
|
|
|
|
case OBJECT_TRIGGER:
|
|
|
|
renametrig(relid,
|
|
|
|
stmt->subname, /* old att name */
|
|
|
|
stmt->newname); /* new att name */
|
|
|
|
break;
|
2006-02-11 22:17:19 +00:00
|
|
|
case OBJECT_CONSTRAINT:
|
|
|
|
/* XXX could do extra function renameconstr() - but I
|
|
|
|
* don't know where it should go */
|
|
|
|
/* renameconstr(relid,
|
|
|
|
stmt->subname,
|
|
|
|
stmt->newname); */
|
|
|
|
{
|
|
|
|
List *depRelOids;
|
|
|
|
ListCell *l;
|
|
|
|
Oid conId =
|
|
|
|
GetRelationConstraintOid(relid,
|
|
|
|
stmt->subname);
|
|
|
|
if (!OidIsValid(conId)) {
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("constraint with name \"%s\" "
|
|
|
|
"does not exist",
|
|
|
|
stmt->subname)));
|
|
|
|
}
|
|
|
|
RenameConstraint(conId, stmt->newname,
|
|
|
|
false, NULL);
|
|
|
|
depRelOids = getReferencingOids(
|
|
|
|
ConstraintRelationId, conId, 0,
|
|
|
|
RelationRelationId,
|
|
|
|
DEPENDENCY_INTERNAL);
|
|
|
|
foreach(l, depRelOids)
|
|
|
|
{
|
|
|
|
Oid depRelOid;
|
|
|
|
Oid nspOid;
|
|
|
|
depRelOid = lfirst_oid(l);
|
|
|
|
nspOid = get_rel_namespace(depRelOid);
|
|
|
|
if (get_rel_relkind(depRelOid) == RELKIND_INDEX)
|
|
|
|
{
|
|
|
|
ereport(NOTICE,
|
|
|
|
(errmsg("ALTER TABLE / CONSTRAINT will implicitly rename index "
|
|
|
|
"\"%s\" to \"%s\" on table \"%s.%s\"",
|
|
|
|
get_rel_name(depRelOid),
|
|
|
|
stmt->newname,
|
|
|
|
get_namespace_name(nspOid),
|
|
|
|
get_rel_name(relid))));
|
|
|
|
renamerel(depRelOid, stmt->newname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2003-08-04 00:43:34 +00:00
|
|
|
default:
|
|
|
|
/* can't happen */ ;
|
|
|
|
}
|
|
|
|
break;
|
2003-06-27 14:45:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2003-07-20 21:56:35 +00:00
|
|
|
elog(ERROR, "unrecognized rename stmt type: %d",
|
|
|
|
(int) stmt->renameType);
|
2003-06-27 14:45:32 +00:00
|
|
|
}
|
|
|
|
}
|
2004-06-25 21:55:59 +00:00
|
|
|
|
2005-08-01 04:03:59 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
2005-10-15 02:49:52 +00:00
|
|
|
|
2005-08-01 04:03:59 +00:00
|
|
|
case OBJECT_SEQUENCE:
|
|
|
|
case OBJECT_TABLE:
|
|
|
|
CheckRelationOwnership(stmt->relation, true);
|
|
|
|
AlterTableNamespace(stmt->relation, stmt->newschema);
|
|
|
|
break;
|
2005-10-15 02:49:52 +00:00
|
|
|
|
2005-08-01 04:03:59 +00:00
|
|
|
case OBJECT_TYPE:
|
|
|
|
case OBJECT_DOMAIN:
|
|
|
|
AlterTypeNamespace(stmt->object, stmt->newschema);
|
|
|
|
break;
|
2005-10-15 02:49:52 +00:00
|
|
|
|
2005-08-01 04:03:59 +00:00
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
|
|
|
|
(int) stmt->objectType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-25 21:55:59 +00:00
|
|
|
/*
|
|
|
|
* Executes an ALTER OBJECT / OWNER TO statement. Based on the object
|
|
|
|
* type, the function appropriate to that type is executed.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
|
|
|
|
{
|
2005-10-15 02:49:52 +00:00
|
|
|
Oid newowner = get_roleid_checked(stmt->newowner);
|
2004-06-25 21:55:59 +00:00
|
|
|
|
|
|
|
switch (stmt->objectType)
|
|
|
|
{
|
|
|
|
case OBJECT_AGGREGATE:
|
|
|
|
AlterAggregateOwner(stmt->object,
|
|
|
|
(TypeName *) linitial(stmt->objarg),
|
|
|
|
newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_CONVERSION:
|
|
|
|
AlterConversionOwner(stmt->object, newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_DATABASE:
|
|
|
|
AlterDatabaseOwner((char *) linitial(stmt->object), newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_FUNCTION:
|
|
|
|
AlterFunctionOwner(stmt->object, stmt->objarg, newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_OPERATOR:
|
|
|
|
AlterOperatorOwner(stmt->object,
|
|
|
|
(TypeName *) linitial(stmt->objarg),
|
|
|
|
(TypeName *) lsecond(stmt->objarg),
|
|
|
|
newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_OPCLASS:
|
|
|
|
AlterOpClassOwner(stmt->object, stmt->addname, newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_SCHEMA:
|
|
|
|
AlterSchemaOwner((char *) linitial(stmt->object), newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TABLESPACE:
|
|
|
|
AlterTableSpaceOwner((char *) linitial(stmt->object), newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TYPE:
|
|
|
|
case OBJECT_DOMAIN: /* same as TYPE */
|
|
|
|
AlterTypeOwner(stmt->object, newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
|
|
|
|
(int) stmt->objectType);
|
|
|
|
}
|
|
|
|
}
|