mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
First batch of object rename commands.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
# Makefile for backend/commands
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.31 2002/08/27 04:55:07 tgl Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.32 2003/06/27 14:45:27 petere Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -12,7 +12,7 @@ subdir = src/backend/commands
|
||||
top_builddir = ../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
OBJS = aggregatecmds.o analyze.o async.o cluster.o comment.o \
|
||||
OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
|
||||
conversioncmds.o copy.o \
|
||||
dbcommands.o define.o explain.o functioncmds.o \
|
||||
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.7 2003/06/25 21:30:26 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.8 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
@@ -193,3 +194,75 @@ RemoveAggregate(RemoveAggrStmt *stmt)
|
||||
|
||||
performDeletion(&object, stmt->behavior);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RenameAggregate(List *name, TypeName *basetype, const char *newname)
|
||||
{
|
||||
Oid basetypeOid;
|
||||
Oid procOid;
|
||||
Oid namespaceOid;
|
||||
Oid oid_array[FUNC_MAX_ARGS];
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
AclResult aclresult;
|
||||
|
||||
/*
|
||||
* if a basetype is passed in, then attempt to find an aggregate for
|
||||
* that specific type.
|
||||
*
|
||||
* else attempt to find an aggregate with a basetype of ANYOID. This
|
||||
* means that the aggregate is to apply to all basetypes (eg, COUNT).
|
||||
*/
|
||||
if (basetype)
|
||||
basetypeOid = typenameTypeId(basetype);
|
||||
else
|
||||
basetypeOid = ANYOID;
|
||||
|
||||
rel = heap_openr(ProcedureRelationName, RowExclusiveLock);
|
||||
|
||||
procOid = find_aggregate_func("RenameAggregate", name, basetypeOid);
|
||||
|
||||
tup = SearchSysCacheCopy(PROCOID,
|
||||
ObjectIdGetDatum(procOid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "RenameAggregate: couldn't find pg_proc tuple for %s",
|
||||
NameListToString(name));
|
||||
|
||||
namespaceOid = ((Form_pg_proc) GETSTRUCT(tup))->pronamespace;
|
||||
|
||||
/* make sure the new name doesn't exist */
|
||||
MemSet(oid_array, 0, sizeof(oid_array));
|
||||
oid_array[0] = basetypeOid;
|
||||
if (SearchSysCacheExists(PROCNAMENSP,
|
||||
CStringGetDatum(newname),
|
||||
Int16GetDatum(1),
|
||||
PointerGetDatum(oid_array),
|
||||
ObjectIdGetDatum(namespaceOid)))
|
||||
{
|
||||
if (basetypeOid == ANYOID)
|
||||
elog(ERROR, "function %s(*) already exists in schema %s",
|
||||
newname, get_namespace_name(namespaceOid));
|
||||
else
|
||||
elog(ERROR, "function %s(%s) already exists in schema %s",
|
||||
newname, format_type_be(basetypeOid), get_namespace_name(namespaceOid));
|
||||
}
|
||||
|
||||
/* must be owner */
|
||||
if (!pg_proc_ownercheck(procOid, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(name));
|
||||
|
||||
/* must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, get_namespace_name(namespaceOid));
|
||||
|
||||
/* rename */
|
||||
namestrcpy(&(((Form_pg_proc) GETSTRUCT(tup))->proname), newname);
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
159
src/backend/commands/alter.c
Normal file
159
src/backend/commands/alter.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* alter.c
|
||||
* Drivers for generic alter commands
|
||||
*
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/alter.c,v 1.1 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/htup.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_class.h"
|
||||
#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"
|
||||
#include "commands/trigger.h"
|
||||
#include "commands/user.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/parse_clause.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static void
|
||||
CheckOwnership(RangeVar *rel, bool noCatalogs)
|
||||
{
|
||||
Oid relOid;
|
||||
HeapTuple tuple;
|
||||
|
||||
relOid = RangeVarGetRelid(rel, false);
|
||||
tuple = SearchSysCache(RELOID,
|
||||
ObjectIdGetDatum(relOid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "Relation \"%s\" does not exist", rel->relname);
|
||||
|
||||
if (!pg_class_ownercheck(relOid, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, rel->relname);
|
||||
|
||||
if (noCatalogs)
|
||||
{
|
||||
if (!allowSystemTableMods &&
|
||||
IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
|
||||
elog(ERROR, "relation \"%s\" is a system catalog",
|
||||
rel->relname);
|
||||
}
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExecRenameStmt(RenameStmt *stmt)
|
||||
{
|
||||
switch (stmt->renameType)
|
||||
{
|
||||
case OBJECT_AGGREGATE:
|
||||
RenameAggregate(stmt->object, (TypeName *) lfirst(stmt->objarg), stmt->newname);
|
||||
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_GROUP:
|
||||
RenameGroup(stmt->subname, stmt->newname);
|
||||
break;
|
||||
|
||||
case OBJECT_LANGUAGE:
|
||||
RenameLanguage(stmt->subname, stmt->newname);
|
||||
break;
|
||||
|
||||
case OBJECT_OPCLASS:
|
||||
RenameOpClass(stmt->object, stmt->subname, stmt->newname);
|
||||
break;
|
||||
|
||||
case OBJECT_SCHEMA:
|
||||
RenameSchema(stmt->subname, stmt->newname);
|
||||
break;
|
||||
|
||||
case OBJECT_USER:
|
||||
RenameUser(stmt->subname, stmt->newname);
|
||||
break;
|
||||
|
||||
case OBJECT_TABLE:
|
||||
case OBJECT_COLUMN:
|
||||
case OBJECT_TRIGGER:
|
||||
{
|
||||
Oid relid;
|
||||
|
||||
CheckOwnership(stmt->relation, true);
|
||||
|
||||
relid = RangeVarGetRelid(stmt->relation, false);
|
||||
|
||||
switch (stmt->renameType)
|
||||
{
|
||||
case OBJECT_TABLE:
|
||||
{
|
||||
/*
|
||||
* RENAME TABLE requires that we (still) hold
|
||||
* CREATE rights on the containing namespace, as
|
||||
* well as ownership of the table.
|
||||
*/
|
||||
Oid namespaceId = get_rel_namespace(relid);
|
||||
AclResult aclresult;
|
||||
|
||||
aclresult = pg_namespace_aclcheck(namespaceId,
|
||||
GetUserId(),
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult,
|
||||
get_namespace_name(namespaceId));
|
||||
|
||||
renamerel(relid, stmt->newname);
|
||||
break;
|
||||
}
|
||||
case OBJECT_COLUMN:
|
||||
renameatt(relid,
|
||||
stmt->subname, /* old att name */
|
||||
stmt->newname, /* new att name */
|
||||
interpretInhOption(stmt->relation->inhOpt), /* recursive? */
|
||||
false); /* recursing already? */
|
||||
break;
|
||||
case OBJECT_TRIGGER:
|
||||
renametrig(relid,
|
||||
stmt->subname, /* old att name */
|
||||
stmt->newname); /* new att name */
|
||||
break;
|
||||
default:
|
||||
/*can't happen*/;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
elog(ERROR, "invalid object type for RenameStmt: %d", stmt->renameType);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.54 2003/05/27 17:49:45 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.55 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -192,7 +192,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
onerel = relation_open(relid, AccessShareLock);
|
||||
|
||||
if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
|
||||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
|
||||
(pg_database_ownercheck(MyDatabaseId, GetUserId()) && !onerel->rd_rel->relisshared)))
|
||||
{
|
||||
/* No need for a WARNING if we already complained during VACUUM */
|
||||
if (!vacstmt->vacuum)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.62 2003/03/10 22:28:18 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.63 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -71,40 +71,40 @@ CommentObject(CommentStmt *stmt)
|
||||
{
|
||||
switch (stmt->objtype)
|
||||
{
|
||||
case COMMENT_ON_INDEX:
|
||||
case COMMENT_ON_SEQUENCE:
|
||||
case COMMENT_ON_TABLE:
|
||||
case COMMENT_ON_VIEW:
|
||||
case OBJECT_INDEX:
|
||||
case OBJECT_SEQUENCE:
|
||||
case OBJECT_TABLE:
|
||||
case OBJECT_VIEW:
|
||||
CommentRelation(stmt->objtype, stmt->objname, stmt->comment);
|
||||
break;
|
||||
case COMMENT_ON_COLUMN:
|
||||
case OBJECT_COLUMN:
|
||||
CommentAttribute(stmt->objname, stmt->comment);
|
||||
break;
|
||||
case COMMENT_ON_DATABASE:
|
||||
case OBJECT_DATABASE:
|
||||
CommentDatabase(stmt->objname, stmt->comment);
|
||||
break;
|
||||
case COMMENT_ON_RULE:
|
||||
case OBJECT_RULE:
|
||||
CommentRule(stmt->objname, stmt->comment);
|
||||
break;
|
||||
case COMMENT_ON_TYPE:
|
||||
case OBJECT_TYPE:
|
||||
CommentType(stmt->objname, stmt->comment);
|
||||
break;
|
||||
case COMMENT_ON_AGGREGATE:
|
||||
case OBJECT_AGGREGATE:
|
||||
CommentAggregate(stmt->objname, stmt->objargs, stmt->comment);
|
||||
break;
|
||||
case COMMENT_ON_FUNCTION:
|
||||
case OBJECT_FUNCTION:
|
||||
CommentProc(stmt->objname, stmt->objargs, stmt->comment);
|
||||
break;
|
||||
case COMMENT_ON_OPERATOR:
|
||||
case OBJECT_OPERATOR:
|
||||
CommentOperator(stmt->objname, stmt->objargs, stmt->comment);
|
||||
break;
|
||||
case COMMENT_ON_TRIGGER:
|
||||
case OBJECT_TRIGGER:
|
||||
CommentTrigger(stmt->objname, stmt->comment);
|
||||
break;
|
||||
case COMMENT_ON_SCHEMA:
|
||||
case OBJECT_SCHEMA:
|
||||
CommentNamespace(stmt->objname, stmt->comment);
|
||||
break;
|
||||
case COMMENT_ON_CONSTRAINT:
|
||||
case OBJECT_CONSTRAINT:
|
||||
CommentConstraint(stmt->objname, stmt->comment);
|
||||
break;
|
||||
default:
|
||||
@@ -301,22 +301,22 @@ CommentRelation(int objtype, List *relname, char *comment)
|
||||
|
||||
switch (objtype)
|
||||
{
|
||||
case COMMENT_ON_INDEX:
|
||||
case OBJECT_INDEX:
|
||||
if (relation->rd_rel->relkind != RELKIND_INDEX)
|
||||
elog(ERROR, "relation \"%s\" is not an index",
|
||||
RelationGetRelationName(relation));
|
||||
break;
|
||||
case COMMENT_ON_SEQUENCE:
|
||||
case OBJECT_SEQUENCE:
|
||||
if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
|
||||
elog(ERROR, "relation \"%s\" is not a sequence",
|
||||
RelationGetRelationName(relation));
|
||||
break;
|
||||
case COMMENT_ON_TABLE:
|
||||
case OBJECT_TABLE:
|
||||
if (relation->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "relation \"%s\" is not a table",
|
||||
RelationGetRelationName(relation));
|
||||
break;
|
||||
case COMMENT_ON_VIEW:
|
||||
case OBJECT_VIEW:
|
||||
if (relation->rd_rel->relkind != RELKIND_VIEW)
|
||||
elog(ERROR, "relation \"%s\" is not a view",
|
||||
RelationGetRelationName(relation));
|
||||
@@ -410,7 +410,7 @@ CommentDatabase(List *qualname, char *comment)
|
||||
|
||||
/* Allow if the user matches the database dba or is a superuser */
|
||||
|
||||
if (!(superuser() || is_dbadmin(oid)))
|
||||
if (!pg_database_ownercheck(oid, GetUserId()))
|
||||
elog(ERROR, "you are not permitted to comment on database \"%s\"",
|
||||
database);
|
||||
|
||||
|
||||
@@ -8,14 +8,17 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v 1.5 2002/11/02 02:33:03 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v 1.6 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "catalog/pg_conversion.h"
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
@@ -23,7 +26,9 @@
|
||||
#include "miscadmin.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -98,3 +103,58 @@ DropConversionCommand(List *name, DropBehavior behavior)
|
||||
|
||||
ConversionDrop(conversionOid, behavior);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rename conversion
|
||||
*/
|
||||
void
|
||||
RenameConversion(List *name, const char *newname)
|
||||
{
|
||||
Oid conversionOid;
|
||||
Oid namespaceOid;
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
AclResult aclresult;
|
||||
|
||||
rel = heap_openr(ConversionRelationName, RowExclusiveLock);
|
||||
|
||||
conversionOid = FindConversionByName(name);
|
||||
if (!OidIsValid(conversionOid))
|
||||
elog(ERROR, "conversion %s not found", NameListToString(name));
|
||||
|
||||
tup = SearchSysCacheCopy(CONOID,
|
||||
ObjectIdGetDatum(conversionOid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "couldn't find pg_conversion tuple for %s",
|
||||
NameListToString(name));
|
||||
|
||||
namespaceOid = ((Form_pg_conversion) GETSTRUCT(tup))->connamespace;
|
||||
|
||||
/* make sure the new name doesn't exist */
|
||||
if (SearchSysCacheExists(CONNAMENSP,
|
||||
CStringGetDatum(newname),
|
||||
ObjectIdGetDatum(namespaceOid),
|
||||
0, 0))
|
||||
{
|
||||
elog(ERROR, "conversion %s already exists in schema %s",
|
||||
newname, get_namespace_name(namespaceOid));
|
||||
}
|
||||
|
||||
/* must be owner */
|
||||
if (!superuser() && ((Form_pg_conversion) GETSTRUCT(tup))->conowner != GetUserId())
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(name));
|
||||
|
||||
/* must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, get_namespace_name(namespaceOid));
|
||||
|
||||
/* rename */
|
||||
namestrcpy(&(((Form_pg_conversion) GETSTRUCT(tup))->conname), newname);
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.115 2003/05/15 17:59:17 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.116 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/catalog.h"
|
||||
@@ -31,6 +32,7 @@
|
||||
#include "miscadmin.h"
|
||||
#include "storage/freespace.h"
|
||||
#include "storage/sinval.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
@@ -402,13 +404,13 @@ dropdb(const char *dbname)
|
||||
char *nominal_loc;
|
||||
char dbpath[MAXPGPATH];
|
||||
Relation pgdbrel;
|
||||
HeapScanDesc pgdbscan;
|
||||
SysScanDesc pgdbscan;
|
||||
ScanKeyData key;
|
||||
HeapTuple tup;
|
||||
|
||||
AssertArg(dbname);
|
||||
|
||||
if (strcmp(dbname, DatabaseName) == 0)
|
||||
if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0)
|
||||
elog(ERROR, "DROP DATABASE: cannot be executed on the currently open database");
|
||||
|
||||
PreventTransactionChain((void *) dbname, "DROP DATABASE");
|
||||
@@ -454,9 +456,9 @@ dropdb(const char *dbname)
|
||||
ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
|
||||
F_OIDEQ, ObjectIdGetDatum(db_id));
|
||||
|
||||
pgdbscan = heap_beginscan(pgdbrel, SnapshotNow, 1, &key);
|
||||
pgdbscan = systable_beginscan(pgdbrel, DatabaseOidIndex, true, SnapshotNow, 1, &key);
|
||||
|
||||
tup = heap_getnext(pgdbscan, ForwardScanDirection);
|
||||
tup = systable_getnext(pgdbscan);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
/*
|
||||
@@ -470,7 +472,7 @@ dropdb(const char *dbname)
|
||||
/* Remove the database's tuple from pg_database */
|
||||
simple_heap_delete(pgdbrel, &tup->t_self);
|
||||
|
||||
heap_endscan(pgdbscan);
|
||||
systable_endscan(pgdbscan);
|
||||
|
||||
/*
|
||||
* Delete any comments associated with the database
|
||||
@@ -513,6 +515,94 @@ dropdb(const char *dbname)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rename database
|
||||
*/
|
||||
void
|
||||
RenameDatabase(const char *oldname, const char *newname)
|
||||
{
|
||||
HeapTuple tup, newtup;
|
||||
Relation rel;
|
||||
SysScanDesc scan, scan2;
|
||||
ScanKeyData key, key2;
|
||||
|
||||
/*
|
||||
* Obtain AccessExclusiveLock so that no new session gets started
|
||||
* while the rename is in progress.
|
||||
*/
|
||||
rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
|
||||
|
||||
ScanKeyEntryInitialize(&key, 0, Anum_pg_database_datname,
|
||||
F_NAMEEQ, NameGetDatum(oldname));
|
||||
scan = systable_beginscan(rel, DatabaseNameIndex, true, SnapshotNow, 1, &key);
|
||||
|
||||
tup = systable_getnext(scan);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("database \"%s\" does not exist", oldname)));
|
||||
|
||||
/*
|
||||
* XXX Client applications probably store the current database
|
||||
* somewhere, so renaming it could cause confusion. On the other
|
||||
* hand, there may not be an actual problem besides a little
|
||||
* confusion, so think about this and decide.
|
||||
*/
|
||||
if (HeapTupleGetOid(tup) == MyDatabaseId)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("current database may not be renamed")));
|
||||
|
||||
/*
|
||||
* Make sure the database does not have active sessions. Might
|
||||
* not be necessary, but it's consistent with other database
|
||||
* operations.
|
||||
*/
|
||||
if (DatabaseHasActiveBackends(HeapTupleGetOid(tup), false))
|
||||
elog(ERROR, "database \"%s\" is being accessed by other users", oldname);
|
||||
|
||||
/* make sure the new name doesn't exist */
|
||||
ScanKeyEntryInitialize(&key2, 0, Anum_pg_database_datname,
|
||||
F_NAMEEQ, NameGetDatum(newname));
|
||||
scan2 = systable_beginscan(rel, DatabaseNameIndex, true, SnapshotNow, 1, &key2);
|
||||
if (HeapTupleIsValid(systable_getnext(scan2)))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("database \"%s\" already exists", newname)));
|
||||
}
|
||||
systable_endscan(scan2);
|
||||
|
||||
/* must be owner */
|
||||
if (!pg_database_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, oldname);
|
||||
|
||||
/* must have createdb */
|
||||
if (!have_createdb_privilege())
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("permission denied")));
|
||||
}
|
||||
|
||||
/* rename */
|
||||
newtup = heap_copytuple(tup);
|
||||
namestrcpy(&(((Form_pg_database) GETSTRUCT(newtup))->datname), newname);
|
||||
simple_heap_update(rel, &tup->t_self, newtup);
|
||||
CatalogUpdateIndexes(rel, newtup);
|
||||
|
||||
systable_endscan(scan);
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
/*
|
||||
* Force dirty buffers out to disk, so that newly-connecting
|
||||
* backends will see the renamed database in pg_database right
|
||||
* away. (They'll see an uncommitted tuple, but they don't care;
|
||||
* see GetRawDatabaseInfo.)
|
||||
*/
|
||||
BufferSync();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ALTER DATABASE name SET ...
|
||||
@@ -525,7 +615,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
|
||||
newtuple;
|
||||
Relation rel;
|
||||
ScanKeyData scankey;
|
||||
HeapScanDesc scan;
|
||||
SysScanDesc scan;
|
||||
Datum repl_val[Natts_pg_database];
|
||||
char repl_null[Natts_pg_database];
|
||||
char repl_repl[Natts_pg_database];
|
||||
@@ -535,8 +625,8 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
|
||||
rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
|
||||
ScanKeyEntryInitialize(&scankey, 0, Anum_pg_database_datname,
|
||||
F_NAMEEQ, NameGetDatum(stmt->dbname));
|
||||
scan = heap_beginscan(rel, SnapshotNow, 1, &scankey);
|
||||
tuple = heap_getnext(scan, ForwardScanDirection);
|
||||
scan = systable_beginscan(rel, DatabaseNameIndex, true, SnapshotNow, 1, &scankey);
|
||||
tuple = systable_getnext(scan);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "database \"%s\" does not exist", stmt->dbname);
|
||||
|
||||
@@ -583,7 +673,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
|
||||
/* Update indexes */
|
||||
CatalogUpdateIndexes(rel, newtuple);
|
||||
|
||||
heap_endscan(scan);
|
||||
systable_endscan(scan);
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
@@ -601,7 +691,7 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
{
|
||||
Relation relation;
|
||||
ScanKeyData scanKey;
|
||||
HeapScanDesc scan;
|
||||
SysScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
bool gottuple;
|
||||
|
||||
@@ -613,9 +703,9 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
|
||||
F_NAMEEQ, NameGetDatum(name));
|
||||
|
||||
scan = heap_beginscan(relation, SnapshotNow, 1, &scanKey);
|
||||
scan = systable_beginscan(relation, DatabaseNameIndex, true, SnapshotNow, 1, &scanKey);
|
||||
|
||||
tuple = heap_getnext(scan, ForwardScanDirection);
|
||||
tuple = systable_getnext(scan);
|
||||
|
||||
gottuple = HeapTupleIsValid(tuple);
|
||||
if (gottuple)
|
||||
@@ -667,7 +757,7 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
}
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
systable_endscan(scan);
|
||||
heap_close(relation, AccessShareLock);
|
||||
|
||||
return gottuple;
|
||||
@@ -790,7 +880,7 @@ get_database_oid(const char *dbname)
|
||||
{
|
||||
Relation pg_database;
|
||||
ScanKeyData entry[1];
|
||||
HeapScanDesc scan;
|
||||
SysScanDesc scan;
|
||||
HeapTuple dbtuple;
|
||||
Oid oid;
|
||||
|
||||
@@ -799,9 +889,9 @@ get_database_oid(const char *dbname)
|
||||
ScanKeyEntryInitialize(&entry[0], 0x0,
|
||||
Anum_pg_database_datname, F_NAMEEQ,
|
||||
CStringGetDatum(dbname));
|
||||
scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
|
||||
scan = systable_beginscan(pg_database, DatabaseNameIndex, true, SnapshotNow, 1, entry);
|
||||
|
||||
dbtuple = heap_getnext(scan, ForwardScanDirection);
|
||||
dbtuple = systable_getnext(scan);
|
||||
|
||||
/* We assume that there can be at most one matching tuple */
|
||||
if (HeapTupleIsValid(dbtuple))
|
||||
@@ -809,45 +899,46 @@ get_database_oid(const char *dbname)
|
||||
else
|
||||
oid = InvalidOid;
|
||||
|
||||
heap_endscan(scan);
|
||||
systable_endscan(scan);
|
||||
heap_close(pg_database, AccessShareLock);
|
||||
|
||||
return oid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_database_owner - given a database OID, fetch the owner's usesysid.
|
||||
* get_database_name - given a database OID, look up the name
|
||||
*
|
||||
* Errors out if database not found.
|
||||
* Returns InvalidOid if database name not found.
|
||||
*
|
||||
* This is not actually used in this file, but is exported for use elsewhere.
|
||||
*/
|
||||
Oid
|
||||
get_database_owner(Oid dbid)
|
||||
char *
|
||||
get_database_name(Oid dbid)
|
||||
{
|
||||
Relation pg_database;
|
||||
ScanKeyData entry[1];
|
||||
HeapScanDesc scan;
|
||||
SysScanDesc scan;
|
||||
HeapTuple dbtuple;
|
||||
int32 dba;
|
||||
char *result;
|
||||
|
||||
/* There's no syscache for pg_database, so must look the hard way */
|
||||
pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
|
||||
ScanKeyEntryInitialize(&entry[0], 0x0,
|
||||
ObjectIdAttributeNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(dbid));
|
||||
scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
|
||||
scan = systable_beginscan(pg_database, DatabaseOidIndex, true, SnapshotNow, 1, entry);
|
||||
|
||||
dbtuple = heap_getnext(scan, ForwardScanDirection);
|
||||
dbtuple = systable_getnext(scan);
|
||||
|
||||
if (!HeapTupleIsValid(dbtuple))
|
||||
elog(ERROR, "database %u does not exist", dbid);
|
||||
/* We assume that there can be at most one matching tuple */
|
||||
if (HeapTupleIsValid(dbtuple))
|
||||
result = pstrdup(NameStr(((Form_pg_database) GETSTRUCT(dbtuple))->datname));
|
||||
else
|
||||
result = NULL;
|
||||
|
||||
dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
|
||||
|
||||
heap_endscan(scan);
|
||||
systable_endscan(scan);
|
||||
heap_close(pg_database, AccessShareLock);
|
||||
|
||||
/* XXX some confusion about whether userids are OID or int4 ... */
|
||||
return (Oid) dba;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.25 2003/02/01 22:09:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.26 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* These routines take the parse tree and pick out the
|
||||
@@ -591,6 +591,72 @@ RemoveFunctionById(Oid funcOid)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rename function
|
||||
*/
|
||||
void
|
||||
RenameFunction(List *name, List *argtypes, const char *newname)
|
||||
{
|
||||
Oid procOid;
|
||||
Oid namespaceOid;
|
||||
Oid oid_array[FUNC_MAX_ARGS];
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
AclResult aclresult;
|
||||
int16 nargs;
|
||||
|
||||
rel = heap_openr(ProcedureRelationName, RowExclusiveLock);
|
||||
|
||||
procOid = LookupFuncNameTypeNames(name, argtypes, "RenameFunction");
|
||||
|
||||
tup = SearchSysCacheCopy(PROCOID,
|
||||
ObjectIdGetDatum(procOid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "RenameFunction: couldn't find pg_proc tuple for %s",
|
||||
NameListToString(name));
|
||||
|
||||
if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("%s is an aggregate function", NameListToString(name)),
|
||||
errhint("Use ALTER AGGREGATE to rename aggregate functions.")));
|
||||
|
||||
namespaceOid = ((Form_pg_proc) GETSTRUCT(tup))->pronamespace;
|
||||
|
||||
/* make sure the new name doesn't exist */
|
||||
nargs = compute_parameter_types(argtypes, ((Form_pg_proc) GETSTRUCT(tup))->prolang, oid_array);
|
||||
if (SearchSysCacheExists(PROCNAMENSP,
|
||||
CStringGetDatum(newname),
|
||||
Int16GetDatum(nargs),
|
||||
PointerGetDatum(oid_array),
|
||||
ObjectIdGetDatum(namespaceOid)))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("function %s with the same argument types already exists in schema %s",
|
||||
newname, get_namespace_name(namespaceOid))));
|
||||
}
|
||||
|
||||
/* must be owner */
|
||||
if (!pg_proc_ownercheck(procOid, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(name));
|
||||
|
||||
/* must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, get_namespace_name(namespaceOid));
|
||||
|
||||
/* rename */
|
||||
namestrcpy(&(((Form_pg_proc) GETSTRUCT(tup))->proname), newname);
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SetFunctionReturnType - change declared return type of a function
|
||||
*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.100 2003/05/28 16:03:56 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.101 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "commands/dbcommands.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "commands/tablecmds.h"
|
||||
#include "executor/executor.h"
|
||||
@@ -644,10 +645,10 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
||||
|
||||
AssertArg(dbname);
|
||||
|
||||
if (strcmp(dbname, DatabaseName) != 0)
|
||||
if (strcmp(dbname, get_database_name(MyDatabaseId)) != 0)
|
||||
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
|
||||
|
||||
if (!(superuser() || is_dbadmin(MyDatabaseId)))
|
||||
if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
|
||||
elog(ERROR, "REINDEX DATABASE: Permission denied.");
|
||||
|
||||
if (!allowSystemTableMods)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.9 2002/11/13 00:39:46 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.10 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -550,7 +550,7 @@ RemoveOpClassById(Oid opclassOid)
|
||||
ObjectIdGetDatum(opclassOid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "RemoveOpClassById: couldn't find pg_class entry %u",
|
||||
elog(ERROR, "RemoveOpClassById: couldn't find pg_opclass entry %u",
|
||||
opclassOid);
|
||||
|
||||
simple_heap_delete(rel, &tup->t_self);
|
||||
@@ -595,3 +595,94 @@ RemoveOpClassById(Oid opclassOid)
|
||||
systable_endscan(scan);
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rename opclass
|
||||
*/
|
||||
void
|
||||
RenameOpClass(List *name, const char *access_method, const char *newname)
|
||||
{
|
||||
Oid opcOid;
|
||||
Oid amOid;
|
||||
Oid namespaceOid;
|
||||
char *schemaname;
|
||||
char *opcname;
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
AclResult aclresult;
|
||||
|
||||
amOid = GetSysCacheOid(AMNAME,
|
||||
CStringGetDatum(access_method),
|
||||
0, 0, 0);
|
||||
if (!OidIsValid(amOid))
|
||||
elog(ERROR, "access method \"%s\" not found", access_method);
|
||||
|
||||
rel = heap_openr(OperatorClassRelationName, RowExclusiveLock);
|
||||
|
||||
/*
|
||||
* Look up the opclass
|
||||
*/
|
||||
DeconstructQualifiedName(name, &schemaname, &opcname);
|
||||
|
||||
if (schemaname)
|
||||
{
|
||||
namespaceOid = LookupExplicitNamespace(schemaname);
|
||||
|
||||
tup = SearchSysCacheCopy(CLAAMNAMENSP,
|
||||
ObjectIdGetDatum(amOid),
|
||||
PointerGetDatum(opcname),
|
||||
ObjectIdGetDatum(namespaceOid),
|
||||
0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "operator class \"%s\" for access method \"%s\" does not exist",
|
||||
opcname, access_method);
|
||||
|
||||
opcOid = HeapTupleGetOid(tup);
|
||||
}
|
||||
else
|
||||
{
|
||||
opcOid = OpclassnameGetOpcid(amOid, opcname);
|
||||
if (!OidIsValid(opcOid))
|
||||
elog(ERROR, "operator class \"%s\" for access method \"%s\" does not exist",
|
||||
opcname, access_method);
|
||||
|
||||
tup = SearchSysCacheCopy(CLAOID,
|
||||
ObjectIdGetDatum(opcOid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "couldn't find pg_opclass tuple for %u", opcOid);
|
||||
|
||||
namespaceOid = ((Form_pg_opclass) GETSTRUCT(tup))->opcnamespace;
|
||||
}
|
||||
|
||||
/* make sure the new name doesn't exist */
|
||||
if (SearchSysCacheExists(CLAAMNAMENSP,
|
||||
ObjectIdGetDatum(amOid),
|
||||
CStringGetDatum(newname),
|
||||
ObjectIdGetDatum(namespaceOid),
|
||||
0))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
|
||||
newname, access_method, get_namespace_name(namespaceOid))));
|
||||
}
|
||||
|
||||
/* must be owner */
|
||||
if (!pg_opclass_ownercheck(opcOid, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(name));
|
||||
|
||||
/* must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, get_namespace_name(namespaceOid));
|
||||
|
||||
/* rename */
|
||||
namestrcpy(&(((Form_pg_opclass) GETSTRUCT(tup))->opcname), newname);
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.43 2002/09/21 18:39:25 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.44 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -231,3 +231,47 @@ DropProceduralLanguageById(Oid langOid)
|
||||
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rename language
|
||||
*/
|
||||
void
|
||||
RenameLanguage(const char *oldname, const char *newname)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
|
||||
rel = heap_openr(ShadowRelationName, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCacheCopy(LANGNAME,
|
||||
CStringGetDatum(oldname),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("language \"%s\" does not exist", oldname)));
|
||||
|
||||
/* make sure the new name doesn't exist */
|
||||
if (SearchSysCacheExists(LANGNAME,
|
||||
CStringGetDatum(newname),
|
||||
0, 0, 0))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("language \"%s\" already exists", newname)));
|
||||
}
|
||||
|
||||
/* must be superuser */
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("permission denied")));
|
||||
|
||||
/* rename */
|
||||
namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname);
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.9 2003/05/06 20:26:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.10 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -18,8 +18,10 @@
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "commands/dbcommands.h"
|
||||
#include "commands/schemacmds.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/analyze.h"
|
||||
@@ -86,7 +88,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
|
||||
*/
|
||||
aclresult = pg_database_aclcheck(MyDatabaseId, saved_userid, ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, DatabaseName);
|
||||
aclcheck_error(aclresult, get_database_name(MyDatabaseId));
|
||||
|
||||
if (!allowSystemTableMods && IsReservedName(schemaName))
|
||||
elog(ERROR, "CREATE SCHEMA: Illegal schema name: \"%s\" -- pg_ is reserved for system schemas",
|
||||
@@ -212,3 +214,57 @@ RemoveSchemaById(Oid schemaOid)
|
||||
|
||||
heap_close(relation, RowExclusiveLock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rename schema
|
||||
*/
|
||||
void
|
||||
RenameSchema(const char *oldname, const char *newname)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
AclResult aclresult;
|
||||
|
||||
rel = heap_openr(NamespaceRelationName, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCacheCopy(NAMESPACENAME,
|
||||
CStringGetDatum(oldname),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("schema \"%s\" does not exist", oldname)));
|
||||
|
||||
/* make sure the new name doesn't exist */
|
||||
if (HeapTupleIsValid(
|
||||
SearchSysCache(NAMESPACENAME,
|
||||
CStringGetDatum(newname),
|
||||
0, 0, 0)))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("schema \"%s\" already exists", newname)));
|
||||
}
|
||||
|
||||
/* must be owner */
|
||||
if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, oldname);
|
||||
|
||||
/* must have CREATE privilege on database */
|
||||
aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, get_database_name(MyDatabaseId));
|
||||
|
||||
if (!allowSystemTableMods && IsReservedName(newname))
|
||||
elog(ERROR, "illegal schema name: \"%s\" -- pg_ is reserved for system schemas",
|
||||
newname);
|
||||
|
||||
/* rename */
|
||||
namestrcpy(&(((Form_pg_namespace) GETSTRUCT(tup))->nspname), newname);
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.117 2003/05/12 23:08:50 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.118 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1091,6 +1091,64 @@ DropUser(DropUserStmt *stmt)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rename user
|
||||
*/
|
||||
void
|
||||
RenameUser(const char *oldname, const char *newname)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
|
||||
/* ExclusiveLock because we need to update the password file */
|
||||
rel = heap_openr(ShadowRelationName, ExclusiveLock);
|
||||
|
||||
tup = SearchSysCacheCopy(SHADOWNAME,
|
||||
CStringGetDatum(oldname),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("user \"%s\" does not exist", oldname)));
|
||||
|
||||
/*
|
||||
* XXX Client applications probably store the session user
|
||||
* somewhere, so renaming it could cause confusion. On the other
|
||||
* hand, there may not be an actual problem besides a little
|
||||
* confusion, so think about this and decide.
|
||||
*/
|
||||
if (((Form_pg_shadow) GETSTRUCT(tup))->usesysid == GetSessionUserId())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("session user may not be renamed")));
|
||||
|
||||
/* make sure the new name doesn't exist */
|
||||
if (SearchSysCacheExists(SHADOWNAME,
|
||||
CStringGetDatum(newname),
|
||||
0, 0, 0))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("user \"%s\" already exists", newname)));
|
||||
}
|
||||
|
||||
/* must be superuser */
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("permission denied")));
|
||||
|
||||
/* rename */
|
||||
namestrcpy(&(((Form_pg_shadow) GETSTRUCT(tup))->usename), newname);
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
|
||||
user_file_update_needed = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CheckPgUserAclNotNull
|
||||
@@ -1566,3 +1624,51 @@ DropGroup(DropGroupStmt *stmt)
|
||||
*/
|
||||
group_file_update_needed = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rename group
|
||||
*/
|
||||
void
|
||||
RenameGroup(const char *oldname, const char *newname)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
|
||||
/* ExclusiveLock because we need to update the flat group file */
|
||||
rel = heap_openr(GroupRelationName, ExclusiveLock);
|
||||
|
||||
tup = SearchSysCacheCopy(GRONAME,
|
||||
CStringGetDatum(oldname),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("group \"%s\" does not exist", oldname)));
|
||||
|
||||
/* make sure the new name doesn't exist */
|
||||
if (SearchSysCacheExists(GRONAME,
|
||||
CStringGetDatum(newname),
|
||||
0, 0, 0))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("a group \"%s\" already exists", newname)));
|
||||
}
|
||||
|
||||
/* must be superuser */
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION),
|
||||
errmsg("permission denied")));
|
||||
|
||||
/* rename */
|
||||
namestrcpy(&(((Form_pg_group) GETSTRUCT(tup))->groname), newname);
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
|
||||
group_file_update_needed = true;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.255 2003/05/28 16:03:56 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.256 2003/06/27 14:45:27 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -771,7 +771,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
|
||||
onerel = relation_open(relid, lmode);
|
||||
|
||||
if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
|
||||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
|
||||
(pg_database_ownercheck(MyDatabaseId, GetUserId()) && !onerel->rd_rel->relisshared)))
|
||||
{
|
||||
elog(WARNING, "Skipping \"%s\" --- only table or database owner can VACUUM it",
|
||||
RelationGetRelationName(onerel));
|
||||
|
||||
Reference in New Issue
Block a user