CREATE TYPE

Nome

CREATE TYPE -- cria um tipo de dado

Sinopse

CREATE TYPE nome AS
    ( nome_do_atributo tipo_de_dado [, ... ] )

CREATE TYPE nome (
    INPUT = função_de_entrada,
    OUTPUT = função_de_saída
    [ , RECEIVE = função_de_recepção ]
    [ , SEND = função_de_envio ]
    [ , INTERNALLENGTH = { comprimento_interno | VARIABLE } ]
    [ , PASSEDBYVALUE ]
    [ , ALIGNMENT = alinhamento ]
    [ , STORAGE = armazenamento ]
    [ , DEFAULT = padrão ]
    [ , ELEMENT = elemento ]
    [ , DELIMITER = delimitador ]
)

Descrição

O comando CREATE TYPE registra um novo tipo de dado para uso no banco de dados corrente. O usuário que define o tipo se torna o seu dono.

Se o nome do esquema for fornecido, então o tipo será criado no esquema especificado, senão será criado no esquema corrente. O nome do tipo deve ser distinto do nome de qualquer tipo ou domínio existente no mesmo esquema (como as tabelas possuem tipos de dado associados, o nome do tipo também deve ser distinto do nome de qualquer tabela existente no mesmo esquema).

Tipos Compostos

A primeira forma de CREATE TYPE cria um tipo composto. O tipo composto é especificado por uma lista de nomes de atributo e tipos de dado. É essencialmente a mesma coisa que o tipo de uma linha de tabela, mas o uso de CREATE TYPE evita a necessidade de criar uma tabela real quando tudo o que se deseja é apenas definir um tipo. Um tipo composto autônomo é útil como argumento ou tipo retornado por uma função.

Tipos Base

A segunda forma do comando CREATE TYPE cria um novo tipo base (tipo escalar). Os parâmetros podem estar em qualquer ordem, e não apenas na ordem mostrada acima, e a maior parte é opcional. Requer o registro de duas ou mais funções (utilizando CREATE FUNCTION) antes de definir o tipo. 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 e função_de_envio são opcionais. Geralmente estas funções precisam ser codificadas em C ou em outra linguagem de baixo nível.

A função_de_entrada converte a representação textual externa do tipo na representação interna utilizada pelos operadores e funções definidos para o tipo. 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 cstring, ou recebendo três argumentos dos tipos cstring, oid e integer. O primeiro argumento é o texto de entrada como uma cadeia de caracteres C, o segundo argumento é o OID do tipo do elemento no caso de ser um tipo matriz, e o terceiro é o typmod da coluna de destino, se for conhecido. A função de entrada deve retornar um valor do próprio tipo de dado. A função de saída pode ser declarada como recebendo um argumento do novo tipo de dado, ou como recebendo dois argumentos dos quais o segundo é do tipo oid. O segundo argumento é novamente o OID do tipo do elemento da matriz para tipos matriz. A função de saída deve ter um retorno do tipo cstring.

