Reputation: 454
This looks like a very basic need, but I do not find any quick and suitable answer. I have a role in Postgres which has privileges to many other tables in various databases.
I need to drop this role. I have one postgres instance and then many databases on top of it.
SELECT DISTINCT 'REVOKE ALL ON TABLE ' || table_schema || '.' || table_name || ' FROM ' || r.param_role_name || ';'
FROM information_schema.table_privileges CROSS JOIN (SELECT 'some_role_name'::text AS param_role_name) r
WHERE grantee ~* r.param_role_name;
I can do like above, by going to each and every database and find all revoke statements and then drop the role. Is there any way I can find all revoke statements at one place for all the databases.
Or something like I can alter owned by this role, can I alter all privileges with one statement?
Edit1: As most of the replies are targeted to reassign owned by and drop owned by, I want to be more specific. I can execute below commands on each database and drop the roles once all the dependencies are removed.
REASSIGN OWNED BY some_role_name TO postgres;
DROP OWNED BY some_role_name;
but there are many databases so I am looking for something forcefully flush all privileges and drop this role.
Upvotes: 3
Views: 12136
Reputation: 657847
I need to drop this role.
Run this in every database of the same cluster where the role might own anything or have any granted privileges:
REASSIGN OWNED BY some_role_name TO postgres;
DROP OWNED BY some_role_name;
postgres
being the default superuser, you can pick any other. It is going to own objects currently owned by the old role. Immediately after REASSIGN OWNED
, there are no objects left that would be owned by the same user. It may seem unintuitive to run DROP OWNED
. The wording of the command is misleading, since it also revokes all privileges and default privileges for the role in the same database. The manual:
DROP OWNED
drops all the objects within the current database that are owned by one of the specified roles. Any privileges granted to the given roles on objects in the current database and on shared objects (databases, tablespaces) will also be revoked.
Bold emphasis mine.
You still have to execute it in every single database where the role owns anything or has any granted privileges. The manual:
Because
REASSIGN OWNED
does not affect objects within other databases, it is usually necessary to execute this command in each database that contains objects owned by a role that is to be removed.
Finally, run (once):
DROP role some_role_name;
Roles are stored in a cluster-wide system catalog, while ownership and privileges on objects are stored in database-local system catalogs.
Detailed explanation in this related answer:
There is a related page in the manual with instructions.
There is no single command to do it all. But you can let Postgres generate a complete psql script for you.
Dependencies for roles are stored in the system catalog pg_shdepend
:
This information allows PostgreSQL to ensure that those objects are unreferenced before attempting to delete them.
Since we (potentially) need to connect to different databases, we need a combination of psql meta-commands (\c my_database
) and SQL DDL commands as shown above. Create this function somewhere in your DB cluster once:
CREATE OR REPLACE FUNCTION f_generate_ddl_to_remove_role(dead_role_walking regrole)
RETURNS text
LANGUAGE sql AS
$func$
SELECT concat_ws(
E'\n'
,(SELECT string_agg(format(E'\\c %I\nREASSIGN OWNED BY %2$s TO postgres; DROP OWNED BY %2$s;'
, d.datname, dead_role_walking)
, E'\n')
FROM (
SELECT DISTINCT dbid
FROM pg_shdepend
WHERE refobjid = dead_role_walking
) s
JOIN pg_database d ON d.oid = s.dbid)
, format(E'DROP role %s;\n', dead_role_walking)
)
$func$;
Call:
SELECT f_generate_ddl_to_remove_role('some_role_name');
Produces a string like:
\c my_db1
REASSIGN OWNED BY some_role_name TO postgres; DROP OWNED BY some_role_name;
\c my_db2
REASSIGN OWNED BY some_role_name TO postgres; DROP OWNED BY some_role_name;
DROP role some_role_name;
Or, if the role does not own anything and has no privileges, just:
DROP role some_role_name;
If you provide a non-existing role name, you get an error.
Copy the string (without enclosing single quotes) to a psql session opened with a superuser like postgres
. Or concatenate a bash script with it. All done.
There are several related answers with more explanation for dynamic SQL:
Upvotes: 9
Reputation: 186
You cannot drop a role until there are dependent objects in any of the database.
You will have to reassign the objects owned by this user (some_role_name) to another user. Once it is done for all objects in all the databases, you can then delete the user.
REASSIGN OWNED BY some_role_name TO some_other_role_name;
If the dependent objects are not required, you can also go ahead using DROP OWNED BY, removing all the object that are owned by some_role_name.
DROP OWNED BY some_role_name;
Upvotes: 3