diff options
Diffstat (limited to 'src/backend/commands/alter.c')
-rw-r--r-- | src/backend/commands/alter.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 0d0227d04ad..6c9ba1eb359 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -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); @@ -203,6 +239,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. */ |