Wie schreibe ich ein SQL-Skript, um eine ROLLE in PostgreSQL 9.1 zu erstellen, ohne jedoch einen Fehler auszulösen, wenn dieser bereits vorhanden ist?
Das aktuelle Skript hat einfach:
CREATE ROLE my_user LOGIN PASSWORD 'my_password';
Dies schlägt fehl, wenn der Benutzer bereits vorhanden ist. Ich hätte gerne etwas wie:
IF NOT EXISTS (SELECT * FROM pg_user WHERE username = 'my_user')
BEGIN
CREATE ROLE my_user LOGIN PASSWORD 'my_password';
END;
... aber das funktioniert nicht - IF
scheint in einfachem SQL nicht unterstützt zu werden.
Ich habe eine Batch-Datei, die eine PostgreSQL 9.1-Datenbank, eine Rolle und einige andere Dinge erstellt. Es ruft psql.exe auf und übergibt den Namen eines auszuführenden SQL-Skripts. Bisher sind alle diese Skripte einfaches SQL und ich möchte PL / pgSQL und dergleichen nach Möglichkeit vermeiden.
$
Ihr Client eine besondere Bedeutung hat, müssen Sie diese gemäß den Syntaxregeln Ihres Clients maskieren . Versuchen Sie,$
mit\$
in der Linux-Shell zu entkommen . Oder starten Sie eine neue Frage - Kommentare sind nicht der richtige Ort. Sie können jederzeit einen Link zu diesem für den Kontext erstellen.Die akzeptierte Antwort leidet unter einer Race-Bedingung, wenn zwei solcher Skripte gleichzeitig auf demselben Postgres-Cluster (DB-Server) ausgeführt werden, wie dies in Umgebungen mit kontinuierlicher Integration üblich ist .
Im Allgemeinen ist es sicherer, zu versuchen, die Rolle zu erstellen und Probleme beim Erstellen ordnungsgemäß zu lösen:
quelle
DUPLICATE_OBJECT
ist die genaue Bedingung in diesem Fall, wenn Sie nicht so gut wie alle Bedingungen mit fangen wollenOTHERS
.Oder wenn die Rolle nicht der Eigentümer von Datenbankobjekten ist, kann man Folgendes verwenden:
Aber nur wenn das Fallenlassen dieses Benutzers keinen Schaden anrichtet.
quelle
Bash- Alternative (für Bash-Scripting ):
(ist nicht die Antwort auf die Frage! es ist nur für diejenigen, die nützlich sein können)
quelle
FROM pg_roles WHERE rolname
stattFROM pg_user WHERE usename
Hier ist eine generische Lösung mit plpgsql:
Verwendung:
quelle
Einige Antworten schlagen vor, Muster zu verwenden: Überprüfen Sie, ob keine Rolle vorhanden ist, und geben Sie dann einen
CREATE ROLE
Befehl aus. Dies hat einen Nachteil: Rennbedingung. Wenn jemand anderes eine neue Rolle zwischen Prüfung und Ausgabe desCREATE ROLE
Befehls 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 ROLE
bedingungslose 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 ROLE
kann auch andere Fehler auslösen und die SimulationIF NOT EXISTS
sollte nur Fehler zum Schweigen bringen, wenn die Rolle bereits vorhanden ist.CREATE ROLE
duplicate_object
Fehler 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 EXISTS
Befehle fügen, skipping
ihrer 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 EXISTS
mit korrekter Ausnahme und SQLstate-Weitergabe:Testausgabe (zweimal über DO und dann direkt aufgerufen):
quelle
Wenn Sie sich in 9.x befinden, können Sie dies in eine DO-Anweisung einschließen:
quelle
Mein Team hatte eine Situation mit mehreren Datenbanken auf einem Server. Je nachdem, mit welcher Datenbank Sie verbunden waren, wurde die betreffende ROLLE nicht zurückgegeben
SELECT * FROM pg_catalog.pg_user
, wie von @ erwin-brandstetter und @a_horse_with_no_name vorgeschlagen. Der bedingte Block wurde ausgeführt und wir haben getroffenrole "my_user" already exists
.Leider sind wir uns der genauen Bedingungen nicht sicher, aber diese Lösung umgeht das Problem:
Es könnte wahrscheinlich spezifischer gemacht werden, andere Ausnahmen auszuschließen.
quelle
Sie können dies in Ihrer Batch-Datei tun, indem Sie die Ausgabe von:
und dann
psql.exe
erneut ausgeführt, wenn die Rolle nicht vorhanden ist.quelle
Die gleiche Lösung wie für Simulate CREATE DATABASE, WENN NICHT FÜR PostgreSQL EXISTIERT? sollte funktionieren - senden Sie eine
CREATE USER …
an\gexec
.Problemumgehung innerhalb von psql
Problemumgehung aus der Shell
Weitere Informationen finden Sie in der dort akzeptierten Antwort .
quelle