1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-01 12:18:01 +03:00

Allow granting SET and ALTER SYSTEM privileges on GUC parameters.

This patch allows "PGC_SUSET" parameters to be set by non-superusers
if they have been explicitly granted the privilege to do so.
The privilege to perform ALTER SYSTEM SET/RESET on a specific parameter
can also be granted.
Such privileges are cluster-wide, not per database.  They are tracked
in a new shared catalog, pg_parameter_acl.

Granting and revoking these new privileges works as one would expect.
One caveat is that PGC_USERSET GUCs are unaffected by the SET privilege
--- one could wish that those were handled by a revocable grant to
PUBLIC, but they are not, because we couldn't make it robust enough
for GUCs defined by extensions.

Mark Dilger, reviewed at various times by Andrew Dunstan, Robert Haas,
Joshua Brindle, and myself

Discussion: https://postgr.es/m/3D691E20-C1D5-4B80-8BA5-6BEB63AF3029@enterprisedb.com
This commit is contained in:
Tom Lane
2022-04-06 13:24:33 -04:00
parent 2ef6f11b0c
commit a0ffa885e4
44 changed files with 2465 additions and 194 deletions

View File

@@ -38,6 +38,7 @@ OBJS = \
pg_largeobject.o \
pg_namespace.o \
pg_operator.o \
pg_parameter_acl.o \
pg_proc.o \
pg_publication.o \
pg_range.o \
@@ -68,7 +69,8 @@ CATALOG_HEADERS := \
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
pg_foreign_table.h pg_policy.h pg_replication_origin.h \
pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \
pg_collation.h pg_partitioned_table.h pg_range.h pg_transform.h \
pg_collation.h pg_parameter_acl.h pg_partitioned_table.h \
pg_range.h pg_transform.h \
pg_sequence.h pg_publication.h pg_publication_namespace.h \
pg_publication_rel.h pg_subscription.h pg_subscription_rel.h

View File

