mirror of
https://github.com/postgres/postgres.git
synced 2025-10-16 17:07:43 +03:00
refactor ALTER some-obj SET OWNER implementation
Remove duplicate implementation of catalog munging and miscellaneous privilege and consistency checks. Instead rely on already existing data in objectaddress.c to do the work. Author: KaiGai Kohei Tweaked by me Reviewed by Robert Haas
This commit is contained in:
@@ -267,18 +267,3 @@ RenameAggregate(List *name, List *args, const char *newname)
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change aggregate owner
|
||||
*/
|
||||
void
|
||||
AlterAggregateOwner(List *name, List *args, Oid newOwnerId)
|
||||
{
|
||||
Oid procOid;
|
||||
|
||||
/* Look up function and make sure it's an aggregate */
|
||||
procOid = LookupAggNameTypeNames(name, args, false);
|
||||
|
||||
/* The rest is just like a function */
|
||||
AlterFunctionOwner_oid(procOid, newOwnerId);
|
||||
}
|
||||
|
@@ -15,10 +15,12 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/htup_details.h"
|
||||
#include "access/sysattr.h"
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_largeobject.h"
|
||||
#include "catalog/pg_largeobject_metadata.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "commands/alter.h"
|
||||
#include "commands/collationcmds.h"
|
||||
@@ -37,9 +39,11 @@
|
||||
#include "miscadmin.h"
|
||||
#include "tcop/utility.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/tqual.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -446,71 +450,19 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
|
||||
|
||||
switch (stmt->objectType)
|
||||
{
|
||||
case OBJECT_AGGREGATE:
|
||||
AlterAggregateOwner(stmt->object, stmt->objarg, newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_COLLATION:
|
||||
AlterCollationOwner(stmt->object, newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_CONVERSION:
|
||||
AlterConversionOwner(stmt->object, newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_DATABASE:
|
||||
AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_FUNCTION:
|
||||
AlterFunctionOwner(stmt->object, stmt->objarg, newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_LANGUAGE:
|
||||
AlterLanguageOwner(strVal(linitial(stmt->object)), newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_LARGEOBJECT:
|
||||
LargeObjectAlterOwner(oidparse(linitial(stmt->object)), newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_OPERATOR:
|
||||
Assert(list_length(stmt->objarg) == 2);
|
||||
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_OPFAMILY:
|
||||
AlterOpFamilyOwner(stmt->object, stmt->addname, newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_SCHEMA:
|
||||
AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_TABLESPACE:
|
||||
AlterTableSpaceOwner(strVal(linitial(stmt->object)), newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_TYPE:
|
||||
case OBJECT_DOMAIN: /* same as TYPE */
|
||||
AlterTypeOwner(stmt->object, newowner, stmt->objectType);
|
||||
break;
|
||||
|
||||
case OBJECT_TSDICTIONARY:
|
||||
AlterTSDictionaryOwner(stmt->object, newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_TSCONFIGURATION:
|
||||
AlterTSConfigurationOwner(stmt->object, newowner);
|
||||
break;
|
||||
|
||||
case OBJECT_FDW:
|
||||
AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)),
|
||||
newowner);
|
||||
@@ -524,8 +476,240 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
|
||||
AlterEventTriggerOwner(strVal(linitial(stmt->object)), newowner);
|
||||
break;
|
||||
|
||||
/* Generic cases */
|
||||
case OBJECT_AGGREGATE:
|
||||
case OBJECT_COLLATION:
|
||||
case OBJECT_CONVERSION:
|
||||
case OBJECT_FUNCTION:
|
||||
case OBJECT_LANGUAGE:
|
||||
case OBJECT_LARGEOBJECT:
|
||||
case OBJECT_OPERATOR:
|
||||
case OBJECT_OPCLASS:
|
||||
case OBJECT_OPFAMILY:
|
||||
case OBJECT_TABLESPACE:
|
||||
case OBJECT_TSDICTIONARY:
|
||||
case OBJECT_TSCONFIGURATION:
|
||||
{
|
||||
Relation catalog;
|
||||
Relation relation;
|
||||
Oid classId;
|
||||
ObjectAddress address;
|
||||
|
||||
address = get_object_address(stmt->objectType,
|
||||
stmt->object,
|
||||
stmt->objarg,
|
||||
&relation,
|
||||
AccessExclusiveLock,
|
||||
false);
|
||||
Assert(relation == NULL);
|
||||
classId = address.classId;
|
||||
|
||||
/*
|
||||
* XXX - get_object_address returns Oid of pg_largeobject
|
||||
* catalog for OBJECT_LARGEOBJECT because of historical
|
||||
* reasons. Fix up it here.
|
||||
*/
|
||||
if (classId == LargeObjectRelationId)
|
||||
classId = LargeObjectMetadataRelationId;
|
||||
|
||||
catalog = heap_open(classId, RowExclusiveLock);
|
||||
|
||||
AlterObjectOwner_internal(catalog, address.objectId, newowner);
|
||||
heap_close(catalog, RowExclusiveLock);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
|
||||
(int) stmt->objectType);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a copy of the tuple for the object with the given object OID, from
|
||||
* the given catalog (which must have been opened by the caller and suitably
|
||||
* locked). NULL is returned if the OID is not found.
|
||||
*
|
||||
* We try a syscache first, if available.
|
||||
*
|
||||
* XXX this function seems general in possible usage. Given sufficient callers
|
||||
* elsewhere, we should consider moving it to a more appropriate place.
|
||||
*/
|
||||
static HeapTuple
|
||||
get_catalog_object_by_oid(Relation catalog, Oid objectId)
|
||||
{
|
||||
HeapTuple tuple;
|
||||
Oid classId = RelationGetRelid(catalog);
|
||||
int oidCacheId = get_object_catcache_oid(classId);
|
||||
|
||||
if (oidCacheId > 0)
|
||||
{
|
||||
tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
|
||||
if (!HeapTupleIsValid(tuple)) /* should not happen */
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
Oid oidIndexId = get_object_oid_index(classId);
|
||||
SysScanDesc scan;
|
||||
ScanKeyData skey;
|
||||
|
||||
Assert(OidIsValid(oidIndexId));
|
||||
|
||||
ScanKeyInit(&skey,
|
||||
ObjectIdAttributeNumber,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(objectId));
|
||||
|
||||
scan = systable_beginscan(catalog, oidIndexId, true,
|
||||
SnapshotNow, 1, &skey);
|
||||
tuple = systable_getnext(scan);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
systable_endscan(scan);
|
||||
return NULL;
|
||||
}
|
||||
tuple = heap_copytuple(tuple);
|
||||
|
||||
systable_endscan(scan);
|
||||
}
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic function to change the ownership of a given object, for simple
|
||||
* cases (won't work for tables, nor other cases where we need to do more than
|
||||
* change the ownership column of a single catalog entry).
|
||||
*
|
||||
* rel: catalog relation containing object (RowExclusiveLock'd by caller)
|
||||
* objectId: OID of object to change the ownership of
|
||||
* new_ownerId: OID of new object owner
|
||||
*/
|
||||
void
|
||||
AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
|
||||
{
|
||||
Oid classId = RelationGetRelid(rel);
|
||||
AttrNumber Anum_owner = get_object_attnum_owner(classId);
|
||||
AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
|
||||
AttrNumber Anum_acl = get_object_attnum_acl(classId);
|
||||
AttrNumber Anum_name = get_object_attnum_name(classId);
|
||||
HeapTuple oldtup;
|
||||
Datum datum;
|
||||
bool isnull;
|
||||
Oid old_ownerId;
|
||||
Oid namespaceId = InvalidOid;
|
||||
|
||||
oldtup = get_catalog_object_by_oid(rel, objectId);
|
||||
if (oldtup == NULL)
|
||||
elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
|
||||
objectId, RelationGetRelationName(rel));
|
||||
|
||||
datum = heap_getattr(oldtup, Anum_owner,
|
||||
RelationGetDescr(rel), &isnull);
|
||||
Assert(!isnull);
|
||||
old_ownerId = DatumGetObjectId(datum);
|
||||
|
||||
if (Anum_namespace != InvalidAttrNumber)
|
||||
{
|
||||
datum = heap_getattr(oldtup, Anum_namespace,
|
||||
RelationGetDescr(rel), &isnull);
|
||||
Assert(!isnull);
|
||||
namespaceId = DatumGetObjectId(datum);
|
||||
}
|
||||
|
||||
if (old_ownerId != new_ownerId)
|
||||
{
|
||||
AttrNumber nattrs;
|
||||
HeapTuple newtup;
|
||||
Datum *values;
|
||||
bool *nulls;
|
||||
bool *replaces;
|
||||
|
||||
/* Superusers can bypass permission checks */
|
||||
if (!superuser())
|
||||
{
|
||||
AclObjectKind aclkind = get_object_aclkind(classId);
|
||||
|
||||
/* must be owner */
|
||||
if (!has_privs_of_role(GetUserId(), old_ownerId))
|
||||
{
|
||||
char *objname;
|
||||
char namebuf[NAMEDATALEN];
|
||||
|
||||
if (Anum_name != InvalidAttrNumber)
|
||||
{
|
||||
datum = heap_getattr(oldtup, Anum_name,
|
||||
RelationGetDescr(rel), &isnull);
|
||||
Assert(!isnull);
|
||||
objname = NameStr(*DatumGetName(datum));
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(namebuf, sizeof(namebuf), "%u",
|
||||
HeapTupleGetOid(oldtup));
|
||||
objname = namebuf;
|
||||
}
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, aclkind, objname);
|
||||
}
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), new_ownerId);
|
||||
|
||||
/* New owner must have CREATE privilege on namespace */
|
||||
if (OidIsValid(namespaceId))
|
||||
{
|
||||
AclResult aclresult;
|
||||
|
||||
aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, aclkind,
|
||||
get_namespace_name(namespaceId));
|
||||
}
|
||||
}
|
||||
|
||||
/* Build a modified tuple */
|
||||
nattrs = RelationGetNumberOfAttributes(rel);
|
||||
values = palloc0(nattrs * sizeof(Datum));
|
||||
nulls = palloc0(nattrs * sizeof(bool));
|
||||
replaces = palloc0(nattrs * sizeof(bool));
|
||||
values[Anum_owner - 1] = ObjectIdGetDatum(new_ownerId);
|
||||
replaces[Anum_owner - 1] = true;
|
||||
|
||||
/*
|
||||
* Determine the modified ACL for the new owner. This is only
|
||||
* necessary when the ACL is non-null.
|
||||
*/
|
||||
if (Anum_acl != InvalidAttrNumber)
|
||||
{
|
||||
datum = heap_getattr(oldtup,
|
||||
Anum_acl, RelationGetDescr(rel), &isnull);
|
||||
if (!isnull)
|
||||
{
|
||||
Acl *newAcl;
|
||||
|
||||
newAcl = aclnewowner(DatumGetAclP(datum),
|
||||
old_ownerId, new_ownerId);
|
||||
values[Anum_acl - 1] = PointerGetDatum(newAcl);
|
||||
replaces[Anum_acl - 1] = true;
|
||||
}
|
||||
}
|
||||
|
||||
newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
|
||||
values, nulls, replaces);
|
||||
|
||||
/* Perform actual update */
|
||||
simple_heap_update(rel, &newtup->t_self, newtup);
|
||||
CatalogUpdateIndexes(rel, newtup);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
if (classId == LargeObjectMetadataRelationId)
|
||||
classId = LargeObjectRelationId;
|
||||
changeDependencyOnOwner(classId, HeapTupleGetOid(newtup), new_ownerId);
|
||||
|
||||
/* Release memory */
|
||||
pfree(values);
|
||||
pfree(nulls);
|
||||
pfree(replaces);
|
||||
}
|
||||
}
|
||||
|
@@ -34,9 +34,6 @@
|
||||
#include "utils/rel.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
static void AlterCollationOwner_internal(Relation rel, Oid collationOid,
|
||||
Oid newOwnerId);
|
||||
|
||||
/*
|
||||
* CREATE COLLATION
|
||||
*/
|
||||
@@ -211,104 +208,6 @@ RenameCollation(List *name, const char *newname)
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change collation owner, by name
|
||||
*/
|
||||
void
|
||||
AlterCollationOwner(List *name, Oid newOwnerId)
|
||||
{
|
||||
Oid collationOid;
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(CollationRelationId, RowExclusiveLock);
|
||||
|
||||
collationOid = get_collation_oid(name, false);
|
||||
|
||||
AlterCollationOwner_internal(rel, collationOid, newOwnerId);
|
||||
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change collation owner, by oid
|
||||
*/
|
||||
void
|
||||
AlterCollationOwner_oid(Oid collationOid, Oid newOwnerId)
|
||||
{
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(CollationRelationId, RowExclusiveLock);
|
||||
|
||||
AlterCollationOwner_internal(rel, collationOid, newOwnerId);
|
||||
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* AlterCollationOwner_internal
|
||||
*
|
||||
* Internal routine for changing the owner. rel must be pg_collation, already
|
||||
* open and suitably locked; it will not be closed.
|
||||
*/
|
||||
static void
|
||||
AlterCollationOwner_internal(Relation rel, Oid collationOid, Oid newOwnerId)
|
||||
{
|
||||
Form_pg_collation collForm;
|
||||
HeapTuple tup;
|
||||
|
||||
Assert(RelationGetRelid(rel) == CollationRelationId);
|
||||
|
||||
tup = SearchSysCacheCopy1(COLLOID, ObjectIdGetDatum(collationOid));
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for collation %u", collationOid);
|
||||
|
||||
collForm = (Form_pg_collation) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* If the new owner is the same as the existing owner, consider the
|
||||
* command to have succeeded. This is for dump restoration purposes.
|
||||
*/
|
||||
if (collForm->collowner != newOwnerId)
|
||||
{
|
||||
AclResult aclresult;
|
||||
|
||||
/* Superusers can always do it */
|
||||
if (!superuser())
|
||||
{
|
||||
/* Otherwise, must be owner of the existing object */
|
||||
if (!pg_collation_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION,
|
||||
NameStr(collForm->collname));
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
/* New owner must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(collForm->collnamespace,
|
||||
newOwnerId,
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
||||
get_namespace_name(collForm->collnamespace));
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify the owner --- okay to scribble on tup because it's a copy
|
||||
*/
|
||||
collForm->collowner = newOwnerId;
|
||||
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(CollationRelationId, collationOid,
|
||||
newOwnerId);
|
||||
}
|
||||
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute ALTER COLLATION SET SCHEMA
|
||||
*/
|
||||
|
@@ -31,9 +31,6 @@
|
||||
#include "utils/rel.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
static void AlterConversionOwner_internal(Relation rel, Oid conversionOid,
|
||||
Oid newOwnerId);
|
||||
|
||||
/*
|
||||
* CREATE CONVERSION
|
||||
*/
|
||||
@@ -168,101 +165,3 @@ RenameConversion(List *name, const char *newname)
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change conversion owner, by name
|
||||
*/
|
||||
void
|
||||
AlterConversionOwner(List *name, Oid newOwnerId)
|
||||
{
|
||||
Oid conversionOid;
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(ConversionRelationId, RowExclusiveLock);
|
||||
|
||||
conversionOid = get_conversion_oid(name, false);
|
||||
|
||||
AlterConversionOwner_internal(rel, conversionOid, newOwnerId);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change conversion owner, by oid
|
||||
*/
|
||||
void
|
||||
AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId)
|
||||
{
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(ConversionRelationId, RowExclusiveLock);
|
||||
|
||||
AlterConversionOwner_internal(rel, conversionOid, newOwnerId);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* AlterConversionOwner_internal
|
||||
*
|
||||
* Internal routine for changing the owner. rel must be pg_conversion, already
|
||||
* open and suitably locked; it will not be closed.
|
||||
*/
|
||||
static void
|
||||
AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId)
|
||||
{
|
||||
Form_pg_conversion convForm;
|
||||
HeapTuple tup;
|
||||
|
||||
Assert(RelationGetRelid(rel) == ConversionRelationId);
|
||||
|
||||
tup = SearchSysCacheCopy1(CONVOID, ObjectIdGetDatum(conversionOid));
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for conversion %u", conversionOid);
|
||||
|
||||
convForm = (Form_pg_conversion) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* If the new owner is the same as the existing owner, consider the
|
||||
* command to have succeeded. This is for dump restoration purposes.
|
||||
*/
|
||||
if (convForm->conowner != newOwnerId)
|
||||
{
|
||||
AclResult aclresult;
|
||||
|
||||
/* Superusers can always do it */
|
||||
if (!superuser())
|
||||
{
|
||||
/* Otherwise, must be owner of the existing object */
|
||||
if (!pg_conversion_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
|
||||
NameStr(convForm->conname));
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
/* New owner must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(convForm->connamespace,
|
||||
newOwnerId,
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
||||
get_namespace_name(convForm->connamespace));
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify the owner --- okay to scribble on tup because it's a copy
|
||||
*/
|
||||
convForm->conowner = newOwnerId;
|
||||
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(ConversionRelationId, conversionOid,
|
||||
newOwnerId);
|
||||
}
|
||||
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
@@ -2750,95 +2750,3 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
|
||||
if (relation != NULL)
|
||||
relation_close(relation, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* AlterExtensionOwner_internal
|
||||
*
|
||||
* Internal routine for changing the owner of an extension. rel must be
|
||||
* pg_extension, already open and suitably locked; it will not be closed.
|
||||
*
|
||||
* Note that this only changes ownership of the extension itself; it doesn't
|
||||
* change the ownership of objects it contains. Since this function is
|
||||
* currently only called from REASSIGN OWNED, this restriction is okay because
|
||||
* said objects would also be affected by our caller. But it's not enough for
|
||||
* a full-fledged ALTER OWNER implementation, so beware.
|
||||
*/
|
||||
static void
|
||||
AlterExtensionOwner_internal(Relation rel, Oid extensionOid, Oid newOwnerId)
|
||||
{
|
||||
Form_pg_extension extForm;
|
||||
HeapTuple tup;
|
||||
SysScanDesc scandesc;
|
||||
ScanKeyData entry[1];
|
||||
|
||||
Assert(RelationGetRelid(rel) == ExtensionRelationId);
|
||||
|
||||
ScanKeyInit(&entry[0],
|
||||
ObjectIdAttributeNumber,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(extensionOid));
|
||||
|
||||
scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
|
||||
SnapshotNow, 1, entry);
|
||||
|
||||
/* We assume that there can be at most one matching tuple */
|
||||
tup = systable_getnext(scandesc);
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for extension %u", extensionOid);
|
||||
|
||||
tup = heap_copytuple(tup);
|
||||
systable_endscan(scandesc);
|
||||
|
||||
extForm = (Form_pg_extension) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* If the new owner is the same as the existing owner, consider the
|
||||
* command to have succeeded. This is for dump restoration purposes.
|
||||
*/
|
||||
if (extForm->extowner != newOwnerId)
|
||||
{
|
||||
/* Superusers can always do it */
|
||||
if (!superuser())
|
||||
{
|
||||
/* Otherwise, must be owner of the existing object */
|
||||
if (!pg_extension_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
|
||||
NameStr(extForm->extname));
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
/* no privilege checks on namespace are required */
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify the owner --- okay to scribble on tup because it's a copy
|
||||
*/
|
||||
extForm->extowner = newOwnerId;
|
||||
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(ExtensionRelationId, extensionOid,
|
||||
newOwnerId);
|
||||
}
|
||||
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change extension owner, by OID
|
||||
*/
|
||||
void
|
||||
AlterExtensionOwner_oid(Oid extensionOid, Oid newOwnerId)
|
||||
{
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(ExtensionRelationId, RowExclusiveLock);
|
||||
|
||||
AlterExtensionOwner_internal(rel, extensionOid, newOwnerId);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
@@ -66,11 +66,6 @@
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/tqual.h"
|
||||
|
||||
|
||||
static void AlterFunctionOwner_internal(Relation rel, HeapTuple tup,
|
||||
Oid newOwnerId);
|
||||
|
||||
|
||||
/*
|
||||
* Examine the RETURNS clause of the CREATE FUNCTION statement
|
||||
* and return information about it as *prorettype_p and *returnsSet.
|
||||
@@ -1109,138 +1104,6 @@ RenameFunction(List *name, List *argtypes, const char *newname)
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change function owner by name and args
|
||||
*/
|
||||
void
|
||||
AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
|
||||
{
|
||||
Relation rel;
|
||||
Oid procOid;
|
||||
HeapTuple tup;
|
||||
|
||||
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
|
||||
|
||||
procOid = LookupFuncNameTypeNames(name, argtypes, false);
|
||||
|
||||
tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procOid));
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for function %u", procOid);
|
||||
|
||||
if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("\"%s\" is an aggregate function",
|
||||
NameListToString(name)),
|
||||
errhint("Use ALTER AGGREGATE to change owner of aggregate functions.")));
|
||||
|
||||
AlterFunctionOwner_internal(rel, tup, newOwnerId);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change function owner by Oid
|
||||
*/
|
||||
void
|
||||
AlterFunctionOwner_oid(Oid procOid, Oid newOwnerId)
|
||||
{
|
||||
Relation rel;
|
||||
HeapTuple tup;
|
||||
|
||||
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procOid));
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for function %u", procOid);
|
||||
AlterFunctionOwner_internal(rel, tup, newOwnerId);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
static void
|
||||
AlterFunctionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
|
||||
{
|
||||
Form_pg_proc procForm;
|
||||
AclResult aclresult;
|
||||
Oid procOid;
|
||||
|
||||
Assert(RelationGetRelid(rel) == ProcedureRelationId);
|
||||
Assert(tup->t_tableOid == ProcedureRelationId);
|
||||
|
||||
procForm = (Form_pg_proc) GETSTRUCT(tup);
|
||||
procOid = HeapTupleGetOid(tup);
|
||||
|
||||
/*
|
||||
* If the new owner is the same as the existing owner, consider the
|
||||
* command to have succeeded. This is for dump restoration purposes.
|
||||
*/
|
||||
if (procForm->proowner != newOwnerId)
|
||||
{
|
||||
Datum repl_val[Natts_pg_proc];
|
||||
bool repl_null[Natts_pg_proc];
|
||||
bool repl_repl[Natts_pg_proc];
|
||||
Acl *newAcl;
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
HeapTuple newtuple;
|
||||
|
||||
/* Superusers can always do it */
|
||||
if (!superuser())
|
||||
{
|
||||
/* Otherwise, must be owner of the existing object */
|
||||
if (!pg_proc_ownercheck(procOid, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
|
||||
NameStr(procForm->proname));
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
/* New owner must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(procForm->pronamespace,
|
||||
newOwnerId,
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
||||
get_namespace_name(procForm->pronamespace));
|
||||
}
|
||||
|
||||
memset(repl_null, false, sizeof(repl_null));
|
||||
memset(repl_repl, false, sizeof(repl_repl));
|
||||
|
||||
repl_repl[Anum_pg_proc_proowner - 1] = true;
|
||||
repl_val[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(newOwnerId);
|
||||
|
||||
/*
|
||||
* Determine the modified ACL for the new owner. This is only
|
||||
* necessary when the ACL is non-null.
|
||||
*/
|
||||
aclDatum = SysCacheGetAttr(PROCOID, tup,
|
||||
Anum_pg_proc_proacl,
|
||||
&isNull);
|
||||
if (!isNull)
|
||||
{
|
||||
newAcl = aclnewowner(DatumGetAclP(aclDatum),
|
||||
procForm->proowner, newOwnerId);
|
||||
repl_repl[Anum_pg_proc_proacl - 1] = true;
|
||||
repl_val[Anum_pg_proc_proacl - 1] = PointerGetDatum(newAcl);
|
||||
}
|
||||
|
||||
newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val,
|
||||
repl_null, repl_repl);
|
||||
|
||||
simple_heap_update(rel, &newtuple->t_self, newtuple);
|
||||
CatalogUpdateIndexes(rel, newtuple);
|
||||
|
||||
heap_freetuple(newtuple);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(ProcedureRelationId, procOid, newOwnerId);
|
||||
}
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements the ALTER FUNCTION utility command (except for the
|
||||
* RENAME and OWNER clauses, which are handled as part of the generic
|
||||
|
@@ -81,11 +81,6 @@ static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
|
||||
List *operators);
|
||||
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
|
||||
List *procedures);
|
||||
static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple,
|
||||
Oid newOwnerId);
|
||||
static void AlterOpFamilyOwner_internal(Relation rel, HeapTuple tuple,
|
||||
Oid newOwnerId);
|
||||
|
||||
|
||||
/*
|
||||
* OpFamilyCacheLookup
|
||||
@@ -1809,249 +1804,6 @@ RenameOpFamily(List *name, const char *access_method, const char *newname)
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change opclass owner by name
|
||||
*/
|
||||
void
|
||||
AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
|
||||
{
|
||||
Oid amOid;
|
||||
Relation rel;
|
||||
HeapTuple tup;
|
||||
HeapTuple origtup;
|
||||
|
||||
amOid = get_am_oid(access_method, false);
|
||||
|
||||
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
|
||||
|
||||
/* Look up the opclass. */
|
||||
origtup = OpClassCacheLookup(amOid, name, false);
|
||||
tup = heap_copytuple(origtup);
|
||||
ReleaseSysCache(origtup);
|
||||
|
||||
AlterOpClassOwner_internal(rel, tup, newOwnerId);
|
||||
|
||||
heap_freetuple(tup);
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change operator class owner, specified by OID
|
||||
*/
|
||||
void
|
||||
AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCacheCopy1(CLAOID, ObjectIdGetDatum(opclassOid));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
|
||||
|
||||
AlterOpClassOwner_internal(rel, tup, newOwnerId);
|
||||
|
||||
heap_freetuple(tup);
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* The first parameter is pg_opclass, opened and suitably locked. The second
|
||||
* parameter is a copy of the tuple from pg_opclass we want to modify.
|
||||
*/
|
||||
static void
|
||||
AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
|
||||
{
|
||||
Oid namespaceOid;
|
||||
AclResult aclresult;
|
||||
Form_pg_opclass opcForm;
|
||||
|
||||
Assert(tup->t_tableOid == OperatorClassRelationId);
|
||||
Assert(RelationGetRelid(rel) == OperatorClassRelationId);
|
||||
|
||||
opcForm = (Form_pg_opclass) GETSTRUCT(tup);
|
||||
|
||||
namespaceOid = opcForm->opcnamespace;
|
||||
|
||||
/*
|
||||
* If the new owner is the same as the existing owner, consider the
|
||||
* command to have succeeded. This is for dump restoration purposes.
|
||||
*/
|
||||
if (opcForm->opcowner != newOwnerId)
|
||||
{
|
||||
/* Superusers can always do it */
|
||||
if (!superuser())
|
||||
{
|
||||
/* Otherwise, must be owner of the existing object */
|
||||
if (!pg_opclass_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
|
||||
NameStr(opcForm->opcname));
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
/* New owner must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
||||
get_namespace_name(namespaceOid));
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify the owner --- okay to scribble on tup because it's a copy
|
||||
*/
|
||||
opcForm->opcowner = newOwnerId;
|
||||
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(OperatorClassRelationId, HeapTupleGetOid(tup),
|
||||
newOwnerId);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Change opfamily owner by name
|
||||
*/
|
||||
void
|
||||
AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId)
|
||||
{
|
||||
Oid amOid;
|
||||
Relation rel;
|
||||
HeapTuple tup;
|
||||
char *opfname;
|
||||
char *schemaname;
|
||||
|
||||
amOid = get_am_oid(access_method, false);
|
||||
|
||||
rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
|
||||
|
||||
/*
|
||||
* Look up the opfamily
|
||||
*/
|
||||
DeconstructQualifiedName(name, &schemaname, &opfname);
|
||||
|
||||
if (schemaname)
|
||||
{
|
||||
Oid namespaceOid;
|
||||
|
||||
namespaceOid = LookupExplicitNamespace(schemaname);
|
||||
|
||||
tup = SearchSysCacheCopy3(OPFAMILYAMNAMENSP,
|
||||
ObjectIdGetDatum(amOid),
|
||||
PointerGetDatum(opfname),
|
||||
ObjectIdGetDatum(namespaceOid));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
|
||||
opfname, access_method)));
|
||||
}
|
||||
else
|
||||
{
|
||||
Oid opfOid;
|
||||
|
||||
opfOid = OpfamilynameGetOpfid(amOid, opfname);
|
||||
if (!OidIsValid(opfOid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
|
||||
opfname, access_method)));
|
||||
|
||||
tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfOid));
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
|
||||
}
|
||||
|
||||
AlterOpFamilyOwner_internal(rel, tup, newOwnerId);
|
||||
|
||||
heap_freetuple(tup);
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change operator family owner, specified by OID
|
||||
*/
|
||||
void
|
||||
AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCacheCopy1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
|
||||
|
||||
AlterOpFamilyOwner_internal(rel, tup, newOwnerId);
|
||||
|
||||
heap_freetuple(tup);
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* The first parameter is pg_opfamily, opened and suitably locked. The second
|
||||
* parameter is a copy of the tuple from pg_opfamily we want to modify.
|
||||
*/
|
||||
static void
|
||||
AlterOpFamilyOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
|
||||
{
|
||||
Oid namespaceOid;
|
||||
AclResult aclresult;
|
||||
Form_pg_opfamily opfForm;
|
||||
|
||||
Assert(tup->t_tableOid == OperatorFamilyRelationId);
|
||||
Assert(RelationGetRelid(rel) == OperatorFamilyRelationId);
|
||||
|
||||
opfForm = (Form_pg_opfamily) GETSTRUCT(tup);
|
||||
|
||||
namespaceOid = opfForm->opfnamespace;
|
||||
|
||||
/*
|
||||
* If the new owner is the same as the existing owner, consider the
|
||||
* command to have succeeded. This is for dump restoration purposes.
|
||||
*/
|
||||
if (opfForm->opfowner != newOwnerId)
|
||||
{
|
||||
/* Superusers can always do it */
|
||||
if (!superuser())
|
||||
{
|
||||
/* Otherwise, must be owner of the existing object */
|
||||
if (!pg_opfamily_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
|
||||
NameStr(opfForm->opfname));
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
/* New owner must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
||||
get_namespace_name(namespaceOid));
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify the owner --- okay to scribble on tup because it's a copy
|
||||
*/
|
||||
opfForm->opfowner = newOwnerId;
|
||||
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(OperatorFamilyRelationId, HeapTupleGetOid(tup),
|
||||
newOwnerId);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* get_am_oid - given an access method name, look up the OID
|
||||
*
|
||||
|
@@ -51,9 +51,6 @@
|
||||
#include "utils/rel.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static void AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId);
|
||||
|
||||
/*
|
||||
* DefineOperator
|
||||
* this function extracts all the information from the
|
||||
@@ -333,93 +330,3 @@ RemoveOperatorById(Oid operOid)
|
||||
|
||||
heap_close(relation, RowExclusiveLock);
|
||||
}
|
||||
|
||||
void
|
||||
AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId)
|
||||
{
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(OperatorRelationId, RowExclusiveLock);
|
||||
|
||||
AlterOperatorOwner_internal(rel, operOid, newOwnerId);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* change operator owner
|
||||
*/
|
||||
void
|
||||
AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
|
||||
Oid newOwnerId)
|
||||
{
|
||||
Oid operOid;
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(OperatorRelationId, RowExclusiveLock);
|
||||
|
||||
operOid = LookupOperNameTypeNames(NULL, name,
|
||||
typeName1, typeName2,
|
||||
false, -1);
|
||||
|
||||
AlterOperatorOwner_internal(rel, operOid, newOwnerId);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
static void
|
||||
AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
|
||||
{
|
||||
HeapTuple tup;
|
||||
AclResult aclresult;
|
||||
Form_pg_operator oprForm;
|
||||
|
||||
Assert(RelationGetRelid(rel) == OperatorRelationId);
|
||||
|
||||
tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(operOid));
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for operator %u", operOid);
|
||||
|
||||
oprForm = (Form_pg_operator) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* If the new owner is the same as the existing owner, consider the
|
||||
* command to have succeeded. This is for dump restoration purposes.
|
||||
*/
|
||||
if (oprForm->oprowner != newOwnerId)
|
||||
{
|
||||
/* Superusers can always do it */
|
||||
if (!superuser())
|
||||
{
|
||||
/* Otherwise, must be owner of the existing object */
|
||||
if (!pg_oper_ownercheck(operOid, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
|
||||
NameStr(oprForm->oprname));
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
/* New owner must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(oprForm->oprnamespace,
|
||||
newOwnerId,
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
||||
get_namespace_name(oprForm->oprnamespace));
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify the owner --- okay to scribble on tup because it's a copy
|
||||
*/
|
||||
oprForm->oprowner = newOwnerId;
|
||||
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(OperatorRelationId, operOid, newOwnerId);
|
||||
}
|
||||
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
@@ -55,9 +55,6 @@ static void create_proc_lang(const char *languageName, bool replace,
|
||||
Oid languageOwner, Oid handlerOid, Oid inlineOid,
|
||||
Oid valOid, bool trusted);
|
||||
static PLTemplate *find_language_template(const char *languageName);
|
||||
static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel,
|
||||
Oid newOwnerId);
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* CREATE PROCEDURAL LANGUAGE
|
||||
@@ -574,120 +571,6 @@ RenameLanguage(const char *oldname, const char *newname)
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change language owner
|
||||
*/
|
||||
void
|
||||
AlterLanguageOwner(const char *name, Oid newOwnerId)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(LanguageRelationId, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCache1(LANGNAME, CStringGetDatum(name));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("language \"%s\" does not exist", name)));
|
||||
|
||||
AlterLanguageOwner_internal(tup, rel, newOwnerId);
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Change language owner, specified by OID
|
||||
*/
|
||||
void
|
||||
AlterLanguageOwner_oid(Oid oid, Oid newOwnerId)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
|
||||
rel = heap_open(LanguageRelationId, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCache1(LANGOID, ObjectIdGetDatum(oid));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "cache lookup failed for language %u", oid);
|
||||
|
||||
AlterLanguageOwner_internal(tup, rel, newOwnerId);
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Workhorse for AlterLanguageOwner variants
|
||||
*/
|
||||
static void
|
||||
AlterLanguageOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
|
||||
{
|
||||
Form_pg_language lanForm;
|
||||
|
||||
lanForm = (Form_pg_language) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* If the new owner is the same as the existing owner, consider the
|
||||
* command to have succeeded. This is for dump restoration purposes.
|
||||
*/
|
||||
if (lanForm->lanowner != newOwnerId)
|
||||
{
|
||||
Datum repl_val[Natts_pg_language];
|
||||
bool repl_null[Natts_pg_language];
|
||||
bool repl_repl[Natts_pg_language];
|
||||
Acl *newAcl;
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
HeapTuple newtuple;
|
||||
|
||||
/* Otherwise, must be owner of the existing object */
|
||||
if (!pg_language_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
|
||||
NameStr(lanForm->lanname));
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
memset(repl_null, false, sizeof(repl_null));
|
||||
memset(repl_repl, false, sizeof(repl_repl));
|
||||
|
||||
repl_repl[Anum_pg_language_lanowner - 1] = true;
|
||||
repl_val[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(newOwnerId);
|
||||
|
||||
/*
|
||||
* Determine the modified ACL for the new owner. This is only
|
||||
* necessary when the ACL is non-null.
|
||||
*/
|
||||
aclDatum = SysCacheGetAttr(LANGNAME, tup,
|
||||
Anum_pg_language_lanacl,
|
||||
&isNull);
|
||||
if (!isNull)
|
||||
{
|
||||
newAcl = aclnewowner(DatumGetAclP(aclDatum),
|
||||
lanForm->lanowner, newOwnerId);
|
||||
repl_repl[Anum_pg_language_lanacl - 1] = true;
|
||||
repl_val[Anum_pg_language_lanacl - 1] = PointerGetDatum(newAcl);
|
||||
}
|
||||
|
||||
newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
|
||||
repl_val, repl_null, repl_repl);
|
||||
|
||||
simple_heap_update(rel, &newtuple->t_self, newtuple);
|
||||
CatalogUpdateIndexes(rel, newtuple);
|
||||
|
||||
heap_freetuple(newtuple);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(LanguageRelationId, HeapTupleGetOid(tup),
|
||||
newOwnerId);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* get_language_oid - given a language name, look up the OID
|
||||
*
|
||||
|
@@ -883,105 +883,6 @@ RenameTableSpace(const char *oldname, const char *newname)
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change tablespace owner
|
||||
*/
|
||||
void
|
||||
AlterTableSpaceOwner(const char *name, Oid newOwnerId)
|
||||
{
|
||||
Relation rel;
|
||||
ScanKeyData entry[1];
|
||||
HeapScanDesc scandesc;
|
||||
Form_pg_tablespace spcForm;
|
||||
HeapTuple tup;
|
||||
|
||||
/* Search pg_tablespace */
|
||||
rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
|
||||
|
||||
ScanKeyInit(&entry[0],
|
||||
Anum_pg_tablespace_spcname,
|
||||
BTEqualStrategyNumber, F_NAMEEQ,
|
||||
CStringGetDatum(name));
|
||||
scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
|
||||
tup = heap_getnext(scandesc, ForwardScanDirection);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("tablespace \"%s\" does not exist", name)));
|
||||
|
||||
spcForm = (Form_pg_tablespace) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* If the new owner is the same as the existing owner, consider the
|
||||
* command to have succeeded. This is for dump restoration purposes.
|
||||
*/
|
||||
if (spcForm->spcowner != newOwnerId)
|
||||
{
|
||||
Datum repl_val[Natts_pg_tablespace];
|
||||
bool repl_null[Natts_pg_tablespace];
|
||||
bool repl_repl[Natts_pg_tablespace];
|
||||
Acl *newAcl;
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
HeapTuple newtuple;
|
||||
|
||||
/* Otherwise, must be owner of the existing object */
|
||||
if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
|
||||
name);
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
/*
|
||||
* Normally we would also check for create permissions here, but there
|
||||
* are none for tablespaces so we follow what rename tablespace does
|
||||
* and omit the create permissions check.
|
||||
*
|
||||
* NOTE: Only superusers may create tablespaces to begin with and so
|
||||
* initially only a superuser would be able to change its ownership
|
||||
* anyway.
|
||||
*/
|
||||
|
||||
memset(repl_null, false, sizeof(repl_null));
|
||||
memset(repl_repl, false, sizeof(repl_repl));
|
||||
|
||||
repl_repl[Anum_pg_tablespace_spcowner - 1] = true;
|
||||
repl_val[Anum_pg_tablespace_spcowner - 1] = ObjectIdGetDatum(newOwnerId);
|
||||
|
||||
/*
|
||||
* Determine the modified ACL for the new owner. This is only
|
||||
* necessary when the ACL is non-null.
|
||||
*/
|
||||
aclDatum = heap_getattr(tup,
|
||||
Anum_pg_tablespace_spcacl,
|
||||
RelationGetDescr(rel),
|
||||
&isNull);
|
||||
if (!isNull)
|
||||
{
|
||||
newAcl = aclnewowner(DatumGetAclP(aclDatum),
|
||||
spcForm->spcowner, newOwnerId);
|
||||
repl_repl[Anum_pg_tablespace_spcacl - 1] = true;
|
||||
repl_val[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(newAcl);
|
||||
}
|
||||
|
||||
newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl);
|
||||
|
||||
simple_heap_update(rel, &newtuple->t_self, newtuple);
|
||||
CatalogUpdateIndexes(rel, newtuple);
|
||||
|
||||
heap_freetuple(newtuple);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(TableSpaceRelationId, HeapTupleGetOid(tup),
|
||||
newOwnerId);
|
||||
}
|
||||
|
||||
heap_endscan(scandesc);
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Alter table space options
|
||||
*/
|
||||
|
@@ -716,66 +716,6 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* ALTER TEXT SEARCH DICTIONARY OWNER
|
||||
*/
|
||||
void
|
||||
AlterTSDictionaryOwner(List *name, Oid newOwnerId)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
Oid dictId;
|
||||
Oid namespaceOid;
|
||||
AclResult aclresult;
|
||||
Form_pg_ts_dict form;
|
||||
|
||||
rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
|
||||
|
||||
dictId = get_ts_dict_oid(name, false);
|
||||
|
||||
tup = SearchSysCacheCopy1(TSDICTOID, ObjectIdGetDatum(dictId));
|
||||
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for text search dictionary %u",
|
||||
dictId);
|
||||
|
||||
form = (Form_pg_ts_dict) GETSTRUCT(tup);
|
||||
namespaceOid = form->dictnamespace;
|
||||
|
||||
if (form->dictowner != newOwnerId)
|
||||
{
|
||||
/* Superusers can always do it */
|
||||
if (!superuser())
|
||||
{
|
||||
/* must be owner */
|
||||
if (!pg_ts_dict_ownercheck(dictId, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
|
||||
NameListToString(name));
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
/* New owner must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId, ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
||||
get_namespace_name(namespaceOid));
|
||||
}
|
||||
|
||||
form->dictowner = newOwnerId;
|
||||
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(TSDictionaryRelationId, HeapTupleGetOid(tup),
|
||||
newOwnerId);
|
||||
}
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
/* ---------------------- TS Template commands -----------------------*/
|
||||
|
||||
/*
|
||||
@@ -1390,66 +1330,6 @@ RemoveTSConfigurationById(Oid cfgId)
|
||||
heap_close(relMap, RowExclusiveLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* ALTER TEXT SEARCH CONFIGURATION OWNER
|
||||
*/
|
||||
void
|
||||
AlterTSConfigurationOwner(List *name, Oid newOwnerId)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation rel;
|
||||
Oid cfgId;
|
||||
AclResult aclresult;
|
||||
Oid namespaceOid;
|
||||
Form_pg_ts_config form;
|
||||
|
||||
rel = heap_open(TSConfigRelationId, RowExclusiveLock);
|
||||
|
||||
cfgId = get_ts_config_oid(name, false);
|
||||
|
||||
tup = SearchSysCacheCopy1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
|
||||
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "cache lookup failed for text search configuration %u",
|
||||
cfgId);
|
||||
|
||||
form = (Form_pg_ts_config) GETSTRUCT(tup);
|
||||
namespaceOid = form->cfgnamespace;
|
||||
|
||||
if (form->cfgowner != newOwnerId)
|
||||
{
|
||||
/* Superusers can always do it */
|
||||
if (!superuser())
|
||||
{
|
||||
/* must be owner */
|
||||
if (!pg_ts_config_ownercheck(cfgId, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
|
||||
NameListToString(name));
|
||||
|
||||
/* Must be able to become new owner */
|
||||
check_is_member_of_role(GetUserId(), newOwnerId);
|
||||
|
||||
/* New owner must have CREATE privilege on namespace */
|
||||
aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId, ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
||||
get_namespace_name(namespaceOid));
|
||||
}
|
||||
|
||||
form->cfgowner = newOwnerId;
|
||||
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
CatalogUpdateIndexes(rel, tup);
|
||||
|
||||
/* Update owner dependency reference */
|
||||
changeDependencyOnOwner(TSConfigRelationId, HeapTupleGetOid(tup),
|
||||
newOwnerId);
|
||||
}
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
heap_freetuple(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* ALTER TEXT SEARCH CONFIGURATION - main entry point
|
||||
*/
|
||||
|
Reference in New Issue
Block a user