CREATE TYPE

CREATE TYPE — define un nuevo tipo de datos

Synopsis

CREATE TYPE nombre AS
    ( [ nombre_atributo tipo_datos [ COLLATE ordenación ] [, ... ] ] )

CREATE TYPE nombre AS ENUM
    ( [ 'etiqueta' [, ... ] ] )

CREATE TYPE nombre AS RANGE (
    SUBTYPE = subtipo
    [ , SUBTYPE_OPCLASS = clase_op_subtipo ]
    [ , COLLATION = ordenación ]
    [ , CANONICAL = función_canónica ]
    [ , SUBTYPE_DIFF = función_dif_subtipo ]
    [ , MULTIRANGE_TYPE_NAME = nombre_tipo_multirango ]
)

CREATE TYPE nombre (
    INPUT = función_entrada,
    OUTPUT = función_salida
    [ , RECEIVE = función_recepción ]
    [ , SEND = función_envío ]
    [ , TYPMOD_IN = función_entrada_mod_tipo ]
    [ , TYPMOD_OUT = función_salida_mod_tipo ]
    [ , ANALYZE = función_analyze ]
    [ , SUBSCRIPT = función_subíndice ]
    [ , INTERNALLENGTH = { longitud_interna | VARIABLE } ]
    [ , PASSEBYVALUE ]
    [ , ALIGNMENT = alineación ]
    [ , STORAGE = almacenamiento ]
    [ , LIKE = tipo_like ]
    [ , CATEGORY = categoría ]
    [ , PREFERRED = preferido ]
    [ , DEFAULT = por_defecto ]
    [ , ELEMENT = elemento ]
    [ , DELIMITER = delimitador ]
    [ , COLLATABLE = ordenable ]
)

CREATE TYPE nombre

Descripción

CREATE TYPE registra un nuevo tipo de datos para su uso en la base de datos actual. El usuario que define un tipo se convierte en su propietario.

Si se proporciona un nombre de esquema, el tipo se creará en el esquema especificado. De lo contrario, se creará en el esquema actual. El nombre del tipo debe ser diferente del nombre de cualquier tipo o dominio existente en el mismo esquema. (Debido a que las tablas tienen tipos de datos asociados, el nombre del tipo también debe ser diferente del nombre de cualquier tabla existente en el mismo esquema).

Existen cinco formas de CREATE TYPE, como se muestra en la sinopsis de la sintaxis anterior. Crean respectivamente un tipo compuesto, un tipo enum, un tipo de rango, un tipo base o un tipo shell. Las primeras cuatro formas se analizan a continuación. Un tipo shell es simplemente un marcador de posición para un tipo que se definirá más adelante; se crea ejecutando CREATE TYPE sin más parámetros que el nombre del tipo. Los tipos shell son necesarios como referencias directas al crear tipos de rango y tipos base, como se explica en esas secciones.

Tipos compuestos

La primera forma de CREATE TYPE crea un tipo compuesto. El tipo compuesto se especifica mediante una lista de nombres de atributos y tipos de datos. También se puede especificar la ordenación de un atributo si su tipo de datos es ordenable. Un tipo compuesto es esencialmente lo mismo que el tipo de fila de una tabla, pero el uso de CREATE TYPE evita la necesidad de crear una tabla real cuando todo lo que se desea es definir un tipo. Un tipo compuesto independiente es útil, por ejemplo, como argumento o tipo de retorno de una función.

Para poder crear un tipo compuesto, debes tener el privilegio USAGE en todos los tipos de atributos.

Tipos enumerados (Enum)

La segunda forma de CREATE TYPE crea un tipo enumerado (enum), como se describe en Section 8.7. Los tipos enum toman una lista de etiquetas entre comillas, cada una de las cuales debe tener menos de NAMEDATALEN bytes de longitud (64 bytes en una compilación estándar de PostgreSQL). (Es posible crear un tipo enumerado con cero etiquetas, pero dicho tipo no se puede usar para contener valores antes de que se agregue al menos una etiqueta usando ALTER TYPE).

Tipos de rango

La tercera forma de CREATE TYPE crea un nuevo tipo de rango, como se describe en Section 8.17.

