Postgres Alternative to \du to view group role membership - postgresql

Is there an alternative to using psql \du to retrieve the Member of column using a builtin Postgres function or view? Thank you.

In psql you can echo the actual queries generated by backslash commands.
Use the --echo-hidden parameter
psql --echo-hidden ...
or set the variable ECHO_HIDDEN in psql, example:
test=# \set ECHO_HIDDEN on
test=# \du
********* QUERY **********
SELECT r.rolname, r.rolsuper, r.rolinherit,
r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,
r.rolconnlimit, r.rolvaliduntil,
ARRAY(SELECT b.rolname
FROM pg_catalog.pg_auth_members m
JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)
WHERE m.member = r.oid) as memberof
, r.rolreplication
, r.rolbypassrls
FROM pg_catalog.pg_roles r
ORDER BY 1;
******************************
Read about psql in the documentation.

I figured it out and here's my answer:
SELECT
pg_roles.rolname,
pg_auth_members.member,
(SELECT pg_roles.rolname FROM pg_roles WHERE oid = pg_auth_members.member)
FROM
pg_roles, pg_auth_members
WHERE
pg_auth_members.roleid = ( SELECT oid FROM pg_roles WHERE rolname = 'my_group') and pg_roles.rolname = 'my_group';
So, this query would return something like this:
rolname | member | rolname
------------+--------+---------
my_group | 18068 | first_member
my_group | 18069 | second_member
(2 rows)

Related

How to check all roles/user/group_role have what privileges in postgres database?

I have postgres database.
I want the list of users with access privileges they are being assigned.
I tried to find query and also looked in to psql command line help. (\nu and all) but I haven't found any usefull information.
Is anyone knows about that can help me out.
Thanks.
Here as a supplement to the previous.
To check the privileges of user by following:
SELECT * FROM pg_user;
As the same way, to check roles:
SELECT * FROM pg_roles;
There are few basic command like \du and \l that will provide the general information.
For getting the detailed information you may use the below function.
CREATE OR REPLACE FUNCTION database_privs(text) RETURNS table(username text,dbname name,privileges text[])
AS
$$
SELECT $1, datname, array(select privs from unnest(ARRAY[
( CASE WHEN has_database_privilege($1,c.oid,'CONNECT') THEN 'CONNECT' ELSE NULL END),
(CASE WHEN has_database_privilege($1,c.oid,'CREATE') THEN 'CREATE' ELSE NULL END),
(CASE WHEN has_database_privilege($1,c.oid,'TEMPORARY') THEN 'TEMPORARY' ELSE NULL END),
(CASE WHEN has_database_privilege($1,c.oid,'TEMP') THEN 'CONNECT' ELSE NULL END)])foo(privs) WHERE privs IS NOT NULL) FROM pg_database c WHERE
has_database_privilege($1,c.oid,'CONNECT,CREATE,TEMPORARY,TEMP') AND datname not in ('template0');
$$ language sql;
and then call the same function by providing the username/role that you get from \du
postgres=# \du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
test | | {}
test2 | | {}
test3 | | {}
postgres=# select * from database_privs('test');
username | dbname | privileges
----------+-----------+-----------------------------
test | postgres | {CONNECT,TEMPORARY,CONNECT}
test | template1 | {CONNECT}
test | test | {CONNECT,TEMPORARY,CONNECT}
(3 rows)

PSQL User Cannot See Extensions Created By Superuser

