PostgreSQL ne prend pas en charge IF NOT EXISTS
de CREATE DATABASE
déclaration. Il est pris en charge uniquement dans CREATE SCHEMA
. De plus, CREATE DATABASE
il ne peut pas être émis en transaction, il ne peut donc pas être en DO
bloc avec capture d'exception.
Lorsque CREATE SCHEMA IF NOT EXISTS
est é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' 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 du PL/pgSQL
code qui simule entièrement CREATE DATABASE IF NOT EXISTS
avec le même comportement que dansCREATE SCHEMA IF NOT EXISTS
. Il appelle CREATE DATABASE
via dblink
, catch duplicate_database
exception (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é , skipping
de 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_database
erreur. Donc, il se comporte vraiment comme il se IF NOT EXISTS
doit.
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
.