El subtipo del tipo de rango puede ser cualquier tipo con una clase de operador b-tree asociada (para determinar el orden de los valores para el tipo de rango). Normalmente, la clase de operador b-tree por defecto del subtipo se utiliza para determinar el orden; para utilizar una clase de operador que no sea la por defecto, especifica su nombre con clase_op_subtipo. Si el subtipo es ordenable y deseas utilizar una ordenación que no sea la por defecto en el orden del rango, especifica la ordenación deseada con la opción ordenación.

La función opcional canónica debe tomar un argumento del tipo de rango que se está definiendo y devolver un valor del mismo tipo. Esto se utiliza para convertir los valores del rango a una forma canónica, cuando corresponda. Consulta Section 8.17.8 para obtener más información. Crear una función canónica es un poco complejo, ya que debe definirse antes de que se pueda declarar el tipo de rango. Para hacer esto, primero debes crear un tipo shell, que es un tipo de marcador de posición que no tiene propiedades excepto un nombre y un propietario. Esto se hace ejecutando el comando CREATE TYPE nombre sin parámetros adicionales. Luego, la función se puede declarar utilizando el tipo shell como argumento y resultado, y finalmente se puede declarar el tipo de rango utilizando el mismo nombre. Esto reemplaza automáticamente la entrada del tipo shell con un tipo de rango válido.

La función opcional función_dif_subtipo debe tomar dos valores del tipo subtipo como argumento y devolver un valor de tipo double precision que represente la diferencia entre los dos valores dados. Aunque esto es opcional, proporcionarlo permite una eficiencia mucho mayor de los índices GiST en las columnas del tipo de rango. Consulta Section 8.17.8 para obtener más información.

El parámetro opcional nombre_tipo_multirango especifica el nombre del tipo multirango correspondiente. Si no se especifica, este nombre se elige automáticamente de la siguiente manera. Si el nombre del tipo de rango contiene la subcadena range, entonces el nombre del tipo multirango se forma reemplazando la subcadena range con multirange en el nombre del tipo de rango. De lo contrario, el nombre del tipo multirango se forma agregando un sufijo _multirange al nombre del tipo de rango.

Tipos base

La cuarta forma de CREATE TYPE crea un nuevo tipo base (tipo escalar). Para crear un nuevo tipo base, debes ser superusuario. (Esta restricción se aplica porque una definición de tipo errónea podría confundir o incluso hacer caer el servidor).

Los parámetros pueden aparecer en cualquier orden, no solo en el ilustrado arriba, y la mayoría son opcionales. Debes registrar dos o más funciones (usando CREATE FUNCTION) antes de definir el tipo. Las funciones de soporte función_entrada y función_salida son obligatorias, mientras que las funciones función_recepción, función_envío, función_entrada_mod_tipo, función_salida_mod_tipo, función_analyze y función_subíndice son opcionales. Generalmente, estas funciones deben estar escritas en C o en otro lenguaje de bajo nivel.

La función_entrada convierte la representación textual externa del tipo en la representación interna utilizada por los operadores y funciones definidos para el tipo. La función_salida realiza la transformación inversa. La función de entrada se puede declarar como una función que toma un argumento de tipo cstring, o que toma tres argumentos de tipos cstring, oid, integer. El primer argumento es el texto de entrada como una cadena de C, el segundo argumento es el propio OID del tipo (excepto para los tipos de array, que en su lugar reciben el OID de su tipo de elemento) y el tercero es el typmod de la columna de destino, si se conoce (se pasará -1 si no se conoce). La función de entrada debe devolver un valor del propio tipo de datos. Por lo general, una función de entrada debe declararse como STRICT; si no lo es, se llamará con un primer parámetro NULL al leer un valor de entrada NULL. En este caso, la función debe seguir devolviendo NULL, a menos que genere un error. (Este caso está pensado principalmente para admitir funciones de entrada de dominio, que podrían necesitar rechazar entradas NULL). La función de salida debe declararse como una función que toma un argumento del nuevo tipo de datos. La función de salida debe devolver el tipo cstring. Las funciones de salida no se invocan para valores NULL.