@@ -48,6 +48,7 @@
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_parameter_acl.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_subscription.h"
@@ -112,11 +113,13 @@ static void ExecGrant_Largeobject(InternalGrant *grantStmt);
static void ExecGrant_Namespace(InternalGrant *grantStmt);
static void ExecGrant_Tablespace(InternalGrant *grantStmt);
static void ExecGrant_Type(InternalGrant *grantStmt);
static void ExecGrant_Parameter(InternalGrant *grantStmt);
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
static void SetDefaultACL(InternalDefaultACL *iacls);
static List *objectNamesToOids(ObjectType objtype, List *objnames);
static List *objectNamesToOids(ObjectType objtype, List *objnames,
bool is_grant);
static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
static List *getRelationsInNamespace(Oid namespaceId, char relkind);
static void expand_col_privileges(List *colnames, Oid table_oid,
@@ -259,6 +262,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
case OBJECT_TYPE:
whole_mask = ACL_ALL_RIGHTS_TYPE;
break;
case OBJECT_PARAMETER_ACL:
whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
break;
default:
elog(ERROR, "unrecognized object type: %d", objtype);
/* not reached, but keep compiler quiet */
@@ -390,7 +396,8 @@ ExecuteGrantStmt(GrantStmt *stmt)
switch (stmt->targtype)
{
case ACL_TARGET_OBJECT:
istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
stmt->is_grant);
break;
case ACL_TARGET_ALL_IN_SCHEMA:
istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
@@ -498,6 +505,10 @@ ExecuteGrantStmt(GrantStmt *stmt)
all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
errormsg = gettext_noop("invalid privilege type %s for foreign server");
break;
case OBJECT_PARAMETER_ACL:
all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
errormsg = gettext_noop("invalid privilege type %s for parameter");
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) stmt->objtype);
@@ -600,6 +611,9 @@ ExecGrantStmt_oids(InternalGrant *istmt)
case OBJECT_TABLESPACE:
ExecGrant_Tablespace(istmt);
break;
case OBJECT_PARAMETER_ACL:
ExecGrant_Parameter(istmt);
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) istmt->objtype);
@@ -626,7 +640,7 @@ ExecGrantStmt_oids(InternalGrant *istmt)
* to fail.
*/
static List *
objectNamesToOids(ObjectType objtype, List *objnames)
objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
{
List *objects = NIL;
ListCell *cell;
@@ -759,6 +773,37 @@ objectNamesToOids(ObjectType objtype, List *objnames)
objects = lappend_oid(objects, srvid);
}
break;
case OBJECT_PARAMETER_ACL:
foreach(cell, objnames)
{
/*
* In this code we represent a GUC by the OID of its entry in
* pg_parameter_acl, which we have to manufacture here if it
* doesn't exist yet. (That's a hack for sure, but it avoids
* messing with all the GRANT/REVOKE infrastructure that
* expects to use OIDs for object identities.) However, if
* this is a REVOKE, we can instead just ignore any GUCs that
* don't have such an entry, as they must not have any
* privileges needing removal.
*/
char *parameter = strVal(lfirst(cell));
Oid parameterId = ParameterAclLookup(parameter, true);
if (!OidIsValid(parameterId) && is_grant)
{
parameterId = ParameterAclCreate(parameter);
/*
* Prevent error when processing duplicate objects, and
* make this new entry visible so that ExecGrant_Parameter
* can update it.
*/
CommandCounterIncrement();
}
if (OidIsValid(parameterId))
objects = lappend_oid(objects, parameterId);
}
break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) objtype);
@@ -1494,6 +1539,9 @@ RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
case ForeignDataWrapperRelationId:
istmt.objtype = OBJECT_FDW;
break;
case ParameterAclRelationId:
istmt.objtype = OBJECT_PARAMETER_ACL;
break;
default:
elog(ERROR, "unexpected object class %u", classid);
break;
@@ -3225,6 +3273,154 @@ ExecGrant_Type(InternalGrant *istmt)
table_close(relation, RowExclusiveLock);
}
static void
ExecGrant_Parameter(InternalGrant *istmt)
{
Relation relation;
ListCell *cell;
if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
istmt->privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
relation = table_open(ParameterAclRelationId, RowExclusiveLock);
foreach(cell, istmt->objects)
{
Oid parameterId = lfirst_oid(cell);
Datum nameDatum;
const char *parname;
Datum aclDatum;
bool isNull;
AclMode avail_goptions;
AclMode this_privileges;
Acl *old_acl;
Acl *new_acl;
Oid grantorId;
Oid ownerId;
HeapTuple tuple;
int noldmembers;
int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for parameter ACL %u",
parameterId);
/* We'll need the GUC's name */
nameDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
Anum_pg_parameter_acl_parname,
&isNull);
Assert(!isNull);
parname = TextDatumGetCString(nameDatum);
/* Treat all parameters as belonging to the bootstrap superuser. */
ownerId = BOOTSTRAP_SUPERUSERID;
/*
* Get working copy of existing ACL. If there's no ACL, substitute the
* proper default.
*/
aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
Anum_pg_parameter_acl_paracl,
&isNull);
if (isNull)
{
old_acl = acldefault(istmt->objtype, ownerId);
/* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
else
{
old_acl = DatumGetAclPCopy(aclDatum);
/* Get the roles mentioned in the existing ACL */
noldmembers = aclmembers(old_acl, &oldmembers);
}
/* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), istmt->privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/*
* Restrict the privileges to what we can actually grant, and emit the
* standards-mandated warning and error messages.
*/
this_privileges =
restrict_and_check_grant(istmt->is_grant, avail_goptions,
istmt->all_privs, istmt->privileges,
parameterId, grantorId,
OBJECT_PARAMETER_ACL,
parname,
0, NULL);
/*
* Generate new ACL.
*/
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
istmt->grant_option, istmt->behavior,
istmt->grantees, this_privileges,
grantorId, ownerId);
/*
* We need the members of both old and new ACLs so we can correct the
* shared dependency information.
*/
nnewmembers = aclmembers(new_acl, &newmembers);
/*
* If the new ACL is equal to the default, we don't need the catalog
* entry any longer. Delete it rather than updating it, to avoid
* leaving a degenerate entry.
*/
if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
{
CatalogTupleDelete(relation, &tuple->t_self);
}
else
{
/* finished building new ACL value, now insert it */
HeapTuple newtuple;
Datum values[Natts_pg_parameter_acl];
bool nulls[Natts_pg_parameter_acl];
bool replaces[Natts_pg_parameter_acl];
MemSet(values, 0, sizeof(values));
MemSet(nulls, false, sizeof(nulls));
MemSet(replaces, false, sizeof(replaces));
replaces[Anum_pg_parameter_acl_paracl - 1] = true;
values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
values, nulls, replaces);
CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
}
/* Update initial privileges for extensions */
recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
new_acl);
/* Update the shared dependency ACL info */
updateAclDependencies(ParameterAclRelationId, parameterId, 0,
ownerId,
noldmembers, oldmembers,
nnewmembers, newmembers);
ReleaseSysCache(tuple);
pfree(new_acl);
/* prevent error when processing duplicate objects */
CommandCounterIncrement();
}
table_close(relation, RowExclusiveLock);
}
static AclMode
string_to_privilege(const char *privname)
@@ -3255,6 +3451,10 @@ string_to_privilege(const char *privname)
return ACL_CREATE_TEMP;
if (strcmp(privname, "connect") == 0)
return ACL_CONNECT;
if (strcmp(privname, "set") == 0)
return ACL_SET;
if (strcmp(privname, "alter system") == 0)
return ACL_ALTER_SYSTEM;
if (strcmp(privname, "rule") == 0)
return 0; /* ignore old RULE privileges */
ereport(ERROR,
@@ -3292,6 +3492,10 @@ privilege_to_string(AclMode privilege)
return "TEMP";
case ACL_CONNECT:
return "CONNECT";
case ACL_SET:
return "SET";
case ACL_ALTER_SYSTEM:
return "ALTER SYSTEM";
default:
elog(ERROR, "unrecognized privilege: %d", (int) privilege);
}
@@ -3376,6 +3580,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
case OBJECT_OPFAMILY:
msg = gettext_noop("permission denied for operator family %s");
break;
case OBJECT_PARAMETER_ACL:
msg = gettext_noop("permission denied for parameter %s");
break;
case OBJECT_POLICY:
msg = gettext_noop("permission denied for policy %s");
break;
@@ -3567,6 +3774,7 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
case OBJECT_DEFAULT:
case OBJECT_DEFACL:
case OBJECT_DOMCONSTRAINT:
case OBJECT_PARAMETER_ACL:
case OBJECT_PUBLICATION_NAMESPACE:
case OBJECT_PUBLICATION_REL:
case OBJECT_ROLE:
@@ -3653,6 +3861,8 @@ pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid,
case OBJECT_LARGEOBJECT:
return pg_largeobject_aclmask_snapshot(table_oid, roleid,
mask, how, NULL);
case OBJECT_PARAMETER_ACL:
return pg_parameter_acl_aclmask(table_oid, roleid, mask, how);
case OBJECT_SCHEMA:
return pg_namespace_aclmask(table_oid, roleid, mask, how);
case OBJECT_STATISTIC_EXT:
@@ -4000,6 +4210,121 @@ pg_database_aclmask(Oid db_oid, Oid roleid,
return result;
}
/*
* Exported routine for examining a user's privileges for a configuration
* parameter (GUC), identified by GUC name.
*/
AclMode
pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
{
AclMode result;
char *parname;
text *partext;
HeapTuple tuple;
/* Superusers bypass all permission checking. */
if (superuser_arg(roleid))
return mask;
/* Convert name to the form it should have in pg_parameter_acl... */
parname = convert_GUC_name_for_parameter_acl(name);
partext = cstring_to_text(parname);
/* ... and look it up */
tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
if (!HeapTupleIsValid(tuple))
{
/* If no entry, GUC has no permissions for non-superusers */
result = ACL_NO_RIGHTS;
}
else
{
Datum aclDatum;
bool isNull;
Acl *acl;
aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
Anum_pg_parameter_acl_paracl,
&isNull);
if (isNull)
{
/* No ACL, so build default ACL */
acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
aclDatum = (Datum) 0;
}
else
{
/* detoast ACL if necessary */
acl = DatumGetAclP(aclDatum);
}
result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
/* if we have a detoasted copy, free it */
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
ReleaseSysCache(tuple);
}
pfree(parname);
pfree(partext);
return result;
}
/*
* Exported routine for examining a user's privileges for a configuration
* parameter (GUC), identified by the OID of its pg_parameter_acl entry.
*/
AclMode
pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
{
AclMode result;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
Acl *acl;
/* Superusers bypass all permission checking. */
if (superuser_arg(roleid))
return mask;
/* Get the ACL from pg_parameter_acl */
tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("parameter ACL with OID %u does not exist",
acl_oid)));
aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
Anum_pg_parameter_acl_paracl,
&isNull);
if (isNull)
{
/* No ACL, so build default ACL */
acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
aclDatum = (Datum) 0;
}
else
{
/* detoast ACL if necessary */
acl = DatumGetAclP(aclDatum);
}
result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
/* if we have a detoasted copy, free it */
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
ReleaseSysCache(tuple);
return result;
}
/*
* Exported routine for examining a user's privileges for a function
*/
@@ -4713,6 +5038,32 @@ pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
return ACLCHECK_NO_PRIV;
}
/*
* Exported routine for checking a user's access privileges to a configuration
* parameter (GUC), identified by GUC name.
*/
AclResult
pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
{
if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
return ACLCHECK_OK;
else
return ACLCHECK_NO_PRIV;
}
/*
* Exported routine for checking a user's access privileges to a configuration
* parameter (GUC), identified by the OID of its pg_parameter_acl entry.
*/
AclResult
pg_parameter_acl_aclcheck(Oid acl_oid, Oid roleid, AclMode mode)
{
if (pg_parameter_acl_aclmask(acl_oid, roleid, mode, ACLMASK_ANY) != 0)
return ACLCHECK_OK;
else
return ACLCHECK_NO_PRIV;
}
/*
* Exported routine for checking a user's access privileges to a function
*/

