Exit Codes in psql

In PostgreSQL certain commands are forbidden in transactions or functions, and lack IF NOT EXISTS variants. Examples include CREATE DATABASE and CREATE ROLE. How can one create a database idempotently?

The psql documentation says this about exit codes:

psql returns 0 to the shell if it finished normally, 1 if a fatal error of its own occurs (e.g., out of memory, file not found), 2 if the connection to the server went bad and the session was not interactive, and 3 if an error occurred in a script and the variable ON_ERROR_STOP was set.

Based on that description, I tried this:

$ psql postgresql://postgres@localhost:5432/postgres -c 'CREATE DATABASE fubar;' -v ON_ERROR_STOP=off

But this exits 1 if the database already exists!

After this surprise I tried numerous variations on the theme. These versions use -c command:

$ psql postgresql://postgres@localhost:5432/postgres -c "CREATE DATABASE fubar;" -v ON_ERROR_STOP=off; echo $?
ERROR:  database "fubar" already exists
1
$ psql postgresql://postgres@localhost:5432/postgres -A -t -c "CREATE DATABASE fubar;" -v ON_ERROR_STOP=off; echo $?
ERROR:  database "fubar" already exists
1
$ psql postgresql://postgres@localhost:5432/postgres -A -t -c "CREATE DATABASE fubar; select 'after';" -v ON_ERROR_STOP=off; echo $?
ERROR:  CREATE DATABASE cannot run inside a transaction block
1
$ psql postgresql://postgres@localhost:5432/postgres -A -t -c "CREATE DATABASE fubar;" -c "select 'after';" -v ON_ERROR_STOP=off; echo $?
ERROR:  database "fubar" already exists
after
0

These versions read commands from standard input:

$ echo "CREATE DATABASE fubar;" | psql postgresql://postgres@localhost:5432/postgres -A -t -v ON_ERROR_STOP=off; echo $?
ERROR:  database "fubar" already exists
0
$ echo "CREATE DATABASE fubar; select 'after';" | psql postgresql://postgres@localhost:5432/postgres -A -t -v ON_ERROR_STOP=off; echo $?
ERROR:  database "fubar" already exists
after
0
$ echo "CREATE DATABASE fubar;" | psql postgresql://postgres@localhost:5432/postgres -A -t -v ON_ERROR_STOP=on; echo $?
ERROR:  database "fubar" already exists
3
$ echo "CREATE DATABASE fubar; select 'after';" | psql postgresql://postgres@localhost:5432/postgres -A -t -v ON_ERROR_STOP=on; echo $?
ERROR:  database "fubar" already exists
3

These versions read commands from a file that contains only CREATE DATABASE fubar;:

$ psql postgresql://postgres@localhost:5432/postgres -A -t -f test0.sql -v ON_ERROR_STOP=off; echo $?
psql:test0.sql:1: ERROR:  database "fubar" already exists
0
$ psql postgresql://postgres@localhost:5432/postgres -A -t -f test0.sql -v ON_ERROR_STOP=on; echo $?
psql:test0.sql:1: ERROR:  database "fubar" already exists
3
$ psql postgresql://postgres@localhost:5432/postgres -A -t -f test1.sql -v ON_ERROR_STOP=off; echo $?
psql:test1.sql:1: ERROR:  database "fubar" already exists
after in file
0
$ psql postgresql://postgres@localhost:5432/postgres -A -t -f test1.sql -v ON_ERROR_STOP=on; echo $?
psql:test1.sql:1: ERROR:  database "fubar" already exists
3

The presence of additional commands in the file appears to make no difference.

In case it makes any difference, my database connection runs through a pgbouncer instance. I believe this has no impact on psql exit codes.

There are ways to accomplish the goal. I imagine that the under-the-hood logic is clearer. From the outside, this degree of inconsistency seems impressive.