La función opcional función_recepción convierte la representación binaria externa del tipo en la representación interna. Si no se proporciona esta función, el tipo no puede participar en la entrada binaria. La representación binaria debe elegirse para que sea económica de convertir a la forma interna, a la vez que sea razonablemente portable. (Por ejemplo, los tipos de datos enteros estándar utilizan el orden de bytes de red como representación binaria externa, mientras que la representación interna está en el orden de bytes nativo de la máquina). La función de recepción debe realizar la comprobación adecuada para garantizar que el valor sea válido. La función de recepción se puede declarar como una función que toma un argumento de tipo internal, o que toma tres argumentos de tipos internal, oid, integer. El primer argumento es un puntero a un búfer StringInfo que contiene la cadena de bytes recibida; los argumentos opcionales son los mismos que para la función de entrada de texto. La función de recepción debe devolver un valor del propio tipo de datos. Por lo general, una función de recepción debe declararse como STRICT; si no lo es, se llamará con un primer parámetro NULL al leer un valor de entrada NULL. La función debe seguir devolviendo NULL en este caso, a menos que genere un error. (Este caso está pensado principalmente para admitir funciones de recepción de dominio, que podrían necesitar rechazar entradas NULL). Del mismo modo, la función opcional función_envío convierte la representación interna a la representación binaria externa. Si no se proporciona esta función, el tipo no puede participar en la salida binaria. La función de envío debe declararse como una función que toma un argumento del nuevo tipo de datos. La función de envío debe devolver el tipo bytea. Las funciones de envío no se invocan para valores NULL.

Llegados a este punto deberías preguntarte cómo se pueden declarar las funciones de entrada y salida para tener resultados o argumentos del nuevo tipo, cuando se tienen que crear antes de que se pueda crear el nuevo tipo. La respuesta es que el tipo debe definirse primero como un tipo shell, que es un tipo marcador de posición que no tiene propiedades excepto un nombre y un propietario. Esto se hace ejecutando el comando CREATE TYPE nombre sin parámetros adicionales. Luego, las funciones de E/S de C se pueden definir haciendo referencia al tipo shell. Finalmente, CREATE TYPE con una definición completa reemplaza la entrada shell con una definición de tipo completa y válida, tras lo cual el nuevo tipo se puede usar normalmente.

Las funciones opcionales función_entrada_mod_tipo y función_salida_mod_tipo son necesarias si el tipo admite modificadores, que son restricciones opcionales añadidas a la declaración de un tipo, como char(5) o numeric(30,2). PostgreSQL permite que los tipos definidos por el usuario tomen una o más constantes o identificadores simples como modificadores. Sin embargo, esta información debe ser capaz de empaquetarse en un único valor entero no negativo para su almacenamiento en los catálogos del sistema. A la función_entrada_mod_tipo se le pasan los modificadores declarados en forma de un array de cstring. Debe comprobar la validez de los valores (generando un error si son incorrectos) y, si son correctos, devolver un único valor integer no negativo que se almacenará como el typmod de la columna. Los modificadores de tipo se rechazarán si el tipo no tiene una función_entrada_mod_tipo. La función_salida_mod_tipo convierte el valor typmod entero interno de nuevo al formato correcto para la visualización del usuario. Debe devolver un valor de tipo cstring que sea la cadena exacta que se va a añadir al nombre del tipo; por ejemplo, la función de numeric podría devolver (30,2). Se permite omitir la función_salida_mod_tipo, en cuyo caso el formato de visualización por defecto es simplemente el valor typmod entero almacenado entre paréntesis.

La función opcional función_analyze realiza la recopilación de estadísticas específicas del tipo para las columnas de dicho tipo de datos. Por defecto, ANALYZE intentará recopilar estadísticas utilizando los operadores igual y menor que del tipo, si existe una clase de operador b-tree por defecto para el tipo. Para los tipos no escalares, este comportamiento probablemente no sea adecuado, por lo que se puede anular especificando una función de análisis personalizada. La función de análisis debe declararse de modo que tome un único argumento de tipo internal y devuelva un resultado boolean. La API detallada para las funciones de análisis aparece en src/include/commands/vacuum.h.