A função_de_recepção opcional converte a representação binária externa do tipo para a representação interna. Se esta função não for fornecida, o tipo não pode participar de entrada binária. A representação binária deve ser escolhida para ser de baixo custo converter para a forma interna, e ao mesmo tempo razoavelmente portável (Por exemplo, os tipos de dado inteiro padrão utilizam a ordem de byte de rede como sendo a 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 realizar uma verificação adequada para garantir que o valor seja válido. A função de recepção pode ser declarada como recebendo um argumento do tipo internal, ou dois argumentos dos tipos internal e oid. Deve retornar um valor do próprio tipo de dado (O primeiro argumento é um ponteiro para o buffer StringInfo, que armazena a cadeia de bytes recebida; o segundo argumento opcional é o OID do tipo do elemento no caso de ser um tipo matriz). Da mesma maneira, 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 não pode participar de saída binária. A função de envio pode ser declarada como recebendo um argumento do novo tipo de dado, ou como recebendo dois argumentos dos quais o segundo é do tipo oid. O segundo argumento é novamente o OID do tipo do elemento da matriz para tipos matriz. A função de envio deve possuir um retorno do tipo bytea.

Neste ponto podemos estar querendo saber como as funções de entrada e de saída podem ser declaradas possuindo resultados ou argumentos do novo tipo, se devem ser criadas antes que o novo tipo possa ser criado. A resposta é que a função de entrada deve ser criada primeiro, depois a função de saída (e as funções binárias de entrada e de saída, se for desejado) e, finalmente, o tipo de dado. O PostgreSQL vê primeiro o nome do novo tipo de dado como tipo retornado pela função de entrada, e cria um tipo de "abrigo", que é simplesmente uma entrada no catálogo do sistema, e vincula a definição da função de entrada ao tipo de abrigo. Da mesma maneira, as outras funções são vinculadas ao (agora já existente) tipo de abrigo. Por último, o comando CREATE TYPE substitui a entrada de abrigo com a definição completa do tipo, e o novo tipo poderá ser usado.

Enquanto os detalhes da representação interna do novo tipo são conhecidos somente pelas funções de entrada e de saída e por outras funções criadas pelo usuário para trabalhar com o tipo, existem várias propriedades da representação interna que devem ser declaradas para o PostgreSQL. A mais importante destas é o comprimento_interno. Os tipos de dado base podem ser de comprimento fixo e, neste caso, o comprimento_interno é um inteiro positivo, ou de comprimento variável, indicado pela definição do comprimento_interno como VARIABLE (Internamente isto é representado definindo typlen como -1). A representação interna de todos os tipos de comprimento variável devem começar por um inteiro de 4 bytes fornecendo o comprimento total deste valor do tipo.

O sinalizador opcional PASSEDBYVALUE indica que os valores deste tipo de dado são passados por valor, e não por referência. Não é possível passar por valor tipos cuja representação interna seja maior do que o tamanho do tipo Datum (4 bytes na maioria das máquinas, e 8 bytes em poucas).

O parâmetro alinhamento especifica o alinhamento de armazenamento requerido por este tipo de dado. Os valores permitidos igualam-se ao alinhamento nas fronteiras de 1, 2, 4 ou 8 bytes. Deve ser observado que os tipos de comprimento variável devem ter um alinhamento de pelo menos 4, porque contêm, necessariamente, um int4 como seu primeiro componente.

O parâmetro armazenamento permite selecionar estratégias de armazenamento para tipos de dado de comprimento variável (somente é permitido plain para os tipos de comprimento fixo). plain especifica que os dados deste tipo são sempre armazenado em-linha e não comprimidos. extended especifica que primeiro o sistema tentará comprimir um valor de dado longo e, depois, movê-lo para fora da linha da tabela principal se ainda permanecerem muito longo. external permite mover os valores para fora da tabela principal, mas o sistema não tentará comprimi-los. main permite a compressão, mas desencoraja mover o valor para fora da tabela principal (os itens de dado com esta estratégia de armazenamento só são movidos para fora da tabela principal se não houver outra maneira de fazer a linha caber, mas têm mais preferência para serem mantidos na tabela principal do que os itens extended e external).

Pode ser especificado um valor padrão, quando se deseja que as colunas com este tipo de dado tenham como padrão algo diferente do valor nulo. O valor padrão é especificado pela palavra chave DEFAULT; este padrão pode ser substituído por uma cláusula DEFAULT explícita anexada a uma determinada coluna.

Para indicar que o tipo é uma matriz, deve ser especificado o tipo dos elementos da matriz utilizando a palavra chave ELEMENT. Por exemplo, para definir uma matriz de inteiros de 4 bytes (int4), deve ser especificado ELEMENT = int4. Mais detalhes sobre tipos matriz são mostrados abaixo.

Para indicar o delimitador a ser usado entre os valores na representação externa das matrizes deste tipo, pode-se definir delimitador como um caractere específico. O delimitador padrão é a vírgula (,). Deve ser observado que o delimitador está associado ao tipo do elemento da matriz, e não à própria matriz.

Tipos matriz

Sempre que um tipo de dado base definido pelo usuário é criado, o PostgreSQL cria automaticamente um tipo matriz (array) associado, cujo nome consiste no nome do tipo base prefixado pelo caractere sublinhado. O analisador compreende esta convenção de nome, e traduz as solicitações para colunas do tipo foo[] em solicitações para o tipo _foo. O tipo matriz criado implicitamente é de comprimento variável e usa as funções de entrada e saída nativas array_in e array_out.

Pode ser perguntado, com razão, por que existe a opção ELEMENT se o sistema produz o tipo matriz correto automaticamente. O único caso onde é útil utilizar ELEMENT é quando se constrói um tipo de comprimento fixo que é internamente uma matriz de componentes idênticos, e deseja-se que estes componentes sejam acessados diretamente por índices, além de qualquer outra operação que se planeje fornecer para este tipo como um todo. Por exemplo, o tipo name permite que os elementos char que o constituem sejam acessados desta forma. Um tipo point 2-D pode permitir que os dois números que o compõe sejam acessados como point[0] e point[1]. Deve ser observado que esta praticidade somente funciona em tipos de comprimento fixo cuja forma interna seja exatamente uma seqüência de campos idênticos de comprimento fixo. Para permitir o uso de índices, um tipo de comprimento variável deve possuir a representação interna generalizada usada por array_in e array_out. Por razões históricas (ou seja, claramente errado mas muito tarde para mudar) os índices dos tipos matriz de comprimento fixo começam por zero, em vez de começar por um como no caso matrizes de comprimento variável.

Parâmetros

nome
O nome (opcionalmente qualificado pelo esquema) do tipo a ser criado.
nome_do_atributo
O nome de um atributo (coluna) para o tipo composto.
tipo_de_dado
O nome de um tipo de dado existente que será uma coluna do tipo composto.
função_de_entrada
O nome da função que converte os dados da forma textual externa para a forma interna.
função_de_saída
O nome da função que converte os dados da forma interna do tipo para a forma textual externa.
função_de_recepção
O nome da função que converte os dados da forma binária externa do tipo para a forma interna.
função_de_envio
O nome da função que converte os dados da forma interna do tipo para a forma binária externa.
comprimento_interno
Uma constante numérica que especifica o comprimento em bytes da representação interna do novo tipo. O padrão é assumir como sendo de comprimento variável.
alinhamento
O alinhamento de armazenamento requerido por este tipo de dado. Se for especificado, deve ser char, int2, int4 ou double; o padrão é int4.
armazenamento
A estratégia de armazenamento para este tipo de dado. Se for especificado, deve ser plain, external, extended ou main; o padrão é plain.
padrão
O valor padrão para este tipo de dado. Se for omitido, o padrão é nulo.
elemento
O tipo sendo criado é uma matriz (array); especifica o tipo dos elementos da matriz.
delimitador
O caractere delimitador a ser usado entre os valores nas matrizes (arrays) feitas deste tipo.

Observações

Os nomes de tipo definidos pelo usuário não podem começar pelo caractere sublinhado (_), e só podem ter 62 caracteres de comprimento (ou, de modo geral, NAMEDATALEN-2, em vez dos NAMEDATALEN-1 caracteres permitidos para os outros nomes). Os nomes de tipo começados por sublinhado são reservados para os nomes de tipo matriz criados internamente.

Nas versões do PostgreSQL anteriores a 7.3, era costume evitar criar um tipo "abrigo" substituindo as referências à frente da função para o nome do tipo usando o pseudotipo opaque. Os argumentos e resultados cstring também tinham que ser declarados como opaque antes da versão 7.3. Para permitir a carga de cópias de segurança antigas, o comando CREATE TYPE aceita funções declaradas como retornando opaque, mas mostra uma mensagem e muda a declaração da função para usar o tipo correto.

Exemplos

Este exemplo cria um tipo composto e o utiliza na definição de uma 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 o tipo de dado base box e, em seguida, o utiliza na definição da tabela:

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 ter sido usado

CREATE TYPE box (
    INTERNALLENGTH = 16,
    INPUT = my_box_in_function,
    OUTPUT = my_box_out_function,
    ELEMENT = float4
);

o que permitiria acessar o valor de um componente de box através de índice. Fora isso, o tipo se comporta do mesmo modo que o anterior.

Este exemplo cria um tipo objeto grande e o utiliza na definição de uma tabela:

CREATE TYPE bigobj (
    INPUT = lo_filein, OUTPUT = lo_fileout,
    INTERNALLENGTH = VARIABLE
);
CREATE TABLE big_objs (
    id integer,
    obj bigobj
);

Outros exemplos, incluindo funções de entrada e de saída, podem ser encontrados no Capítulo 33 .

Compatibilidade

Este comando CREATE TYPE é uma extensão do PostgreSQL. Existe um comando CREATE TYPE no SQL:1999 e posterior que é bastante diferente nos detalhes.

Veja também

CREATE FUNCTION , DROP TYPE
SourceForge.net Logo