1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-07 00:36:50 +03:00

Add more ALTER <object> .. SET SCHEMA commands.

This adds support for changing the schema of a conversion, operator,
operator class, operator family, text search configuration, text search
dictionary, text search parser, or text search template.

Dimitri Fontaine, with assorted corrections and other kibitzing.
This commit is contained in:
Robert Haas
2010-11-26 17:27:23 -05:00
parent 1d9a0abec1
commit 55109313f9
21 changed files with 620 additions and 13 deletions

View File

@ -14,8 +14,11 @@
*/
#include "postgres.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_namespace.h"
#include "commands/alter.h"
#include "commands/conversioncmds.h"
#include "commands/dbcommands.h"
@ -33,6 +36,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
/*
@ -178,11 +182,27 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
stmt->newschema);
break;
case OBJECT_CONVERSION:
AlterConversionNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_FUNCTION:
AlterFunctionNamespace(stmt->object, stmt->objarg, false,
stmt->newschema);
break;
case OBJECT_OPERATOR:
AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
break;
case OBJECT_OPCLASS:
AlterOpClassNamespace(stmt->object, stmt->objarg, stmt->newschema);
break;
case OBJECT_OPFAMILY:
AlterOpFamilyNamespace(stmt->object, stmt->objarg, stmt->newschema);
break;
case OBJECT_SEQUENCE:
case OBJECT_TABLE:
case OBJECT_VIEW:
@ -191,6 +211,22 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
stmt->objectType, AccessExclusiveLock);
break;
case OBJECT_TSPARSER:
AlterTSParserNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_TSDICTIONARY:
AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_TSTEMPLATE:
AlterTSTemplateNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_TSCONFIGURATION:
AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_TYPE:
case OBJECT_DOMAIN:
AlterTypeNamespace(stmt->object, stmt->newschema);
@ -202,6 +238,104 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
}
}
/*
* Generic function to change the namespace of a given object, for simple
* cases (won't work for tables or functions, objects which have more than 2
* key-attributes to use when searching for their syscache entries --- we
* don't want nor need to get this generic here).
*
* The AlterFooNamespace() calls just above will call a function whose job
* is to lookup the arguments for the generic function here.
*
* Relation must already by open, it's the responsibility of the caller to
* close it.
*/
void
AlterObjectNamespace(Relation rel, int cacheId,
Oid classId, Oid objid, Oid nspOid,
int Anum_name, int Anum_namespace, int Anum_owner,
AclObjectKind acl_kind,
bool superuser_only)
{
Oid oldNspOid;
Datum name, namespace;
bool isnull;
HeapTuple tup, newtup = NULL;
Datum *values;
bool *nulls;
bool *replaces;
tup = SearchSysCacheCopy1(cacheId, ObjectIdGetDatum(objid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for object %u: %s",
objid, getObjectDescriptionOids(classId, objid));
name = heap_getattr(tup, Anum_name, rel->rd_att, &isnull);
namespace = heap_getattr(tup, Anum_namespace, rel->rd_att, &isnull);
oldNspOid = DatumGetObjectId(namespace);
/* Check basic namespace related issues */
CheckSetNamespace(oldNspOid, nspOid, classId, objid);
/* check for duplicate name (more friendly than unique-index failure) */
if (SearchSysCacheExists2(cacheId, name, ObjectIdGetDatum(nspOid)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("%s already exists in schema \"%s\"",
getObjectDescriptionOids(classId, objid),
get_namespace_name(nspOid))));
/* Superusers can always do it */
if (!superuser())
{
Datum owner;
Oid ownerId;
AclResult aclresult;
if (superuser_only)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser to SET SCHEMA of %s",
getObjectDescriptionOids(classId, objid)))));
/* Otherwise, must be owner of the existing object */
owner = heap_getattr(tup, Anum_owner, rel->rd_att, &isnull);
ownerId = DatumGetObjectId(owner);
if (!has_privs_of_role(GetUserId(), ownerId))
aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind,
NameStr(*(DatumGetName(name))));
/* owner must have CREATE privilege on namespace */
aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(oldNspOid));
}
/* Prepare to update tuple */
values = palloc0(rel->rd_att->natts * sizeof(Datum));
nulls = palloc0(rel->rd_att->natts * sizeof(bool));
replaces = palloc0(rel->rd_att->natts * sizeof(bool));
values[Anum_namespace - 1] = nspOid;
replaces[Anum_namespace - 1] = true;
newtup = heap_modify_tuple(tup, rel->rd_att, values, nulls, replaces);
/* Perform actual update */
simple_heap_update(rel, &tup->t_self, newtup);
CatalogUpdateIndexes(rel, newtup);
/* Release memory */
pfree(values);
pfree(nulls);
pfree(replaces);
/* update dependencies to point to the new schema */
changeDependencyFor(classId, objid,
NamespaceRelationId, oldNspOid, nspOid);
}
/*
* Executes an ALTER OBJECT / OWNER TO statement. Based on the object
* type, the function appropriate to that type is executed.