La función opcional función_subíndice permite añadir subíndices al tipo de datos en los comandos SQL. Especificar esta función no hace que el tipo sea considerado como un tipo de array verdadero; por ejemplo, no será candidato para el tipo de resultado de las construcciones ARRAY[]. Pero si aplicar un subíndice a un valor del tipo es una notación natural para extraer datos de él, entonces se puede escribir una función_subíndice para definir qué significa eso. La función de subíndice debe declararse para tomar un único argumento de tipo internal y devolver un resultado internal, que es un puntero a una estructura de métodos (funciones) que implementan el subindexado. La API detallada para las funciones de subíndice aparece en src/include/nodes/subscripting.h. También puede ser útil leer la implementación del array en src/backend/utils/adt/arraysubs.c, o el código más simple en contrib/hstore/hstore_subs.c. Aparece información adicional en Tipos de array a continuación.

Aunque los detalles de la representación interna del nuevo tipo solo son conocidos por las funciones de E/S y otras funciones que crees para trabajar con el tipo, existen varias propiedades de la representación interna que deben declararse a PostgreSQL. La más importante de ellas es longitud_interna. Los tipos de datos base pueden ser de longitud fija, en cuyo caso longitud_interna es un entero positivo, o de longitud variable, lo que se indica estableciendo longitud_interna a VARIABLE. (Internamente, esto se representa estableciendo typlen a -1). La representación interna de todos los tipos de longitud variable debe comenzar con un entero de 4 bytes que proporcione la longitud total de este valor del tipo. (Ten en cuenta que el campo de longitud a menudo se codifica, como se describe en Section 66.2; no es aconsejable acceder a él directamente).

La bandera opcional PASSEDBYVALUE indica que los valores de este tipo de datos se pasan por valor, en lugar de por referencia. Los tipos pasados por valor deben ser de longitud fija, y su representación interna no puede ser mayor que el tamaño del tipo Datum (4 bytes en algunas máquinas, 8 bytes en otras).

El parámetro alineación especifica la alineación de almacenamiento requerida para el tipo de datos. Los valores permitidos equivalen a la alineación en límites de 1, 2, 4 u 8 bytes. Ten en cuenta que los tipos de longitud variable deben tener una alineación de al menos 4, ya que necesariamente contienen un int4 como su primer componente.

El parámetro almacenamiento permite seleccionar estrategias de almacenamiento para tipos de datos de longitud variable. (Solo se permite plain para tipos de longitud fija). plain especifica que los datos del tipo siempre se almacenarán en línea y no se comprimirán. extended especifica que el sistema primero intentará comprimir un valor de datos largo y lo moverá fuera de la fila de la tabla principal si sigue siendo demasiado largo. external permite que el valor se mueva fuera de la tabla principal, pero el sistema no intentará comprimirlo. main permite la compresión, pero desaconseja mover el valor fuera de la tabla principal. (Los elementos de datos con esta estrategia de almacenamiento aún podrían moverse fuera de la tabla principal si no hay otra forma de hacer que una fila quepa, pero se mantendrán en la tabla principal de manera preferente sobre los elementos extended y external).

Todos los valores de almacenamiento distintos de plain implican que las funciones del tipo de datos pueden manejar valores que han sido toasted (tostados), como se describe en Section 66.2 y Section 36.13.1. El otro valor específico dado simplemente determina la estrategia de almacenamiento TOAST por defecto para las columnas de un tipo de datos de almacenamiento "toastable"; los usuarios pueden elegir otras estrategias para columnas individuales utilizando ALTER TABLE SET STORAGE.

El parámetro tipo_like proporciona un método alternativo para especificar las propiedades de representación básicas de un tipo de datos: copiarlas de algún tipo existente. Los valores de longitud_interna, passedbyvalue, alineación y almacenamiento se copian de ese tipo. (Es posible, aunque generalmente no deseable, anular algunos de estos valores especificándolos junto con la cláusula LIKE). Especificar la representación de esta manera es especialmente útil cuando la implementación de bajo nivel del nuevo tipo se apoya en un tipo existente de alguna manera.

