/* *InternalformatusedbyALTERDEFAULTPRIVILEGES.
*/ typedefstruct
{
Oid roleid; /* owning role */
Oid nspid; /* namespace, or InvalidOid if none */ /* remaining fields are same as in InternalGrant: */ bool is_grant;
ObjectType objtype; bool all_privs;
AclMode privileges;
List *grantees; bool grant_option;
DropBehavior behavior;
} InternalDefaultACL;
/* *Grantoptionscanonlybegrantedtoindividualroles,notPUBLIC. *Thereasonisthatifauserwouldre-grantaprivilegethathe *heldthroughPUBLIC,andlatertheuserisremoved,thesituation *isimpossibletocleanup.
*/ if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("grant options can only be granted to roles")));
/* *Restricttheoperationtowhatwecanactuallygrantorrevoke,and *issueawarningifappropriate.(ForREVOKEthisisn'tquitewhatthe *specsaystodo:thespecseemstowantawarningonlyifnoprivilege *bitsactuallychangeintheACL.Inpracticethatbehaviorseemsmuch *toonoisy,aswellasinconsistentwiththeGRANTcase.)
*/
this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions); if (is_grant)
{ if (this_privileges == 0)
{ if (objtype == OBJECT_COLUMN && colname)
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
colname, objname))); else
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
errmsg("no privileges were granted for \"%s\"",
objname)));
} elseif (!all_privs && this_privileges != privileges)
{ if (objtype == OBJECT_COLUMN && colname)
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
colname, objname))); else
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
errmsg("not all privileges were granted for \"%s\"",
objname)));
}
} else
{ if (this_privileges == 0)
{ if (objtype == OBJECT_COLUMN && colname)
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
colname, objname))); else
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
errmsg("no privileges could be revoked for \"%s\"",
objname)));
} elseif (!all_privs && this_privileges != privileges)
{ if (objtype == OBJECT_COLUMN && colname)
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
colname, objname))); else
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
errmsg("not all privileges could be revoked for \"%s\"",
objname)));
}
}
/* *Currently,thisclauseisonlyforSQLcompatibility,notvery *interestingotherwise.
*/ if (grantor != GetUserId())
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("grantor must be current user")));
}
/* Collect the OIDs of the target objects */ switch (stmt->targtype)
{ case ACL_TARGET_OBJECT:
istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
stmt->is_grant); break; case ACL_TARGET_ALL_IN_SCHEMA:
istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects); break; /* ACL_TARGET_DEFAULTS should not be seen here */ default:
elog(ERROR, "unrecognized GrantStmt.targtype: %d",
(int) stmt->targtype);
}
/* all_privs to be filled below */ /* privileges to be filled below */
istmt.col_privs = NIL; /* may get filled below */
istmt.grantees = NIL; /* filled below */
istmt.grant_option = stmt->grant_option;
istmt.behavior = stmt->behavior;
/* Deconstruct the "options" part of the statement */
foreach(cell, stmt->options)
{
DefElem *defel = (DefElem *) lfirst(cell);
if (strcmp(defel->defname, "schemas") == 0)
{ if (dnspnames)
errorConflictingDefElem(defel, pstate);
dnspnames = defel;
} elseif (strcmp(defel->defname, "roles") == 0)
{ if (drolespecs)
errorConflictingDefElem(defel, pstate);
drolespecs = defel;
} else
elog(ERROR, "option \"%s\" not recognized", defel->defname);
}
if (dnspnames)
nspnames = (List *) dnspnames->arg; if (drolespecs)
rolespecs = (List *) drolespecs->arg;
/* Prepare the InternalDefaultACL representation of the statement */ /* roleid to be filled below */ /* nspid to be filled in SetDefaultACLsInSchemas */
iacls.is_grant = action->is_grant;
iacls.objtype = action->objtype; /* all_privs to be filled below */ /* privileges to be filled below */
iacls.grantees = NIL; /* filled below */
iacls.grant_option = action->grant_option;
iacls.behavior = action->behavior;
if (!has_privs_of_role(GetUserId(), iacls.roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to change default privileges")));
SetDefaultACLsInSchemas(&iacls, nspnames);
}
}
}
/* *ProcessALTERDEFAULTPRIVILEGESforalistoftargetschemas * *Allfieldsof*iaclsexceptnspidwerefilledalready
*/ staticvoid
SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
{ if (nspnames == NIL)
{ /* Set database-wide permissions if no schema was specified */
iacls->nspid = InvalidOid;
SetDefaultACL(iacls);
} else
{ /* Look up the schema OIDs and set permissions for each one */
ListCell *nspcell;
case OBJECT_SEQUENCE:
objtype = DEFACLOBJ_SEQUENCE; if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
this_privileges = ACL_ALL_RIGHTS_SEQUENCE; break;
case OBJECT_FUNCTION:
objtype = DEFACLOBJ_FUNCTION; if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
this_privileges = ACL_ALL_RIGHTS_FUNCTION; break;
case OBJECT_TYPE:
objtype = DEFACLOBJ_TYPE; if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
this_privileges = ACL_ALL_RIGHTS_TYPE; break;
case OBJECT_SCHEMA: if (OidIsValid(iacls->nspid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("cannot use IN SCHEMA clause when using %s", "GRANT/REVOKE ON SCHEMAS")));
objtype = DEFACLOBJ_NAMESPACE; if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
this_privileges = ACL_ALL_RIGHTS_SCHEMA; break;
case OBJECT_LARGEOBJECT: if (OidIsValid(iacls->nspid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("cannot use IN SCHEMA clause when using %s", "GRANT/REVOKE ON LARGE OBJECTS")));
objtype = DEFACLOBJ_LARGEOBJECT; if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
this_privileges = ACL_ALL_RIGHTS_LARGEOBJECT; break;
/* Search for existing row for this object type in catalog */
tuple = SearchSysCache3(DEFACLROLENSPOBJ,
ObjectIdGetDatum(iacls->roleid),
ObjectIdGetDatum(iacls->nspid),
CharGetDatum(objtype));
if (HeapTupleIsValid(tuple))
{
Datum aclDatum; bool isNull;
if (old_acl != NULL)
{ /* *WeneedthemembersofbotholdandnewACLssowecancorrectthe *shareddependencyinformation.Collectdatabefore *merge_acl_with_grantthrowsawayold_acl.
*/
noldmembers = aclmembers(old_acl, &oldmembers);
} else
{ /* If no or null entry, start with the default ACL value */
old_acl = aclcopy(def_acl); /* There are no old member roles according to the catalogs */
noldmembers = 0;
oldmembers = NULL;
}
/* *Iftheresultisthesameasthedefaultvalue,wedonotneedan *explicitpg_default_aclentry,andshouldinfactremovetheentryif *itexists.Mustsortbotharraystocompareproperly.
*/
aclitemsort(new_acl);
aclitemsort(def_acl); if (aclequal(new_acl, def_acl))
{ /* delete old entry, if indeed there is one */ if (!isNew)
{
ObjectAddress myself;
/* these dependencies don't change in an update */ if (isNew)
{ /* dependency on role */
recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
iacls->roleid);
/* dependency on namespace */ if (OidIsValid(iacls->nspid))
{
ObjectAddress myself,
referenced;
/* *Thisprocessesattributes,butexpectstobecalledfrom *ExecGrant_Relation,notdirectlyfromExecuteGrantStmt.
*/ staticvoid
ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, constchar *relname,
AttrNumber attnum, Oid ownerId, AclMode col_privileges,
Relation attRelation, const Acl *old_rel_acl)
{
HeapTuple attr_tuple;
Form_pg_attribute pg_attribute_tuple;
Acl *old_acl;
Acl *new_acl;
Acl *merged_acl;
Datum aclDatum; bool isNull;
Oid grantorId;
AclMode avail_goptions; bool need_update;
HeapTuple newtuple;
Datum values[Natts_pg_attribute] = {0}; bool nulls[Natts_pg_attribute] = {0}; bool replaces[Natts_pg_attribute] = {0}; int noldmembers; int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
attr_tuple = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relOid),
Int16GetDatum(attnum)); if (!HeapTupleIsValid(attr_tuple))
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, relOid);
pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
/* *GetworkingcopyofexistingACL.Ifthere'snoACL,substitutethe *properdefault.
*/
aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
&isNull); if (isNull)
{
old_acl = acldefault(OBJECT_COLUMN, 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(), col_privileges,
merged_acl, ownerId,
&grantorId, &avail_goptions);
foreach(cell, istmt->objects)
{
Oid relOid = lfirst_oid(cell);
Datum aclDatum;
Form_pg_class pg_class_tuple; bool isNull;
AclMode this_privileges;
AclMode *col_privileges; int num_col_privileges; bool have_col_privileges;
Acl *old_acl;
Acl *old_rel_acl; int noldmembers;
Oid *oldmembers;
Oid ownerId;
HeapTuple tuple;
ListCell *cell_colprivs;
tuple = SearchSysCacheLocked1(RELOID, ObjectIdGetDatum(relOid)); if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for relation %u", relOid);
pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
/* Not sensible to grant on an index */ if (pg_class_tuple->relkind == RELKIND_INDEX ||
pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is an index",
NameStr(pg_class_tuple->relname))));
/* Composite types aren't tables either */ if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is a composite type",
NameStr(pg_class_tuple->relname))));
/* Used GRANT SEQUENCE on a non-sequence? */ if (istmt->objtype == OBJECT_SEQUENCE &&
pg_class_tuple->relkind != RELKIND_SEQUENCE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a sequence",
NameStr(pg_class_tuple->relname))));
/* Adjust the default permissions based on object type */ if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
{ if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
this_privileges = ACL_ALL_RIGHTS_SEQUENCE; else
this_privileges = ACL_ALL_RIGHTS_RELATION;
} else
this_privileges = istmt->privileges;
/* *TheGRANTTABLEsyntaxcanbeusedforsequencesandnon-sequences, *sowehavetolookattherelkindtodeterminethesupported *permissions.TheORoftableandsequencepermissionswerealready *checked.
*/ if (istmt->objtype == OBJECT_TABLE)
{ if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
{ /* *Forbackwardcompatibility,justthrowawarningfor *invalidsequencepermissionswhenusingthenon-sequence *GRANTsyntax.
*/ if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
{ /* *Mentiontheobjectnamebecausetheuserneedstoknow *whichoperationssucceeded.Thisisrequiredbecause *WARNINGallowsthecommandtocontinue.
*/
ereport(WARNING,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
NameStr(pg_class_tuple->relname))));
this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
}
} else
{ if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
{ /* *USAGEistheonlypermissionsupportedbysequencesbut *notbynon-sequences.Don'tmentiontheobjectname *becausewedidn'tinthecombinedTABLE|SEQUENCE *check.
*/
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("invalid privilege type %s for table", "USAGE")));
}
}
}
/* *GetownerIDandworkingcopyofexistingACL.Ifthere'snoACL, *substitutetheproperdefault.
*/
ownerId = pg_class_tuple->relowner;
aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
&isNull); if (isNull)
{ switch (pg_class_tuple->relkind)
{ case RELKIND_SEQUENCE:
old_acl = acldefault(OBJECT_SEQUENCE, ownerId); break; default:
old_acl = acldefault(OBJECT_TABLE, ownerId); break;
} /* 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);
}
/* Need an extra copy of original rel ACL for column handling */
old_rel_acl = aclcopy(old_acl);
/* *Handlerelation-levelprivileges,ifanywerespecified
*/ if (this_privileges != ACL_NO_RIGHTS)
{
AclMode avail_goptions;
Acl *new_acl;
Oid grantorId;
HeapTuple newtuple;
Datum values[Natts_pg_class] = {0}; bool nulls[Natts_pg_class] = {0}; bool replaces[Natts_pg_class] = {0}; int nnewmembers;
Oid *newmembers;
ObjectType objtype;
/* Determine ID to do the grant as, and available grant options */
select_best_grantor(GetUserId(), this_privileges,
old_acl, ownerId,
&grantorId, &avail_goptions);
/* finished building new ACL value, now insert it */
replaces[Anum_pg_class_relacl - 1] = true;
values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("invalid privilege type %s for column",
privilege_to_string(this_privileges))));
staticvoid
ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
{ int cacheid;
Relation relation;
ListCell *cell;
if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
istmt->privileges = default_privs;
cacheid = get_object_catcache_oid(classid);
relation = table_open(classid, RowExclusiveLock);
foreach(cell, istmt->objects)
{
Oid objectid = lfirst_oid(cell);
Datum aclDatum;
Datum nameDatum; bool isNull;
AclMode avail_goptions;
AclMode this_privileges;
Acl *old_acl;
Acl *new_acl;
Oid grantorId;
Oid ownerId;
HeapTuple tuple;
HeapTuple newtuple;
Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts); bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts); bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts); int noldmembers; int nnewmembers;
Oid *oldmembers;
Oid *newmembers;
tuple = SearchSysCacheLocked1(cacheid, ObjectIdGetDatum(objectid)); if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
/* *Additionalobject-type-specificchecks
*/ if (object_check)
object_check(istmt, tuple);
/* *GetownerIDandworkingcopyofexistingACL.Ifthere'snoACL, *substitutetheproperdefault.
*/
ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
tuple,
get_object_attnum_owner(classid)));
aclDatum = SysCacheGetAttr(cacheid,
tuple,
get_object_attnum_acl(classid),
&isNull); if (isNull)
{
old_acl = acldefault(get_object_type(classid, objectid), 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);
/* finished building new ACL value, now insert it */
replaces[get_object_attnum_acl(classid) - 1] = true;
values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
if (!pg_language_tuple->lanpltrusted)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("language \"%s\" is not trusted",
NameStr(pg_language_tuple->lanname)),
errdetail("GRANT and REVOKE are not allowed on untrusted languages, " "because only superusers can use untrusted languages.")));
}
/* *GetownerIDandworkingcopyofexistingACL.Ifthere'snoACL, *substitutetheproperdefault.
*/
ownerId = form_lo_meta->lomowner;
aclDatum = heap_getattr(tuple,
Anum_pg_largeobject_metadata_lomacl,
RelationGetDescr(relation), &isNull); if (isNull)
{
old_acl = acldefault(OBJECT_LARGEOBJECT, 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);
/* finished building new ACL value, now insert it */
replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
values[Anum_pg_largeobject_metadata_lomacl - 1]
= PointerGetDatum(new_acl);
/* Disallow GRANT on dependent types */ if (IsTrueArrayType(pg_type_tuple))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("cannot set privileges of array types"),
errhint("Set the privileges of the element type instead."))); if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("cannot set privileges of multirange types"),
errhint("Set the privileges of the range type instead.")));
}
foreach(cell, istmt->objects)
{
Oid parameterId = lfirst_oid(cell);
Datum nameDatum; constchar *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 = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
Anum_pg_parameter_acl_parname);
parname = TextDatumGetCString(nameDatum);
/* Treat all parameters as belonging to the bootstrap superuser. */
ownerId = BOOTSTRAP_SUPERUSERID;
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);
/* 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(constchar *privname)
{ if (strcmp(privname, "insert") == 0) return ACL_INSERT; if (strcmp(privname, "select") == 0) return ACL_SELECT; if (strcmp(privname, "update") == 0) return ACL_UPDATE; if (strcmp(privname, "delete") == 0) return ACL_DELETE; if (strcmp(privname, "truncate") == 0) return ACL_TRUNCATE; if (strcmp(privname, "references") == 0) return ACL_REFERENCES; if (strcmp(privname, "trigger") == 0) return ACL_TRIGGER; if (strcmp(privname, "execute") == 0) return ACL_EXECUTE; if (strcmp(privname, "usage") == 0) return ACL_USAGE; if (strcmp(privname, "create") == 0) return ACL_CREATE; if (strcmp(privname, "temporary") == 0) return ACL_CREATE_TEMP; if (strcmp(privname, "temp") == 0) 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, "maintain") == 0) return ACL_MAINTAIN;
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unrecognized privilege type \"%s\"", privname))); return0; /* appease compiler */
}
staticconstchar *
privilege_to_string(AclMode privilege)
{ switch (privilege)
{ case ACL_INSERT: return"INSERT"; case ACL_SELECT: return"SELECT"; case ACL_UPDATE: return"UPDATE"; case ACL_DELETE: return"DELETE"; case ACL_TRUNCATE: return"TRUNCATE"; case ACL_REFERENCES: return"REFERENCES"; case ACL_TRIGGER: return"TRIGGER"; case ACL_EXECUTE: return"EXECUTE"; case ACL_USAGE: return"USAGE"; case ACL_CREATE: return"CREATE"; case ACL_CREATE_TEMP: return"TEMP"; case ACL_CONNECT: return"CONNECT"; case ACL_SET: return"SET"; case ACL_ALTER_SYSTEM: return"ALTER SYSTEM"; case ACL_MAINTAIN: return"MAINTAIN"; default:
elog(ERROR, "unrecognized privilege: %d", (int) privilege);
} return NULL; /* appease compiler */
}
/* *Standardizedreportingofaclcheckpermissionsfailures. * *Note:wedonotdouble-quotethe%s'sbelow,becausemanycallers *supplystringsthatmightbealreadyquoted.
*/ void
aclcheck_error(AclResult aclerr, ObjectType objtype, constchar *objectname)
{ switch (aclerr)
{ case ACLCHECK_OK: /* no error, so return to caller */ break; case ACLCHECK_NO_PRIV:
{ constchar *msg = "???";
switch (objtype)
{ case OBJECT_AGGREGATE:
msg = gettext_noop("permission denied for aggregate %s"); break; case OBJECT_COLLATION:
msg = gettext_noop("permission denied for collation %s"); break; case OBJECT_COLUMN:
msg = gettext_noop("permission denied for column %s"); break; case OBJECT_CONVERSION:
msg = gettext_noop("permission denied for conversion %s"); break; case OBJECT_DATABASE:
msg = gettext_noop("permission denied for database %s"); break; case OBJECT_DOMAIN:
msg = gettext_noop("permission denied for domain %s"); break; case OBJECT_EVENT_TRIGGER:
msg = gettext_noop("permission denied for event trigger %s"); break; case OBJECT_EXTENSION:
msg = gettext_noop("permission denied for extension %s"); break; case OBJECT_FDW:
msg = gettext_noop("permission denied for foreign-data wrapper %s"); break; case OBJECT_FOREIGN_SERVER:
msg = gettext_noop("permission denied for foreign server %s"); break; case OBJECT_FOREIGN_TABLE:
msg = gettext_noop("permission denied for foreign table %s"); break; case OBJECT_FUNCTION:
msg = gettext_noop("permission denied for function %s"); break; case OBJECT_INDEX:
msg = gettext_noop("permission denied for index %s"); break; case OBJECT_LANGUAGE:
msg = gettext_noop("permission denied for language %s"); break; case OBJECT_LARGEOBJECT:
msg = gettext_noop("permission denied for large object %s"); break; case OBJECT_MATVIEW:
msg = gettext_noop("permission denied for materialized view %s"); break; case OBJECT_OPCLASS:
msg = gettext_noop("permission denied for operator class %s"); break; case OBJECT_OPERATOR:
msg = gettext_noop("permission denied for operator %s"); break; 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; case OBJECT_PROCEDURE:
msg = gettext_noop("permission denied for procedure %s"); break; case OBJECT_PUBLICATION:
msg = gettext_noop("permission denied for publication %s"); break; case OBJECT_ROUTINE:
msg = gettext_noop("permission denied for routine %s"); break; case OBJECT_SCHEMA:
msg = gettext_noop("permission denied for schema %s"); break; case OBJECT_SEQUENCE:
msg = gettext_noop("permission denied for sequence %s"); break; case OBJECT_STATISTIC_EXT:
msg = gettext_noop("permission denied for statistics object %s"); break; case OBJECT_SUBSCRIPTION:
msg = gettext_noop("permission denied for subscription %s"); break; case OBJECT_TABLE:
msg = gettext_noop("permission denied for table %s"); break; case OBJECT_TABLESPACE:
msg = gettext_noop("permission denied for tablespace %s"); break; case OBJECT_TSCONFIGURATION:
msg = gettext_noop("permission denied for text search configuration %s"); break; case OBJECT_TSDICTIONARY:
msg = gettext_noop("permission denied for text search dictionary %s"); break; case OBJECT_TYPE:
msg = gettext_noop("permission denied for type %s"); break; case OBJECT_VIEW:
msg = gettext_noop("permission denied for view %s"); break; /* these currently aren't used */ case OBJECT_ACCESS_METHOD: case OBJECT_AMOP: case OBJECT_AMPROC: case OBJECT_ATTRIBUTE: case OBJECT_CAST: case OBJECT_DEFAULT: case OBJECT_DEFACL: case OBJECT_DOMCONSTRAINT: case OBJECT_PUBLICATION_NAMESPACE: case OBJECT_PUBLICATION_REL: case OBJECT_ROLE: case OBJECT_RULE: case OBJECT_TABCONSTRAINT: case OBJECT_TRANSFORM: case OBJECT_TRIGGER: case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: case OBJECT_USER_MAPPING:
elog(ERROR, "unsupported object type: %d", objtype);
}
switch (objtype)
{ case OBJECT_AGGREGATE:
msg = gettext_noop("must be owner of aggregate %s"); break; case OBJECT_COLLATION:
msg = gettext_noop("must be owner of collation %s"); break; case OBJECT_CONVERSION:
msg = gettext_noop("must be owner of conversion %s"); break; case OBJECT_DATABASE:
msg = gettext_noop("must be owner of database %s"); break; case OBJECT_DOMAIN:
msg = gettext_noop("must be owner of domain %s"); break; case OBJECT_EVENT_TRIGGER:
msg = gettext_noop("must be owner of event trigger %s"); break; case OBJECT_EXTENSION:
msg = gettext_noop("must be owner of extension %s"); break; case OBJECT_FDW:
msg = gettext_noop("must be owner of foreign-data wrapper %s"); break; case OBJECT_FOREIGN_SERVER:
msg = gettext_noop("must be owner of foreign server %s"); break; case OBJECT_FOREIGN_TABLE:
msg = gettext_noop("must be owner of foreign table %s"); break; case OBJECT_FUNCTION:
msg = gettext_noop("must be owner of function %s"); break; case OBJECT_INDEX:
msg = gettext_noop("must be owner of index %s"); break; case OBJECT_LANGUAGE:
msg = gettext_noop("must be owner of language %s"); break; case OBJECT_LARGEOBJECT:
msg = gettext_noop("must be owner of large object %s"); break; case OBJECT_MATVIEW:
msg = gettext_noop("must be owner of materialized view %s"); break; case OBJECT_OPCLASS:
msg = gettext_noop("must be owner of operator class %s"); break; case OBJECT_OPERATOR:
msg = gettext_noop("must be owner of operator %s"); break; case OBJECT_OPFAMILY:
msg = gettext_noop("must be owner of operator family %s"); break; case OBJECT_PROCEDURE:
msg = gettext_noop("must be owner of procedure %s"); break; case OBJECT_PUBLICATION:
msg = gettext_noop("must be owner of publication %s"); break; case OBJECT_ROUTINE:
msg = gettext_noop("must be owner of routine %s"); break; case OBJECT_SEQUENCE:
msg = gettext_noop("must be owner of sequence %s"); break; case OBJECT_SUBSCRIPTION:
msg = gettext_noop("must be owner of subscription %s"); break; case OBJECT_TABLE:
msg = gettext_noop("must be owner of table %s"); break; case OBJECT_TYPE:
msg = gettext_noop("must be owner of type %s"); break; case OBJECT_VIEW:
msg = gettext_noop("must be owner of view %s"); break; case OBJECT_SCHEMA:
msg = gettext_noop("must be owner of schema %s"); break; case OBJECT_STATISTIC_EXT:
msg = gettext_noop("must be owner of statistics object %s"); break; case OBJECT_TABLESPACE:
msg = gettext_noop("must be owner of tablespace %s"); break; case OBJECT_TSCONFIGURATION:
msg = gettext_noop("must be owner of text search configuration %s"); break; case OBJECT_TSDICTIONARY:
msg = gettext_noop("must be owner of text search dictionary %s"); break;
/* *Specialcases:Forthese,theerrormessagetalks *about"relation",becausethat'swherethe *ownershipisattached.Seealso *check_object_ownership().
*/ case OBJECT_COLUMN: case OBJECT_POLICY: case OBJECT_RULE: case OBJECT_TABCONSTRAINT: case OBJECT_TRIGGER:
msg = gettext_noop("must be owner of relation %s"); break; /* these currently aren't used */ case OBJECT_ACCESS_METHOD: case OBJECT_AMOP: case OBJECT_AMPROC: case OBJECT_ATTRIBUTE: case OBJECT_CAST: case OBJECT_DEFAULT: case OBJECT_DEFACL: case OBJECT_DOMCONSTRAINT: case OBJECT_PARAMETER_ACL: case OBJECT_PUBLICATION_NAMESPACE: case OBJECT_PUBLICATION_REL: case OBJECT_ROLE: case OBJECT_TRANSFORM: case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: case OBJECT_USER_MAPPING:
elog(ERROR, "unsupported object type: %d", objtype);
}
/* *Genericroutineforexaminingauser'sprivilegesforanobject, *withis_missing
*/ static AclMode
object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
AclMode mask, AclMaskHow how, bool *is_missing)
{ int cacheid;
AclMode result;
HeapTuple tuple;
Datum aclDatum; bool isNull;
Acl *acl;
Oid ownerId;
/* Special cases */ switch (classid)
{ case NamespaceRelationId: return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
is_missing); case TypeRelationId: return pg_type_aclmask_ext(objectid, roleid, mask, how,
is_missing);
}
/* Even more special cases */
Assert(classid != RelationRelationId); /* should use pg_class_acl* */
Assert(classid != LargeObjectMetadataRelationId); /* should use
* pg_largeobject_acl* */
/* Superusers bypass all permission checking. */ if (superuser_arg(roleid)) return mask;
/* *Gettheobject'sACLfromitscatalog
*/
cacheid = get_object_catcache_oid(classid);
tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid)); if (!HeapTupleIsValid(tuple))
{ if (is_missing != NULL)
{ /* return "no privileges" instead of throwing an error */
*is_missing = true; return0;
} else
elog(ERROR, "cache lookup failed for %s %u",
get_object_class_descr(classid), objectid);
}
/* *First,getthecolumn'sACLfromitspg_attributeentry
*/
attTuple = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(table_oid),
Int16GetDatum(attnum)); if (!HeapTupleIsValid(attTuple))
{ if (is_missing != NULL)
{ /* return "no privileges" instead of throwing an error */
*is_missing = true; return0;
} else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("attribute %d of relation with OID %u does not exist",
attnum, table_oid)));
}
/* Check dropped columns, too */ if (attributeForm->attisdropped)
{ if (is_missing != NULL)
{ /* return "no privileges" instead of throwing an error */
*is_missing = true;
ReleaseSysCache(attTuple); return0;
} else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("attribute %d of relation with OID %u does not exist",
attnum, table_oid)));
}
/* *Routineforexaminingauser'sprivilegesforatable,withis_missing
*/ static AclMode
pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
AclMaskHow how, bool *is_missing)
{
AclMode result;
HeapTuple tuple;
Form_pg_class classForm;
Datum aclDatum; bool isNull;
Acl *acl;
Oid ownerId;
/* *Mustgettherelation'stuplefrompg_class
*/
tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid)); if (!HeapTupleIsValid(tuple))
{ if (is_missing != NULL)
{ /* return "no privileges" instead of throwing an error */
*is_missing = true; return0;
} else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation with OID %u does not exist",
table_oid)));
}
/* 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);
/* 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);
tuple = systable_getnext(scan); if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("large object %u does not exist", lobj_oid)));
/* *Gettheschema'sACLfrompg_namespace
*/
tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid)); if (!HeapTupleIsValid(tuple))
{ if (is_missing != NULL)
{ /* return "no privileges" instead of throwing an error */
*is_missing = true; return0;
} else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_SCHEMA),
errmsg("schema with OID %u does not exist", nsp_oid)));
}
/* *Routineforexaminingauser'sprivilegesforatype,withis_missing
*/ static AclMode
pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
{
AclMode result;
HeapTuple tuple;
Form_pg_type typeForm;
Datum aclDatum; bool isNull;
Acl *acl;
Oid ownerId;
/* Bypass permission checks for superusers */ if (superuser_arg(roleid)) return mask;
/* *Mustgetthetype'stuplefrompg_type
*/
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid)); if (!HeapTupleIsValid(tuple))
{ if (is_missing != NULL)
{ /* return "no privileges" instead of throwing an error */
*is_missing = true; return0;
} else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type with OID %u does not exist",
type_oid)));
}
typeForm = (Form_pg_type) GETSTRUCT(tuple);
/* *"True"arraytypesdon'tmanagepermissionsoftheirown;consultthe *elementtypeinstead.
*/ if (IsTrueArrayType(typeForm))
{
Oid elttype_oid = typeForm->typelem;
ReleaseSysCache(tuple);
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid)); if (!HeapTupleIsValid(tuple))
{ if (is_missing != NULL)
{ /* return "no privileges" instead of throwing an error */
*is_missing = true; return0;
} else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type with OID %u does not exist",
elttype_oid)));
}
typeForm = (Form_pg_type) GETSTRUCT(tuple);
}
/* *Likewise,multirangetypesdon'tmanagetheirownpermissions;consult *theassociatedrangetype.(Notewemustdothisafterthearraystep *togettherightanswerforarraysofmultiranges.)
*/ if (typeForm->typtype == TYPTYPE_MULTIRANGE)
{
Oid rangetype = get_multirange_range(typeForm->oid);
ReleaseSysCache(tuple);
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype)); if (!HeapTupleIsValid(tuple))
{ if (is_missing != NULL)
{ /* return "no privileges" instead of throwing an error */
*is_missing = true; return0;
} else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type with OID %u does not exist",
rangetype)));
}
typeForm = (Form_pg_type) GETSTRUCT(tuple);
}
/* if we have a detoasted copy, free it */ if ((Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
}
ReleaseSysCache(attTuple);
if (attmask != 0)
{
result = ACLCHECK_OK; if (how == ACLMASK_ANY) break; /* succeed on any success */
} else
{
result = ACLCHECK_NO_PRIV; if (how == ACLMASK_ALL) break; /* fail on any failure */
}
}
/* *Genericownershipcheckforanobject
*/ bool
object_ownercheck(Oid classid, Oid objectid, Oid roleid)
{ int cacheid;
Oid ownerId;
/* Superusers bypass all permission checking. */ if (superuser_arg(roleid)) returntrue;
/* For large objects, the catalog to consult is pg_largeobject_metadata */ if (classid == LargeObjectRelationId)
classid = LargeObjectMetadataRelationId;
cacheid = get_object_catcache_oid(classid); if (cacheid != -1)
{ /* we can get the object's tuple from the syscache */
HeapTuple tuple;
tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid)); if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for %s %u",
get_object_class_descr(classid), objectid);
ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
tuple,
get_object_attnum_owner(classid)));
ReleaseSysCache(tuple);
} else
{ /* for catalogs without an appropriate syscache */
Relation rel;
ScanKeyData entry[1];
SysScanDesc scan;
HeapTuple tuple; bool isnull;
tuple = systable_getnext(scan); if (!HeapTupleIsValid(tuple))
elog(ERROR, "could not find tuple for %s %u",
get_object_class_descr(classid), objectid);
/* *UseNULLduringbootstrap,sincepg_default_aclprobablyisn'tthere *yet.
*/ if (IsBootstrapProcessingMode()) return NULL;
/* Check if object type is supported in pg_default_acl */ switch (objtype)
{ case OBJECT_TABLE:
defaclobjtype = DEFACLOBJ_RELATION; break;
case OBJECT_SEQUENCE:
defaclobjtype = DEFACLOBJ_SEQUENCE; break;
case OBJECT_FUNCTION:
defaclobjtype = DEFACLOBJ_FUNCTION; break;
case OBJECT_TYPE:
defaclobjtype = DEFACLOBJ_TYPE; break;
case OBJECT_SCHEMA:
defaclobjtype = DEFACLOBJ_NAMESPACE; break;
case OBJECT_LARGEOBJECT:
defaclobjtype = DEFACLOBJ_LARGEOBJECT; break;
default: return NULL;
}
/* Look up the relevant pg_default_acl entries */
glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
/* Quick out if neither entry exists */ if (glob_acl == NULL && schema_acl == NULL) return NULL;
/* We need to know the hard-wired default value, too */
def_acl = acldefault(objtype, ownerId);
/* If there's no global entry, substitute the hard-wired default */ if (glob_acl == NULL)
glob_acl = def_acl;
/* Merge in any per-schema privileges */
result = aclmerge(glob_acl, schema_acl, ownerId);
/* *Forefficiency,wewanttoreturnNULLiftheresultequalsdefault. *Thisrequiressortingbotharraystogetanaccuratecomparison.
*/
aclitemsort(result);
aclitemsort(def_acl); if (aclequal(result, def_acl))
result = NULL;
return result;
}
/* *Recorddependenciesonrolesmentionedinanewobject'sACL.
*/ void
recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
Oid ownerId, Acl *acl)
{ int nmembers;
Oid *members;
/* Nothing to do if ACL is defaulted */ if (acl == NULL) return;
/* Add the record, if any, for the top-level object */ if (!isNull)
recordExtensionInitPrivWorker(objoid, classoid, 0,
DatumGetAclP(aclDatum));
systable_endscan(scan);
} /* This will error on unsupported classoid. */ elseif (get_object_attnum_acl(classoid) != InvalidAttrNumber)
{ int cacheid;
Datum aclDatum; bool isNull;
HeapTuple tuple;
cacheid = get_object_catcache_oid(classoid);
tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid)); if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for %s %u",
get_object_class_descr(classoid), objoid);
/* There should exist only one entry or none. */
oldtuple = systable_getnext(scan);
/* If we find an entry, update it with the latest ACL. */ if (HeapTupleIsValid(oldtuple))
{
Datum values[Natts_pg_init_privs] = {0}; bool nulls[Natts_pg_init_privs] = {0}; bool replace[Natts_pg_init_privs] = {0};
Datum oldAclDatum; bool isNull;
Acl *old_acl;
/* Update pg_shdepend for roles mentioned in the old/new ACLs. */
oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
RelationGetDescr(relation), &isNull);
Assert(!isNull);
old_acl = DatumGetAclP(oldAclDatum);
noldmembers = aclmembers(old_acl, &oldmembers);
/* If we have a new ACL to set, then update the row with it. */ if (new_acl && ACL_NUM(new_acl) != 0)
{
values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
replace[Anum_pg_init_privs_initprivs - 1] = true;
/* Get a writable copy of the existing ACL. */
oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
RelationGetDescr(rel), &isNull);
Assert(!isNull);
old_acl = DatumGetAclPCopy(oldAclDatum);
/* Get a writable copy of the existing ACL. */
oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
RelationGetDescr(rel), &isNull);
Assert(!isNull);
old_acl = DatumGetAclPCopy(oldAclDatum);
/* Must find out the owner's OID the hard way. */
cacheid = get_object_catcache_oid(classid);
objtuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objid)); if (!HeapTupleIsValid(objtuple))
elog(ERROR, "cache lookup failed for %s %u",
get_object_class_descr(classid), objid);
/* If we end with an empty ACL, delete the pg_init_privs entry. */ if (new_acl == NULL || ACL_NUM(new_acl) == 0)
{
CatalogTupleDelete(rel, &oldtuple->t_self);
} else
{
Datum values[Natts_pg_init_privs] = {0}; bool nulls[Natts_pg_init_privs] = {0}; bool replaces[Natts_pg_init_privs] = {0};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.