PostgreSQLはステートメントをサポートIF NOT EXISTS
していませんCREATE DATABASE
。でのみサポートされていCREATE SCHEMA
ます。さらにCREATE DATABASE
、トランザクション内で発行することはできないため、DO
例外をキャッチしてブロックにすることはできません。
いつ CREATE SCHEMA IF NOT EXISTS
発行され、スキーマがすでに重複するオブジェクト情報と、その後の通知(ないエラー)が存在する場合に発生します。
これらの問題を解決するにはdblink
、データベースサーバーへの新しい接続を開き、トランザクションを開始せずにクエリを実行する拡張機能を使用する必要があります。空の文字列を指定すると、接続パラメーターを再利用できます。
以下は、のような同じ動作PL/pgSQL
で完全にシミュレーションCREATE DATABASE IF NOT EXISTS
するコードですCREATE SCHEMA IF NOT EXISTS
です。CREATE DATABASE
viaを呼び出してdblink
、duplicate_database
例外をキャッチし(データベースが既に存在する場合に発行されます)、それを伝達して通知に変換しerrcode
ます。文字列メッセージは, skipping
、同じように追加されます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
$$;
このソリューションには、他の回答のように競合状態がありません。データベースが存在するかどうかの確認と独自の作成の間に外部プロセス(または同じスクリプトの他のインスタンス)によってデータベースを作成できます。
さらに、CREATE DATABASE
データベースがすでに存在する以外のエラーで失敗した場合、このエラーはエラーとして伝播され、警告なく破棄されません。duplicate_database
エラーのキャッチのみがあります。したがって、実際には正常に動作しIF NOT EXISTS
ます。
このコードを独自の関数に入れ、直接またはトランザクションから呼び出すことができます。ロールバック(ドロップされたデータベースの復元)だけでは機能しません。
テスト出力(DOを介して2回呼び出され、次に直接呼び出されます):
$ 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
。