So I have created two extensions with my superuser but when I try to use these extensions as a (non-super) user, it cannot find them.
As superuser:
postgres=# SELECT e.extname
postgres-# , n.nspname AS home_schema_of_extension
postgres-# , extrelocatable AS extension_can_be_relocated
postgres-# FROM pg_catalog.pg_extension e
postgres-# JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace;
extname | home_schema_of_extension | extension_can_be_relocated
---------------+--------------------------+----------------------------
adminpack | pg_catalog | f
plpgsql | pg_catalog | f
fuzzystrmatch | public | t
btree_gist | public | t
(4 rows)
And as another user:
toggleme=> SELECT e.extname
toggleme-> , n.nspname AS home_schema_of_extension
toggleme-> , extrelocatable AS extension_can_be_relocated
toggleme-> FROM pg_catalog.pg_extension e
toggleme-> JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace;
extname | home_schema_of_extension | extension_can_be_relocated
---------+--------------------------+----------------------------
plpgsql | pg_catalog | f
(1 row)
Why is the non-super-user unable to use these extensions? Non-super-user has public in his search path but still can't even see that these extensions exist.
The superuser and normal user are connected to different databases in the same PostgreSQL instance.
CREATE EXTENSION is database-local.

How can I review all database and object grants for a role?

I am trying to audit all of the permissions for an application before release and I want to ensure no role has more access than it needs. I have looked at the different functions and system tables, but everything is very piecemeal.
Is there a good query or method to be able to dump out every grant a particular role has?
I am using pg 9.5.
The column relacl of the system catalog pg_class contains all informations on privileges.
Example data in schema public owned by postgres with grants to newuser:
create table test(id int);
create view test_view as select * from test;
grant select, insert, update on test to newuser;
grant select on test_view to newuser;
Querying the pg_class:
select
relname,
relkind,
coalesce(nullif(s[1], ''), 'public') as grantee,
s[2] as privileges
from
pg_class c
join pg_namespace n on n.oid = relnamespace
join pg_roles r on r.oid = relowner,
unnest(coalesce(relacl::text[], format('{%s=arwdDxt/%s}', rolname, rolname)::text[])) acl,
regexp_split_to_array(acl, '=|/') s
where nspname = 'public'
and relname like 'test%';
relname | relkind | grantee | privileges
-----------+---------+----------+------------
test | r | postgres | arwdDxt <- owner postgres has all privileges on the table
test | r | newuser | arw <- newuser has append/read/write privileges
test_view | v | postgres | arwdDxt <- owner postgres has all privileges on the view
test_view | v | newuser | r <- newuser has read privilege
(4 rows)
Comments:
coalesce(relacl::text[], format('{%s=arwdDxt/%s}', rolname, rolname)) - Null in relacl means that the owner has all privileges;
unnest(...) acl - relacl is an array of aclitem, one array element for a user;
regexp_split_to_array(acl, '=|/') s - split aclitem into: s[1] username, s[2] privileges;
coalesce(nullif(s[1], ''), 'public') as grantee - empty username means public.
Modify the query to select individual user or specific kind of relation or another schemas, etc...
Read in the documentation:
The catalog pg_class,
GRANT with the description of acl system.
In a similar way you can get information about privileges granted on schemas (the column nspacl in pg_namespace) and databases (datacl in pg_database)
The relacl column (and others of type aclitem) doesn't have to be parsed as text.
The function aclexplode unnests array, which makes it suitable for lateral join. Result is record with well named fields, just convert oid to human-readable name:
select c.*, n.nspname,
acl.grantor, acl.grantee,
pg_catalog.pg_get_userbyid(acl.grantor), pg_catalog.pg_get_userbyid(acl.grantee),
acl.privilege_type, acl.is_grantable
from pg_catalog.pg_class c
join pg_catalog.pg_namespace n on n.oid = c.relnamespace,
lateral aclexplode(c.relacl) acl;

Is there a psql command to show table definitions?

