CREATE CAST — define uma nova conversão de tipo de dados
CREATE CAST (tipo_de_dados_origemAStipo_de_dados_destino) WITH FUNCTIONnome_da_função[ (tipo_de_dados_do_argumento[, ...]) ] [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (tipo_de_dados_origemAStipo_de_dados_destino) WITHOUT FUNCTION [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (tipo_de_dados_origemAStipo_de_dados_destino) WITH INOUT [ AS ASSIGNMENT | AS IMPLICIT ]
O comando CREATE CAST define uma nova
conversão de tipo de dados, especificando como realizar esta
conversão entre os dois tipos de dados. Por exemplo,
SELECT CAST(42 AS float8);
converte a constante inteira 42 para o tipo float8,
chamando uma função previamente especificada, neste caso
float8(int4).
(Se nenhuma conversão adequada estiver definida, a conversão falha.)
Dois tipos de dados podem ser
coercíveis binariamente, significando que a
conversão pode ser realizada “gratuitamente”, sem chamar
nenhuma função.
Isto requer que os valores correspondentes usem a mesma representação
interna.
Por exemplo, os tipos text e varchar
são coercíveis binariamente nos dois sentidos.
A coercibilidade binária não é necessariamente uma relação simétrica.
Por exemplo, a conversão de xml para text
pode ser realizada gratuitamente na presente implementação,
mas a direção inversa requer uma função que execute pelo menos
uma verificação de sintaxe.
(Dois tipos que são coercíveis binariamente nos dois sentidos também
são referidos como binariamente compatíveis.)
Uma conversão pode ser definida como
conversão de E/S usando a sintaxe
WITH INOUT.
Uma conversão de E/S é realizada chamando a função de saída do
tipo de dados de origem, e passando a cadeia de caracteres
resultante para a função de entrada do tipo de dados de destino.
Em muitos casos comuns, este recurso evita a necessidade de escrever
uma função de conversão separada para conversão.
Uma conversão de E/S age da mesma forma que uma conversão regular
baseada em função; apenas a implementação é diferente.
Por padrão, uma conversão pode ser chamada apenas por uma solicitação
de conversão explícita, ou seja, uma construção
CAST(, ou
x AS
nome_do_tipo_de_dados)x::nome_do_tipo_de_dados.
Se a conversão estiver marcada como AS ASSIGNMENT,
ela poderá ser chamada implicitamente ao atribuir um valor a uma
coluna do tipo de dados de destino.
Por exemplo, supondo que foo.f1 seja uma coluna
do tipo de dados text, então
INSERT INTO foo (f1) VALUES (42);
será permitido se a conversão do tipo integer para o tipo
text estiver marcada como AS ASSIGNMENT,
caso contrário, não.
(É geralmente usado o termo
conversão de atribuição
para descrever este tipo de conversão.)
Se a conversão estiver marcada como AS IMPLICIT,
ela poderá ser chamada implicitamente em qualquer contexto, seja de
atribuição, ou internamente em uma expressão.
(É geralmente usado o termo conversão implícita
para descrever este tipo de conversão.)
Por exemplo, considere a seguinte consulta:
SELECT 2 + 4.0;
O analisador inicialmente marca as constantes como sendo do tipo
integer e numeric, respectivamente.
Não existe o operador integer +
numeric nos catálogos do sistema, mas existe o operador
numeric + numeric.
A consulta, portanto, será bem-sucedida se estiver disponível uma
conversão de integer para numeric,
e estiver marcada como AS IMPLICIT —
como de fato está.
Então, o analisador aplicará a conversão implícita e resolverá
a consulta como se tivesse sido escrito:
SELECT CAST ( 2 AS numeric ) + 4.0;
Agora, os catálogos também fornecem uma conversão de
numeric para integer.
Se esta conversão estivesse marcada como AS IMPLICIT
— que não é o caso — então o analisador enfrentaria
a escolha entre a interpretação acima, e a alternativa de converter
a constante numeric para integer
e aplicar o operador
integer + integer.
Sem saber qual escolha preferir, o analisador desistiria e declararia
a consulta ambígua.
O fato de apenas uma das duas conversões ser implícita, é a maneira
pela qual foi instruído ao analisador preferir a resolução de uma
expressão mista numeric-e-integer como
numeric; não há conhecimento nativo sobre isto.
É bom ser conservador ao marcar as conversões como implícitas.
Uma superabundância de opções de conversão implícitas pode fazer com
que o PostgreSQL faça escolhas
surpreendentes de comandos, ou seja, incapaz de resolver os comandos,
porque existem várias opções possíveis.
Uma boa regra é tornar uma conversão passível de ser chamada
implicitamente apenas para transformações que preservam as
informações entre tipos na mesma categoria de tipo geral.
Por exemplo, é razoável a conversão de int2 para
int4 ser implícita, mas a conversão de
float8 para int4 provavelmente deve ser
apenas de atribuição.
Conversões de tipo cruzado, como text para
int4, é melhor serem apenas explícitas.
Às vezes, é necessário, por razões de usabilidade ou conformidade com padrões, fornecer várias conversões implícitas entre um conjunto de tipos de dados, resultando em ambiguidades que não podem ser evitadas como referido acima. O analisador tem uma heurística de recurso, baseada em categorias de tipo e tipos preferidos, que pode ajudar a fornecer o comportamento desejado nesses casos. Veja CREATE TYPE para obter mais informações.
Para poder criar uma conversão, deve-se ser o dono do tipo de dados
de origem ou de destino, e ter o privilégio USAGE
no outro tipo.
Para criar uma conversão coercível binariamente, é necessário ser
um superusuário.
(Esta restrição é feita, porque uma conversão coercível binariamente
errada pode, facilmente, travar o servidor.)
tipo_de_dados_origemO nome do tipo de dados de origem da conversão.
tipo_de_dados_destinoO nome do tipo de dados de destino da conversão.
nome_da_função[(tipo_de_dados_do_argumento [, ...])]A função usada para realizar a conversão. O nome da função pode ser qualificado pelo esquema. Se não for, a função será procurada no caminho de procura de esquema. O tipo de dados do resultado da função deve corresponder ao tipo de dados de destino da conversão. Seus argumentos são discutidos abaixo. Se não for especificada nenhuma lista de argumentos, o nome da função deverá ser único em seu esquema.
WITHOUT FUNCTIONIndica que o tipo de dados da origem é coercível binariamente para o tipo de dados de destino, portanto, não é necessária nenhuma função para executar a conversão.
WITH INOUTIndica que a conversão é uma conversão de E/S, realizada chamando a função de saída do tipo de dados de origem, e passando a cadeia de caracteres resultante para a função de entrada do tipo de dados de destino.
AS ASSIGNMENTIndica que a conversão pode ser chamada implicitamente em contextos de atribuição.
AS IMPLICITIndica que a conversão pode ser chamada implicitamente em qualquer contexto.
As funções de implementação de conversão podem ter de um a três
argumentos.
O tipo de dados do primeiro argumento deve ser idêntico, ou
coercível binariamente, ao tipo de dados de origem da conversão.
O segundo argumento, se estiver presente, deve ser do tipo de dados
integer; ele recebe o modificador de tipo de dados
associado ao tipo de dados de destino, ou -1
se não houver nenhum.
O terceiro argumento, se estiver presente, deve ser do tipo de dados
boolean; ele recebe true, se a
conversão for explícita, ou false caso contrário.
(Estranhamente, o padrão SQL exige comportamentos
diferentes para conversões explícitas e implícitas em alguns casos.
Este argumento é fornecido para funções que devem implementar estas
conversões. Não é recomendado que se crie tipos de dados onde isto
seja importante.)
O tipo de dados de retorno de uma função de conversão deve ser idêntico, ou coercível binariamente, ao tipo de dados de destino da conversão.
Normalmente, uma conversão deve ter tipos de dados de origem e destino diferentes. Entretanto, é permitido declarar uma conversão com tipos de dados de origem e destino idênticos, se ela tiver uma função de implementação de conversão com mais de um argumento. Isto é usado para representar funções de coerção de comprimento do tipo de dados específicas, nos catálogos do sistema. A função indicada é usada para forçar um valor do tipo de dados para o valor do modificador de tipo de dados fornecido por seu segundo argumento.
Quando uma conversão tem tipos de dados de origem e destino diferentes, e uma função contendo mais de um argumento, ela oferece suporte à conversão de um tipo de dados para outro e à aplicação de uma coerção de comprimento em uma única etapa. Quando esta entrada não está disponível, a coerção para um tipo de dados que usa um modificador de tipo de dados envolve duas etapas de conversão, uma para converter entre os tipos de dados, e uma segunda para aplicar o modificador.
Atualmente, uma conversão de ou para um tipo de domínio não tem efeito. A conversão de ou para um domínio usa as conversões associadas ao seu tipo subjacente.
Para remover conversões definidas pelo usuário deve ser usado o comando DROP CAST.
Lembre-se que, se for desejado converter tipos de dados das duas maneiras, é necessário declarar as conversões das duas maneiras explicitamente.
Normalmente não é necessário criar conversões entre os tipos de dados
definidos pelo usuário e os tipos cadeia de caracteres padrão
(text, varchar, e
char(,
bem como os tipos definidos pelo usuário, que estão definidos para
estar na categoria cadeia de caracteres).
O PostgreSQL fornece conversão automática
de E/S para esta situação.
As conversões automáticas para os tipos
cadeias de caracteres são tratadas como conversões de atribuição,
enquanto as conversões automáticas de tipos
cadeias de caracteres são apenas explícitas.
É possível mudar este comportamento declarando sua própria conversão
para substituir a conversão automática, mas geralmente o único
motivo para fazer isto é se for desejado que a conversão possa ser
chamada com mais facilidade do que a configuração padrão de somente
atribuição ou somente explícita.
Outra razão possível é se for desejado que a conversão se comporte
de maneira diferente da função de E/S do tipo de dados;
mas isto é suficientemente surpreendente para que se pense duas vezes
se é uma boa ideia.
(Um pequeno número de tipos nativos realmente tem comportamentos
diferentes para conversões, principalmente devido aos requisitos
do padrão SQL.)
n)
Embora não seja exigido, é recomendável que se continue seguindo a
antiga convenção de dar nomes às funções de implementação de conversão
segundo o tipo de dados de destino.
Muitos usuários estão acostumados a poder escrever tipos de dados
usando uma notação de estilo de função, ou seja,
nome_do_tipo_de_dados(x).
Esta notação é, de fato, nada mais nada menos que uma chamada da
função de implementação da conversão;
não é tratada especialmente como uma conversão.
Se suas funções de conversão não receberem nomes seguindo esta
convenção, os usuários vão ficar surpresos.
Como o PostgreSQL permite a sobrecarga do
mesmo nome de função com diferentes tipos de dados de argumento,
não há dificuldade em ter várias funções de conversão de diferentes
tipos de dados que usam o nome do tipo de dados de destino.
Na verdade, o parágrafo anterior é uma simplificação excessiva:
há dois casos onde uma construção de chamada de função será tratada
como uma solicitação de conversão sem corresponder a uma função real.
Se uma chamada de função
nome(x)
não corresponder exatamente a nenhuma função existente, mas
nome é o nome de um tipo de dados, e
pg_cast fornece uma coerção binária para
este tipo de dados a partir do tipo de x,
então a chamada será interpretada como uma coerção binária.
Esta exceção é feita para que as conversões coercíveis binariamente
possam ser chamadas usando a sintaxe de função, mesmo que não tenham
nenhuma função.
Da mesma forma, se não houver entrada em pg_cast,
mas a conversão for de ou para um tipo cadeia de caracteres,
a chamada será interpretada como uma conversão de E/S.
Esta exceção permite que conversões de E/S sejam chamadas usando a
sintaxe de função.
Há também uma exceção a exceção:
as conversões de E/S de tipos de dados compostos para tipos de dados
cadeia de caracteres não podem ser chamadas usando a sintaxe de função,
devendo ser escritas na sintaxe de conversão explícita
(seja CAST ou ::).
Esta exceção foi incluída porque, após a introdução de conversão de
E/S fornecidas automaticamente, ficou muito fácil chamar acidentalmente
esta conversão quando o que se pretendia era uma função ou referência
de coluna.
Para criar uma conversão de atribuição do tipo de dados
bigint para o tipo de dados int4
usando a função int4(bigint):
CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;
(Esta conversão já está predefinida no sistema.)
O comando CREATE CAST está em conformidade com
o padrão SQL, exceto que o padrão
SQL não faz provisões para tipos coercíveis
binariamente, ou argumentos extras para as funções de implementação.
A cláusula AS IMPLICIT também é uma extensão do
PostgreSQL.