CREATE TYPE — define un nuevo tipo de datos
CREATE TYPEnombreAS ( [nombre_atributotipo_datos[ COLLATEordenación] [, ... ] ] ) CREATE TYPEnombreAS ENUM ( [ 'etiqueta' [, ... ] ] ) CREATE TYPEnombreAS 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 TYPEnombre( 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 TYPEnombre
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.
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.
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).
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
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.
nombre
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.
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 sin parámetros adicionales. Luego, las funciones de E/S de C se pueden
definir haciendo referencia al tipo shell. Finalmente, nombreCREATE 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.
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.
nombreEl nombre (opcionalmente calificado por esquema) de un tipo que se va a crear.
nombre_atributoEl nombre de un atributo (columna) para el tipo compuesto.
tipo_datosEl nombre de un tipo de datos existente que se convertirá en una columna del tipo compuesto.
ordenaciónEl nombre de una ordenación existente que se asociará con una columna de un tipo compuesto o con un tipo de rango.
etiquetaUn literal de cadena que representa la etiqueta de texto asociada con un valor de un tipo enum.
subtipoEl nombre del tipo de elemento del cual el tipo de rango representará rangos.
clase_op_subtipoEl nombre de una clase de operador b-tree para el subtipo.
función_canónicaEl nombre de la función de canonización para el tipo de rango.
función_dif_subtipoEl nombre de una función de diferencia para el subtipo.
nombre_tipo_multirangoEl nombre del tipo multirango correspondiente.
función_entradaEl nombre de una función que convierte datos de la forma textual externa del tipo a su forma interna.
función_salidaEl nombre de una función que convierte datos de la forma interna del tipo a su forma textual externa.
función_recepciónEl nombre de una función que convierte datos de la forma binaria externa del tipo a su forma interna.
función_envíoEl nombre de una función que convierte datos de la forma interna del tipo a su forma binaria externa.
función_entrada_mod_tipoEl nombre de una función que convierte un array de modificadores para el tipo a su forma interna.
función_salida_mod_tipoEl nombre de una función que convierte la forma interna de los modificadores del tipo a su forma textual externa.
función_analyzeEl nombre de una función que realiza el análisis estadístico para el tipo de datos.
función_subíndiceEl nombre de una función que define qué hace el subindexado de un valor del tipo de datos.
longitud_internaUna 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.
preferidoTrue 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_defectoEl valor por defecto para el tipo de datos. Si se omite, el valor por defecto es nulo.
elementoEl tipo que se está creando es un array; esto especifica el tipo de los elementos del array.
delimitadorEl carácter delimitador que se utilizará entre los valores en los arrays formados por este tipo.
ordenableTrue si las operaciones de este tipo pueden usar información de ordenación. El valor por defecto es false.
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
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.
nombre
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.
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.
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).