PostgreSQL ne supporte pas IF NOT EXISTS
para CREATE DATABASE
déclaration. Elle n'est prise en charge que dans CREATE SCHEMA
. De plus, CREATE DATABASE
ne peut pas être émis en transaction, il ne peut donc pas être en DO
avec capture des exceptions.
Cuando CREATE SCHEMA IF NOT EXISTS
est émis et que le schéma existe déjà, un avis (et non une erreur) contenant des informations sur les objets en double est émis.
Pour résoudre ces problèmes, vous devez utiliser dblink
extension 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 PL/pgSQL
qui simule entièrement CREATE DATABASE IF NOT EXISTS
avec le même comportement que dans CREATE SCHEMA IF NOT EXISTS
. Il appelle CREATE DATABASE
via dblink
, attrape duplicate_database
(qui est émise lorsque la base de données existe déjà) et la convertit en avis avec propagation de l'information. errcode
. Le message String a été ajouté , skipping
de la même manière qu'il le fait 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 aucune race condition comme dans les 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, lorsque CREATE DATABASE
échoue avec une autre erreur que celle de la base de données déjà existante, alors cette erreur est propagée comme une erreur et n'est pas ignorée silencieusement. Il n'y a qu'une seule solution pour duplicate_database
erreur. Il se comporte donc réellement comme IF NOT EXISTS
devrait.
Vous pouvez mettre ce code dans votre propre fonction, l'appeler directement ou depuis une transaction. Un simple rollback (restauration d'une base de données abandonnée) ne fonctionnerait pas.
Test de sortie (appelé deux fois via DO et ensuite 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