postgresql delete role with similar names - postgresql

I have created roles with similar names like abc_ where number varies but abc_ always stays same. I can see the roles with following query
select * from pg_roles where rolname like 'abc_%';
But I don't know how to drop all role with similar name. I have got following query but it takes full name.
DROP ROLE name;
I am trying to dropping from psql and I am not writing any functions. Is there any query to to drop roles where I can have like 'abc_%'?

Without using dynamic SQL of some sort, no, you can't do that. A simple example using dynamic SQL to drop the roles:
select 'DROP ROLE ' || rolname || ';' from pg_roles where rolname like 'abc_%';
If you are unwilling to paste the results into a psql session, you can also pipe it from one session to another.
psql -d yourdb -U youruser -qtAc "select 'DROP ROLE ' || rolname || ';' from pg_roles where rolname like 'abc_%'" | psql -d yourdb -U youruser

Related

Store multiline EOSQL and with \ char query in variable and run it with psql

I have the following code in a shell script that initializes the postgres database in a docker container:
if [ "$ENV" == "development" ];
then
psql --username "postgres" --dbname "postgres" <<EOSQL
SELECT 'CREATE DATABASE $DATABASE' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$DATABASE');\gexec
\connect "$DATABASE";
DO \$\$
BEGIN
-- Some stuff
END
\$\$;
-- Other stuff
EOSQL
else
psql --host "$HOST" --username "postgres" --dbname "postgres" <<EOSQL
SELECT 'CREATE DATABASE $DATABASE' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$DATABASE');\gexec
\connect "$DATABASE";
DO \$\$
BEGIN
-- Some stuff
END
\$\$;
-- Other stuff
EOSQL
fi
In the if and else statement the SQL query is identical and I would like to put in a variable so I don't have to repeat it.
I tried to do QUERY="...", then psql ... -c "$QUERY" but I get errors on the \ char.
Is there a way to store this multiline SQL query in a variable and run it with psql
I always endeavor to avoid these cases and try to come up with a way around it if possible. You could do it this way (and not change anything in your query code which works already!):
hostoption=""
if [[ "$ENV" != "development" ]]
then
hostoption="--host $HOST"
fi
psql $hostoption --username "postgres" --dbname "postgres" <<EOSQL
SELECT 'CREATE DATABASE $DATABASE' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$DATABASE');\gexec
\connect "$DATABASE";
DO \$\$
BEGIN
-- Some stuff
END
\$\$;
-- Other stuff
EOSQL
This way, hostoption is empty for development. And adding a space after psql will not break anything.
For other environments, it contains the host option.
To easily test your query, it's best to store it in a script and use -f from psql. But if you really need this query in the shell-script itself, you can use apostrophes to enclose your delimiter word (EOF) and inhibit shell expansion, than you can just copy-paste your tested sql-script into shell-script, like:
psql $hostoption --username "postgres" --dbname "postgres" <<'EOSQL'
SELECT 'CREATE DATABASE $DATABASE' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$DATABASE');\gexec
\connect "$DATABASE";
DO $$
BEGIN
-- Some stuff
END
$$;
-- Other stuff
EOSQL
A better programming logic for your question was already pointed out by #Nic3500.

How to execute "DROP OWNED BY" only if the user exists?

I'm trying to write a bash script that will create a Postgres database, as well as the user and the user privileges to access that database. I'm using Postgres 9.6. I have the below ...
create_db_command="SELECT 'CREATE DATABASE $DB_NAME' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$DB_NAME')\gexec"
drop_owned_by_command="DROP OWNED BY $DB_USER;"
drop_role_command="DROP ROLE IF EXISTS $DB_USER;"
create_user_command="create user $DB_USER with encrypted password '$DB_PASS';"
grant_privs_command="grant all privileges on database $DB_NAME to $DB_USER;"
PGPASSWORD=$ROOT_PASSWORD
# This command creates the db if it doesn't already exist
echo "SELECT 'CREATE DATABASE $DB_NAME' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$DB_NAME')\gexec" | psql -U$PG_USER
psql -U$PG_USER $DB_NAME -c "$drop_owned_by_command"
psql -U$PG_USER -c "$drop_role_command"
psql -U$PG_USER -c "$create_user_command"
psql -U$PG_USER -c "$grant_privs_command"
The problem is when the script is run the very first time, the command
DROP OWNED BY $DB_USER;
fails because the user does not yet exist. Is there a way to write the above command so that it will only run if the user exists? Similar to DROP USER IF EXISTS ..., but DROP OWNED has no IF EXISTS clause.
You can use a similar technique like you already have for CREATE DATABASE.
In the shell:
drop_owned_by_command="SELECT 'DROP OWNED BY $DB_USER' FROM pg_roles WHERE rolname = '$DB_USER'\gexec"
echo $drop_owned_by_command | psql -U$PG_USER $DB_NAME
The SELECT only returns a row (containing the DDL command) if the role a actually exists. This is in turn executed by the psql command \gexec.
So we have a combination of SQL and psql commands and cannot use psql -c since, quoting the manual on --command:
command must be either a command string that is completely parsable by the server (i.e., it contains no psql-specific features),
or a single backslash command. Thus you cannot mix SQL and psql
meta-commands within a -c option.
Instead, pipe the echo to psql like demonstrated - and like suggested in the manual and in my related answer below and like you already do for CREATE DATABASE.
Related:
Simulate CREATE DATABASE IF NOT EXISTS for PostgreSQL?
Shell script to execute pgsql commands in files

