PostgreSQL does not support IF NOT EXISTS for the CREATE DATABASE statement. Supported only in CREATE SCHEMA . Moreover, CREATE DATABASE cannot be issued in a transaction, so it cannot be in a DO block with catching exceptions.
When CREATE SCHEMA IF NOT EXISTS is issued and the circuit already exists, then a notification (not an error) appears with duplicate information about the object.
To solve these problems, you must use the dblink extension dblink which opens a new connection to the database server and executes the request without entering into a transaction. You can reuse connection parameters by specifying an empty string.
Below is the PL/pgSQL code that fully imitates CREATE DATABASE IF NOT EXISTS with the same behavior as in CREATE SCHEMA IF NOT EXISTS . It calls CREATE DATABASE via dblink , catches the duplicate_database exception (which is thrown when the database already exists) and converts it into a notification with errcode . A string message has been added , skipping same as CREATE SCHEMA IF NOT EXISTS .
CREATE EXTENSION IF NOT EXISTS dblink; DO $$ BEGIN PERFORM dblink_exec('', 'CREATE DATABASE testdb'); EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE; END $$;
This solution is without any race conditions, as in other answers, where the database can be created by an external process (or another instance of the same scenario) between checking if the database exists and its own creation.
Moreover, when CREATE DATABASE fails with an error other than that the database already exists, this error propagates as an error and is not discarded silently. There is only a trap for duplicate_database errors. So it really behaves like IF NOT EXISTS .
You can put this code in your own function, call it directly or from a transaction. Just rolling back (restoring a deleted database) will not work.
Testing the output (called twice through DO, and then directly):
$ sudo -u postgres psql psql (9.6.12) Type "help" for help. postgres=# \set ON_ERROR_STOP on postgres=# \set VERBOSITY verbose postgres=# postgres=# CREATE EXTENSION IF NOT EXISTS dblink; CREATE EXTENSION postgres=# DO $$ postgres$# BEGIN postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb'); postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE; postgres$# END postgres$# $$; DO postgres=# postgres=# CREATE EXTENSION IF NOT EXISTS dblink; NOTICE: 42710: extension "dblink" already exists, skipping LOCATION: CreateExtension, extension.c:1539 CREATE EXTENSION postgres=# DO $$ postgres$# BEGIN postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb'); postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE; postgres$# END postgres$# $$; NOTICE: 42P04: database "testdb" already exists, skipping LOCATION: exec_stmt_raise, pl_exec.c:3165 DO postgres=# postgres=# CREATE DATABASE testdb; ERROR: 42P04: database "testdb" already exists LOCATION: createdb, dbcommands.c:467