PostgreSQL command Automation in batch script - postgresql

I need to automate the below commands through batch job, is there a way to do it. Currently command prompt is stopping after executing the first step(psql -U nrgadmin -d enwdb). Inside the enwdb database, I need to manually execute the steps from begin to commit. Any help would be appreciated.
psql -U nrgadmin -d enwdb;
begin;
alter schema asset_enw rename to asset_enw_backup;
alter schema asset_import rename to asset_enw;
alter table enw.geom rename to geom_backup;
alter table enw.geom_backup set schema asset_enw_backup;
alter table import.geom set schema enw;
commit;

Put your commands in a script file and use the -f option of psql while running it.
psql -U nrgadmin -d enwdb -f myscript.sql
Or, if you are in a Unix environment, you could put it all in a here document in a shell script and run the shell script.
#!/bin/sh
psql -U nrgadmin -d enwdb <<EOF
BEGIN;
alter schema asset_enw rename to asset_enw_backup;
#other statements
#--
COMMIT;
EOF

Related

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

postgresql: run SQL commands using psql in commandline

I have the below three lines to be run in commandline using psql how can i do it.
CREATE DATABASE myproject;
CREATE USER myprojectuser WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
I just want to pass the sql strings as it is.
As per the docs psql -c 'command;'
psql -c 'CREATE DATABASE myproject;' -c "CREATE USER myprojectuser WITH PASSWORD 'password';" -c 'GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;'
As #horse suggested -f filename is a better option. You can also put them into a variable using a here document and execute it with the -c option .
read -r -d '' my_sqls << EOM
CREATE DATABASE myproject;
CREATE USER myprojectuser WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
EOM
psql -c "$my_sqls" # running all the lines.

pg_dump without setting search_path

When I use pg_dump to export schema from a database, it adds the following line at the beginning:
SELECT pg_catalog.set_config('search_path', '', false);
Is it possible set an option where pg_dump will not add this line? It is causing issues later when I try to execute other SQL commands, without the schema qualifier.
This is the pg_dump command I am using right now:
pg_dump -O -x -h <db-host> -p <db-port> -U <db-user> -d <db-name> --schema public --schema-only > public-schema.sql
No, there is no such option.
I recommend that you restore a dump with psql -f dumpfile rather than using \i to execute it in the current session.

postgres: how to execute script inside a .sql file

In SQLite you can do
sqlite3 i.db < x.sql
where x.sql is a create table statement and i.db is the database
What is the equivalent in PostgreSQL ?
The default command line tool for Postgres is psql it supports command line parameters to specify the database and a script name:
psql -d db_name -f x.sql
For details (e.g. how to specify the database user you want to use for the connection) see the manual: https://www.postgresql.org/docs/current/static/app-psql.html
With a similar approach:
psql -U your_role your_db < x.sql
Within psql:
\i /path/to/x.sql

I want to restore the database with a different schema

I have taken a dump of a database named temp1, by using the follwing command
$ pg_dump -i -h localhost -U postgres -F c -b -v -f pub.backup temp1
Now I want to restore the dump in a different database called "db_temp" , but in that I just want that all the tables should be created in a "temp_schema" ( not the default schema which is in the fms temp1 database ) which is in the "db_temp" database.
Is there any way to do this using pg_restore command?
Any other method also be appreciated!
A quick and dirty way:
1) rename default schema:
alter schema public rename to public_save;
2) create new schema as default schema:
create schema public;
3) restore data
pg_restore -f pub.backup db_temp [and whatever other options]
4) rename schemas according to need:
alter schema public rename to temp_schema;
alter schema public_save rename to public;
There is a simple solution:
Create your backup dump in plain SQL format (format "p" using the parameter --format=p or -F p)
Edit your pub.backup.sql dump with your favorite editor and add the following two lines at the top of your file:
create schema myschema;
SET search_path TO myschema;
Now you can restore your backup dump with the command
psql -f pub.backup.sql
The set search_path to <schema> command will set myschema as the default, so that new tables and other objects are created in this schema, independently of the "default" schema where they lived before.
There's no way in pg_restore itself. What you can do is use pg_restore to generate SQL output, and then send this through for example a sed script to change it. You need to be careful about how you write that sed script though, so it doesn't match and change things inside your data.
Probably the easiest method would be to simply rename the schema after restore, ie with the following SQL:
ALTER SCHEMA my_schema RENAME TO temp_schema
I believe that because you're using the compressed archive format for the output of pg_dump you can't alter it before restoring. The option would be to use the default output and do a search and replace on the schema name, but that would be risky and could perhaps cause data to be corrupted if you were not careful.
If you only have a few tables then you can restore one table at a time, pg_restore accepts -d database when you specify -t tablename. Of course, you'll have to set up the schema before restoring the tables and then sort out the indexes and constraints when you're done restoring the tables.
Alternatively, set up another server on a different port, restore using the new PostgreSQL server, rename the schema, dump it, and restore into your original database. This is a bit of a kludge of course but it will get the job done.
If you're adventurous you might be able to change the database name in the dump file using a hex editor. I think it is only mentioned in one place in the dump and as long as the new and old database names are the same it should work. YMMV, don't do anything like this in a production environment, don't blame me if this blows up and levels your home town, and all the rest of the usual disclaimers.
Rename the schema in a temporary database.
Export the schema:
pg_dump --schema-only --schema=prod > prod.sql
Create a new database. Restore the export:
psql -f prod.sql
ALTER SCHEMA prod RENAME TO somethingelse;
pg_dump --schema-only --schema=somethingelse > somethingelse.sql
(delete the database)
For the data you can just modify the set search_path at the top.
As noted, there's no direct support in pg_dump, psql or pg_restore to change the schema name during a dump/restore process. But it's fairly straightforward to export using "plain" format then modify the .sql file. This Bash script does the basics:
rename_schema () {
# Change search path so by default everything will go into the specified schema
perl -pi -e "s/SET search_path = $2, pg_catalog/SET search_path = $3, pg_catalog, $2;/" "$1"
# Change 'ALTER FUNCTION foo.' to 'ALTER FUNCTION bar.'
perl -pi -e 's/^([A-Z]+ [A-Z]+) '$2'\./$1 '$3'./' "$1"
# Change the final GRANT ALL ON SCHEMA foo TO PUBLIC
perl -pi -e 's/SCHEMA '$2'/SCHEMA '$3'/' "$1"
}
Usage:
pg_dump --format plain --schema=foo --file dump.sql MYDB
rename_schema dump.sql foo bar
psql -d MYDB -c 'CREATE SCHEMA bar;'
psql -d MYDB -f dumpsql
The question is pretty old, but maybe can help some one.
Streaming the output of pg_restore to sed and replace the schema name in order to import the dump to a different schema.
Something like:
pg_restore ${dumpfile} | \
sed -e "s/OWNER TO ${source_owner}/OWNER TO ${target_owner}/" \
-e "s/${source_schema}/${target_schema}/" | \
psql -h ${pgserver} -d ${dbname} -U ${pguser}