Jak napisać skrypt SQL w celu utworzenia roli w PostgreSQL 9.1, ale bez zgłaszania błędu, jeśli już istnieje?
Obecny skrypt ma po prostu:
CREATE ROLE my_user LOGIN PASSWORD 'my_password';
Nie powiedzie się, jeśli użytkownik już istnieje. Chciałbym coś takiego:
IF NOT EXISTS (SELECT * FROM pg_user WHERE username = 'my_user')
BEGIN
CREATE ROLE my_user LOGIN PASSWORD 'my_password';
END;
... ale to nie działa - IF
nie wydaje się być obsługiwane w zwykłym języku SQL.
Mam plik wsadowy, który tworzy bazę danych PostgreSQL 9.1, rolę i kilka innych rzeczy. Wywołuje psql.exe, przekazując nazwę skryptu SQL do uruchomienia. Jak dotąd wszystkie te skrypty to zwykły SQL i chciałbym unikać PL / pgSQL i tym podobnych, jeśli to możliwe.
$
ma specjalne znaczenie w twoim kliencie, musisz go uciec zgodnie z regułami składni twojego klienta. Spróbuj uciec$
z\$
w powłoce Linuksa. Lub zacznij nowe pytanie - komentarze nie są miejscem. Zawsze możesz utworzyć link do tego, aby uzyskać kontekst.Zaakceptowana odpowiedź cierpi z powodu sytuacji wyścigu, jeśli dwa takie skrypty są wykonywane jednocześnie w tym samym klastrze Postgres (serwerze DB), co jest powszechne w środowiskach ciągłej integracji .
Generalnie bezpieczniej jest spróbować utworzyć rolę i z wdziękiem rozwiązywać problemy podczas jej tworzenia:
źródło
DUPLICATE_OBJECT
to dokładny warunek w tym przypadku, jeśli nie chcesz złapać prawie wszystkich warunkówOTHERS
.Lub jeśli rola nie jest właścicielem żadnych obiektów bazy danych, których można użyć:
Ale tylko wtedy, gdy upuszczenie tego użytkownika nie spowoduje żadnej szkody.
źródło
Alternatywa Bash (dla skryptów Bash ):
(nie jest odpowiedzią na pytanie! jest tylko dla tych, którzy mogą się przydać)
źródło
FROM pg_roles WHERE rolname
zamiastFROM pg_user WHERE usename
Oto ogólne rozwiązanie wykorzystujące plpgsql:
Stosowanie:
źródło
Niektóre odpowiedzi sugerowały użycie wzorca: sprawdź, czy rola nie istnieje, a jeśli nie, wydaj
CREATE ROLE
polecenie. Ma to jedną wadę: stan wyścigu. Jeśli ktoś inny utworzy nową rolę między sprawdzeniem a wydaniemCREATE ROLE
poleceniaCREATE ROLE
oczywiście nie powiedzie się z błędem krytycznym.Aby rozwiązać powyższy problem, więcej innych odpowiedzi wspominało już o użyciu
PL/pgSQL
, wydawaniuCREATE ROLE
bezwarunkowym, a następnie wyłapywaniu wyjątków od tego połączenia. Z tymi rozwiązaniami jest tylko jeden problem. Po cichu odrzucają wszelkie błędy, w tym te, które nie są generowane przez fakt, że rola już istnieje.CREATE ROLE
może generować również inne błędy, a symulacjaIF NOT EXISTS
powinna wyciszać błędy tylko wtedy, gdy rola już istnieje.CREATE ROLE
zgłosićduplicate_object
błąd, gdy rola już istnieje. Program obsługi wyjątków powinien wychwycić tylko ten jeden błąd. Jak wspomniały inne odpowiedzi, dobrym pomysłem jest przekształcenie błędu krytycznego w proste powiadomienie. InneIF NOT EXISTS
polecenia PostgreSQL są dodawane, skipping
do ich wiadomości, więc dla spójności dodam je tutaj.Oto pełny kod SQL do symulacji
CREATE ROLE IF NOT EXISTS
z poprawnym wyjątkiem i propagacją stanu sql :Wyjście testowe (wywoływane dwukrotnie przez DO, a następnie bezpośrednio):
źródło
Ponieważ korzystasz z 9.x, możesz zawrzeć to w oświadczeniu DO:
źródło
Mój zespół miał problem z wieloma bazami danych na jednym serwerze, w zależności od tego, z którą bazą danych się
SELECT * FROM pg_catalog.pg_user
łączyłeś , dana ROLA nie została zwrócona , zgodnie z propozycjami @ erwin-brandstetter i @a_horse_with_no_name. Blok warunkowy został wykonany i trafiliśmyrole "my_user" already exists
.Niestety nie jesteśmy pewni dokładnych warunków, ale to rozwiązanie pozwala obejść problem:
Prawdopodobnie można by było doprecyzować, aby wykluczyć inne wyjątki.
źródło
Możesz to zrobić w swoim pliku wsadowym, analizując dane wyjściowe:
a następnie uruchamiany
psql.exe
ponownie, jeśli rola nie istnieje.źródło
Takie samo rozwiązanie jak w przypadku Symuluj STWÓRZ BAZY DANYCH, JEŚLI NIE ISTNIEJE dla PostgreSQL? powinno działać - wyślij
CREATE USER …
do\gexec
.Obejście z poziomu psql
Obejście z powłoki
Zobacz zaakceptowaną odpowiedź, aby uzyskać więcej informacji.
źródło