The sqlite3 CLI has a command .schema that will display the columns of all tables in the database.
The psql CLI for PostgreSQL has a meta-commands \d that shows columns for all "relations" (table, view, index, sequence, or foreign table) and a meta-command \dt that lists the relations that are tables but does not show the columns of those tables.
Is there a way to get psql to show output like sqlite3's .schema - show the output of \d on just relations that are tables? \d * shows columns for all relations, which in my database of 32 tables contains 63 tables and sequences. The pattern (* in this example) seems able to match on relation name but not relation type. Is there a pattern for "match all tables"?
If you want this like output:
sqlite> .schema t24
CREATE TABLE t24 (
i integer,
t text
);
You should use pg_dump -s, not psql:
bash>pg_dump -t t24 -s
CREATE TABLE t24 (
i integer,
t text
);
It created DDL just like .schema...
Now regarding the queries in comments, if you modify them a little:
t=# \d t24
Table "public.t24"
Column | Type | Modifiers
--------+---------+-----------
i | integer |
t | text |
t=# SELECT a.attname as "Column",pg_catalog.format_type(a.atttypid, a.atttypmod) as "Type",
(SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
FROM pg_catalog.pg_attrdef d
WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef) as "Modifiers"
FROM pg_catalog.pg_attribute a
join pg_catalog.pg_class c on a.attrelid = c.oid
WHERE true
AND relname like 't24'
AND c.relkind = 'r'::"char"
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY relname, a.attnum;
Column | Type | Modifiers
--------+---------+-----------
i | integer |
t | text |
(2 rows)
This query will show only tables in same manner as \d meta-command.
BTW I took the query from this metacommand. If you launch psql -E, and run '\d table_name` you will see that all meta commands are just wraps for select queries...

How can I get a list of all functions stored in the database of a particular schema in PostgreSQL?