Los parámetros categoría y preferido se pueden usar para ayudar a controlar qué conversión implícita se aplicará en situaciones ambiguas. Cada tipo de datos pertenece a una categoría nombrada por un único carácter ASCII, y cada tipo es preferido o no dentro de su categoría. El analizador preferirá realizar la conversión a tipos preferidos (pero solo desde otros tipos dentro de la misma categoría) cuando esta regla sea útil para resolver funciones u operadores sobrecargados. Para obtener más detalles, consulta Chapter 10. Para los tipos que no tienen conversiones implícitas hacia o desde otros tipos, es suficiente dejar estas configuraciones en los valores por defecto. Sin embargo, para un grupo de tipos relacionados que tienen conversiones implícitas, a menudo es útil marcarlos a todos como pertenecientes a una categoría y seleccionar uno o dos de los tipos más generales como preferidos dentro de la categoría. El parámetro categoría es especialmente útil cuando se añade un tipo definido por el usuario a una categoría integrada existente, como los tipos numéricos o de cadena. Sin embargo, también es posible crear nuevas categorías de tipos completamente definidas por el usuario. Selecciona cualquier carácter ASCII que no sea una letra mayúscula para dar nombre a dicha categoría.

Se puede especificar un valor por defecto en caso de que un usuario desee que las columnas del tipo de datos tengan por defecto algo distinto del valor nulo. Especifica el valor por defecto con la palabra clave DEFAULT. (Dicho valor por defecto se puede anular mediante una cláusula DEFAULT explícita adjunta a una columna en particular).

Para indicar que un tipo es un tipo de array de longitud fija, especifica el tipo de los elementos del array utilizando la palabra clave ELEMENT. Por ejemplo, para definir un array de enteros de 4 bytes (int4), especifica ELEMENT = int4. Para obtener más detalles, consulta Tipos de array a continuación.

Para indicar el delimitador que se utilizará entre los valores en la representación externa de los arrays de este tipo, se puede establecer delimitador en un carácter específico. El delimitador por defecto es la coma (,). Ten en cuenta que el delimitador está asociado con el tipo de elemento del array, no con el propio tipo de array.

Si el parámetro booleano opcional ordenable es true, las definiciones de columnas y expresiones del tipo pueden llevar información de ordenación mediante el uso de la cláusula COLLATE. Corresponde a las implementaciones de las funciones que operan en el tipo hacer uso real de la información de ordenación; esto no sucede automáticamente simplemente por marcar el tipo como ordenable.

Tipos de array

Siempre que se crea un tipo definido por el usuario, PostgreSQL crea automáticamente un tipo de array asociado, cuyo nombre consiste en el nombre del tipo de elemento precedido por un carácter de subrayado y truncado si es necesario para mantenerlo con menos de NAMEDATALEN bytes de longitud. (Si el nombre así generado choca con un nombre de tipo existente, el proceso se repite hasta que se encuentre un nombre que no choque). Este tipo de array creado implícitamente es de longitud variable y utiliza las funciones de entrada y salida integradas array_in y array_out. Además, este tipo es el que utiliza el sistema para construcciones como ARRAY[] sobre el tipo definido por el usuario. El tipo de array realiza un seguimiento de cualquier cambio en el propietario o esquema de su tipo de elemento, y se elimina si se elimina el tipo de elemento.

Podrías preguntarte por qué existe la opción ELEMENT si el sistema crea el tipo de array correcto automáticamente. El caso principal en el que es útil utilizar ELEMENT es cuando estás creando un tipo de longitud fija que resulta ser internamente un array de una serie de elementos idénticos, y deseas permitir que se acceda directamente a estos elementos mediante subíndices, además de las operaciones que planeas proporcionar para el tipo en su conjunto. Por ejemplo, el tipo point se representa simplemente como dos números de coma flotante, a los que se puede acceder utilizando point[0] y point[1]. Ten en cuenta que esta facilidad solo funciona para tipos de longitud fija cuya forma interna es exactamente una secuencia de campos idénticos de longitud fija. Por razones históricas (es decir, esto es claramente incorrecto pero es demasiado tarde para cambiarlo), el subindexado de los tipos de array de longitud fija comienza desde cero, en lugar de comenzar desde uno como ocurre con los arrays de longitud variable.

Especificar la opción SUBSCRIPT permite que un tipo de datos sea subindexado, aunque el sistema no lo considere de otra manera como un tipo de array. El comportamiento recién descrito para los arrays de longitud fija es en realidad implementado por la función controladora de subíndice SUBSCRIPT raw_array_subscript_handler, que se utiliza automáticamente si especificas ELEMENT para un tipo de longitud fija sin escribir también SUBSCRIPT.

