36.2. O sistema de tipos de dados do PostgreSQL #

36.2.1. Tipos de dados base
36.2.2. Tipos de dados contenedores
36.2.3. Domínios
36.2.4. Pseudo tipos de dados
36.2.5. Tipos de dados polimórficos

Os tipos de dados do PostgreSQL podem ser divididos em tipos de dados base, e tipos de dados contenedores [113], domínios e pseudo-tipos.

36.2.1. Tipos de dados base #

Os tipos de dados base são aqueles, como integer, implementados abaixo do nível da linguagem SQL (normalmente em uma linguagem de baixo nível, como C). Correspondem geralmente ao que se chama de tipos de dados abstratos. O PostgreSQL só pode operar nesses tipos de dados por meio de funções fornecidas pelo usuário, e só entende o comportamento desses tipos de dados à medida que os usuários os descrevem. Os tipos de dados base nativos estão descritos em Tipos de dados.

Os tipos de dados enumerados (enum) podem ser considerados uma subcategoria dos tipos de dados base. A principal diferença é poderem ser criados usando apenas comandos SQL, sem nenhuma programação de baixo nível. Veja Tipos de dados de enumeração para obter mais informações.

36.2.2. Tipos de dados contenedores #

O PostgreSQL possui três tipos de dados contenedores, que são tipos de dados que contêm vários valores de outros tipos de dados: são os tipos de dados matriz, composto e intervalo.

As matrizes podem conter vários valores que são todos do mesmo tipo de dados. Um tipo de dados matriz é criado automaticamente para cada tipo de dados base, tipo de dados composto, tipo de dados intervalo e tipo de dados de domínio. Mas não há matrizes de matrizes. No que diz respeito ao sistema de tipos de dados, as matrizes multidimensionais são iguais às matrizes unidimensionais. Veja Tipos de dados matriz para obter mais informações.

Os tipos de dados compostos, ou tipos de dados linha, são criados sempre que o usuário cria uma tabela. Também é possível usar CREATE TYPE para definir um tipo de dados composto autônomo (stand-alone) sem tabela associada. Um tipo de dados composto é apenas uma lista de tipos de dados com nomes de campos associados. Um valor do tipo de dados composto é uma linha ou registro de valores de campo. Veja Tipos de dados compostos para obter mais informações.

O tipo de dados intervalo pode conter dois valores do mesmo tipo de dados, que são os limites inferior e superior do intervalo. Os tipos de dados intervalo são criados pelo usuário, embora existam alguns nativos. Veja Tipos de dados de intervalo para obter mais informações.

36.2.3. Domínios #

Um domínio é baseado em um tipo de dados subjacente específico e, para muitos propósitos, é intercambiável com seu tipo de dados subjacente. Entretanto, um domínio pode ter restrições que limitam seus valores válidos a um subconjunto do que o tipo de dados subjacente permite. Os domínios são criados usando o comando SQL CREATE DOMAIN. Veja Tipos de dados de domínio para obter mais informações.

36.2.4. Pseudo tipos de dados #

Existem alguns pseudo-tipos para propósitos especiais. Pseudotipos não podem aparecer como colunas de tabelas, ou componentes de tipos de dados contenedores, mas podem ser usados para declarar tipos de dados de argumento e resultado de funções. Isso fornece um mecanismo dentro do sistema de tipos de dados para identificar classes especiais de funções. A Tabela 8.27 lista os pseudo-tipos existentes.

36.2.5. Tipos de dados polimórficos #

Alguns pseudo-tipos de dados de interesse especial são os tipos de dados polimórficos [114], usados para declarar funções polimórficas. Esse poderoso recurso permite que uma única definição de função opere em muitos tipos de dados diferentes, com os tipos de dados específicos sendo determinado pelos tipos de dados realmente passados para a função em uma determinada chamada. Os tipos de dados polimórficos são mostrados na Tabela 36.1. Alguns exemplos de uso são mostrados em Funções SQL polimórficas.

Tabela 36.1. Tipos de dados polimórficos

