PostgreSQL unterstützt nicht IF NOT EXISTS
für CREATE DATABASE
Anweisung. Es wird nur in unterstützt CREATE SCHEMA
. Darüber hinaus CREATE DATABASE
kann es nicht in einer Transaktion ausgegeben werden, daher kann es DO
mit Ausnahme des Fangens nicht blockiert werden.
Wenn CREATE SCHEMA IF NOT EXISTS
ausgegeben wird und das Schema bereits vorhanden ist, wird ein Hinweis (kein Fehler) mit doppelten Objektinformationen ausgelöst.
Um diese Probleme zu lösen, müssen Sie die dblink
Erweiterung verwenden, die eine neue Verbindung zum Datenbankserver herstellt und die Abfrage ausführt, ohne eine Transaktion abzuschließen. Sie können Verbindungsparameter wiederverwenden, indem Sie eine leere Zeichenfolge angeben.
Unten finden Sie PL/pgSQL
Code, der CREATE DATABASE IF NOT EXISTS
mit demselben Verhalten wie in vollständig simuliert CREATE SCHEMA IF NOT EXISTS
. Es ruft CREATE DATABASE
via dblink
, catch- duplicate_database
Ausnahme auf (die ausgegeben wird, wenn die Datenbank bereits vorhanden ist) und konvertiert sie mit Propagierung in Benachrichtigung errcode
. Die String-Nachricht wurde , skipping
auf die gleiche Weise angehängt wie sie 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
$$;
Diese Lösung ist ohne Race-Bedingung wie in anderen Antworten, bei denen die Datenbank durch einen externen Prozess (oder eine andere Instanz desselben Skripts) zwischen der Überprüfung, ob eine Datenbank vorhanden ist, und ihrer eigenen Erstellung erstellt werden kann.
Wenn ein CREATE DATABASE
Fehler mit einem anderen Fehler als der Datenbank bereits vorliegt, wird dieser Fehler als Fehler weitergegeben und nicht stillschweigend verworfen. Es gibt nur duplicate_database
Fehler. Es verhält sich also wirklich so, wie es IF NOT EXISTS
sollte.
Sie können diesen Code in eine eigene Funktion einfügen, direkt oder über eine Transaktion aufrufen. Nur ein Rollback (wiederhergestellte Datenbank wiederherstellen) würde nicht funktionieren.
Testausgabe (zweimal über DO und dann direkt aufgerufen):
$ 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
.