View File

@@ -33,6 +33,7 @@
#include "catalog/pg_db_role_setting.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_parameter_acl.h"
#include "catalog/pg_replication_origin.h"
#include "catalog/pg_shdepend.h"
#include "catalog/pg_shdescription.h"
@@ -247,32 +248,35 @@ IsSharedRelation(Oid relationId)
if (relationId == AuthIdRelationId ||
relationId == AuthMemRelationId ||
relationId == DatabaseRelationId ||
relationId == SharedDescriptionRelationId ||
relationId == SharedDependRelationId ||
relationId == SharedSecLabelRelationId ||
relationId == TableSpaceRelationId ||
relationId == DbRoleSettingRelationId ||
relationId == ParameterAclRelationId ||
relationId == ReplicationOriginRelationId ||
relationId == SubscriptionRelationId)
relationId == SharedDependRelationId ||
relationId == SharedDescriptionRelationId ||
relationId == SharedSecLabelRelationId ||
relationId == SubscriptionRelationId ||
relationId == TableSpaceRelationId)
return true;
/* These are their indexes */
if (relationId == AuthIdRolnameIndexId ||
relationId == AuthIdOidIndexId ||
relationId == AuthMemRoleMemIndexId ||
if (relationId == AuthIdOidIndexId ||
relationId == AuthIdRolnameIndexId ||
relationId == AuthMemMemRoleIndexId ||
relationId == AuthMemRoleMemIndexId ||
relationId == DatabaseNameIndexId ||
relationId == DatabaseOidIndexId ||
relationId == SharedDescriptionObjIndexId ||
relationId == SharedDependDependerIndexId ||
relationId == SharedDependReferenceIndexId ||
relationId == SharedSecLabelObjectIndexId ||
relationId == TablespaceOidIndexId ||
relationId == TablespaceNameIndexId ||
relationId == DbRoleSettingDatidRolidIndexId ||
relationId == ParameterAclOidIndexId ||
relationId == ParameterAclParnameIndexId ||
relationId == ReplicationOriginIdentIndex ||
relationId == ReplicationOriginNameIndex ||
relationId == SharedDependDependerIndexId ||
relationId == SharedDependReferenceIndexId ||
relationId == SharedDescriptionObjIndexId ||
relationId == SharedSecLabelObjectIndexId ||
relationId == SubscriptionNameIndexId ||
relationId == SubscriptionObjectIndexId ||
relationId == SubscriptionNameIndexId)
relationId == TablespaceNameIndexId ||
relationId == TablespaceOidIndexId)
return true;
/* These are their toast tables and toast indexes */
if (relationId == PgAuthidToastTable ||
@@ -281,6 +285,8 @@ IsSharedRelation(Oid relationId)
relationId == PgDatabaseToastIndex ||
relationId == PgDbRoleSettingToastTable ||
relationId == PgDbRoleSettingToastIndex ||
relationId == PgParameterAclToastTable ||
relationId == PgParameterAclToastIndex ||
relationId == PgReplicationOriginToastTable ||
relationId == PgReplicationOriginToastIndex ||
relationId == PgShdescriptionToastTable ||

View File

@@ -46,6 +46,7 @@
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_parameter_acl.h"
#include "catalog/pg_policy.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_publication.h"
@@ -178,6 +179,7 @@ static const Oid object_classes[] = {
DefaultAclRelationId, /* OCLASS_DEFACL */
ExtensionRelationId, /* OCLASS_EXTENSION */
EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */
ParameterAclRelationId, /* OCLASS_PARAMETER_ACL */
PolicyRelationId, /* OCLASS_POLICY */
PublicationNamespaceRelationId, /* OCLASS_PUBLICATION_NAMESPACE */
PublicationRelationId, /* OCLASS_PUBLICATION */
@@ -1507,6 +1509,7 @@ doDeletion(const ObjectAddress *object, int flags)
case OCLASS_DATABASE:
case OCLASS_TBLSPACE:
case OCLASS_SUBSCRIPTION:
case OCLASS_PARAMETER_ACL:
elog(ERROR, "global objects cannot be deleted by doDeletion");
break;
@@ -2861,6 +2864,9 @@ getObjectClass(const ObjectAddress *object)
case EventTriggerRelationId:
return OCLASS_EVENT_TRIGGER;
case ParameterAclRelationId:
return OCLASS_PARAMETER_ACL;
case PolicyRelationId:
return OCLASS_POLICY;

View File

@@ -45,6 +45,7 @@
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_parameter_acl.h"
#include "catalog/pg_policy.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_publication.h"
@@ -818,6 +819,10 @@ static const struct object_type_map
{
"event trigger", OBJECT_EVENT_TRIGGER
},
/* OCLASS_PARAMETER_ACL */
{
"parameter ACL", OBJECT_PARAMETER_ACL
},
/* OCLASS_POLICY */
{
"policy", OBJECT_POLICY
@@ -1014,6 +1019,7 @@ get_object_address(ObjectType objtype, Node *object,
case OBJECT_FDW:
case OBJECT_FOREIGN_SERVER:
case OBJECT_EVENT_TRIGGER:
case OBJECT_PARAMETER_ACL:
case OBJECT_ACCESS_METHOD:
case OBJECT_PUBLICATION:
case OBJECT_SUBSCRIPTION:
@@ -1315,6 +1321,11 @@ get_object_address_unqualified(ObjectType objtype,
address.objectId = get_event_trigger_oid(name, missing_ok);
address.objectSubId = 0;
break;
case OBJECT_PARAMETER_ACL:
address.classId = ParameterAclRelationId;
address.objectId = ParameterAclLookup(name, missing_ok);
address.objectSubId = 0;
break;
case OBJECT_PUBLICATION:
address.classId = PublicationRelationId;
address.objectId = get_publication_oid(name, missing_ok);
@@ -2307,6 +2318,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
case OBJECT_FDW:
case OBJECT_FOREIGN_SERVER:
case OBJECT_LANGUAGE:
case OBJECT_PARAMETER_ACL:
case OBJECT_PUBLICATION:
case OBJECT_ROLE:
case OBJECT_SCHEMA:
@@ -2597,6 +2609,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
case OBJECT_TSPARSER:
case OBJECT_TSTEMPLATE:
case OBJECT_ACCESS_METHOD:
case OBJECT_PARAMETER_ACL:
/* We treat these object types as being owned by superusers */
if (!superuser_arg(roleid))
ereport(ERROR,
@@ -3880,6 +3893,32 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok)
break;
}
case OCLASS_PARAMETER_ACL:
{
HeapTuple tup;
Datum nameDatum;
bool isNull;
char *parname;
tup = SearchSysCache1(PARAMETERACLOID,
ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup))
{
if (!missing_ok)
elog(ERROR, "cache lookup failed for parameter ACL %u",
object->objectId);
break;
}
nameDatum = SysCacheGetAttr(PARAMETERACLOID, tup,
Anum_pg_parameter_acl_parname,
&isNull);
Assert(!isNull);
parname = TextDatumGetCString(nameDatum);
appendStringInfo(&buffer, _("parameter %s"), parname);
ReleaseSysCache(tup);
break;
}
case OCLASS_POLICY:
{
Relation policy_rel;
@@ -4547,6 +4586,10 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
appendStringInfoString(&buffer, "event trigger");
break;
case OCLASS_PARAMETER_ACL:
appendStringInfoString(&buffer, "parameter ACL");
break;
case OCLASS_POLICY:
appendStringInfoString(&buffer, "policy");
break;
@@ -5693,6 +5736,34 @@ getObjectIdentityParts(const ObjectAddress *object,
break;
}
case OCLASS_PARAMETER_ACL:
{
HeapTuple tup;
Datum nameDatum;
bool isNull;
char *parname;
tup = SearchSysCache1(PARAMETERACLOID,
ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup))
{
if (!missing_ok)
elog(ERROR, "cache lookup failed for parameter ACL %u",
object->objectId);
break;
}
nameDatum = SysCacheGetAttr(PARAMETERACLOID, tup,
Anum_pg_parameter_acl_parname,
&isNull);
Assert(!isNull);
parname = TextDatumGetCString(nameDatum);
appendStringInfoString(&buffer, parname);
if (objname)
*objname = list_make1(parname);
ReleaseSysCache(tup);
break;
}
case OCLASS_POLICY:
{
Relation polDesc;

View File

@@ -0,0 +1,118 @@
/*-------------------------------------------------------------------------
*
* pg_parameter_acl.c
* routines to support manipulation of the pg_parameter_acl relation
*
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/catalog/pg_parameter_acl.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_parameter_acl.h"
#include "utils/builtins.h"
#include "utils/pg_locale.h"
#include "utils/rel.h"
#include "utils/syscache.h"
/*
* ParameterAclLookup - Given a configuration parameter name,
* look up the associated configuration parameter ACL's OID.
*
* If missing_ok is false, throw an error if ACL entry not found. If
* true, just return InvalidOid.
*/
Oid
ParameterAclLookup(const char *parameter, bool missing_ok)
{
Oid oid;
char *parname;
/* Convert name to the form it should have in pg_parameter_acl... */
parname = convert_GUC_name_for_parameter_acl(parameter);
/* ... and look it up */
oid = GetSysCacheOid1(PARAMETERACLNAME, Anum_pg_parameter_acl_oid,
PointerGetDatum(cstring_to_text(parname)));
if (!OidIsValid(oid) && !missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("parameter ACL \"%s\" does not exist", parameter)));
pfree(parname);
return oid;
}
/*
* ParameterAclCreate
*
* Add a new tuple to pg_parameter_acl.
*
* parameter: the parameter name to create an entry for.
* Caller should have verified that there's no such entry already.
*
* Returns the new entry's OID.
*/
Oid
ParameterAclCreate(const char *parameter)
{
Oid parameterId;
char *parname;
Relation rel;
TupleDesc tupDesc;
HeapTuple tuple;
Datum values[Natts_pg_parameter_acl];
bool nulls[Natts_pg_parameter_acl];
/*
* To prevent cluttering pg_parameter_acl with useless entries, insist
* that the name be valid.
*/
if (!check_GUC_name_for_parameter_acl(parameter))
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
errmsg("invalid parameter name \"%s\"",
parameter)));
/* Convert name to the form it should have in pg_parameter_acl. */
parname = convert_GUC_name_for_parameter_acl(parameter);
/*
* Create and insert a new record containing a null ACL.
*
* We don't take a strong enough lock to prevent concurrent insertions,
* relying instead on the unique index.
*/
rel = table_open(ParameterAclRelationId, RowExclusiveLock);
tupDesc = RelationGetDescr(rel);
MemSet(values, 0, sizeof(values));
MemSet(nulls, false, sizeof(nulls));
parameterId = GetNewOidWithIndex(rel,
ParameterAclOidIndexId,
Anum_pg_parameter_acl_oid);
values[Anum_pg_parameter_acl_oid - 1] = ObjectIdGetDatum(parameterId);
values[Anum_pg_parameter_acl_parname - 1] =
PointerGetDatum(cstring_to_text(parname));
nulls[Anum_pg_parameter_acl_paracl - 1] = true;
tuple = heap_form_tuple(tupDesc, values, nulls);
CatalogTupleInsert(rel, tuple);
/* Close pg_parameter_acl, but keep lock till commit. */
heap_freetuple(tuple);
table_close(rel, NoLock);
return parameterId;
}

View File

@@ -658,6 +658,7 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
case OCLASS_DEFACL:
case OCLASS_EXTENSION:
case OCLASS_EVENT_TRIGGER:
case OCLASS_PARAMETER_ACL:
case OCLASS_POLICY:
case OCLASS_PUBLICATION:
case OCLASS_PUBLICATION_NAMESPACE:

View File

@@ -940,6 +940,7 @@ EventTriggerSupportsObjectType(ObjectType obtype)
case OBJECT_DATABASE:
case OBJECT_TABLESPACE:
case OBJECT_ROLE:
case OBJECT_PARAMETER_ACL:
/* no support for global objects */
return false;
case OBJECT_EVENT_TRIGGER:
@@ -1015,6 +1016,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass)
case OCLASS_DATABASE:
case OCLASS_TBLSPACE:
case OCLASS_ROLE:
case OCLASS_PARAMETER_ACL:
/* no support for global objects */
return false;
case OCLASS_EVENT_TRIGGER:
@@ -2042,6 +2044,8 @@ stringify_grant_objtype(ObjectType objtype)
return "LARGE OBJECT";
case OBJECT_SCHEMA:
return "SCHEMA";
case OBJECT_PARAMETER_ACL:
return "PARAMETER";
case OBJECT_PROCEDURE:
return "PROCEDURE";
case OBJECT_ROUTINE:
@@ -2153,6 +2157,7 @@ stringify_adefprivs_objtype(ObjectType objtype)
case OBJECT_OPCLASS:
case OBJECT_OPERATOR:
case OBJECT_OPFAMILY:
case OBJECT_PARAMETER_ACL:
case OBJECT_POLICY:
case OBJECT_PUBLICATION:
case OBJECT_PUBLICATION_NAMESPACE:

