Como escrevo um script SQL para criar um ROLE no PostgreSQL 9.1, mas sem gerar um erro se ele já existir?
O script atual simplesmente tem:
CREATE ROLE my_user LOGIN PASSWORD 'my_password';
Isso falhará se o usuário já existir. Eu gostaria de algo como:
IF NOT EXISTS (SELECT * FROM pg_user WHERE username = 'my_user')
BEGIN
CREATE ROLE my_user LOGIN PASSWORD 'my_password';
END;
... mas isso não funciona - IF
não parece ser suportado em SQL simples.
Eu tenho um arquivo em lote que cria um banco de dados PostgreSQL 9.1, função e algumas outras coisas. Ele chama psql.exe, passando o nome de um script SQL a ser executado. Até agora, todos esses scripts são SQL simples e, se possível, gostaria de evitar PL / pgSQL e tal.
$
tiver um significado especial em seu cliente, você precisa escapar dele de acordo com as regras de sintaxe de seu cliente. Tente escapar$
com\$
no shell do Linux. Ou comece uma nova pergunta - comentários não são o lugar. Você sempre pode criar um link para este para contexto.A resposta aceita sofre de uma condição de corrida se dois desses scripts são executados simultaneamente no mesmo cluster Postgres (servidor de banco de dados), como é comum em ambientes de integração contínua .
Geralmente é mais seguro tentar criar a função e lidar com problemas ao criá-la:
fonte
DUPLICATE_OBJECT
é a condição precisa neste caso, se você não quiser capturar quase todas as condições comOTHERS
.Ou se a função não for o proprietário de nenhum objeto db, pode-se usar:
Mas somente se deixar cair este usuário não causará nenhum dano.
fonte
Alternativa Bash (para scripts Bash ):
(não é a resposta para a pergunta! é apenas para aqueles que podem ser úteis)
fonte
FROM pg_roles WHERE rolname
vez deFROM pg_user WHERE usename
Aqui está uma solução genérica usando plpgsql:
Uso:
fonte
Algumas respostas sugeriram usar o padrão: verifique se a função não existe e se não, emita o
CREATE ROLE
comando. Isso tem uma desvantagem: condição de corrida. Se outra pessoa criar uma nova função entre verificar e emitir oCREATE ROLE
comando,CREATE ROLE
obviamente falhará com um erro fatal.Para resolver o problema acima, mais outras respostas já mencionaram o uso de
PL/pgSQL
, emitindoCREATE ROLE
incondicionalmente e, em seguida, pegando exceções dessa chamada. Existe apenas um problema com essas soluções. Eles silenciosamente eliminam quaisquer erros, incluindo aqueles que não são gerados pelo fato de que a função já existe.CREATE ROLE
também pode lançar outros erros e a simulaçãoIF NOT EXISTS
deve silenciar apenas o erro quando a função já existe.CREATE ROLE
lançarduplicate_object
erro quando a função já existe. E o manipulador de exceções deve capturar apenas este erro. Como outras respostas mencionadas, é uma boa ideia converter o erro fatal em aviso simples. OutrosIF NOT EXISTS
comandos PostgreSQL adicionam, skipping
à mensagem, portanto, para consistência, estou adicionando-os aqui também.Aqui está o código SQL completo para simulação
CREATE ROLE IF NOT EXISTS
com exceção correta e propagação sqlstate:Saída de teste (chamado duas vezes via DO e depois diretamente):
fonte
Como você está no 9.x, você pode embrulhar isso em uma instrução DO:
fonte
Minha equipe estava enfrentando uma situação com vários bancos de dados em um servidor, dependendo de qual banco de dados você se conectou, o ROLE em questão não foi retornado por
SELECT * FROM pg_catalog.pg_user
, conforme proposto por @ erwin-brandstetter e @a_horse_with_no_name. O bloco condicional foi executado e atingimosrole "my_user" already exists
.Infelizmente, não temos certeza das condições exatas, mas esta solução contorna o problema:
Provavelmente, poderia ser mais específico para descartar outras exceções.
fonte
Você pode fazer isso em seu arquivo em lote, analisando a saída de:
e, em seguida, executando
psql.exe
novamente se a função não existir.fonte
A mesma solução para Simular CREATE DATABASE IF NOT EXISTS para PostgreSQL? deve funcionar - envie um
CREATE USER …
para\gexec
.Solução alternativa de dentro do psql
Solução alternativa do shell
Veja a resposta aceita para mais detalhes.
fonte