CREATE CAST

CREATE CAST — define uma nova conversão de tipo de dados

Sinopse

CREATE CAST (tipo_de_dados_origem AS tipo_de_dados_destino)
    WITH FUNCTION nome_da_função [ (tipo_de_dados_do_argumento [, ...]) ]
    [ AS ASSIGNMENT | AS IMPLICIT ]

CREATE CAST (tipo_de_dados_origem AS tipo_de_dados_destino)
    WITHOUT FUNCTION
    [ AS ASSIGNMENT | AS IMPLICIT ]

CREATE CAST (tipo_de_dados_origem AS tipo_de_dados_destino)
    WITH INOUT
    [ AS ASSIGNMENT | AS IMPLICIT ]

Descrição

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(x AS nome_do_tipo_de_dados), ou 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.

Nota

À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.)

Parâmetros

tipo_de_dados_origem

O nome do tipo de dados de origem da conversão.

tipo_de_dados_destino

O 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 FUNCTION

Indica 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 INOUT

Indica 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 ASSIGNMENT

Indica que a conversão pode ser chamada implicitamente em contextos de atribuição.

AS IMPLICIT

Indica 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.

Notas

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(n), 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.)

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.

Nota

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.

Nota

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.

Exemplos

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.)

Conformidade

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.

Veja também

CREATE FUNCTION, CREATE TYPE, DROP CAST