NomeFamíliaDescrição
anyelementSimplesIndica que a função aceita qualquer tipo de dados
anyarraySimplesIndica que a função aceita qualquer tipo de dados matriz
anynonarraySimplesIndica que a função aceita qualquer tipo de dados não matriz
anyenumSimplesIndica que a função aceita qualquer tipo de dados enum (veja Tipos de dados de enumeração)
anyrangeSimplesIndica que a função aceita qualquer tipo de dados intervalo (veja Tipos de dados de intervalo)
anymultirangeSimplesIndica que a função aceita qualquer tipo de dados multi-intervalo (veja Tipos de dados de intervalo)
anycompatibleComumIndica que a função aceita qualquer tipo de dados, com promoção automática dos vários argumentos para um tipo de dados comum
anycompatiblearrayComumIndica que a função aceita qualquer tipo de dados matriz, com promoção automática dos vários argumentos para um tipo de dados comum
anycompatiblenonarrayComumIndica que a função aceita qualquer tipo de dados não matriz, com promoção automática dos vários argumentos para um tipo de dados comum
anycompatiblerangeComumIndica que a função aceita qualquer tipo de dados intervalo, com promoção automática dos vários argumentos para um tipo de dados comum
anycompatiblemultirangeComumIndica que a função aceita qualquer tipo de dados multi-intervalo, com promoção automática dos vários argumentos para um tipo de dados comum

Os argumentos e resultados polimórficos são vinculados entre si, sendo resolvidos para os tipos de dados específicos quando a consulta que chama a função polimórfica é analisada. Quando há mais de um argumento polimórfico, os tipos de dados reais dos valores de entrada devem corresponder conforme descrito abaixo. Se o tipo de dados do resultado da função for polimórfico, ou tiver parâmetros de saída de tipos de dados polimórficos, os tipos de dados desses resultados serão deduzidos dos tipos de dados reais das entradas polimórficas, conforme descrito abaixo.

Para os tipos de dados polimórficos da família simples, as regras de correspondência e dedução funcionam assim:

Cada posição (argumento ou valor retornado) declarada como anyelement pode receber qualquer tipo de dados real, mas em uma determinada chamada da função, todos devem ser do mesmo tipo de dados real. Cada posição declarada como anyarray pode receber qualquer tipo de dados matriz, mas, da mesma forma, todos devem ser do mesmo tipo de dados. Da mesma forma, as posições declaradas como anyrange devem ser todas do mesmo tipo de dados intervalo. Da mesma forma para anymultirange.

Além disso, havendo posições declaradas como anyarray, e outras declaradas como anyelement, o tipo de dados real matriz nas posições anyarray deve ser uma matriz cujos elementos são do mesmo tipo de dados aparecendo nas posições de anyelement. O tipo de dados anynonarray é tratado exatamente da mesma forma que anyelement, mas adiciona a restrição extra de que o tipo de dados real não deve ser um tipo de dados matriz. O tipo de dados anyenum é tratado exatamente da mesma forma que anyelement, mas adiciona a restrição extra de que o tipo de dados real deve ser um tipo de dados enum.

Da mesma forma, havendo posições declaradas como anyrange, e outras declaradas como anyelement ou anyarray, o tipo de dados real intervalo nas posições anyrange devem ser um intervalo cujo subtipo de dados é do mesmo tipo de dados aparecendo nas posições anyelement, e idêntico ao tipo de dados de elemento das posições anyarray. Havendo posições declaradas como anymultirange, seu tipo de dados real multi-intervalo deve conter intervalos correspondentes aos parâmetros declarados como anyrange, e elementos base correspondentes aos parâmetros declarados como anyelement e anyarray.

Assim, quando mais de uma posição de argumento é declarada com um tipo de dados polimórfico, o efeito líquido é que apenas certas combinações de tipos de dados reais de argumentos são permitidas. Por exemplo, uma função declarada como equal(anyelement, anyelement) recebe quaisquer dois valores de entrada, desde que sejam do mesmo tipo de dados.

Quando o valor retornado por uma função é declarado como de tipo de dados polimórfico, deve haver pelo menos uma posição de argumento que também seja polimórfica, e os tipos de dados reais fornecidos para os argumentos polimórficos determinam o tipo de dados real de resultado para essa chamada. Por exemplo, se ainda não existisse um mecanismo de índice de matriz, seria possível definir uma função que implementasse o índice como indice(anyarray, integer) returns anyelement. Essa declaração restringe o primeiro argumento real a ser do tipo de dados matriz, permitindo que o analisador infira o tipo de dados do resultado correto a partir do tipo de dados do primeiro argumento real. Outro exemplo é que uma função declarada como f(anyarray) returns anyenum aceita apenas matrizes de tipos de dados enum.

