/* *ObjectProperty * *Thisarrayprovidesacommonpartofsystemobjectstructure;tohelp *consolidateroutinestohandlevariouskindofobjectclasses.
*/ typedefstruct
{ constchar *class_descr; /* string describing the catalog, for internal
* error messages */
Oid class_oid; /* oid of catalog */
Oid oid_index_oid; /* oid of index on system oid column */ int oid_catcache_id; /* id of catcache on system oid column */ int name_catcache_id; /* id of catcache on (name,namespace), or *(name)iftheobjectdoesnotliveina
* namespace */
AttrNumber attnum_oid; /* attribute number of oid column */
AttrNumber attnum_name; /* attnum of name field */
AttrNumber attnum_namespace; /* attnum of namespace field */
AttrNumber attnum_owner; /* attnum of owner field */
AttrNumber attnum_acl; /* attnum of acl field */
ObjectType objtype; /* OBJECT_* of this object type */ bool is_nsp_name_unique; /* can the nsp/name combination (or name *alone,ifthere'snonamespace)be *consideredauniqueidentifierforan
* object of this class? */
} ObjectPropertyType;
/* Look up object address. */ switch (objtype)
{ case OBJECT_INDEX: case OBJECT_SEQUENCE: case OBJECT_TABLE: case OBJECT_VIEW: case OBJECT_MATVIEW: case OBJECT_FOREIGN_TABLE:
address =
get_relation_by_qualified_name(objtype, castNode(List, object),
&relation, lockmode,
missing_ok); break; case OBJECT_ATTRIBUTE: case OBJECT_COLUMN:
address =
get_object_address_attribute(objtype, castNode(List, object),
&relation, lockmode,
missing_ok); break; case OBJECT_DEFAULT:
address =
get_object_address_attrdef(objtype, castNode(List, object),
&relation, lockmode,
missing_ok); break; case OBJECT_RULE: case OBJECT_TRIGGER: case OBJECT_TABCONSTRAINT: case OBJECT_POLICY:
address = get_object_address_relobject(objtype, castNode(List, object),
&relation, missing_ok); break; case OBJECT_DOMCONSTRAINT:
{
List *objlist;
ObjectAddress domaddr; char *constrname;
relation = relation_openrv_extended(makeRangeVarFromNameList(object),
lockmode, missing_ok); if (!relation) return address;
switch (objtype)
{ case OBJECT_INDEX: if (relation->rd_rel->relkind != RELKIND_INDEX &&
relation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not an index",
RelationGetRelationName(relation)))); break; case OBJECT_SEQUENCE: if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a sequence",
RelationGetRelationName(relation)))); break; case OBJECT_TABLE: if (relation->rd_rel->relkind != RELKIND_RELATION &&
relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a table",
RelationGetRelationName(relation)))); break; case OBJECT_VIEW: if (relation->rd_rel->relkind != RELKIND_VIEW)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a view",
RelationGetRelationName(relation)))); break; case OBJECT_MATVIEW: if (relation->rd_rel->relkind != RELKIND_MATVIEW)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a materialized view",
RelationGetRelationName(relation)))); break; case OBJECT_FOREIGN_TABLE: if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a foreign table",
RelationGetRelationName(relation)))); break; default:
elog(ERROR, "unrecognized object type: %d", (int) objtype); break;
}
/* *Findobjectaddressforanobjectthatisattachedtoarelation. * *NotethatwetakeonlyanAccessShareLockontherelation.Weneednot *passdowntheLOCKMODEfromget_object_address(),becausethatisthelock *modefortheobjectitself,nottherelationtowhichitisattached.
*/ static ObjectAddress
get_object_address_relobject(ObjectType objtype, List *object,
Relation *relp, bool missing_ok)
{
ObjectAddress address;
Relation relation = NULL; int nnames; constchar *depname;
List *relname;
Oid reloid;
/* Extract name of dependent object. */
depname = strVal(llast(object));
/* Separate relation name from dependent object name. */
nnames = list_length(object); if (nnames < 2)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("must specify relation and object name")));
/* Extract relation name and open relation. */
relname = list_copy_head(object, nnames - 1);
relation = table_openrv_extended(makeRangeVarFromNameList(relname),
AccessShareLock,
missing_ok);
/* Avoid relcache leak when object not found. */ if (!OidIsValid(address.objectId))
{ if (relation != NULL)
table_close(relation, AccessShareLock);
relation = NULL; /* department of accident prevention */ return address;
}
/* Done. */
*relp = relation; return address;
}
/* *FindtheObjectAddressforanattribute.
*/ static ObjectAddress
get_object_address_attribute(ObjectType objtype, List *object,
Relation *relp, LOCKMODE lockmode, bool missing_ok)
{
ObjectAddress address;
List *relname;
Oid reloid;
Relation relation; constchar *attname;
AttrNumber attnum;
/* Extract relation name and open relation. */ if (list_length(object) < 2)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("column name must be qualified")));
attname = strVal(llast(object));
relname = list_copy_head(object, list_length(object) - 1); /* XXX no missing_ok support here */
relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
reloid = RelationGetRelid(relation);
/* Look up attribute and construct return value. */
attnum = get_attnum(reloid, attname); if (attnum == InvalidAttrNumber)
{ if (!missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
attname, NameListToString(relname))));
/* *FindtheObjectAddressforanattribute'sdefaultvalue.
*/ static ObjectAddress
get_object_address_attrdef(ObjectType objtype, List *object,
Relation *relp, LOCKMODE lockmode, bool missing_ok)
{
ObjectAddress address;
List *relname;
Oid reloid;
Relation relation; constchar *attname;
AttrNumber attnum;
TupleDesc tupdesc;
Oid defoid;
/* Extract relation name and open relation. */ if (list_length(object) < 2)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("column name must be qualified")));
attname = strVal(llast(object));
relname = list_copy_head(object, list_length(object) - 1); /* XXX no missing_ok support here */
relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
reloid = RelationGetRelid(relation);
tupdesc = RelationGetDescr(relation);
/* Look up attribute number and fetch the pg_attrdef OID */
attnum = get_attnum(reloid, attname);
defoid = InvalidOid; if (attnum != InvalidAttrNumber && tupdesc->constr != NULL)
defoid = GetAttrDefaultOid(reloid, attnum); if (!OidIsValid(defoid))
{ if (!missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("default value for column \"%s\" of relation \"%s\" does not exist",
attname, NameListToString(relname))));
tup = LookupTypeName(NULL, typename, NULL, missing_ok); if (!HeapTupleIsValid(tup))
{ if (!missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type \"%s\" does not exist",
TypeNameToString(typename)))); return address;
}
address.objectId = typeTypeId(tup);
if (objtype == OBJECT_DOMAIN)
{ if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a domain",
TypeNameToString(typename))));
}
ReleaseSysCache(tup);
return address;
}
/* *FindtheObjectAddressforanopclassoropfamily.
*/ static ObjectAddress
get_object_address_opcf(ObjectType objtype, List *object, bool missing_ok)
{
Oid amoid;
ObjectAddress address;
/* XXX no missing_ok support here */
amoid = get_index_am_oid(strVal(linitial(object)), false);
object = list_copy_tail(object, 1);
/* fetch string names from input lists, for error messages */
username = strVal(linitial(object));
servername = strVal(lsecond(object));
/* look up pg_authid OID of mapped user; InvalidOid if PUBLIC */ if (strcmp(username, "public") == 0)
userid = InvalidOid; else
{
tp = SearchSysCache1(AUTHNAME,
CStringGetDatum(username)); if (!HeapTupleIsValid(tp))
{ if (!missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
username, servername))); return address;
}
userid = ((Form_pg_authid) GETSTRUCT(tp))->oid;
ReleaseSysCache(tp);
}
/* Now look up the pg_user_mapping tuple */
server = GetForeignServerByName(servername, true); if (!server)
{ if (!missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("server \"%s\" does not exist", servername))); return address;
}
tp = SearchSysCache2(USERMAPPINGUSERSERVER,
ObjectIdGetDatum(userid),
ObjectIdGetDatum(server->serverid)); if (!HeapTupleIsValid(tp))
{ if (!missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
username, servername))); return address;
}
/* fetch publication name from input list */
pubname = strVal(lsecond(object));
/* Now look up the pg_publication tuple */
pub = GetPublicationByName(pubname, missing_ok); if (!pub)
{
relation_close(relation, AccessShareLock); return address;
}
/* Find the publication relation mapping in syscache. */
address.objectId =
GetSysCacheOid2(PUBLICATIONRELMAP, Anum_pg_publication_rel_oid,
ObjectIdGetDatum(RelationGetRelid(relation)),
ObjectIdGetDatum(pub->oid)); if (!OidIsValid(address.objectId))
{ if (!missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("publication relation \"%s\" in publication \"%s\" does not exist",
RelationGetRelationName(relation), pubname)));
relation_close(relation, AccessShareLock); return address;
}
not_found: if (!missing_ok)
{ if (schema)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("default ACL for user \"%s\" in schema \"%s\" on %s does not exist",
username, schema, objtype_str))); else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("default ACL for user \"%s\" on %s does not exist",
username, objtype_str)));
} return address;
}
/* *ConvertanarrayofTEXTintoaListofstringValues,asemittedbythe *parser,whichiswhatget_object_addressusesasinput.
*/ static List *
textarray_to_strvaluelist(ArrayType *arr)
{
Datum *elems; bool *nulls; int nelems;
List *list = NIL; int i;
for (i = 0; i < nelems; i++)
{ if (nulls[i])
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name or argument lists may not contain nulls")));
list = lappend(list, makeString(TextDatumGetCString(elems[i])));
}
return list;
}
/* *SQL-callableversionofget_object_address
*/
Datum
pg_get_object_address(PG_FUNCTION_ARGS)
{ char *ttype = TextDatumGetCString(PG_GETARG_DATUM(0));
ArrayType *namearr = PG_GETARG_ARRAYTYPE_P(1);
ArrayType *argsarr = PG_GETARG_ARRAYTYPE_P(2); int itype;
ObjectType type;
List *name = NIL; TypeName *typename = NULL;
List *args = NIL;
Node *objnode = NULL;
ObjectAddress addr;
TupleDesc tupdesc;
Datum values[3]; bool nulls[3];
HeapTuple htup;
Relation relation;
/* Decode object type, raise error if unknown */
itype = read_objtype_from_string(ttype); if (itype < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unsupported object type \"%s\"", ttype)));
type = (ObjectType) itype;
/* *Convertthetextarraytotherepresentationappropriateforthegiven *objecttype.MostuseasimplestringValueslist,buttherearesome *exceptions.
*/ if (type == OBJECT_TYPE || type == OBJECT_DOMAIN || type == OBJECT_CAST ||
type == OBJECT_TRANSFORM || type == OBJECT_DOMCONSTRAINT)
{
Datum *elems; bool *nulls; int nelems;
deconstruct_array_builtin(namearr, TEXTOID, &elems, &nulls, &nelems); if (nelems != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name list length must be exactly %d", 1))); if (nulls[0])
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name or argument lists may not contain nulls"))); typename = typeStringToTypeName(TextDatumGetCString(elems[0]), NULL);
} elseif (type == OBJECT_LARGEOBJECT)
{
Datum *elems; bool *nulls; int nelems;
deconstruct_array_builtin(namearr, TEXTOID, &elems, &nulls, &nelems); if (nelems != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name list length must be exactly %d", 1))); if (nulls[0])
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("large object OID may not be null")));
objnode = (Node *) makeFloat(TextDatumGetCString(elems[0]));
} else
{
name = textarray_to_strvaluelist(namearr); if (name == NIL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name list length must be at least %d", 1)));
}
/* *Ifargsaregiven,decodethemaccordingtotheobjecttype.
*/ if (type == OBJECT_AGGREGATE ||
type == OBJECT_FUNCTION ||
type == OBJECT_PROCEDURE ||
type == OBJECT_ROUTINE ||
type == OBJECT_OPERATOR ||
type == OBJECT_CAST ||
type == OBJECT_AMOP ||
type == OBJECT_AMPROC)
{ /* in these cases, the args list must be of TypeName */
Datum *elems; bool *nulls; int nelems; int i;
args = NIL; for (i = 0; i < nelems; i++)
{ if (nulls[i])
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name or argument lists may not contain nulls")));
args = lappend(args,
typeStringToTypeName(TextDatumGetCString(elems[i]),
NULL));
}
} else
{ /* For all other object types, use string Values */
args = textarray_to_strvaluelist(argsarr);
}
/* *get_object_addressisprettysensitivetothelengthofitsinput *lists;checkthatthey'rewhatitwants.
*/ switch (type)
{ case OBJECT_PUBLICATION_NAMESPACE: case OBJECT_USER_MAPPING: if (list_length(name) != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name list length must be exactly %d", 1))); /* fall through to check args length */ /* FALLTHROUGH */ case OBJECT_DOMCONSTRAINT: case OBJECT_CAST: case OBJECT_PUBLICATION_REL: case OBJECT_DEFACL: case OBJECT_TRANSFORM: if (list_length(args) != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument list length must be exactly %d", 1))); break; case OBJECT_OPFAMILY: case OBJECT_OPCLASS: if (list_length(name) < 2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name list length must be at least %d", 2))); break; case OBJECT_AMOP: case OBJECT_AMPROC: if (list_length(name) < 3)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name list length must be at least %d", 3))); /* fall through to check args length */ /* FALLTHROUGH */ case OBJECT_OPERATOR: if (list_length(args) != 2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument list length must be exactly %d", 2))); break; default: break;
}
/* *NowbuildtheNodetypethatget_object_address()expectsforthegiven *type.
*/ switch (type)
{ case OBJECT_TABLE: case OBJECT_SEQUENCE: case OBJECT_VIEW: case OBJECT_MATVIEW: case OBJECT_INDEX: case OBJECT_FOREIGN_TABLE: case OBJECT_COLUMN: case OBJECT_ATTRIBUTE: case OBJECT_COLLATION: case OBJECT_CONVERSION: case OBJECT_STATISTIC_EXT: case OBJECT_TSPARSER: case OBJECT_TSDICTIONARY: case OBJECT_TSTEMPLATE: case OBJECT_TSCONFIGURATION: case OBJECT_DEFAULT: case OBJECT_POLICY: case OBJECT_RULE: case OBJECT_TRIGGER: case OBJECT_TABCONSTRAINT: case OBJECT_OPCLASS: case OBJECT_OPFAMILY:
objnode = (Node *) name; break; case OBJECT_ACCESS_METHOD: case OBJECT_DATABASE: case OBJECT_EVENT_TRIGGER: case OBJECT_EXTENSION: case OBJECT_FDW: case OBJECT_FOREIGN_SERVER: case OBJECT_LANGUAGE: case OBJECT_PARAMETER_ACL: case OBJECT_PUBLICATION: case OBJECT_ROLE: case OBJECT_SCHEMA: case OBJECT_SUBSCRIPTION: case OBJECT_TABLESPACE: if (list_length(name) != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name list length must be exactly %d", 1)));
objnode = linitial(name); break; case OBJECT_TYPE: case OBJECT_DOMAIN:
objnode = (Node *) typename; break; case OBJECT_CAST: case OBJECT_DOMCONSTRAINT: case OBJECT_TRANSFORM:
objnode = (Node *) list_make2(typename, linitial(args)); break; case OBJECT_PUBLICATION_REL:
objnode = (Node *) list_make2(name, linitial(args)); break; case OBJECT_PUBLICATION_NAMESPACE: case OBJECT_USER_MAPPING:
objnode = (Node *) list_make2(linitial(name), linitial(args)); break; case OBJECT_DEFACL:
objnode = (Node *) lcons(linitial(args), name); break; case OBJECT_AMOP: case OBJECT_AMPROC:
objnode = (Node *) list_make2(name, args); break; case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: case OBJECT_AGGREGATE: case OBJECT_OPERATOR:
{
ObjectWithArgs *owa = makeNode(ObjectWithArgs);
owa->objname = name;
owa->objargs = args;
objnode = (Node *) owa; break;
} case OBJECT_LARGEOBJECT: /* already handled above */ break; /* no default, to let compiler warn about missing case */
}
if (objnode == NULL)
elog(ERROR, "unrecognized object type: %d", type);
/* *Checkownershipofanobjectpreviouslyidentifiedbyget_object_address.
*/ void
check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
Node *object, Relation relation)
{ switch (objtype)
{ case OBJECT_INDEX: case OBJECT_SEQUENCE: case OBJECT_TABLE: case OBJECT_VIEW: case OBJECT_MATVIEW: case OBJECT_FOREIGN_TABLE: case OBJECT_COLUMN: case OBJECT_RULE: case OBJECT_TRIGGER: case OBJECT_POLICY: case OBJECT_TABCONSTRAINT: if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
RelationGetRelationName(relation)); break; case OBJECT_TYPE: case OBJECT_DOMAIN: case OBJECT_ATTRIBUTE: if (!object_ownercheck(address.classId, address.objectId, roleid))
aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId); break; case OBJECT_DOMCONSTRAINT:
{
HeapTuple tuple;
Oid contypid;
tuple = SearchSysCache1(CONSTROID,
ObjectIdGetDatum(address.objectId)); if (!HeapTupleIsValid(tuple))
elog(ERROR, "constraint with OID %u does not exist",
address.objectId);
/* *Fallbacktotypeownershipcheckinthiscaseasthisis *whatdomainconstraintsrelyon.
*/ if (!object_ownercheck(TypeRelationId, contypid, roleid))
aclcheck_error_type(ACLCHECK_NOT_OWNER, contypid);
} break; case OBJECT_AGGREGATE: case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: case OBJECT_OPERATOR: if (!object_ownercheck(address.classId, address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
NameListToString((castNode(ObjectWithArgs, object))->objname)); break; case OBJECT_DATABASE: case OBJECT_EVENT_TRIGGER: case OBJECT_EXTENSION: case OBJECT_FDW: case OBJECT_FOREIGN_SERVER: case OBJECT_LANGUAGE: case OBJECT_PUBLICATION: case OBJECT_SCHEMA: case OBJECT_SUBSCRIPTION: case OBJECT_TABLESPACE: if (!object_ownercheck(address.classId, address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
strVal(object)); break; case OBJECT_COLLATION: case OBJECT_CONVERSION: case OBJECT_OPCLASS: case OBJECT_OPFAMILY: case OBJECT_STATISTIC_EXT: case OBJECT_TSDICTIONARY: case OBJECT_TSCONFIGURATION: if (!object_ownercheck(address.classId, address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
NameListToString(castNode(List, object))); break; case OBJECT_LARGEOBJECT: if (!lo_compat_privileges &&
!object_ownercheck(address.classId, address.objectId, roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be owner of large object %u",
address.objectId))); break; case OBJECT_CAST:
{ /* We can only check permissions on the source/target types */ TypeName *sourcetype = linitial_node(TypeName, castNode(List, object)); TypeName *targettype = lsecond_node(TypeName, castNode(List, object));
Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
Oid targettypeid = typenameTypeId(NULL, targettype);
if (!object_ownercheck(TypeRelationId, sourcetypeid, roleid)
&& !object_ownercheck(TypeRelationId, targettypeid, roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be owner of type %s or type %s",
format_type_be(sourcetypeid),
format_type_be(targettypeid))));
} break; case OBJECT_TRANSFORM:
{ TypeName *typename = linitial_node(TypeName, castNode(List, object));
Oid typeid = typenameTypeId(NULL, typename);
if (!object_ownercheck(TypeRelationId, typeid, roleid))
aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid);
} break; case OBJECT_ROLE:
/* *Wetreatrolesasbeing"owned"bythosewithCREATEROLEpriv, *providedthattheyalsohaveadminoptionontherole. * *However,superusersareonlyownedbysuperusers.
*/ if (superuser_arg(address.objectId))
{ if (!superuser_arg(roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied"),
errdetail("The current user must have the %s attribute.", "SUPERUSER")));
} else
{ if (!has_createrole_privilege(roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied"),
errdetail("The current user must have the %s attribute.", "CREATEROLE"))); if (!is_admin_of_role(roleid, address.objectId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied"),
errdetail("The current user must have the %s option on role \"%s\".", "ADMIN",
GetUserNameFromId(address.objectId, true))));
} break; 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,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser"))); break; case OBJECT_AMOP: case OBJECT_AMPROC: case OBJECT_DEFAULT: case OBJECT_DEFACL: case OBJECT_PUBLICATION_NAMESPACE: case OBJECT_PUBLICATION_REL: case OBJECT_USER_MAPPING: /* These are currently not supported or don't make sense here. */
elog(ERROR, "unsupported object type: %d", (int) objtype); break;
}
}
/* *get_object_namespace * *Findtheschemacontainingthespecifiedobject.Fornon-schemaobjects, *thisfunctionreturnsInvalidOid.
*/
Oid
get_object_namespace(const ObjectAddress *address)
{ int cache;
HeapTuple tuple;
Oid oid; const ObjectPropertyType *property;
/* If not owned by a namespace, just return InvalidOid. */
property = get_object_property_data(address->classId); if (property->attnum_namespace == InvalidAttrNumber) return InvalidOid;
/* Currently, we can only handle object types with system caches. */
cache = property->oid_catcache_id;
Assert(cache != -1);
/* Fetch tuple from syscache and extract namespace attribute. */
tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId)); if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for cache %d oid %u",
cache, address->objectId);
oid = DatumGetObjectId(SysCacheGetAttrNotNull(cache,
tuple,
property->attnum_namespace));
ReleaseSysCache(tuple);
return oid;
}
/* *ReturnObjectTypeforthegivenobjecttypeasgivenby *getObjectTypeDescription;ifnovalidObjectTypecodeexists,butit'sa *possibleoutputtypefromgetObjectTypeDescription,return-1. *Otherwise,anerroristhrown.
*/ int
read_objtype_from_string(constchar *objtype)
{ int i;
for (i = 0; i < lengthof(ObjectTypeMap); i++)
{ if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0) return ObjectTypeMap[i].tm_type;
}
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized object type \"%s\"", objtype)));
case CollationRelationId:
{
HeapTuple collTup;
Form_pg_collation coll; char *nspname;
collTup = SearchSysCache1(COLLOID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(collTup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for collation %u",
object->objectId); break;
}
coll = (Form_pg_collation) GETSTRUCT(collTup);
/* Qualify the name if not visible in search path */ if (CollationIsVisible(object->objectId))
nspname = NULL; else
nspname = get_namespace_name(coll->collnamespace);
case ConstraintRelationId:
{
HeapTuple conTup;
Form_pg_constraint con;
conTup = SearchSysCache1(CONSTROID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(conTup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for constraint %u",
object->objectId); break;
}
con = (Form_pg_constraint) GETSTRUCT(conTup);
if (OidIsValid(con->conrelid))
{
StringInfoData rel;
initStringInfo(&rel);
getRelationDescription(&rel, con->conrelid, false); /* translator: second %s is, e.g., "table %s" */
appendStringInfo(&buffer, _("constraint %s on %s"),
NameStr(con->conname), rel.data);
pfree(rel.data);
} else
{
appendStringInfo(&buffer, _("constraint %s"),
NameStr(con->conname));
}
ReleaseSysCache(conTup); break;
}
case ConversionRelationId:
{
HeapTuple conTup;
Form_pg_conversion conv; char *nspname;
conTup = SearchSysCache1(CONVOID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(conTup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for conversion %u",
object->objectId); break;
}
conv = (Form_pg_conversion) GETSTRUCT(conTup);
/* Qualify the name if not visible in search path */ if (ConversionIsVisible(object->objectId))
nspname = NULL; else
nspname = get_namespace_name(conv->connamespace);
if (!OidIsValid(colobject.objectId))
{ if (!missing_ok)
elog(ERROR, "could not find tuple for attrdef %u",
object->objectId); break;
}
/* translator: %s is typically "column %s of table %s" */
appendStringInfo(&buffer, _("default value for %s"),
getObjectDescription(&colobject, false)); break;
}
case LanguageRelationId:
{ char *langname = get_language_name(object->objectId,
missing_ok);
if (langname)
appendStringInfo(&buffer, _("language %s"),
get_language_name(object->objectId, false)); break;
}
case LargeObjectRelationId: if (!LargeObjectExists(object->objectId)) break;
appendStringInfo(&buffer, _("large object %u"),
object->objectId); break;
opcTup = SearchSysCache1(CLAOID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(opcTup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for opclass %u",
object->objectId); break;
}
opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
amTup = SearchSysCache1(AMOID,
ObjectIdGetDatum(opcForm->opcmethod)); if (!HeapTupleIsValid(amTup))
elog(ERROR, "cache lookup failed for access method %u",
opcForm->opcmethod);
amForm = (Form_pg_am) GETSTRUCT(amTup);
/* Qualify the name if not visible in search path */ if (OpclassIsVisible(object->objectId))
nspname = NULL; else
nspname = get_namespace_name(opcForm->opcnamespace);
appendStringInfo(&buffer, _("operator class %s for access method %s"),
quote_qualified_identifier(nspname,
NameStr(opcForm->opcname)),
NameStr(amForm->amname));
/* Qualify the name if not visible in search path */ if (StatisticsObjIsVisible(object->objectId))
nspname = NULL; else
nspname = get_namespace_name(stxForm->stxnamespace);
case TSParserRelationId:
{
HeapTuple tup;
Form_pg_ts_parser prsForm; char *nspname;
tup = SearchSysCache1(TSPARSEROID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(tup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for text search parser %u",
object->objectId); break;
}
prsForm = (Form_pg_ts_parser) GETSTRUCT(tup);
/* Qualify the name if not visible in search path */ if (TSParserIsVisible(object->objectId))
nspname = NULL; else
nspname = get_namespace_name(prsForm->prsnamespace);
case TSDictionaryRelationId:
{
HeapTuple tup;
Form_pg_ts_dict dictForm; char *nspname;
tup = SearchSysCache1(TSDICTOID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(tup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for text search dictionary %u",
object->objectId); break;
}
dictForm = (Form_pg_ts_dict) GETSTRUCT(tup);
/* Qualify the name if not visible in search path */ if (TSDictionaryIsVisible(object->objectId))
nspname = NULL; else
nspname = get_namespace_name(dictForm->dictnamespace);
case TSTemplateRelationId:
{
HeapTuple tup;
Form_pg_ts_template tmplForm; char *nspname;
tup = SearchSysCache1(TSTEMPLATEOID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(tup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for text search template %u",
object->objectId); break;
}
tmplForm = (Form_pg_ts_template) GETSTRUCT(tup);
/* Qualify the name if not visible in search path */ if (TSTemplateIsVisible(object->objectId))
nspname = NULL; else
nspname = get_namespace_name(tmplForm->tmplnamespace);
case TSConfigRelationId:
{
HeapTuple tup;
Form_pg_ts_config cfgForm; char *nspname;
tup = SearchSysCache1(TSCONFIGOID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(tup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for text search configuration %u",
object->objectId); break;
}
cfgForm = (Form_pg_ts_config) GETSTRUCT(tup);
/* Qualify the name if not visible in search path */ if (TSConfigIsVisible(object->objectId))
nspname = NULL; else
nspname = get_namespace_name(cfgForm->cfgnamespace);
case UserMappingRelationId:
{
HeapTuple tup;
Oid useid; char *usename;
Form_pg_user_mapping umform;
ForeignServer *srv;
tup = SearchSysCache1(USERMAPPINGOID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(tup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for user mapping %u",
object->objectId); break;
}
if (OidIsValid(defacl->defaclnamespace))
nspname = get_namespace_name(defacl->defaclnamespace); else
nspname = NULL;
switch (defacl->defaclobjtype)
{ case DEFACLOBJ_RELATION: if (nspname)
appendStringInfo(&buffer,
_("default privileges on new relations belonging to role %s in schema %s"),
rolename, nspname); else
appendStringInfo(&buffer,
_("default privileges on new relations belonging to role %s"),
rolename); break; case DEFACLOBJ_SEQUENCE: if (nspname)
appendStringInfo(&buffer,
_("default privileges on new sequences belonging to role %s in schema %s"),
rolename, nspname); else
appendStringInfo(&buffer,
_("default privileges on new sequences belonging to role %s"),
rolename); break; case DEFACLOBJ_FUNCTION: if (nspname)
appendStringInfo(&buffer,
_("default privileges on new functions belonging to role %s in schema %s"),
rolename, nspname); else
appendStringInfo(&buffer,
_("default privileges on new functions belonging to role %s"),
rolename); break; case DEFACLOBJ_TYPE: if (nspname)
appendStringInfo(&buffer,
_("default privileges on new types belonging to role %s in schema %s"),
rolename, nspname); else
appendStringInfo(&buffer,
_("default privileges on new types belonging to role %s"),
rolename); break; case DEFACLOBJ_NAMESPACE:
Assert(!nspname);
appendStringInfo(&buffer,
_("default privileges on new schemas belonging to role %s"),
rolename); break; case DEFACLOBJ_LARGEOBJECT:
Assert(!nspname);
appendStringInfo(&buffer,
_("default privileges on new large objects belonging to role %s"),
rolename); break; default: /* shouldn't get here */ if (nspname)
appendStringInfo(&buffer,
_("default privileges belonging to role %s in schema %s"),
rolename, nspname); else
appendStringInfo(&buffer,
_("default privileges belonging to role %s"),
rolename); break;
}
/* translator: first %s is, e.g., "table %s" */
appendStringInfo(&buffer, _("publication of %s in publication %s"),
rel.data, pubname);
pfree(rel.data);
ReleaseSysCache(tup); break;
}
case SubscriptionRelationId:
{ char *subname = get_subscription_name(object->objectId,
missing_ok);
if (subname)
appendStringInfo(&buffer, _("subscription %s"), subname); break;
}
case TransformRelationId:
{
HeapTuple trfTup;
Form_pg_transform trfForm;
trfTup = SearchSysCache1(TRFOID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(trfTup))
{ if (!missing_ok)
elog(ERROR, "could not find tuple for transform %u",
object->objectId); break;
}
trfForm = (Form_pg_transform) GETSTRUCT(trfTup);
appendStringInfo(&buffer, _("transform for %s language %s"),
format_type_be(trfForm->trftype),
get_language_name(trfForm->trflang, false));
relTup = SearchSysCache1(RELOID,
ObjectIdGetDatum(relid)); if (!HeapTupleIsValid(relTup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for relation %u", relid); return;
}
relForm = (Form_pg_class) GETSTRUCT(relTup);
/* Qualify the name if not visible in search path */ if (RelationIsVisible(relid))
nspname = NULL; else
nspname = get_namespace_name(relForm->relnamespace);
opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid)); if (!HeapTupleIsValid(opfTup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for opfamily %u", opfid); return;
}
opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod)); if (!HeapTupleIsValid(amTup))
elog(ERROR, "cache lookup failed for access method %u",
opfForm->opfmethod);
amForm = (Form_pg_am) GETSTRUCT(amTup);
/* Qualify the name if not visible in search path */ if (OpfamilyIsVisible(opfid))
nspname = NULL; else
nspname = get_namespace_name(opfForm->opfnamespace);
appendStringInfo(buffer, _("operator family %s for access method %s"),
quote_qualified_identifier(nspname,
NameStr(opfForm->opfname)),
NameStr(amForm->amname));
/* *SQL-levelcallablefunctiontoobtaintheACLofaspecifiedobject,given *itscatalogOID,objectOIDandsub-objectID.
*/
Datum
pg_get_acl(PG_FUNCTION_ARGS)
{
Oid classId = PG_GETARG_OID(0);
Oid objectId = PG_GETARG_OID(1);
int32 objsubid = PG_GETARG_INT32(2);
Oid catalogId;
AttrNumber Anum_acl;
Datum datum; bool isnull;
HeapTuple tup;
/* for "pinned" items in pg_depend, return null */ if (!OidIsValid(classId) && !OidIsValid(objectId))
PG_RETURN_NULL();
/* for large objects, the catalog to look at is pg_largeobject_metadata */
catalogId = (classId == LargeObjectRelationId) ?
LargeObjectMetadataRelationId : classId;
Anum_acl = get_object_attnum_acl(catalogId);
/* return NULL if no ACL field for this catalog */ if (Anum_acl == InvalidAttrNumber)
PG_RETURN_NULL();
procTup = SearchSysCache1(PROCOID,
ObjectIdGetDatum(procid)); if (!HeapTupleIsValid(procTup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for procedure %u", procid);
/* fallback to "procedure" for an undefined object */
appendStringInfoString(buffer, "routine"); return;
}
procForm = (Form_pg_proc) GETSTRUCT(procTup);
if (procForm->prokind == PROKIND_AGGREGATE)
appendStringInfoString(buffer, "aggregate"); elseif (procForm->prokind == PROKIND_PROCEDURE)
appendStringInfoString(buffer, "procedure"); else/* function or window function */
appendStringInfoString(buffer, "function");
case LanguageRelationId:
{
HeapTuple langTup;
Form_pg_language langForm;
langTup = SearchSysCache1(LANGOID,
ObjectIdGetDatum(object->objectId)); if (!HeapTupleIsValid(langTup))
{ if (!missing_ok)
elog(ERROR, "cache lookup failed for language %u",
object->objectId); break;
}
langForm = (Form_pg_language) GETSTRUCT(langTup);
appendStringInfoString(&buffer,
quote_identifier(NameStr(langForm->lanname))); if (objname)
*objname = list_make1(pstrdup(NameStr(langForm->lanname)));
ReleaseSysCache(langTup); break;
}
case LargeObjectRelationId: if (!LargeObjectExists(object->objectId)) break;
appendStringInfo(&buffer, "%u",
object->objectId); if (objname)
*objname = list_make1(psprintf("%u", object->objectId)); break;
username = GetUserNameFromId(defacl->defaclrole, false);
appendStringInfo(&buffer, "for role %s",
quote_identifier(username));
if (OidIsValid(defacl->defaclnamespace))
{
schema = get_namespace_name_or_temp(defacl->defaclnamespace);
appendStringInfo(&buffer, " in schema %s",
quote_identifier(schema));
} else
schema = NULL;
switch (defacl->defaclobjtype)
{ case DEFACLOBJ_RELATION:
appendStringInfoString(&buffer, " on tables"); break; case DEFACLOBJ_SEQUENCE:
appendStringInfoString(&buffer, " on sequences"); break; case DEFACLOBJ_FUNCTION:
appendStringInfoString(&buffer, " on functions"); break; case DEFACLOBJ_TYPE:
appendStringInfoString(&buffer, " on types"); break; case DEFACLOBJ_NAMESPACE:
appendStringInfoString(&buffer, " on schemas"); break; case DEFACLOBJ_LARGEOBJECT:
appendStringInfoString(&buffer, " on large objects"); break;
}
if (objname)
{
*objname = list_make1(username); if (schema)
*objname = lappend(*objname, schema);
*objargs = list_make1(psprintf("%c", defacl->defaclobjtype));
}
/* *AuxiliaryfunctiontobuildaTEXTarrayoutofalistofC-strings.
*/
ArrayType *
strlist_to_textarray(List *list)
{
ArrayType *arr;
Datum *datums; bool *nulls; int j = 0;
ListCell *cell;
MemoryContext memcxt;
MemoryContext oldcxt; int lb[1];
/* Work in a temp context; easier than individually pfree'ing the Datums */
memcxt = AllocSetContextCreate(CurrentMemoryContext, "strlist to array",
ALLOCSET_DEFAULT_SIZES);
oldcxt = MemoryContextSwitchTo(memcxt);
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.