PostgreSQL non supporta IF NOT EXISTS
per la CREATE DATABASE
dichiarazione. È supportato solo in CREATE SCHEMA
. Inoltre CREATE DATABASE
non può essere emesso in transazione quindi non può essere in DO
blocco 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' dblink
estensione 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/pgSQL
codice che simula completamente CREATE DATABASE IF NOT EXISTS
con lo stesso comportamento come in CREATE SCHEMA IF NOT EXISTS
. Chiama CREATE DATABASE
tramite dblink
, catch duplicate_database
exception (che viene emesso quando il database esiste già) e lo converte in avviso con la propagazione errcode
. Il messaggio stringa è stato aggiunto , skipping
nello 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 DATABASE
fallisce 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_database
errore. Quindi si comporta davvero come IF NOT EXISTS
dovrebbe.
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
.