I want to be able to connect to a PostgreSQL database and find all of the functions for a particular schema.
My thought was that I could make some query to pg_catalog or information_schema and get a list of all functions, but I can't figure out where the names and parameters are stored. I'm looking for a query that will give me the function name and the parameter types it takes (and what order it takes them in).
Is there a way to do this?
\df <schema>.*
in psql gives the necessary information.
To see the query that's used internally connect to a database with psql and supply an extra "-E" (or "--echo-hidden") option and then execute the above command.
After some searching, I was able to find the information_schema.routines table and the information_schema.parameters tables. Using those, one can construct a query for this purpose. LEFT JOIN, instead of JOIN, is necessary to retrieve functions without parameters.
SELECT routines.routine_name, parameters.data_type, parameters.ordinal_position
FROM information_schema.routines
LEFT JOIN information_schema.parameters ON routines.specific_name=parameters.specific_name
WHERE routines.specific_schema='my_specified_schema_name'
ORDER BY routines.routine_name, parameters.ordinal_position;
If any one is interested here is what query is executed by psql on postgres 9.1:
SELECT n.nspname as "Schema",
p.proname as "Name",
pg_catalog.pg_get_function_result(p.oid) as "Result data type",
pg_catalog.pg_get_function_arguments(p.oid) as "Argument data types",
CASE
WHEN p.proisagg THEN 'agg'
WHEN p.proiswindow THEN 'window'
WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN 'trigger'
ELSE 'normal'
END as "Type"
FROM pg_catalog.pg_proc p
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE pg_catalog.pg_function_is_visible(p.oid)
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
ORDER BY 1, 2, 4;
You can get what psql runs for a backslash command by running psql with the -E flag.
There's a handy function, oidvectortypes, that makes this a lot easier.
SELECT format('%I.%I(%s)', ns.nspname, p.proname, oidvectortypes(p.proargtypes))
FROM pg_proc p INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'my_namespace';
Credit to Leo Hsu and Regina Obe at Postgres Online for pointing out oidvectortypes. I wrote similar functions before, but used complex nested expressions that this function gets rid of the need for.
See related answer.
(edit in 2016)
Summarizing typical report options:
-- Compact:
SELECT format('%I.%I(%s)', ns.nspname, p.proname, oidvectortypes(p.proargtypes))
-- With result data type:
SELECT format(
'%I.%I(%s)=%s',
ns.nspname, p.proname, oidvectortypes(p.proargtypes),
pg_get_function_result(p.oid)
)
-- With complete argument description:
SELECT format('%I.%I(%s)', ns.nspname, p.proname, pg_get_function_arguments(p.oid))
-- ... and mixing it.
-- All with the same FROM clause:
FROM pg_proc p INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'my_namespace';
NOTICE: use p.proname||'_'||p.oid AS specific_name to obtain unique names, or to JOIN with information_schema tables — see routines and parameters at #RuddZwolinski's answer.
The function's OID (see pg_catalog.pg_proc) and the function's specific_name (see information_schema.routines) are the main reference options to functions. Below, some useful functions in reporting and other contexts.
--- --- --- --- ---
--- Useful overloads:
CREATE FUNCTION oidvectortypes(p_oid int) RETURNS text AS $$
SELECT oidvectortypes(proargtypes) FROM pg_proc WHERE oid=$1;
$$ LANGUAGE SQL IMMUTABLE;
CREATE FUNCTION oidvectortypes(p_specific_name text) RETURNS text AS $$
-- Extract OID from specific_name and use it in oidvectortypes(oid).
SELECT oidvectortypes(proargtypes)
FROM pg_proc WHERE oid=regexp_replace($1, '^.+?([^_]+)$', '\1')::int;
$$ LANGUAGE SQL IMMUTABLE;
CREATE FUNCTION pg_get_function_arguments(p_specific_name text) RETURNS text AS $$
-- Extract OID from specific_name and use it in pg_get_function_arguments.
SELECT pg_get_function_arguments(regexp_replace($1, '^.+?([^_]+)$', '\1')::int)
$$ LANGUAGE SQL IMMUTABLE;
--- --- --- --- ---
--- User customization:
CREATE FUNCTION pg_get_function_arguments2(p_specific_name text) RETURNS text AS $$
-- Example of "special layout" version.
SELECT trim(array_agg( op||'-'||dt )::text,'{}')
FROM (
SELECT data_type::text as dt, ordinal_position as op
FROM information_schema.parameters
WHERE specific_name = p_specific_name
ORDER BY ordinal_position
) t
$$ LANGUAGE SQL IMMUTABLE;
Run below SQL query to create a view which will show all functions:
CREATE OR REPLACE VIEW show_functions AS
SELECT routine_name FROM information_schema.routines
WHERE routine_type='FUNCTION' AND specific_schema='public';
Get List of function_schema and function_name...
SELECT
n.nspname AS function_schema,
p.proname AS function_name
FROM
pg_proc p
LEFT JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE
n.nspname NOT IN ('pg_catalog', 'information_schema')
ORDER BY
function_schema,
function_name;
Is a good idea named the functions with commun alias on the first words for filtre the name with LIKE
Example with public schema in Postgresql 9.4, be sure to replace with his scheme
SELECT routine_name
FROM information_schema.routines
WHERE routine_type='FUNCTION'
AND specific_schema='public'
AND routine_name LIKE 'aliasmyfunctions%';
Example:
perfdb-# \df information_schema.*;
List of functions
Schema | Name | Result data type | Argument data types | Type
information_schema | _pg_char_max_length | integer | typid oid, typmod integer | normal
information_schema | _pg_char_octet_length | integer | typid oid, typmod integer | normal
information_schema | _pg_datetime_precision| integer | typid oid, typmod integer | normal
.....
information_schema | _pg_numeric_scale | integer | typid oid, typmod integer | normal
information_schema | _pg_truetypid | oid | pg_attribute, pg_type | normal
information_schema | _pg_truetypmod | integer | pg_attribute, pg_type | normal
(11 rows)
This function returns all user defined routines in current database.
SELECT pg_get_functiondef(p.oid) FROM pg_proc p
INNER JOIN pg_namespace ns ON p.pronamespace = ns.oid
WHERE ns.nspname = 'public';
The joins in abovementioned answers returns not only input parameters, but also outputs. So it is necessary to specify also parameter_mode. This select will return list of functions with its input parametrs (if having some). Postgres 14.
select r.routine_name, array_agg(p.data_type::text order by p.ordinal_position) from information_schema.routines r left join information_schema.parameters p on r.specific_name = p.specific_name
where r.routine_type = 'FUNCTION' and r.specific_schema = 'schema_name' and (p.parameter_mode = 'IN' or p.parameter_mode is null)
group by r.routine_name order by r.routine_name;