PostgreSQL ne prend pas en charge IF NOT EXISTSde CREATE DATABASEdéclaration. Il est pris en charge uniquement dans CREATE SCHEMA. De plus, CREATE DATABASEil ne peut pas être émis en transaction, il ne peut donc pas être en DObloc avec capture d'exception.
Lorsque CREATE SCHEMA IF NOT EXISTSest émis et que le schéma existe déjà, une notification (pas d'erreur) avec des informations d'objet en double est générée.
Pour résoudre ces problèmes, vous devez utiliser l' dblinkextension qui ouvre une nouvelle connexion au serveur de base de données et exécute la requête sans entrer dans la transaction. Vous pouvez réutiliser les paramètres de connexion en fournissant une chaîne vide.
Vous trouverez ci-dessous du PL/pgSQLcode qui simule entièrement CREATE DATABASE IF NOT EXISTSavec le même comportement que dansCREATE SCHEMA IF NOT EXISTS . Il appelle CREATE DATABASEvia dblink, catch duplicate_databaseexception (qui est émis lorsque la base de données existe déjà) et le convertit en avis avec propagation errcode. Le message de chaîne a été ajouté , skippingde la même manière 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
$$;
Cette solution est sans condition de concurrence comme dans d'autres réponses, où la base de données peut être créée par un processus externe (ou une autre instance du même script) entre la vérification de l'existence de la base de données et sa propre création.
De plus, en cas d' CREATE DATABASEéchec avec une autre erreur que la base de données existe déjà, cette erreur est propagée en tant qu'erreur et n'est pas supprimée en silence. Il n'y a qu'un piège pour l' duplicate_databaseerreur. Donc, il se comporte vraiment comme il se IF NOT EXISTSdoit.
Vous pouvez mettre ce code dans sa propre fonction, l'appeler directement ou à partir d'une transaction. La simple restauration (restaurer la base de données supprimée) ne fonctionnerait pas.
Sortie de test (appelée deux fois via DO puis directement):
$ 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.