Al especificar una función SUBSCRIPT personalizada, no es necesario especificar ELEMENT a menos que la función controladora de subíndices necesite consultar typelem para averiguar qué devolver. Ten en cuenta que especificar ELEMENT hace que el sistema asuma que el nuevo tipo contiene, o depende físicamente de alguna manera, del tipo de elemento; por lo tanto, por ejemplo, no se permitirá cambiar las propiedades del tipo de elemento si hay alguna columna del tipo dependiente.

Parámetros

nombre

El nombre (opcionalmente calificado por esquema) de un tipo que se va a crear.

nombre_atributo

El nombre de un atributo (columna) para el tipo compuesto.

tipo_datos

El nombre de un tipo de datos existente que se convertirá en una columna del tipo compuesto.

ordenación

El nombre de una ordenación existente que se asociará con una columna de un tipo compuesto o con un tipo de rango.

etiqueta

Un literal de cadena que representa la etiqueta de texto asociada con un valor de un tipo enum.

subtipo

El nombre del tipo de elemento del cual el tipo de rango representará rangos.

clase_op_subtipo

El nombre de una clase de operador b-tree para el subtipo.

función_canónica

El nombre de la función de canonización para el tipo de rango.

función_dif_subtipo

El nombre de una función de diferencia para el subtipo.

nombre_tipo_multirango

El nombre del tipo multirango correspondiente.

función_entrada

El nombre de una función que convierte datos de la forma textual externa del tipo a su forma interna.

función_salida

El nombre de una función que convierte datos de la forma interna del tipo a su forma textual externa.

función_recepción

El nombre de una función que convierte datos de la forma binaria externa del tipo a su forma interna.

función_envío

El nombre de una función que convierte datos de la forma interna del tipo a su forma binaria externa.

función_entrada_mod_tipo

El nombre de una función que convierte un array de modificadores para el tipo a su forma interna.

función_salida_mod_tipo

El nombre de una función que convierte la forma interna de los modificadores del tipo a su forma textual externa.

función_analyze

El nombre de una función que realiza el análisis estadístico para el tipo de datos.

función_subíndice

El nombre de una función que define qué hace el subindexado de un valor del tipo de datos.

longitud_interna

Una constante numérica que especifica la longitud en bytes de la representación interna del nuevo tipo. Se asume por defecto que es de longitud variable.

alineación

El requerimiento de alineación de almacenamiento del tipo de datos. Si se especifica, debe ser char, int2, int4 o double; el valor por defecto es int4.

almacenamiento

La estrategia de almacenamiento para el tipo de datos. Si se especifica, debe ser plain, external, extended o main; el valor por defecto es plain.

tipo_like

El nombre de un tipo de datos existente con el cual el nuevo tipo compartirá la misma representación. Los valores de longitud_interna, passedbyvalue, alineación y almacenamiento se copian de ese tipo, a menos que se anulen mediante especificaciones explícitas en otra parte de este comando CREATE TYPE.

categoría

El código de categoría (un único carácter ASCII) para este tipo. El valor por defecto es 'U' para tipo definido por el usuario. Otros códigos de categoría estándar se pueden encontrar en Table 52.65. También puedes elegir otros caracteres ASCII para crear categorías personalizadas.

preferido

True si este tipo es un tipo preferido dentro de su categoría de tipo, de lo contrario false. El valor por defecto es false. Ten mucho cuidado al crear un nuevo tipo preferido dentro de una categoría de tipo existente, ya que esto podría causar cambios sorprendentes en el comportamiento.

por_defecto

El valor por defecto para el tipo de datos. Si se omite, el valor por defecto es nulo.

elemento

El tipo que se está creando es un array; esto especifica el tipo de los elementos del array.

delimitador

El carácter delimitador que se utilizará entre los valores en los arrays formados por este tipo.

ordenable

True si las operaciones de este tipo pueden usar información de ordenación. El valor por defecto es false.

Notas

