PostgreSQL non supporta IF NOT EXISTSper la CREATE DATABASEdichiarazione. È supportato solo in CREATE SCHEMA. Inoltre CREATE DATABASEnon può essere emesso in transazione quindi non può essere in DOblocco con cattura eccezioni.
quando CREATE SCHEMA IF NOT EXISTS viene emesso e lo schema esiste già, viene generato un avviso (non un errore) con informazioni sull'oggetto duplicato.
Per risolvere questi problemi è necessario utilizzare l' dblinkestensione che apre una nuova connessione al server di database ed esegue la query senza entrare in transazione. È possibile riutilizzare i parametri di connessione fornendo una stringa vuota.
Di seguito è riportato il PL/pgSQLcodice che simula completamente CREATE DATABASE IF NOT EXISTScon lo stesso comportamento come in CREATE SCHEMA IF NOT EXISTS. Chiama CREATE DATABASEtramite dblink, catch duplicate_databaseexception (che viene emesso quando il database esiste già) e lo converte in avviso con la propagazione errcode. Il messaggio stringa è stato aggiunto , skippingnello stesso modo in cui lo fa 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
$$;
Questa soluzione è priva di condizioni di competizione come in altre risposte, dove il database può essere creato da un processo esterno (o altra istanza dello stesso script) tra il controllo dell'esistenza del database e la sua creazione.
Inoltre, quando CREATE DATABASEfallisce con un errore diverso da quello del database già esistente, questo errore viene propagato come errore e non viene eliminato silenziosamente. C'è solo un duplicate_databaseerrore. Quindi si comporta davvero come IF NOT EXISTSdovrebbe.
Puoi inserire questo codice nella propria funzione, chiamarlo direttamente o dalla transazione. Il solo rollback (ripristino del database eliminato) non funzionerebbe.
Test dell'output (chiamato due volte tramite DO e poi direttamente):
$ 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
dblink_connect.