No Postgres bytea
, os valores são convertidos automaticamente text
quando inseridos em text
/ varchar
colunas, com base na bytea_output
configuração.
Estou trabalhando com algum código de programa que converte automaticamente certos valores (strings binárias) no programa para um formato bytea. O problema é que os usuários podem acidentalmente tentar inserir esses valores em uma text
coluna. Por padrão, o Postgres permitirá isso, mas nem sempre isso funcionará sem problemas - por exemplo, se houver bytes não ASCII. Acho que os usuários podem não perceber que o estranho comportamento de inserção é devido ao uso de uma string binária no programa de chamada. Portanto, se ocorrer uma conversão bytea
para text
, quero que o Posgres gere uma exceção.
Estou ciente de CREATE CAST
, mas pelo que entendi, esta é uma ação de todo o sistema. Não quero alterar o comportamento do sistema para outras conexões. Eu poderia fazer CREATE CAST
seguido, DROP CAST
mas isso parece sujo para mim, pois ainda não está contido na conexão.
Como faço conversões (implícitas) de bytea
lançar text
uma exceção apenas dentro da conexão atual?
O sql é emitido automaticamente, então eu posso adicionar uma instrução SQL anterior antes de cada instrução, isso não é problema.
Fiquei um pouco surpreso com esse comportamento porque o Postgres geralmente erra no lado da rigidez, o que eu gosto.
Esta pergunta segue a minha pergunta anterior:
Por que você pensaria assim?
bytea
é forçado ahex
(padrão) ouescape
formato quando atribuído a umatext
coluna. Caracteres não ASCII são codificados automaticamente. Deve funcionar "suavemente" em todos os momentos - exceto que você não deseja permitir isso.Verdade, mas está contido na transação se você criar e soltar o cast dentro: Os comandos DDL são totalmente transacionais no Postgres, portanto, apenas sua sessão (dentro dessa transação atual) verá o cast.
Solução com elenco personalizado
Atualmente (todas as versões incluindo Postgres 13) o cast from
bytea
totext
não tem entrada explícita no catálogo do sistemapg_cast
. É fornecido por funções básicas de entrada/saída dos respectivos tipos. Esse comportamento pode ser anulado com uma entrada explícita, criada comCREATE CAST
.Você precisa ser o proprietário dos tipos envolvidos, então isso basicamente significa que você precisa ser o superusuário para instalá-lo.
Crie esta função de conversão uma vez por banco de dados:
Para permitir a criação/descarte do elenco especial para funções sem privilégios, adicione funções de wrapper. Faça isso como superusuário (ou como função de daemon dedicada):
Agora você pode fazer o que pediu:
db<>fiddle aqui -- a segunda metade não é executada devido à falta de privilégios.
Caso de teste estendido
Tabela de teste:
Nenhuma exceção levantada:
Também sem exceção:
Exceção levantada:
Problema do lado do cliente?
Seu comentário parece revelar uma toca de coelho:
A solução não pode funcionar quando você assume incorretamente o tipo de dados
text
no lado do cliente. O cast só é invocado se você entregarbytea
os valores digitados. Ou seja: use uma função ou instrução preparada com tipo de dados explícito ou anexe um cast explícito a literais de string entregues a umINSERT
comando como demonstrado acima:'\000'::bytea
.Depois de passar literais não tipados, o Postgres não tem como saber se realmente deveria ser
bytea
. E como você pode (incorretamente) prepararbytea
strings paratext
entrada e ainda (corretamente?) adicionar um cast explícito abytea
?