パターンの使用を提案するいくつかの回答:ロールが存在しないかどうかを確認し、存在しない場合はCREATE ROLE
コマンドを発行します。これには1つの欠点があります。競合状態です。他の誰かがチェックとCREATE ROLE
コマンドの発行の間に新しい役割を作成した場合CREATE ROLE
明らかに致命的なエラーで失敗します。
上記の問題を解決するために、他の回答ではすでにの使用について言及しておりPL/pgSQL
、CREATE ROLE
無条件に発行してから、その呼び出しからの例外をキャッチしています。これらのソリューションには問題が1つだけあります。それらは、ロールがすでに存在するという事実によって生成されないエラーを含め、すべてのエラーを静かにドロップします。CREATE ROLE
他のエラーもスローする可能性がありIF NOT EXISTS
、ロールがすでに存在する場合、シミュレーションはエラーのみを無音にします
CREATE ROLE
duplicate_object
ロールがすでに存在する場合はエラーをスローします。そして、例外ハンドラはこの1つのエラーのみをキャッチする必要があります。他の回答が述べたように、致命的なエラーを単純な通知に変換することは良い考えです。その他のPostgreSQL IF NOT EXISTS
コマンドが追加されます, skipping
メッセージにされるため、一貫性を保つためにここにも追加します。
以下はCREATE ROLE IF NOT EXISTS
、正しい例外とsqlstateの伝播を伴うシミュレーション用の完全なSQLコードです。
DO $$
BEGIN
CREATE ROLE test;
EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;
テスト出力(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=# DO $$
postgres$# BEGIN
postgres$# CREATE ROLE test;
postgres$# EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
DO
postgres=#
postgres=# DO $$
postgres$# BEGIN
postgres$# CREATE ROLE test;
postgres$# EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
NOTICE: 42710: role "test" already exists, skipping
LOCATION: exec_stmt_raise, pl_exec.c:3165
DO
postgres=#
postgres=# CREATE ROLE test;
ERROR: 42710: role "test" already exists
LOCATION: CreateRole, user.c:337