Einige Antworten schlagen vor, Muster zu verwenden: Überprüfen Sie, ob keine Rolle vorhanden ist, und geben Sie dann einen CREATE ROLEBefehl aus. Dies hat einen Nachteil: Rennbedingung. Wenn jemand anderes eine neue Rolle zwischen Prüfung und Ausgabe des CREATE ROLEBefehls erstellt, dannCREATE ROLE schlägt dies offensichtlich mit einem schwerwiegenden Fehler fehl.
Um das obige Problem zu lösen, erwähnten weitere Antworten bereits die Verwendung von PL/pgSQL, CREATE ROLEbedingungslose Ausgabe und dann das Abfangen von Ausnahmen von diesem Aufruf. Bei diesen Lösungen gibt es nur ein Problem. Sie löschen stillschweigend alle Fehler, einschließlich solcher, die nicht durch die Tatsache generiert werden, dass die Rolle bereits vorhanden ist. CREATE ROLEkann auch andere Fehler auslösen und die Simulation IF NOT EXISTSsollte nur Fehler zum Schweigen bringen, wenn die Rolle bereits vorhanden ist.
CREATE ROLEduplicate_objectFehler auslösen , wenn die Rolle bereits vorhanden ist. Und der Ausnahmebehandler sollte nur diesen einen Fehler abfangen. Wie in anderen Antworten erwähnt, ist es eine gute Idee, schwerwiegende Fehler in einfache Hinweise umzuwandeln. Andere PostgreSQL- IF NOT EXISTSBefehle fügen , skippingihrer Nachricht hinzu. Aus Gründen der Konsistenz füge ich sie auch hier hinzu.
Hier ist der vollständige SQL-Code für die Simulation CREATE ROLE IF NOT EXISTSmit korrekter Ausnahme und SQLstate-Weitergabe:
DO $$
BEGIN
CREATE ROLE test;
EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;
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=# 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