Greenplum/Postgresql Can I grant a user truncate privileges on tables start with tmp_?

I want to create a user:etl_user to do etl job, so I grant select, update, insert privileges to etl_user, however sometimes truncate also needed, but for security, I want only grant truncate on specific tables, like table name start with tmp_.
Any idea? Thanks in advance.
Usually in such situations, bash helps
for tbl in `psql -qAt -c "select schemaname || '.' || tablename
from pg_tables
where tablename like 'tmp_%';" -d database_name`;
do
psql -c "grant truncate on $tbl to etl_user" -d database_name ;
done

PostgreSql , extract schema objects DDL to separate SQL file

I want to export all objects DDL to separate file example (table_a_create.sql, view_b_create.sql, trigger_c_create.sql, table_contraints.sql ...)
I was trying with pg_dump but it only exports to one file for the whole schema.
I read some questions about this on stackoverflow but still not enough for my requirement
Ex: How to dump PostgreSQL database structure (each object in separate file)
Is there any way to do it? I'm using Windows
If you are on the client machine, you can put this in a SQL script (e.g. export_plpgsql.sql) :
\pset tuples_only on
\pset footer off
\set QUIET on
\pset format unaligned
\set QUIET off
SELECT '\echo ''* Export '||(CASE proKind WHEN 'f' THEN 'Function' ELSE 'Procedure' END)||' : '||proName||''''
||chr(10)||'\copy (SELECT pg_get_functiondef('||p.oid||')) TO '''||:'export_path'||'/'||upper(proName)
||(CASE proKind WHEN 'f' THEN '.fct' ELSE '.prc' END)||''' WITH CSV;' as export_routine
FROM pg_proc p
WHERE proNamespace = (SELECT oid FROM pg_namespace WHERE nspName = lower(:'schema_name'))
ORDER BY proName;
and call it using 2 arguments : schema_name and export_path, for example :
psql -U my_ -d my_db -v schema_name=my_schema -v export_path=C:/temp/export_PG -f export_plpgsql.sql > C:\temp\export_plpgsql.gen.sql
This will generate a script containing all the exports command for your plpgsql routines, e.g.
\copy (SELECT pg_get_functiondef(51296)) TO 'C:/temp/export_PG/my_procedure.prc' WITH CSV;
Last step : run the generated script
psql -U my_ -d my_db -f C:\temp\export_plpgsql.gen.sql
It will generate a .prc file for each procedure and a .fct file for each function.
NB: You may have to refine the script as you can have other kind of functions (proKind) in pg_proc view.

Different views to list users in postgresql 9.5

Somebody could tell me the difference between the views pg_users, users and \du+ command to display users in Postgresql 9.5.
select *
from users
display users that are not in pg_user views
"users" is not a catalog table - it is yours. to check waht happens when you use meta-command in psql - use -E switch, eg:
~]$ psql t -E
Timing is on.
psql (9.5.4)
Type "help" for help.
t=# \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
, pg_catalog.shobj_description(r.oid, 'pg_authid') AS description
, r.rolreplication
, r.rolbypassrls
FROM pg_catalog.pg_roles r
ORDER BY 1;
**************************
List of roles
Role name | Attributes | Member of | Description
------------------+------------------------------------------------------------+-------------+---------------------------------------------------------------------------------------------
vao | | {} |
If you dig further you will find out that in 9.5 at least both pg_user and pg_roles query from pg_authid