36.2. El sistema de tipos de PostgreSQL #

36.2.1. Tipos base
36.2.2. Tipos contenedores
36.2.3. Dominios
36.2.4. Pseudotipos
36.2.5. Tipos polimórficos

Los tipos de datos de PostgreSQL se pueden dividir en tipos base, tipos contenedores, dominios y pseudotipos.

36.2.1. Tipos base #

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.

36.2.2. Tipos contenedores #

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.

36.2.3. Dominios #

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.

36.2.4. Pseudotipos #

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.

36.2.5. Tipos polimórficos #

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

NombreFamiliaDescripción
anyelementSimpleIndica que una función acepta cualquier tipo de datos
anyarraySimpleIndica que una función acepta cualquier tipo de datos de tipo array
anynonarraySimpleIndica que una función acepta cualquier tipo de datos que no sea de tipo array
anyenumSimpleIndica que una función acepta cualquier tipo de datos de tipo enum (ver Section 8.7)
anyrangeSimpleIndica que una función acepta cualquier tipo de datos de tipo rango (ver Section 8.17)
anymultirangeSimpleIndica que una función acepta cualquier tipo de datos de tipo multirango (ver Section 8.17)
anycompatibleComú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
anycompatiblearrayComúnIndica 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
anycompatiblenonarrayComúnIndica 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
anycompatiblerangeComúnIndica 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
anycompatiblemultirangeComúnIndica 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.