Is there an easy way to enumerate all objects that a specific role has some access privilege to? I know of the set of has_*_privilege functions in pg_catalog bu
There's no such view out of the box, but the data needed to create it is in the system catalogs:
http://www.postgresql.org/docs/current/static/catalogs.html
For instance, there's a relacl field in pg_class:
select oid::regclass, relacl from pg_class;
There are similar fields in other catalogs, namely typacl in pg_type and proacl in pg_proc.
You'll presumably want to use two more catalogs, namely pg_authid to know which roles are have superuser privileges, and pg_auth_members to know who has what role.
(The pg_default_acl is only used during object creation, so is not useful.)
There are a couple of aclitem-related internal functions that may come in handy in creating the view. You can list them in psql like so:
\df+ *acl*
In particular aclexplode(). The following example will hopefully be enough to get you started:
select oid::regclass,
(aclexplode(relacl)).grantor,
(aclexplode(relacl)).grantee,
(aclexplode(relacl)).privilege_type,
(aclexplode(relacl)).is_grantable
from pg_class
where relacl is not null;
It can be optimized by expanding the acl rows first, e.g.:
select oid::regclass,
aclitem.grantee
from (select oid, aclexplode(relacl) as aclitem from pg_class) sub
It will lead you straight to the desired result.
Insofar as I'm aware, that's about as good as it'll get using the built-in tools. (Naturally, you could write your own set of operators in C if you'd like to try to optimize this further.)
With respect to your extra questions, I'm afraid they can only be answered by a handful of people in the world, aka the core devs themselves. They hang out on the pg hackers list more often than they do here.
Probably not the best / efficient way, but it helps me a lot! I needed it while having problems dropping roles and having the error.
ERROR: role ROLE_NAME cannot be dropped because some objects depend on it
You can use it as
SELECT * FROM upg_roles_privs WHERE grantee = 'testuser'
The code is below. I'm not including "system" objects (from pg_catalog and information_schema), you can take the conditions out of the query if you wish to enumerate them.
CREATE VIEW upg_roles_privs AS
/* Databases */
select type, objname, r1.rolname grantor, r2.rolname grantee, privilege_type
from
(select
'database'::text as type, datname as objname, datistemplate, datallowconn,
(aclexplode(datacl)).grantor as grantorI,
(aclexplode(datacl)).grantee as granteeI,
(aclexplode(datacl)).privilege_type,
(aclexplode(datacl)).is_grantable
from pg_database) as db
join pg_roles r1 on db.grantorI = r1.oid
join pg_roles r2 on db.granteeI = r2.oid
where r2.rolname not in ('postgres')
union all
/* Schemas / Namespaces */
select type, objname, r1.rolname grantor, r2.rolname grantee, privilege_type from
(select
'schema'::text as type, nspname as objname,
(aclexplode(nspacl)).grantor as grantorI,
(aclexplode(nspacl)).grantee as granteeI,
(aclexplode(nspacl)).privilege_type,
(aclexplode(nspacl)).is_grantable
from pg_catalog.pg_namespace) as ns
join pg_roles r1 on ns.grantorI = r1.oid
join pg_roles r2 on ns.granteeI = r2.oid
where r2.rolname not in ('postgres')
union all
/* Tabelas */
select 'tables'::text as type, table_name||' ('||table_schema||')' as objname, grantor, grantee, privilege_type
from information_schema.role_table_grants
where grantee not in ('postgres')
and table_schema not in ('information_schema', 'pg_catalog')
and grantor <> grantee
union all
/* Colunas (TODO: se o revoke on table from x retirar acesso das colunas, nao precisa desse bloco) */
select
'columns'::text as type, column_name||' ('||table_name||')' as objname,
grantor, grantee, privilege_type
from information_schema.role_column_grants
where
table_schema not in ('information_schema', 'pg_catalog')
and grantor <> grantee
union all
/* Funcoes / Procedures */
select 'routine'::text as type, routine_name as objname, grantor, grantee, privilege_type
from information_schema.role_routine_grants
where grantor <> grantee
and routine_schema not in ('information_schema', 'pg_catalog')
--union all information_schema.role_udt_grants
union all
/* Outros objetos */
select 'object'::text as type, object_name||'( '||object_type||')' as objname, grantor, grantee, privilege_type
from information_schema.role_usage_grants
where object_type <> 'COLLATION' and object_type <> 'DOMAIN'