PostgreSQL 数据类型可分为基本类型、容器类型、域和伪类型。
基本类型即如 integer
之类的,它们在SQL语言层面以下(通常在 C 等低级语言中)实现。它们通常对应所谓的抽象数据类型。只有通过用户提供的函数,PostgreSQL 才能对该类类型进行操作,并且仅在用户描述的范围内理解该类类型的行为。内置基本类型将在 第 8 章 中进行描述。
枚举类型 (enum) 可视为基本类型的子类别。主要区别在于,使用SQL命令,无需任何低级别编程。有关详细信息,请参阅第 8.7 节。
PostgreSQL有三种“容器”类型,它们是包含其他类型的多个值。它们是数组、复合和范围。
数组可以保存所有同类型的多个值。将为每个基础类型、复合类型、范围类型以及域类型自动创建一个数组类型。但不存在数组的数组。就类型系统而言,多维数组与一维数组相同。有关详细信息,请参阅第 8.15 节。
每当用户创建一个表时,就会创建复合类型或行类型。也可以使用CREATE TYPE定义没有关联表的“独立”复合类型。复合类型仅仅是带关联字段名的类型列表。复合类型的值是字段值的行或记录。有关详细信息,请参阅第 8.16 节。
范围类型可以保留相同类型的两个值,即范围的下界和上界。范围类型是用户创建的,虽然存在一些内置范围类型。有关详细信息,请参阅第 8.17 节。
域基于特定的底层类型,并且在很多方面可以与其底层类型互换。但是,域可以拥有约束,将其有效值限制为底层类型允许值的子集。使用SQL命令 CREATE DOMAIN创建域。有关详细信息,请参阅第 8.18 节。
有几个用于特殊目的的“伪类型”。伪类型不能显示为表或容器类型的组件的列,但它们可用于声明函数的参数和结果类型。这提供了一种机制,用于在类型系统内识别特殊类的函数。表 8.27列出了现有的伪类型。
一些特殊利益的伪类型是多态类型,它们用于声明多态函数。这个强大的功能使得一个函数定义能够处理许多不同的数据类型,具体的数据类型由在特定调用中实际传递给它的数据类型决定。多态类型显示在表 36.1中。一些使用示例出现在第 36.5.11 节中。
表 36.1. 多态类型
名称 | 系列 | 描述 |
---|---|---|
anyelement |
简单 | 指示函数接受任何数据类型 |
anyarray |
简单 | 指示函数接受任何数组数据类型 |
anynonarray |
简单 | 指示函数接受任何非数组数据类型 |
anyenum |
简单 | 指示函数接受任何枚举数据类型(请参阅第 8.7 节) |
anyrange |
简单 | 指示函数接受任何范围数据类型(请参阅第 8.17 节) |
anymultirange |
简单 | 指示函数接受任何多范围数据类型(请参阅第 8.17 节) |
anycompatible |
通用 | 指示函数接受任何数据类型,并自动将多个参数提升为一个通用数据类型 |
anycompatiblearray |
通用 | 指示函数接受任何数组数据类型,并自动将多个参数提升为一个通用数据类型 |
anycompatiblenonarray |
通用 | 指示函数接受任何非数组数据类型,并自动将多个参数提升为一个通用数据类型 |
anycompatiblerange |
通用 | 指示函数接受任何范围数据类型,并自动将多个参数提升为一个通用数据类型 |
anycompatiblemultirange |
通用 | 指示函数接受任何多范围数据类型,并自动将多个参数提升为一个通用数据类型 |
多态参数和结果相互关联,并在解析调用多态函数的查询时解析为特定数据类型。如果有多个多态参数,输入值的实际数据类型必须按如下描述相匹配。如果函数的结果类型是多态的,或者它具有多态类型的输出参数,则这些结果的类型将按如下描述从多态输入的实际类型中推断出来。
对于”““simple”多态类型系列,匹配和推断规则的工作方式如下
声明为 anyelement
的每个位置(无论是参数还是返回值)都被允许具有任何具体实际数据类型,但在任何给定的调用中,它们都必须是相同实际类型。声明为 anyarray
的每个位置可以具有任何数组数据类型,但类似地,它们都必须是相同的类型。同样,声明为 anyrange
的位置都必须是相同的范围类型。对 anymultirange
也是如此。
此外,如果有一些位置声明为 anyarray
,其他位置声明为 anyelement
,那么 anyarray
位置中的实际数组类型必须是有元素与出现在 anyelement
位置中相同类型的数组。anynonarray
被视为与 anyelement
完全相同,但增加了实际类型必须是非数组类型的附加约束。anyenum
被视为与 anyelement
完全相同,但增加了实际类型必须是枚举类型的附加约束。
类似地,如果有一些位置声明为 anyrange
,其他位置声明为 anyelement
或 anyarray
,那么 anyrange
位置中的实际范围类型必须是一个子类型与出现在 anyelement
位置中相同类型的范围,并且与 anyarray
位置的元素类型相同。如果有位置声明为 anymultirange
,它们的实际多范围类型必须包含与声明为 anyrange
的参数匹配的范围,以及与声明为 anyelement
和 anyarray
的参数匹配的基本元素。
因此,当多个参数位置声明为具有多态类型时,最终效果是只有允许的特定实际参数类型组合。例如,声明为 equal(anyelement, anyelement)
的函数将接受任何两个输入值,只要它们具有相同的数据类型即可。
当函数的返回值声明为多态类型时,至少必须有一个参数位置也多态,并且为多态参数提供实际数据类型将确定该调用的实际结果类型。例如,如果没有数组下标机制,可以定义一个函数来实现下标为 subscript(anyarray, integer) 返回 anyelement
。该声明将实际第一个参数限制为数组类型,并允许解析器根据实际第一个参数的类型推断出正确的结果类型。另一个示例是声明为 f(anyarray) 返回 anyenum
的函数,它只接受枚举类型的数组。
在大多数情况下,解析器可以从同一系列中不同多态类型的参数推断出多态结果类型的实际数据类型;例如,anyarray
可以从 anyelement
中推导出来,反之亦然。但有一个例外是,类型为 anyrange
的多态结果需要 anyrange
类型的参数;它不能从 anyarray
或 anyelement
参数中推导出来。这是因为具有相同子类型的范围类型可能有多个。
请注意,anynonarray
和 anyenum
并不表示单独的类型变量;它们与 anyelement
是同一种类型,只是增加了一个约束。例如,将函数声明为 f(anyelement, anyenum)
等同于声明为 f(anyenum, anyenum)
:两个实际参数都必须是同一种枚举类型。
对于“公用”多态类型系列,匹配和推断规则与“简单”系列的工作方式大致相同,有一个主要区别:参数的实际类型不必相同,只要它们可以隐式强制转换为一种公用类型即可。根据与 UNION
和相关构造相同的规则选择公用类型(请参见 第 10.5 节)。公用类型的选择考虑 anycompatible
和 anycompatiblenonarray
输入的实际类型,anycompatiblearray
输入的数组元素类型,anycompatiblerange
输入的范围子类型以及 anycompatiblemultirange
输入的多范围子类型。如果存在 anycompatiblenonarray
,则公用类型要求是非数组类型。一旦确定了公用类型,anycompatible
和 anycompatiblenonarray
位置的参数将自动强制转换为该类型,anycompatiblearray
位置的参数将自动强制转换为该类型的数组类型。
由于无法光靠它的子类型来选择一个范围类型,因此 anycompatiblerange
和/或 anycompatiblemultirange
的使用要求所有使用这种类型的参数具有相同实际范围和/或多重范围类型,并且该类型的子类型与选定的公共类型一直,以免需要范围值的转换。与 anyrange
和 anymultirange
一样,将 anycompatiblerange
和 anymultirange
用作函数结果类型要求有一个 anycompatiblerange
或 anycompatiblemultirange
参数。
注意,没有 anycompatibleenum
类型。这样的类型并非十分有用,因为通常情况下枚举类型没有隐式转换,也就是说,无法为不相同的枚举输入确定一个公共类型。
“simple” 和 “common” 多态族代表两组独立的类型变量。例如,考虑
CREATE FUNCTION myfunc(a anyelement, b anyelement, c anycompatible, d anycompatible) RETURNS anycompatible AS ...
在此函数的实际调用中,前两个输入必须完全具有相同类型。最后两个输入必须可提升为一个公共类型,但此类型不需要与前两个输入的类型有任何关系。结果将具有最后两个输入的公共类型。
一个可变参数函数(采用可变数量参数,如 第 36.5.6 节 中)可以是多态的:通过将其最后一个参数声明为 VARIADIC
anyarray
或 VARIADIC
anycompatiblearray
可以实现这一点。对于参数匹配和确定实际结果类型,此类函数的行为与您编写了适当数量的 anynonarray
或 anycompatiblenonarray
参数一样。