Comment écrire un script SQL pour créer un ROLE dans PostgreSQL 9.1, mais sans générer d'erreur s'il existe déjà?
Le script actuel a simplement:
CREATE ROLE my_user LOGIN PASSWORD 'my_password';
Cela échoue si l'utilisateur existe déjà. J'aimerais quelque chose comme:
IF NOT EXISTS (SELECT * FROM pg_user WHERE username = 'my_user')
BEGIN
CREATE ROLE my_user LOGIN PASSWORD 'my_password';
END;
... mais cela ne fonctionne pas - IF
ne semble pas être pris en charge en SQL brut.
J'ai un fichier batch qui crée une base de données PostgreSQL 9.1, un rôle et quelques autres choses. Il appelle psql.exe, en passant le nom d'un script SQL à exécuter. Jusqu'à présent, tous ces scripts sont du SQL pur et j'aimerais éviter PL / pgSQL et autres, si possible.
$
a une signification particulière dans votre client, vous devez l'échapper selon les règles de syntaxe de votre client. Essayez de vous échapper$
avec\$
dans le shell Linux. Ou commencez une nouvelle question - les commentaires ne sont pas l'endroit. Vous pouvez toujours créer un lien vers celui-ci pour le contexte.La réponse acceptée souffre d'une condition de concurrence si deux de ces scripts sont exécutés simultanément sur le même cluster Postgres (serveur de base de données), comme cela est courant dans les environnements d'intégration continue .
Il est généralement plus sûr d'essayer de créer le rôle et de gérer les problèmes avec élégance lors de sa création:
la source
DUPLICATE_OBJECT
est la condition précise dans ce cas, si vous ne voulez pas capturer à peu près toutes les conditions avecOTHERS
.Ou si le rôle n'est le propriétaire d'aucun objet de base de données, on peut utiliser:
Mais seulement si la suppression de cet utilisateur ne fera aucun mal.
la source
Alternative à Bash (pour les scripts Bash ):
(n'est pas la réponse à la question! c'est seulement pour ceux qui peuvent être utiles)
la source
FROM pg_roles WHERE rolname
place deFROM pg_user WHERE usename
Voici une solution générique utilisant plpgsql:
Usage:
la source
Quelques réponses suggèrent d'utiliser le modèle: vérifiez si le rôle n'existe pas et si ce n'est pas le cas, lancez la
CREATE ROLE
commande. Cela a un inconvénient: la condition de course. Si quelqu'un d'autre crée un nouveau rôle entre la vérification et l'émission de laCREATE ROLE
commande, ilCREATE ROLE
échoue évidemment avec une erreur fatale.Pour résoudre le problème ci-dessus, d'autres réponses ont déjà mentionné l'utilisation de
PL/pgSQL
, l'émissionCREATE ROLE
inconditionnelle, puis la capture des exceptions de cet appel. Il n'y a qu'un seul problème avec ces solutions. Ils abandonnent silencieusement toutes les erreurs, y compris celles qui ne sont pas générées par le fait que ce rôle existe déjà.CREATE ROLE
peut également générer d'autres erreurs et la simulationIF NOT EXISTS
ne devrait faire taire l'erreur que lorsque le rôle existe déjà.CREATE ROLE
lancer uneduplicate_object
erreur lorsque le rôle existe déjà. Et le gestionnaire d'exceptions ne doit intercepter que cette seule erreur. Comme d'autres réponses l'ont mentionné, il est judicieux de convertir l'erreur fatale en simple avis. D'autresIF NOT EXISTS
commandes PostgreSQL s'ajoutent, skipping
à leur message, donc par souci de cohérence, je les ajoute ici aussi.Voici le code SQL complet pour la simulation
CREATE ROLE IF NOT EXISTS
avec l'exception correcte et la propagation sqlstate:Sortie de test (appelée deux fois via DO puis directement):
la source
Comme vous êtes sur 9.x, vous pouvez encapsuler cela dans une instruction DO:
la source
Mon équipe rencontrait une situation avec plusieurs bases de données sur un serveur, selon la base de données à laquelle vous vous êtes connecté, le ROLE en question n'a pas été renvoyé par
SELECT * FROM pg_catalog.pg_user
, comme proposé par @ erwin-brandstetter et @a_horse_with_no_name. Le bloc conditionnel s'est exécuté et nous avons frappérole "my_user" already exists
.Malheureusement, nous ne sommes pas sûrs des conditions exactes, mais cette solution résout le problème:
Il pourrait probablement être rendu plus précis pour exclure d'autres exceptions.
la source
Vous pouvez le faire dans votre fichier de commandes en analysant la sortie de:
puis réexécutez
psql.exe
si le rôle n'existe pas.la source
La même solution que pour Simulate CREATE DATABASE IF NOT EXISTS pour PostgreSQL? devrait fonctionner - envoyez un
CREATE USER …
à\gexec
.Solution de contournement à partir de psql
Solution de contournement depuis le shell
Voir la réponse acceptée ici pour plus de détails.
la source