CREATE TYPE — define um novo tipo de dados
CREATE TYPEnomeAS ( [nome_do_atributotipo_de_dados[ COLLATEordenação] [, ... ] ] ) CREATE TYPEnomeAS ENUM ( [ 'rótulo' [, ... ] ] ) CREATE TYPEnomeAS RANGE ( SUBTYPE =subtipo[ , SUBTYPE_OPCLASS =classe_de_operador_do_subtipo] [ , COLLATION =ordenação] [ , CANONICAL =função_de_canonização] [ , SUBTYPE_DIFF =função_de_diferença_de_subtipo] [ , MULTIRANGE_TYPE_NAME =nome_do_tipo_multi_intervalo] ) CREATE TYPEnome( INPUT =função_de_entrada, OUTPUT =função_de_saída[ , RECEIVE =função_de_recepção] [ , SEND =função_de_envio] [ , TYPMOD_IN =função_de_entrada_do_modif_de_tipo] [ , TYPMOD_OUT =função_de_saída_do_modif_de_tipo] [ , ANALYZE =função_de_análise_estatística] [ , SUBSCRIPT =função_de_índice] [ , INTERNALLENGTH = {comprimento_interno| VARIABLE } ] [ , PASSEDBYVALUE ] [ , ALIGNMENT =alinhamento] [ , STORAGE =armazenamento] [ , LIKE =como_o_tipo] [ , CATEGORY =categoria] [ , PREFERRED =preferido] [ , DEFAULT =padrão] [ , ELEMENT =elemento] [ , DELIMITER =delimitador] [ , COLLATABLE =ordenável] ) CREATE TYPEnome
O comando CREATE TYPE registra um novo tipo de
dados para uso no banco de dados corrente
[145].
O usuário que define o tipo de dados torna-se seu dono.
Se for fornecido um nome de esquema, o tipo de dados será criado no esquema especificado. Caso contrário, será criado no esquema corrente. O nome do tipo de dados deve ser diferente do nome de qualquer tipo de dados ou domínio existente no mesmo esquema. (Como as tabelas têm tipos de dados associados, o nome do tipo de dados também deve ser diferente do nome de qualquer tabela existente no mesmo esquema.)
Existem cinco formas do comando CREATE TYPE,
conforme mostrado na sinopse de sintaxe acima.
Estas formas criam, respectivamente, um
tipo de dados composto, um
tipo de dados enum, um
tipo de dados intervalo, um
tipo de dados base (escalar), e um
tipo de dados shell (esqueleto).
Os primeiros quatro são discutidos sucessivamente a seguir.
O tipo shell é simplesmente um
espaço reservado para um tipo de dados a ser definido posteriormente;
é criado executando CREATE TYPE sem parâmetros,
exceto o nome do tipo de dados.
Os tipos de shell são necessários
como referências diretas ao criar tipos intervalo e tipos base,
conforme discutido nas respectivas seções.
A primeira forma do comando CREATE TYPE cria um
tipo de dados composto.
O tipo de dados composto é especificado por uma lista de nomes
de atributos e tipos de dados.
A ordenação do atributo também pode ser especificada, se o
tipo de dados for ordenável.
Um tipo de dados composto é essencialmente o mesmo que o tipo de
dados da linha de uma tabela, mas usar CREATE TYPE
evita a necessidade de criar uma tabela real quando tudo o que se
deseja é definir um tipo de dados.
O tipo de dados composto autônomo é útil, por exemplo, como argumento,
ou como o tipo de dados retornado por uma função.
Para poder criar um tipo de dados composto, deve-se ter o privilégio
USAGE em todos os tipos de dados dos atributos.
A segunda forma do comando CREATE TYPE cria um
tipo de dados enumerado (enum), conforme descrito em
Tipos de dados de enumeração.
Os tipos de enumeração recebem uma lista de rótulos entre apóstrofos,
cada um dos quais deve ter menos de NAMEDATALEN
bytes (64 bytes em uma compilação padrão do
PostgreSQL).
(É possível criar um tipo de dados enumerado com zero rótulos,
mas este tipo de dados não poderá ser usado para conter valores
antes que pelo menos um rótulo seja adicionado usando o comando
ALTER TYPE.)
A terceira forma do comando CREATE TYPE cria um
tipo de dados intervalo, conforme descrito em
Tipos de dados de intervalo.
O subtipo do
tipo de dados intervalo pode ser qualquer tipo de dados com uma
classe de operador árvore-B associada (para determinar a ordem dos
valores para o tipo de dados intervalo).
Normalmente, a classe de operador de árvore-B padrão do subtipo
é usada para determinar a ordenação; para usar uma classe de operador
não padrão, deve ser especificado seu nome em
classe_de_operador_do_subtipo.
Se o subtipo for ordenável, e se desejar usar uma ordenação não-padrão
para ordenação do intervalo, deve ser especificada a ordenação desejada
na opção ordenação.
A função opcional
função_de_canonização
deve receber um argumento do tipo de dados intervalo que está sendo
definido, e retornar um valor do mesmo tipo de dados.
Esta função é usada para converter valores de intervalo na forma
canônica, quando aplicável.
Veja Definição de novos tipos de dados de intervalo para obter mais informações.
Criar uma
função_de_canonização
é um pouco complicado, porque deve ser definida antes que o
tipo de dados intervalo possa ser declarado.
Para fazer isto, deve-se primeiro criar um tipo de dados
shell, que é um tipo de dados de
reserva de espaço, que não possui propriedades, exceto o nome e o
dono.
Isto é feito executando o comando
CREATE TYPE ,
sem parâmetros adicionais.
Em seguida, a função poderá ser declarada usando o tipo de dados
shell como argumento e resultado e,
finalmente, o tipo de dados intervalo poderá ser declarado usando
o mesmo nome.
Isto substitui automaticamente a entrada do tipo de dados
shell por um tipo de dados intervalo
válido.
nome
A função opcional
função_de_diferença_de_subtipo
deve receber dois valores do tipo de dados do
subtipo como argumento,
e retornar um valor do tipo de dados double precision
representando a diferença entre os dois valores fornecidos.
Embora esta função seja opcional, fornecê-la permite uma eficiência
muito maior dos índices GiST em colunas do tipo de dados intervalo.
Veja Definição de novos tipos de dados de intervalo para obter mais informações.
O parâmetro opcional
nome_do_tipo_multi_intervalo
especifica o nome do tipo de dados multi-intervalo correspondente.
Se não for especificado, este nome será escolhido automaticamente
da seguinte maneira.
Se o nome do tipo de dados intervalo contiver a sub-cadeia de
caracteres range, então o nome do tipo de dados
multi-intervalo será formado pela substituição da sub-cadeia de
caracteres range por
multirange no nome do tipo de dados intervalo.
Caso contrário, o nome do tipo de dados multi-intervalo será formado
anexando um sufixo _multirange ao nome do
tipo de dados intervalo.
A quarta forma do comando CREATE TYPE cria um
tipo de dados base (tipo de dados escalar).
Para criar um tipo de dados base, é necessário ser um superusuário.
(Esta restrição ocorre porque uma definição de tipo de dados
errônea pode confundir, ou até mesmo travar, o servidor.)
Os parâmetros podem aparecer em qualquer ordem, e não apenas na
ordem mostrada acima, e a maioria é opcional.
Devem ser registradas duas ou mais funções (usando o comando
CREATE FUNCTION) antes de definir o tipo de dados.
As funções de suporte
função_de_entrada e
função_de_saída
são requeridas, enquanto as funções
função_de_recepção,
função_de_envio,
função_de_entrada_do_modif_de_tipo,
função_de_saída_do_modif_de_tipo,
função_de_análise_estatística, e
função_de_índice
são opcionais.
Geralmente estas funções devem ser codificadas em C,
ou outra linguagem de baixo nível.
A função_de_entrada
converte a representação textual externa do tipo de dados para a
representação interna utilizada pelos operadores e funções definidas
para o tipo de dados.
A função_de_saída
realiza a transformação inversa.
A função de entrada pode ser declarada como recebendo um argumento
do tipo de dados cstring, ou como recebendo três
argumentos dos tipos de dados cstring, oid,
e integer.
O primeiro argumento é o texto de entrada como uma cadeia de caracteres
C, o segundo argumento é o próprio OID do tipo
de dados (exceto para tipos de dados matriz, que em vez disso recebem
o OID do tipo de dados de seus elementos), e o terceiro é o
typmod da coluna de destino, se conhecido
(será passado -1, se não for conhecido).
A função de entrada deve retornar um valor do próprio tipo de dados.
Normalmente, a função de entrada deve ser declarada como estrita
(STRICT); se não for, será chamada com o primeiro
parâmetro NULL ao ler um valor de entrada
NULL.
A função ainda deve retornar NULL neste caso,
a menos que relate um erro.
(Este caso destina-se principalmente a oferecer suporte a funções
de entrada de domínio, que podem precisar rejeitar entradas
NULL.)
A função de saída deve ser declarada como recebendo um argumento
do novo tipo de dados.
A função de saída deve retornar o tipo de dados cstring.
As funções de saída não são chamadas para valores NULL.
A função_de_recepção
opcional converte a representação binária externa do tipo de dados
para a representação interna.
Se esta função não for fornecida, o tipo de dados não poderá
participar de entrada binária.
A representação binária deve ser escolhida de forma a custar pouco para
converter para a forma interna, enquanto seja razoavelmente portátil.
(Por exemplo, os tipos de dados inteiros padrão usam a ordem de byte
da rede como representação binária externa, enquanto a representação
interna está na ordem de byte nativa da máquina.)
A função de recepção deve executar a verificação adequada para
garantir que o valor seja válido.
A função de recepção pode ser declarada como aceitando um argumento
do tipo de dados internal, ou como recebendo três
argumentos dos tipos de dados internal, oid,
e integer.
O primeiro argumento é um ponteiro para um
buffer do tipo de dados
StringInfo (veja Tipos de dados definidos pelo usuário),
contendo a cadeia de bytes recebida;
os argumentos opcionais são os mesmos da função de entrada de texto.
A função de recepção deve retornar um valor do próprio tipo de dados.
Normalmente, uma função de recepção deve ser declarada como estrita
(STRICT); se não for, será chamada com o primeiro
parâmetro NULL ao ler um valor de entrada
NULL.
A função ainda deverá retornar NULL neste caso,
a menos que relate um erro.
(Este caso destina-se principalmente a oferecer suporte a funções
de recepção de domínio, que podem precisar rejeitar entradas
NULL.)
Da mesma forma, a
função_de_envio opcional
converte da representação interna para a representação binária externa.
Se esta função não for fornecida, o tipo de dados não poderá
participar da saída binária.
A função de envio deve ser declarada como recebendo um argumento
do novo tipo de dados.
A função de envio deve retornar o tipo de dados bytea.
As funções de envio não são chamadas para valores NULL.
Neste ponto, deve-se estar se perguntando como as funções de entrada
e saída podem ser declaradas para ter resultados ou argumentos do novo
tipo de dados, quando elas precisam ser criadas antes que o novo
tipo de dados possa ser criado.
A resposta é que o tipo de dados deve ser primeiro definido como um
tipo de dados shell (esqueleto), que é um
tipo de dados de espaço reservado que não possui propriedades,
exceto o nome e o dono.
Isto é feito executando o comando
CREATE TYPE ,
sem parâmetros adicionais.
Então as funções C de E/S podem ser definidas
referenciando o tipo de dados shell.
Por fim, o comando nomeCREATE TYPE com uma definição
completa irá substituir a entrada do tipo de dados
shell por uma definição de
tipo de dados completa e válida, após a qual o novo tipo de dados
poderá ser usado normalmente.
As funções opcionais
função_de_entrada_do_modif_de_tipo e
função_de_saída_do_modif_de_tipo
são necessárias se o tipo de dados oferecer suporte a modificadores,
ou seja, restrições opcionais anexadas a uma declaração de tipo de dados,
como char(5) ou numeric(30,2).
O PostgreSQL permite que tipos de dados
definidos pelo usuário usem uma, ou mais, constantes ou identificadores
simples como modificadores.
Entretanto, estas informações devem poder ser comprimidas em um único
valor inteiro não negativo para armazenamento nos catálogos do sistema.
À função_de_entrada_do_modif_de_tipo
é passado o(s) modificador(es) declarado(s) na forma de uma matriz
cstring.
Esta função deverá verificar a validade dos valores (relatando
um erro se estiverem errados) e, se estiverem corretos, retornar um
único valor integer não negativo que será armazenado
como a coluna “typmod”.
Os modificadores de tipo de dados serão rejeitados se o tipo de dados
não tiver uma
função_de_entrada_do_modif_de_tipo.
A função_de_saída_do_modif_de_tipo
converte o valor “typmod” inteiro interno de volta para
a forma correta para mostrar ao usuário.
A função deverá retornar um valor cstring, que é a
cadeia de caracteres exata a ser anexada ao nome do tipo de dados;
por exemplo, a função numeric pode retornar
(30,2).
É permitido omitir a
função_de_saída_do_modif_de_tipo,
caso em que o formato de exibição padrão é apenas o valor inteiro de
“typmod” armazenado, entre parênteses.
A função_de_análise_estatística
opcional executa coleta de estatísticas específicas do tipo de dados
para colunas do tipo de dados.
Por padrão, o comando ANALYZE tentará reunir
estatísticas usando os operadores “igual a” e
“menor que” do tipo de dados, se houver uma classe de
operador árvore-B padrão para o tipo de dados.
Para tipos de dados não escalares, este comportamento provavelmente
não é adequado, portanto, pode ser substituído especificando uma
função de análise personalizada.
A função de análise deve ser declarada recebendo um único argumento
do tipo de dados internal, e retornar um resultado do
tipo de dados boolean.
A API detalhada para funções de análise está documentada no arquivo
src/include/commands/vacuum.h (arquivo de
cabeçalho para o vacuum cleaner e
analisador de estatísticas do postgres).
A função_de_índice
opcional permite que o tipo de dados seja indexado em comandos
SQL.
Especificar esta função não faz com que o tipo de dados seja
considerado um tipo de dados matriz “verdadeiro”;
por exemplo, não será um candidato para o tipo de dados de resultado
das construções ARRAY[].
Mas se indexar um valor do tipo de dados for uma notação natural para
extrair dados dele, então poderá ser escrita uma
função_de_índice
para definir o que isto significa.
A função de índice deve ser declarada recebendo um único argumento
do tipo de dados internal, e retornando um resultado
do tipo de dados internal, que é um ponteiro para uma
estrutura de métodos (funções) que implementam a indexação.
A API detalhada para funções de índice está documentada no arquivo
src/include/nodes/subscripting.h
(API para indexação de tipo de dados genérico).
Também pode ser útil ler a implementação de matriz no arquivo
src/backend/utils/adt/arraysubs.c
(funções de suporte a indexação para matrizes), ou o código mais
simples no arquivo contrib/hstore/hstore_subs.c
(funções de suporte a indexação para hstore).
Informações adicionais são encontradas em
Tipos matriz abaixo.
Embora os detalhes da representação interna do novo tipo de dados
sejam conhecidos apenas pelas funções de E/S, e outras funções
criadas para trabalhar com o tipo de dados, há várias propriedades
da representação interna que devem ser declaradas para o
PostgreSQL.
A mais importante delas é o
comprimento_interno.
Os tipos de dados base podem ter comprimento fixo, caso em que o
comprimento_interno
é um número inteiro positivo, ou ter comprimento variável, indicado
definindo o
comprimento_interno
como VARIABLE.
(Internamente, isto é representado definindo typlen
como -1.)
A representação interna de todos os tipos de dados de comprimento
variável deve começar com um inteiro de 4 bytes fornecendo
o comprimento total desse valor do tipo de dados.
(Note que o campo de comprimento é geralmente codificado conforme
descrito em TOAST; não é aconselhável
acessá-lo diretamente.)
O sinalizador opcional PASSEDBYVALUE indica que
os valores desse tipo de dados são passados por valor, em vez de
por referência.
Os tipos de dados passados por valor devem ter comprimento fixo,
e sua representação interna não pode ser maior que o tamanho do
tipo de dados Datum
(4 bytes em algumas máquinas, 8 bytes em outras).
O parâmetro alinhamento
especifica o alinhamento de armazenamento necessário para o tipo de
dados.
Os valores permitidos equivalem ao alinhamento em limites de 1, 2, 4
ou 8 bytes.
Note que os tipos de dados de comprimento variável devem ter um
alinhamento de pelo menos 4, porque necessariamente contêm um
int4 como seu primeiro componente.
O parâmetro armazenamento
permite a seleção de estratégias de armazenamento para tipos de dados
de tamanho variável.
(Somente é permitido plain para tipos de dados
de comprimento fixo.)
plain especifica que os dados desse tipo de dados
serão sempre armazenados em-linha e não comprimidos.
extended especifica que o sistema primeiro tentará
comprimir um valor de dados longo, e moverá o valor para fora da
linha da tabela principal se ainda assim for muito longo.
external permite que o valor seja movido para fora
da tabela principal, mas o sistema não tentará comprimi-lo.
main permite compressão, mas desencoraja mover
o valor para fora da tabela principal.
(Os itens de dados com esta estratégia de armazenamento ainda poderão
ser movidos para fora da tabela principal se não houver outra maneira
de ajustar a linha, mas serão preferencialmente mantidos na tabela
principal, ao contrário dos itens extended e
external.)
Todos os valores de
armazenamento diferentes
de plain, implicam que as funções do
tipo de dados podem lidar com valores que foram colocados em
TOAST, conforme descrito em
TOAST e Considerações sobre o TOAST.
O outro valor específico fornecido determina a estratégia de
armazenamento padrão em TOAST para as colunas
de um tipo de dados que pode ser armazenado externamente; os usuários
podem escolher outras estratégias para colunas individuais usando
o comando ALTER TABLE SET STORAGE.
O parâmetro como_o_tipo
fornece um método alternativo para especificar as propriedades
básicas de representação de um tipo de dados:
copiá-los de algum tipo de dados existente.
Os valores de
comprimento_interno,
passado_por_valor,
alinhamento, e
armazenamento,
são copiados do tipo de dados indicado.
(É possível, embora geralmente não desejado, substituir alguns desses
valores especificando-os junto com a cláusula LIKE.)
Especificar a representação desta forma é especialmente útil quando
a implementação de baixo nível do novo tipo de dados
“se apoia” (piggybacks)
em um tipo de dados existente de alguma forma.
Os parâmetros categoria
e preferido podem ser
usados para ajudar a controlar qual conversão implícita será aplicada
em situações ambíguas.
Cada tipo de dados pertence a uma categoria identificada por um único
caractere ASCII, e cada tipo de dados é
“preferido” ou não dentro de sua categoria.
O analisador irá preferir converter para tipos de dados preferidos
(mas apenas de outros tipos de dados dentro da mesma categoria)
quando esta regra servir para resolver funções ou operadores
sobrecarregados.
Para obter mais detalhes, veja Conversão de tipo de dados.
Para tipos de dados que não têm conversões implícitas de ou para
quaisquer outros tipos de dados, é suficiente deixar estas
configurações com seus padrões.
Entretanto, para um grupo de tipos de dados relacionados que possuem
conversões implícitas, geralmente é útil marcá-los todos como
pertencentes a uma categoria, e selecionar um ou dois dos tipos de
dados “mais gerais” como preferidos na categoria.
O parâmetro categoria
é especialmente útil ao adicionar um tipo de dados definido pelo
usuário a uma categoria interna existente, como os tipos de dados
numéricos ou de cadeia de caracteres.
Entretanto, também é possível criar novas categorias de tipo de dados
totalmente definidas pelo usuário.
Deve-se selecionar qualquer caractere ASCII
diferente de uma letra maiúscula para representar esta categoria.
Pode ser especificado um valor padrão, no caso do usuário desejar
que as colunas do tipo de dados sejam padronizadas para algo
diferente do valor nulo.
O padrão é especificado com a palavra-chave DEFAULT.
(Este valor padrão pode ser mudado por uma cláusula
DEFAULT explícita anexada a uma coluna específica.)
Para indicar que o tipo de dados é um tipo de dados matriz de
comprimento fixo, deve ser especificado o tipo de dados dos elementos
da matriz usando a palavra-chave ELEMENT.
Por exemplo, para definir uma matriz de inteiros de 4 bytes
(int4), deve ser especificado
ELEMENT = int4.
Para obter mais detalhes, veja Tipos matriz
abaixo.
Para indicar o delimitador a ser usado entre os valores na
representação externa de matrizes desse tipo de dados, pode-se
definir o delimitador
como um caractere específico.
O delimitador padrão é a vírgula (,).
Note que o delimitador está associado ao tipo de dados do elemento
da matriz, e não ao próprio tipo de dados matriz.
Se o parâmetro booleano opcional
ordenável for verdade,
as definições de coluna e expressões do tipo de dados podem carregar
informações de ordenação através do uso da cláusula
COLLATE.
Cabe às implementações das funções que operam no tipo de dados
realmente fazer uso das informações de ordenação; isto não acontece
automaticamente apenas marcando o tipo de dados como ordenável.
Sempre que é criado um tipo de dados definido pelo usuário, o
PostgreSQL cria automaticamente um
tipo de dados matriz associado, cujo nome consiste no nome do
tipo de dados do elemento, prefixado com um sublinhado, e truncado,
se necessário, para mantê-lo com menos de
NAMEDATALEN bytes de comprimento.
(Se o nome assim gerado colidir com outro nome de tipo de dados
existente, o processo será repetido até que seja encontrado
um nome não conflitante.)
Este tipo de dados matriz criado implicitamente tem comprimento
variável, e usa as funções internas de entrada e saída
array_in e array_out.
Além disso, este tipo de dados é o que o sistema usa para construções
como ARRAY[] sobre o tipo de dados definido pelo
usuário.
O tipo de dados matriz rastreia quaisquer alterações no dono ou
esquema de seu tipo de dados do elemento, sendo descartado se o
tipo de dados do elemento o for.
Pode-se perguntar por que existe uma opção ELEMENT,
se o sistema cria o tipo de dados matriz correto automaticamente.
O principal caso onde é útil usar ELEMENT é
quando se está criando um tipo de dados de comprimento fixo que é
internamente uma matriz de várias coisas idênticas, e se deseja
permitir que estas coisas sejam acessadas diretamente por indexação,
além de quaisquer operações que se planeje fornecer para o
tipo de dados como um todo.
Por exemplo, o tipo de dados point é representado como
apenas dois números de ponto flutuante, que podem ser acessados
usando point[0] e point[1].
Veja que este recurso funciona apenas para tipos de dados de
comprimento fixo, cuja forma interna é exatamente uma sequência
de campos de comprimento fixo idênticos.
Por razões históricas (ou seja, está claramente errado, mas é muito
tarde para mudar), a indexação de tipos de dados matriz de
comprimento fixo começa por zero, em vez de um, como em matrizes
de comprimento variável.
Especificar a opção SUBSCRIPT permite que o tipo
de dados seja indexado, mesmo que o sistema não o considere como
um tipo de dados matriz.
O comportamento recém-descrito para matrizes de comprimento fixo
é realmente implementado pela função
raw_array_subscript_handler do tratador de
SUBSCRIPT, que é usada automaticamente se for
especificado ELEMENT para um tipo de dados de
comprimento fixo sem também escrever SUBSCRIPT.
Ao especificar uma função personalizada SUBSCRIPT,
não é necessário especificar ELEMENT, a menos que
a função do tratador de SUBSCRIPT precise consultar
typelem para descobrir o que retornar.
Esteja ciente de que especificar ELEMENT faz com
que o sistema assuma que o novo tipo de dados contém, ou é de
alguma forma fisicamente dependente, do tipo de dados do elemento;
assim, por exemplo, alterar as propriedades do tipo de dados do
elemento não será permitido se houver colunas dependentes do
tipo de dados.
nomeO nome (opcionalmente qualificado pelo esquema) do tipo de dados a ser criado.
nome_do_atributoO nome do atributo (coluna) para o tipo de dados composto.
tipo_de_dadosO nome do tipo de dados existente a se tornar uma coluna do tipo de dados composto.
ordenaçãoO nome da ordenação existente a ser associada a uma coluna do tipo de dados composto, ou ao tipo de dados intervalo.
rótuloUm literal de cadeia de caracteres representando o rótulo textual associado a um valor do tipo de dados de enumeração.
subtipoO nome do tipo de dados do elemento do qual o tipo de dados intervalo representará os intervalos.
classe_de_operador_do_subtipoO nome da classe de operador árvore-B para o subtipo.
função_de_canonizaçãoO nome da função de canonização para o tipo de dados intervalo.
função_de_diferença_de_subtipoO nome da função de diferença para o subtipo.
nome_do_tipo_multi_intervaloO nome do tipo de dados multi-intervalo correspondente.
função_de_entradaO nome da função que converte dados da forma textual externa do tipo de dados em sua forma interna.
função_de_saídaO nome da função que converte dados da forma interna do tipo de dados em sua forma textual externa.
função_de_recepçãoO nome da função que converte dados do formato binário externo do tipo de dados em seu formato interno.
função_de_envioO nome da função que converte dados da forma interna do tipo de dados em sua forma binária externa.
função_de_entrada_do_modif_de_tipoO nome da função que converte uma matriz de modificadores para o tipo de dados em forma interna.
função_de_saída_do_modif_de_tipoO nome da função que converte a forma interna do(s) modificador(es) do tipo de dados em forma textual externa.
função_de_análise_estatísticaO nome da função que executa análise estatística para o tipo de dados.
função_de_índiceO nome da função que define o que indexar um valor do tipo de dados faz.
comprimento_internoUma constante numérica que especifica o comprimento em bytes da representação interna do novo tipo de dados. A suposição padrão é que é de comprimento variável.
alinhamento
O requisito de alinhamento de armazenamento do tipo de dados.
Se especificado, deverá ser char,
int2, int4, ou
double; o padrão é int4.
armazenamento
A estratégia de armazenamento para o tipo de dados.
Se especificado, deverá ser plain,
external, extended, ou
main; o padrão é plain.
como_o_tipo
O nome do tipo de dados existente que o novo tipo de dados terá
a mesma representação.
Os valores de
comprimento_interno,
passado_por_valor,
alinhamento, e
armazenamento
são copiados desse tipo de dados, a menos que sejam substituídos
por especificação explícita em outro lugar no comando
CREATE TYPE.
categoria
O código de categoria (um único caractere ASCII)
para este tipo de dados.
O valor padrão é 'U' para
“tipo de dados definido pelo usuário”.
Outros códigos de categoria padrão podem ser encontrados em
Tabela 52.65.
Também podem ser escolhidos outros caracteres ASCII
para criar categorias personalizadas.
preferidoVerdade se este tipo de dados for um tipo preferencial dentro de sua categoria de tipo de dados, caso contrário, falso. O padrão é falso. Deve-se tomar muito cuidado ao criar um novo tipo de dados preferencial dentro de uma categoria de tipo de dados existente, porque isto pode causar mudanças surpreendentes no comportamento.
padrãoO valor padrão para o tipo de dados. Se for omitido, o padrão é nulo.
elementoO tipo de dados que está sendo criado é uma matriz; especifica o tipo de dados dos elementos da matriz.
delimitadorO caractere delimitador a ser usado entre valores em matrizes feitas desse tipo de dados.
ordenávelVerdade se as operações desse tipo de dados puderem usar informações de ordenação. O padrão é falso.
Como não há restrições ao uso do tipo de dados após este ser criado, criar um tipo de dados base ou tipo de dados intervalo equivale a conceder permissão de execução pública nas funções mencionadas na definição do tipo de dados. Isto geralmente não é um problema para os tipos de funções que são úteis em uma definição de tipo de dados. Mas pode-se querer pensar duas vezes antes de projetar um tipo de dados de forma que exija informações “secretas” a serem usadas ao convertê-lo de ou para a forma externa.
Antes do PostgreSQL versão 8.3, o nome
do tipo de dados matriz gerado era sempre exatamente o nome do
tipo de dados do elemento com um caractere de sublinhado
(_) anexado.
(Os nomes dos tipos de dados eram, portanto, restritos em comprimento
a um caractere a menos do que os outros nomes.)
Embora este ainda seja geralmente o caso, o nome do tipo de dados
matriz pode variar em caso de nomes de comprimento máximo,
ou colisões com nomes de tipo de dados do usuário que começam com
sublinhado.
Escrever código que depende dessa convenção está, portanto, em
obsolescência.
Em vez disso, deve-se usar
pg_type.typarray
para localizar o tipo de dados matriz associado a um determinado
tipo de dados.
Pode ser aconselhável evitar o uso de nomes de tipo de dados e tabela começando com sublinhado. Embora o servidor altere os nomes dos tipos de dados matriz gerados para evitar colisões com nomes fornecidos pelo usuário, ainda há o risco de confusão, principalmente com software cliente antigo que pode presumir que os nomes de tipo de dados iniciados com sublinhados sempre representam matrizes.
Antes do PostgreSQL versão 8.2, não
existia a sintaxe de criação do tipo de dados
shell
CREATE TYPE .
A maneira de criar um tipo de dados base novo era criar primeiro
sua função de entrada.
Nesta abordagem, o PostgreSQL verá
primeiro o nome do novo tipo de dados como o tipo de dados retornado
pela função de entrada.
O tipo de dados shell é criado
implicitamente nesta situação, podendo ser referenciado nas
definições das funções de E/S restantes.
Esta abordagem ainda funciona, mas está em obsolescência, podendo
ser desativada em algum lançamento futuro.
Além disso, para evitar sobrecarregar acidentalmente os catálogos
com tipos de dados shell como
resultado de simples erros de digitação nas definições de função,
o tipo de dados shell só será criado
dessa maneira quando a função de entrada for escrita em
C.
nome
No PostgreSQL versão 16 e posteriores,
é recomendável que as funções de entrada dos tipos de dados base
retornem erros “soft” (suaves) usando o novo mecanismo
errsave()/ereturn(),
em vez de lançar exceções usando a função ereport()
como era feito nas versões anteriores.
Veja o arquivo src/backend/utils/fmgr/README
para obter mais informações.
Este exemplo cria um tipo de dados composto, e o utiliza em uma definição de função:
CREATE TYPE compfoo AS (f1 int, f2 text);
CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$
SELECT fooid, fooname FROM foo
$$ LANGUAGE SQL;
Este exemplo cria um tipo de dados enumerado, e o utiliza em uma definição de tabela:
CREATE TYPE bug_status AS ENUM ('new', 'open', 'closed');
CREATE TABLE bug (
id serial,
description text,
status bug_status
);
Este exemplo cria um tipo de dados intervalo:
CREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);
Este exemplo cria o tipo de dados base box, e então
o usa em uma definição de tabela:
CREATE TYPE box;
CREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ;
CREATE FUNCTION my_box_out_function(box) RETURNS cstring AS ... ;
CREATE TYPE box (
INTERNALLENGTH = 16,
INPUT = my_box_in_function,
OUTPUT = my_box_out_function
);
CREATE TABLE myboxes (
id integer,
description box
);
Se a estrutura interna de box fosse uma matriz de
quatro elementos float4, poderia ser usado
CREATE TYPE box (
INTERNALLENGTH = 16,
INPUT = my_box_in_function,
OUTPUT = my_box_out_function,
ELEMENT = float4
);
o que permitiria que os números dos componentes de um valor de caixa fossem acessados por indexação. Caso contrário, o tipo de dados se comporta da mesma forma que antes.
Este exemplo cria um tipo de dados de objeto grande, e o utiliza em uma definição de tabela:
CREATE TYPE bigobj (
INPUT = lo_filein, OUTPUT = lo_fileout,
INTERNALLENGTH = VARIABLE
);
CREATE TABLE big_objs (
id integer,
obj bigobj
);
Mais exemplos, incluindo funções de entrada e saída adequadas, podem ser encontradas em Tipos de dados definidos pelo usuário.
A primeira forma do comando CREATE TYPE, que cria
um tipo de dados composto, está em conformidade com o padrão
SQL.
As demais formas são extensões do PostgreSQL.
O comando CREATE TYPE no padrão SQL
também define outras formas que não são implementadas no
PostgreSQL.
A capacidade de criar um tipo de dados composto com zero atributos
é uma extensão ao padrão específica do
PostgreSQL
(análogo ao mesmo caso em CREATE TABLE).
[145]
O comando CREATE TYPE define um tipo de dados
definido pelo usuário no servidor corrente
IBM DB2 12.1.x – CREATE TYPE statement (N. T.)