Dado que no existen restricciones sobre el uso de un tipo de datos una vez que se ha creado, la creación de un tipo base o tipo de rango equivale a otorgar permiso público de ejecución sobre las funciones mencionadas en la definición del tipo. Esto no suele ser un problema para los tipos de funciones que son útiles en una definición de tipo. Pero tal vez quieras pensarlo dos veces antes de diseñar un tipo de manera que requiera información secreta para ser utilizada al convertirlo a o desde su forma externa.

Antes de la versión 8.3 de PostgreSQL, el nombre de un tipo de array generado era siempre exactamente el nombre del tipo de elemento con un carácter de subrayado (_) antepuesto. (Por lo tanto, los nombres de tipo estaban restringidos en longitud a un carácter menos que otros nombres). Aunque esto sigue siendo el caso habitual, el nombre del tipo de array puede variar de esto en caso de nombres de longitud máxima o colisiones con nombres de tipo de usuario que comienzan con subrayado. Por lo tanto, se desaconseja escribir código que dependa de esta convención. En su lugar, utiliza pg_type.typarray para localizar el tipo de array asociado con un tipo dado.

Puede ser aconsejable evitar el uso de nombres de tipo y de tabla que comiencen con subrayado. Aunque el servidor cambiará los nombres de los tipos de array generados para evitar colisiones con los nombres proporcionados por el usuario, sigue existiendo el riesgo de confusión, especialmente con el software cliente antiguo que puede asumir que los nombres de tipo que comienzan con subrayado representan siempre arrays.

Antes de la versión 8.2 de PostgreSQL, la sintaxis de creación de tipo shell CREATE TYPE nombre no existía. La forma de crear un nuevo tipo base era crear primero su función de entrada. Con este enfoque, PostgreSQL verá primero el nombre del nuevo tipo de datos como el tipo de retorno de la función de entrada. El tipo shell se crea implícitamente en esta situación, y luego se puede hacer referencia a él en las definiciones de las funciones de E/S restantes. Este enfoque sigue funcionando, pero está obsoleto y podría no estar permitido en alguna versión futura. Además, para evitar abarrotar accidentalmente los catálogos con tipos shell como resultado de simples errores tipográficos en las definiciones de funciones, solo se creará un tipo shell de esta manera cuando la función de entrada esté escrita en C.

En la versión 16 de PostgreSQL y posteriores, es deseable que las funciones de entrada de los tipos base devuelvan errores suaves utilizando el nuevo mecanismo errsave()/ereturn(), en lugar de lanzar excepciones ereport() como en versiones anteriores. Consulta src/backend/utils/fmgr/README para obtener más información.

Ejemplos

Este ejemplo crea un tipo compuesto y lo utiliza en la definición de una función:

CREATE TYPE compfoo AS (f1 int, f2 text);

CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$
    SELECT fooid, fooname FROM foo
$$ LANGUAGE SQL;

Este ejemplo crea un tipo enumerado y lo utiliza en la definición de una tabla:

CREATE TYPE status_bicho AS ENUM ('nuevo', 'abierto', 'cerrado');

CREATE TABLE bicho (
    id serial,
    description text,
    status status_bicho
);

Este ejemplo crea un tipo de rango:

CREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);

Este ejemplo crea el tipo de datos base box y luego utiliza el tipo en la definición de una tabla:

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

Si la estructura interna de box fuera un array de cuatro elementos float4, podríamos usar en su lugar:

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

lo que permitiría acceder a los números de los componentes de un valor de caja mediante subíndices. Por lo demás, el tipo se comporta igual que antes.

Este ejemplo crea un tipo de objeto grande y lo utiliza en la definición de una tabla:

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

Más ejemplos, incluyendo funciones adecuadas de entrada y salida, se encuentran en Section 36.13.

Compatibilidad

La primera forma del comando CREATE TYPE, que crea un tipo compuesto, cumple con el estándar SQL. Las otras formas son extensiones de PostgreSQL. El comando CREATE TYPE en el estándar SQL también define otras formas que no están implementadas en PostgreSQL.

La capacidad de crear un tipo compuesto con cero atributos es una desviación específica de PostgreSQL con respecto al estándar (análoga al mismo caso en CREATE TABLE).

Consulte también

ALTER TYPE, CREATE DOMAIN, CREATE FUNCTION, DROP TYPE