Geralmente, o analisador pode inferir o tipo de dados real para um tipo de resultado polimórfico a partir de argumentos que são de um tipo de dados polimórfico diferente da mesma família; por exemplo, anyarray pode ser deduzido de anyelement, ou vice-versa. Uma exceção é que um resultado polimórfico do tipo de dados anyrange requer um argumento do tipo de dados anyrange; não pode ser deduzido de argumentos anyarray ou anyelement. Isso acontece, porque pode haver vários tipos de dados intervalo com o mesmo subtipo de dados.

Note que anynonarray e anyenum não representam tipos de dados separados de variáveis; são do mesmo tipo de dados que anyelement, apenas com uma restrição adicional. Por exemplo, declarar uma função como f(anyelement, anyenum) equivale a declará-la como f(anyenum, anyenum): os dois argumentos reais devem ser do mesmo tipo de dados enum.

Para a família de tipos de dados polimórficos comum, as regras de correspondência e dedução funcionam aproximadamente da mesma forma que para a família simples, com uma grande diferença: os tipos de dados reais dos argumentos não precisam ser idênticos, desde que possam ser convertidos implicitamente em um único tipo de dados comum. O tipo de dados comum é selecionado seguindo as mesmas regras de UNION e construções relacionadas (veja UNION, CASE e construções relacionadas). A seleção do tipo de dados comum considera os tipos de dados reais de entrada anycompatible e anycompatiblenonarray, os tipos de dados de elemento matriz de entradas anycompatiblearray, os subtipos de dados intervalo de entradas anycompatiblerange, e os subtipos de dados multi-intervalo de entradas anycompatiblemultirange. Se anycompatiblenonarray estiver presente, o tipo de dados comum deverá ser um tipo de dados não-matriz. Depois que o tipo de dados comum é identificado, os argumentos nas posições anycompatible e anycompatiblenonarray são convertidos automaticamente para esse tipo de dados, e os argumentos nas posições anycompatiblearray são convertidos automaticamente para o tipo de dados matriz para esse tipo de dados.

Como não há como selecionar o tipo de dados intervalo sabendo apenas seu subtipo de dados, o uso de anycompatiblerange e/ou anycompatiblemultirange requer que todos os argumentos declarados com esse tipo de dados tenham o mesmo intervalo real e/ou tipo de dados multi-intervalo, e que o subtipo de dados desse tipo de dados concorde com o tipo de dados comum selecionado, de modo que nenhuma conversão dos valores de intervalo seja necessária. Assim como em anyrange e anymultirange, o uso de anycompatiblerange e anymultirange como tipo de dados de resultado da função requer que exista um argumento anycompatiblerange ou anycompatiblemultirange.

Note não haver nenhum tipo de dados anycompatibleenum. Esse tipo de dados não seria muito útil, porque normalmente não há conversões implícitas para tipos de dados enum, significando que não haveria como resolver um tipo de dados comum para entradas enum diferentes.

As famílias polimórficas simples e comum representam dois conjuntos independentes de tipos de dados de variáveis. Considere por exemplo

CREATE FUNCTION myfunc(a anyelement, b anyelement,
                       c anycompatible, d anycompatible)
RETURNS anycompatible AS ...

Em uma chamada real dessa função, as duas primeiras entradas devem ter o mesmo tipo de dados. As duas últimas entradas devem ser promovidas para um tipo de dados comum, mas esse tipo de dados não precisa ter nada a ver com o tipo de dados das duas primeiras entradas. O resultado terá o tipo de dados comum das duas últimas entradas.

Uma função variádica (aquela que recebe um número variável de argumentos, como em Funções SQL com número variável de argumentos), pode ser polimórfica: isso é feito declarando seu último parâmetro como VARIADIC anyarray ou VARIADIC anycompatiblearray. Para fins de correspondência de argumentos e determinação do tipo de dados de resultado real, essa função se comporta da mesma forma como se tivesse sido escrito o número apropriado de parâmetros anynonarray ou anycompatiblenonarray.



[113] Neologismos usados: contenedor (espanhol), variádica (do inglês variadic) (N. T.)

[114] Polimórfico: relativo à polimorfia, qualidade ou condição do que está sujeito à mudar de forma ou do que se apresenta sob diversas formas: desenho polimórfico, plástico polimórfico. Dicio, Dicionário Online de Português (N. T.)