View File

@@ -78,6 +78,7 @@ SecLabelSupportsObjectType(ObjectType objtype)
case OBJECT_OPCLASS:
case OBJECT_OPERATOR:
case OBJECT_OPFAMILY:
case OBJECT_PARAMETER_ACL:
case OBJECT_POLICY:
case OBJECT_PUBLICATION_NAMESPACE:
case OBJECT_PUBLICATION_REL:

View File

@@ -12655,6 +12655,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
case OCLASS_DEFACL:
case OCLASS_EXTENSION:
case OCLASS_EVENT_TRIGGER:
case OCLASS_PARAMETER_ACL:
case OCLASS_PUBLICATION:
case OCLASS_PUBLICATION_NAMESPACE:
case OCLASS_PUBLICATION_REL:

View File

@@ -371,8 +371,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> foreign_server_version opt_foreign_server_version
%type <str> opt_in_database
%type <str> OptSchemaName
%type <list> OptSchemaEltList
%type <str> OptSchemaName parameter_name
%type <list> OptSchemaEltList parameter_name_list
%type <chr> am_type
@@ -827,7 +827,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
ORDER ORDINALITY OTHERS OUT_P OUTER_P
OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER
PARALLEL PARSER PARTIAL PARTITION PASSING PASSWORD PATH PLACING PLAN PLANS POLICY
PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PATH
PLACING PLAN PLANS POLICY
POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION
@@ -7197,6 +7198,13 @@ privilege: SELECT opt_column_list
n->cols = $2;
$$ = n;
}
| ALTER SYSTEM_P
{
AccessPriv *n = makeNode(AccessPriv);
n->priv_name = pstrdup("alter system");
n->cols = NIL;
$$ = n;
}
| ColId opt_column_list
{
AccessPriv *n = makeNode(AccessPriv);
@@ -7206,6 +7214,28 @@ privilege: SELECT opt_column_list
}
;
parameter_name_list:
parameter_name
{
$$ = list_make1(makeString($1));
}
| parameter_name_list ',' parameter_name
{
$$ = lappend($1, makeString($3));
}
;
parameter_name:
ColId
{
$$ = $1;
}
| parameter_name '.' ColId
{
$$ = psprintf("%s.%s", $1, $3);
}
;
/* Don't bother trying to fold the first two rules into one using
* opt_table. You're going to get conflicts.
@@ -7307,6 +7337,14 @@ privilege_target:
n->objs = $3;
$$ = n;
}
| PARAMETER parameter_name_list
{
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
n->targtype = ACL_TARGET_OBJECT;
n->objtype = OBJECT_PARAMETER_ACL;
n->objs = $2;
$$ = n;
}
| SCHEMA name_list
{
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
@@ -17065,6 +17103,7 @@ unreserved_keyword:
| OWNED
| OWNER
| PARALLEL
| PARAMETER
| PARSER
| PARTIAL
| PARTITION
@@ -17682,6 +17721,7 @@ bare_label_keyword:
| OWNED
| OWNER
| PARALLEL
| PARAMETER
| PARSER
| PARTIAL
| PARTITION

View File

@@ -23,6 +23,7 @@
#include "catalog/pg_authid.h"
#include "catalog/pg_class.h"
#include "catalog/pg_database.h"
#include "catalog/pg_parameter_acl.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "commands/proclang.h"
@@ -36,6 +37,7 @@
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/guc.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@@ -109,6 +111,7 @@ static Oid convert_tablespace_name(text *tablespacename);
static AclMode convert_tablespace_priv_string(text *priv_type_text);
static Oid convert_type_name(text *typename);
static AclMode convert_type_priv_string(text *priv_type_text);
static AclMode convert_parameter_priv_string(text *priv_text);
static AclMode convert_role_priv_string(text *priv_type_text);
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
@@ -306,6 +309,12 @@ aclparse(const char *s, AclItem *aip)
case ACL_CONNECT_CHR:
read = ACL_CONNECT;
break;
case ACL_SET_CHR:
read = ACL_SET;
break;
case ACL_ALTER_SYSTEM_CHR:
read = ACL_ALTER_SYSTEM;
break;
case 'R': /* ignore old RULE privileges */
read = 0;
break;
@@ -794,6 +803,10 @@ acldefault(ObjectType objtype, Oid ownerId)
world_default = ACL_USAGE;
owner_default = ACL_ALL_RIGHTS_TYPE;
break;
case OBJECT_PARAMETER_ACL:
world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL;
break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
@@ -876,6 +889,9 @@ acldefault_sql(PG_FUNCTION_ARGS)
case 'n':
objtype = OBJECT_SCHEMA;
break;
case 'p':
objtype = OBJECT_PARAMETER_ACL;
break;
case 't':
objtype = OBJECT_TABLESPACE;
break;
@@ -1602,6 +1618,10 @@ convert_priv_string(text *priv_type_text)
return ACL_CREATE_TEMP;
if (pg_strcasecmp(priv_type, "CONNECT") == 0)
return ACL_CONNECT;
if (pg_strcasecmp(priv_type, "SET") == 0)
return ACL_SET;
if (pg_strcasecmp(priv_type, "ALTER SYSTEM") == 0)
return ACL_ALTER_SYSTEM;
if (pg_strcasecmp(priv_type, "RULE") == 0)
return 0; /* ignore old RULE privileges */
@@ -1698,6 +1718,10 @@ convert_aclright_to_string(int aclright)
return "TEMPORARY";
case ACL_CONNECT:
return "CONNECT";
case ACL_SET:
return "SET";
case ACL_ALTER_SYSTEM:
return "ALTER SYSTEM";
default:
elog(ERROR, "unrecognized aclright: %d", aclright);
return NULL;
@@ -4429,6 +4453,96 @@ convert_type_priv_string(text *priv_type_text)
return convert_any_priv_string(priv_type_text, type_priv_map);
}
/*
* has_parameter_privilege variants
* These are all named "has_parameter_privilege" at the SQL level.
* They take various combinations of parameter name with
* user name, user OID, or implicit user = current_user.
*
* The result is a boolean value: true if user has been granted
* the indicated privilege or false if not.
*/
/*
* has_param_priv_byname
*
* Helper function to check user privileges on a parameter given the
* role by Oid, parameter by text name, and privileges as AclMode.
*/
static bool
has_param_priv_byname(Oid roleid, const text *parameter, AclMode priv)
{
char *paramstr = text_to_cstring(parameter);
return pg_parameter_aclcheck(paramstr, roleid, priv) == ACLCHECK_OK;
}
/*
* has_parameter_privilege_name_name
* Check user privileges on a parameter given name username, text
* parameter, and text priv name.
*/
Datum
has_parameter_privilege_name_name(PG_FUNCTION_ARGS)
{
Name username = PG_GETARG_NAME(0);
text *parameter = PG_GETARG_TEXT_PP(1);
AclMode priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(2));
Oid roleid = get_role_oid_or_public(NameStr(*username));
PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
}
/*
* has_parameter_privilege_name
* Check user privileges on a parameter given text parameter and text priv
* name. current_user is assumed
*/
Datum
has_parameter_privilege_name(PG_FUNCTION_ARGS)
{
text *parameter = PG_GETARG_TEXT_PP(0);
AclMode priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(1));
PG_RETURN_BOOL(has_param_priv_byname(GetUserId(), parameter, priv));
}
/*
* has_parameter_privilege_id_name
* Check user privileges on a parameter given roleid, text parameter, and
* text priv name.
*/
Datum
has_parameter_privilege_id_name(PG_FUNCTION_ARGS)
{
Oid roleid = PG_GETARG_OID(0);
text *parameter = PG_GETARG_TEXT_PP(1);
AclMode priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(2));
PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
}
/*
* Support routines for has_parameter_privilege family.
*/
/*
* convert_parameter_priv_string
* Convert text string to AclMode value.
*/
static AclMode
convert_parameter_priv_string(text *priv_text)
{
static const priv_map parameter_priv_map[] = {
{"SET", ACL_SET},
{"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SET)},
{"ALTER SYSTEM", ACL_ALTER_SYSTEM},
{"ALTER SYSTEM WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_ALTER_SYSTEM)},
{NULL, 0}
};
return convert_any_priv_string(priv_text, parameter_priv_map);
}
/*
* pg_has_role variants

View File

@@ -47,6 +47,7 @@
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_parameter_acl.h"
#include "catalog/pg_partitioned_table.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_publication.h"
@@ -574,6 +575,28 @@ static const struct cachedesc cacheinfo[] = {
},
8
},
{ParameterAclRelationId, /* PARAMETERACLNAME */
ParameterAclParnameIndexId,
1,
{
Anum_pg_parameter_acl_parname,
0,
0,
0
},
4
},
{ParameterAclRelationId, /* PARAMETERACLOID */
ParameterAclOidIndexId,
1,
{
Anum_pg_parameter_acl_oid,
0,
0,
0
},
4
},
{PartitionedRelationId, /* PARTRELID */
PartitionedRelidIndexId,
1,

View File

@@ -45,6 +45,7 @@
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_parameter_acl.h"
#include "catalog/storage.h"
#include "commands/async.h"
#include "commands/prepare.h"
@@ -5713,6 +5714,65 @@ guc_name_compare(const char *namea, const char *nameb)
}
/*
* Convert a GUC name to the form that should be used in pg_parameter_acl.
*
* We need to canonicalize entries since, for example, case should not be
* significant. In addition, we apply the map_old_guc_names[] mapping so that
* any obsolete names will be converted when stored in a new PG version.
* Note however that this function does not verify legality of the name.
*
* The result is a palloc'd string.
*/
char *
convert_GUC_name_for_parameter_acl(const char *name)
{
char *result;
/* Apply old-GUC-name mapping. */
for (int i = 0; map_old_guc_names[i] != NULL; i += 2)
{
if (guc_name_compare(name, map_old_guc_names[i]) == 0)
{
name = map_old_guc_names[i + 1];
break;
}
}
/* Apply case-folding that matches guc_name_compare(). */
result = pstrdup(name);
for (char *ptr = result; *ptr != '\0'; ptr++)
{
char ch = *ptr;
if (ch >= 'A' && ch <= 'Z')
{
ch += 'a' - 'A';
*ptr = ch;
}
}
return result;
}
/*
* Check whether we should allow creation of a pg_parameter_acl entry
* for the given name. (This can be applied either before or after
* canonicalizing it.)
*/
bool
check_GUC_name_for_parameter_acl(const char *name)
{
/* OK if the GUC exists. */
if (find_option(name, false, true, DEBUG1) != NULL)
return true;
/* Otherwise, it'd better be a valid custom GUC name. */
if (valid_custom_variable_name(name))
return true;
return false;
}
/*
* Initialize GUC options during program startup.
*
@@ -7518,14 +7578,24 @@ set_config_option(const char *name, const char *value,
*/
break;
case PGC_SU_BACKEND:
/* Reject if we're connecting but user is not superuser */
if (context == PGC_BACKEND)
{
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name)));
return 0;
/*
* Check whether the current user has been granted privilege
* to set this GUC.
*/
AclResult aclresult;
aclresult = pg_parameter_aclcheck(name, GetUserId(), ACL_SET);
if (aclresult != ACLCHECK_OK)
{
/* No granted privilege */
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name)));
return 0;
}
}
/* fall through to process the same as PGC_BACKEND */
/* FALLTHROUGH */
@@ -7568,11 +7638,22 @@ set_config_option(const char *name, const char *value,
case PGC_SUSET:
if (context == PGC_USERSET || context == PGC_BACKEND)
{
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name)));
return 0;
/*
* Check whether the current user has been granted privilege
* to set this GUC.
*/
AclResult aclresult;
aclresult = pg_parameter_aclcheck(name, GetUserId(), ACL_SET);
if (aclresult != ACLCHECK_OK)
{
/* No granted privilege */
ereport(elevel,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name)));
return 0;
}
}
break;
case PGC_USERSET:
@@ -8617,11 +8698,6 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
char AutoConfFileName[MAXPGPATH];
char AutoConfTmpFileName[MAXPGPATH];
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to execute ALTER SYSTEM command")));
/*
* Extract statement arguments
*/
@@ -8649,6 +8725,29 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
break;
}
/*
* Check permission to run ALTER SYSTEM on the target variable
*/
if (!superuser())
{
if (resetall)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to perform ALTER SYSTEM RESET ALL")));
else
{
AclResult aclresult;
aclresult = pg_parameter_aclcheck(name, GetUserId(),
ACL_ALTER_SYSTEM);
if (aclresult != ACLCHECK_OK)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to set parameter \"%s\"",
name)));
}
}
/*
* Unless it's RESET_ALL, validate the target variable and value
*/
@@ -8760,13 +8859,18 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
}
/*
* Invoke the post-alter hook for altering this GUC variable.
* Invoke the post-alter hook for setting this GUC variable. GUCs
* typically do not have corresponding entries in pg_parameter_acl, so we
* call the hook using the name rather than a potentially-non-existent
* OID. Nonetheless, we pass ParameterAclRelationId so that this call
* context can be distinguished from others. (Note that "name" will be
* NULL in the RESET ALL case.)
*
* We do this here rather than at the end, because ALTER SYSTEM is not
* transactional. If the hook aborts our transaction, it will be cleaner
* to do so before we touch any files.
*/
InvokeObjectPostAlterHookArgStr(InvalidOid, name,
InvokeObjectPostAlterHookArgStr(ParameterAclRelationId, name,
ACL_ALTER_SYSTEM,
altersysstmt->setstmt->kind,
false);
@@ -8943,9 +9047,9 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
break;
}
/* Invoke the post-alter hook for setting this GUC variable. */
InvokeObjectPostAlterHookArgStr(InvalidOid, stmt->name,
ACL_SET_VALUE, stmt->kind, false);
/* Invoke the post-alter hook for setting this GUC variable, by name. */
InvokeObjectPostAlterHookArgStr(ParameterAclRelationId, stmt->name,
ACL_SET, stmt->kind, false);
}
/*