Los tipos de datos de PostgreSQL se pueden dividir en tipos base, tipos contenedores, dominios y pseudotipos.
Los tipos base son aquellos, como integer, que se implementan por debajo del
nivel del lenguaje SQL (típicamente en un lenguaje de bajo nivel como C).
Generalmente corresponden a lo que a menudo se conoce como tipos de datos abstractos.
PostgreSQL solo puede operar en tales tipos a través de
funciones proporcionadas por el usuario y solo comprende el comportamiento de tales tipos
en la medida en que el usuario los describa. Los tipos base integrados se describen en
la sección Chapter 8.
Los tipos enumerados (enum) se pueden considerar como una subcategoría de los tipos base. La diferencia principal es que se pueden crear utilizando únicamente comandos SQL, sin ninguna programación de bajo nivel. Consulta la sección Section 8.7 para obtener más información.
PostgreSQL tiene tres tipos de “contenedores”, que son tipos que contienen múltiples valores de otros tipos. Estos son arrays, compuestos y rangos.
Los arrays pueden contener múltiples valores que son todos del mismo tipo. Se crea automáticamente un tipo de array para cada tipo base, tipo compuesto, tipo de rango y tipo de dominio. Pero no hay arrays de arrays. En lo que respecta al sistema de tipos, los arrays multidimensionales son lo mismo que los arrays unidimensionales. Consulta la sección Section 8.15 para obtener más información.
Los tipos compuestos, o tipos de fila, se crean cada vez que el usuario crea una tabla. También es posible utilizar CREATE TYPE para definir un tipo compuesto “independiente” sin ninguna tabla asociada. Un tipo compuesto es simplemente una lista de tipos con nombres de campos asociados. Un valor de un tipo compuesto es una fila o registro de valores de campos. Consulta la sección Section 8.16 para obtener más información.
Un tipo de rango puede contener dos valores del mismo tipo, que son los límites inferior y superior del rango. Los tipos de rango son creados por el usuario, aunque existen algunos integrados. Consulta la sección Section 8.17 para obtener más información.
Un dominio se basa en un tipo subyacente particular y, para muchos propósitos, es intercambiable con su tipo subyacente. Sin embargo, un dominio puede tener restricciones que limitan sus valores válidos a un subconjunto de lo que permitiría el tipo subyacente. Los dominios se crean utilizando el comando SQL CREATE DOMAIN. Consulta la sección Section 8.18 para obtener más información.
Existen algunos “pseudotipos” para propósitos especiales. Los pseudotipos no pueden aparecer como columnas de tablas o componentes de tipos contenedores, pero se pueden utilizar para declarar los tipos de argumento y resultado de las funciones. Esto proporciona un mecanismo dentro del sistema de tipos para identificar clases especiales de funciones. La tabla Table 8.27 enumera los pseudotipos existentes.
Algunos pseudotipos de especial interés son los tipos polimórficos, que se utilizan para declarar funciones polimórficas. Esta potente característica permite que una única definición de función funcione en muchos tipos de datos diferentes, determinándose el tipo o tipos de datos específicos según los tipos de datos realmente pasados en una llamada concreta. Los tipos polimórficos se muestran en la tabla Table 36.1. Algunos ejemplos de su uso aparecen en la sección Section 36.5.11.
Table 36.1. Tipos polimórficos
| Nombre | Familia | Descripción |
|---|---|---|
anyelement | Simple | Indica que una función acepta cualquier tipo de datos |
anyarray | Simple | Indica que una función acepta cualquier tipo de datos de tipo array |
anynonarray | Simple | Indica que una función acepta cualquier tipo de datos que no sea de tipo array |
anyenum | Simple | Indica que una función acepta cualquier tipo de datos de tipo enum (ver Section 8.7) |
anyrange | Simple | Indica que una función acepta cualquier tipo de datos de tipo rango (ver Section 8.17) |
anymultirange | Simple | Indica que una función acepta cualquier tipo de datos de tipo multirango (ver Section 8.17) |
anycompatible | Común (Common) | Indica que una función acepta cualquier tipo de datos, con promoción automática de múltiples argumentos a un tipo de datos común |
anycompatiblearray | Común | Indica que una función acepta cualquier tipo de datos de tipo array, con promoción automática de múltiples argumentos a un tipo de datos común |
anycompatiblenonarray | Común | Indica que una función acepta cualquier tipo de datos que no sea de tipo array, con promoción automática de múltiples argumentos a un tipo de datos común |
anycompatiblerange | Común | Indica que una función acepta cualquier tipo de datos de tipo rango, con promoción automática de múltiples argumentos a un tipo de datos común |
anycompatiblemultirange | Común | Indica que una función acepta cualquier tipo de datos de tipo multirango, con promoción automática de múltiples argumentos a un tipo de datos común |
Los argumentos y resultados polimórficos están vinculados entre sí y se resuelven a tipos de datos específicos cuando se analiza una consulta que llama a una función polimórfica. Cuando hay más de un argumento polimórfico, los tipos de datos reales de los valores de entrada deben coincidir como se describe a continuación. Si el tipo de resultado de la función es polimórfico, o tiene parámetros de salida de tipos polimórficos, los tipos de esos resultados se deducen a partir de los tipos reales de las entradas polimórficas como se describe a continuación.
Para la familia “simple” de tipos polimórficos, las reglas de coincidencia y deducción funcionan de la siguiente manera:
Cada posición (ya sea argumento o valor de retorno) declarada como anyelement puede
tener cualquier tipo de datos real específico, pero en cualquier llamada dada todos deben ser el
mismo tipo real. Cada posición declarada como anyarray puede
tener cualquier tipo de datos de tipo array, pero de manera similar todos deben ser del mismo tipo.
Y de manera similar, las posiciones declaradas como anyrange deben ser todas del mismo
tipo de rango. Del mismo modo para anymultirange.
Además, si hay posiciones declaradas como anyarray y otras declaradas como
anyelement, el tipo de array real en las posiciones anyarray debe ser
un array cuyos elementos sean del mismo tipo que aparece en las posiciones anyelement.
El tipo anynonarray se trata exactamente igual que anyelement, pero añade
la restricción adicional de que el tipo real no debe ser un tipo array. El tipo anyenum
se trata exactamente igual que anyelement, pero añade la restricción adicional de que
el tipo real debe ser un tipo enum.
Del mismo modo, si hay posiciones declaradas como anyrange y otras declaradas como
anyelement o anyarray, el tipo de rango real en las posiciones
anyrange debe ser un rango cuyo subtipo sea del mismo tipo que aparece en las posiciones
anyelement y el mismo que el tipo de elemento de las posiciones anyarray.
Si hay posiciones declaradas como anymultirange, su tipo multirango real debe contener
rangos que coincidan con los parámetros declarados como anyrange y elementos base que
coincidan con los parámetros declarados como anyelement y anyarray.
Por lo tanto, cuando se declara más de una posición de argumento con un tipo polimórfico, el efecto
neto es que solo se permiten ciertas combinaciones de tipos de argumentos reales. Por ejemplo, una
función declarada como equal(anyelement, anyelement) aceptará dos valores de entrada
cualesquiera, siempre que sean del mismo tipo de datos.
Cuando el valor de retorno de una función se declara como un tipo polimórfico, debe haber al menos una
posición de argumento que también sea polimórfica, y el tipo o tipos de datos reales proporcionados
para los argumentos polimórficos determinan el tipo de resultado real para esa llamada. Por ejemplo, si
no existiera ya un mecanismo de indexación de arrays, se podría definir una función que implemente
la indexación como subscript(anyarray, integer) returns anyelement. Esta declaración
obliga a que el primer argumento real sea un tipo de array, y permite al analizador inferir el tipo de
resultado correcto a partir del tipo del primer argumento real. Otro ejemplo es que una función declarada
como f(anyarray) returns anyenum solo aceptará arrays de tipos enum.
En la mayoría de los casos, el analizador puede inferir el tipo de datos real para un tipo de resultado
polimórfico a partir de argumentos que son de un tipo polimórfico diferente en la misma familia; por
ejemplo, anyarray se puede deducir de anyelement o viceversa. Una excepción es
que un resultado polimórfico de tipo anyrange requiere un argumento de tipo
anyrange; no se puede deducir a partir de argumentos anyarray o
anyelement. Esto se debe a que podría haber múltiples tipos de rango con el mismo subtipo.
Ten en cuenta que anynonarray y anyenum no representan variables de tipo
independientes; son el mismo tipo que anyelement, solo que con una restricción adicional.
Por ejemplo, declarar una función como f(anyelement, anyenum) equivale a declararla
como f(anyenum, anyenum): ambos argumentos reales deben ser del mismo tipo enum.
Para la familia “común” de tipos polimórficos, las reglas de coincidencia y deducción
funcionan de forma aproximadamente similar a la de la familia “simple”, con una diferencia
importante: los tipos reales de los argumentos no necesitan ser idénticos, siempre que se puedan
convertir implícitamente a un único tipo común. El tipo común se selecciona siguiendo las mismas
reglas que para UNION y construcciones relacionadas (ver Section 10.5). La selección del tipo común considera los tipos reales de las entradas
anycompatible y anycompatiblenonarray, los tipos de elementos de array de las
entradas anycompatiblearray, los subtipos de rango de las entradas
anycompatiblerange y los subtipos multirango de las entradas
anycompatiblemultirange. Si anycompatiblenonarray está presente, se requiere
que el tipo común sea un tipo que no sea array. Una vez identificado un tipo común, los argumentos en
las posiciones anycompatible y anycompatiblenonarray se convierten
automáticamente a ese tipo, y los argumentos en las posiciones anycompatiblearray se
convierten automáticamente al tipo array para ese tipo.
Dado que no hay forma de seleccionar un tipo de rango conociendo únicamente su subtipo, el uso de
anycompatiblerange y/o anycompatiblemultirange requiere que todos los
argumentos declarados con ese tipo tengan el mismo tipo de rango y/o multirango real, y que el subtipo
de ese tipo coincida con el tipo común seleccionado, de modo que no se requiera conversión de los
valores del rango. Al igual que con anyrange y anymultirange, el uso de
anycompatiblerange y anycompatiblemultirange como tipo de resultado de una
función requiere que exista un argumento de tipo anycompatiblerange o
anycompatiblemultirange.
Observa que no existe un tipo anycompatibleenum. Dicho tipo no sería muy útil, ya que
normalmente no existen conversiones implícitas a tipos enum, lo que significa que no habría forma de
resolver un tipo común para entradas de enum diferentes.
Las familias polimórficas “simple” y “común” representan dos conjuntos independientes de variables de tipo. Considera por ejemplo:
CREATE FUNCTION myfunc(a anyelement, b anyelement,
c anycompatible, d anycompatible)
RETURNS anycompatible AS ...
En una llamada real a esta función, las dos primeras entradas deben tener exactamente el mismo tipo. Las dos últimas entradas deben ser promovibles a un tipo común, pero este tipo no tiene por qué tener nada que ver con el tipo de las dos primeras entradas. El resultado tendrá el tipo común de las dos últimas entradas.
Una función variádica (una que toma un número variable de argumentos, como en la sección
Section 36.5.6) puede ser polimórfica: esto se logra declarando
su último parámetro como VARIADIC anyarray o VARIADIC
anycompatiblearray. Para fines de coincidencia de argumentos y determinación del tipo de
resultado real, dicha función se comporta de la misma manera que si se hubiera escrito el número
adecuado de parámetros anynonarray o anycompatiblenonarray.