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:
@ -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.
|
||||
|
Reference in New Issue
Block a user