38.2.PostgreSQL类型系统#
PostgreSQL数据类型可分为基本类型、容器类型、域和伪类型。
38.2.1. 基本类型#
基本类型是指那些在SQL语言级别以下(通常使用 C 等底层语言)实现的类型,例如integer
。它们通常对应于通常所说的抽象数据类型。PostgreSQL只能通过用户提供的函数操作此类类型,并且仅在用户描述的范围内理解此类类型的行为。内置基本类型在第 8 章中进行了描述。
枚举 (enum) 类型可被视为基本类型的子类别。主要区别在于它们可以使用纯SQL命令创建,而无需任何底层编程。有关更多信息,请参阅第 8.7 节。
38.2.2. 容器类型#
PostgreSQL有三种“容器”类型,它们是包含其他类型多个值的类型。它们是数组、复合类型和范围。
数组可以容纳所有类型相同的多个值。为每个基本类型、复合类型、范围类型和域类型自动创建数组类型。但是没有数组的数组。就类型系统而言,多维数组与一维数组相同。有关更多信息,请参阅第 8.15 节。
每当用户创建表时,就会创建复合类型或行类型。还可以使用CREATE TYPE定义没有关联表的“独立”复合类型。复合类型只是具有关联字段名称的类型列表。复合类型的值是字段值的行或记录。有关更多信息,请参阅第 8.16 节。
范围类型可以容纳相同类型的两个值,它们是范围的下限和上限。范围类型是用户创建的,尽管存在一些内置的范围类型。有关更多信息,请参阅第 8.17 节。
38.2.3. 域#
域基于特定的底层类型,并且出于许多目的,可以与其底层类型互换。但是,域可以具有约束,将其有效值限制为底层类型允许的值的子集。使用SQL命令CREATE DOMAIN创建域。有关更多信息,请参阅第 8.18 节。
38.2.4. 伪类型#
有一些用于特殊目的的“伪类型”。伪类型不能作为表的列或容器类型的组件出现,但它们可以用来声明函数的参数和结果类型。这提供了类型系统中识别特殊类函数的机制。表 8.27列出了现有的伪类型。
38.2.5. 多态类型#
一些具有特殊意义的伪类型是多态类型,用于声明多态函数。此强大功能允许单个函数定义对许多不同数据类型进行操作,具体数据类型由在特定调用中实际传递给它的数据类型确定。多态类型显示在表 38.1中。一些使用示例出现在第 38.5.11 节中。
表 38.1. 多态类型
名称 | 系列 | 说明 |
---|---|---|
anyelement | 简单 | 表示函数接受任何数据类型 |
anyarray | 简单 | 表示函数接受任何数组数据类型 |
anynonarray | 简单 | 表示函数接受任何非数组数据类型 |
anyenum | 简单 | 表示函数接受任何枚举数据类型(参见第 8.7 节) |
anyrange | 简单 | 表示函数接受任何范围数据类型(参见第 8.17 节) |
anymultirange | 简单 | 表示函数接受任何多范围数据类型(参见第 8.17 节) |
anycompatible | 通用 | 表示函数接受任何数据类型,并自动将多个参数提升为通用数据类型 |
anycompatiblearray | 通用 | 表示函数接受任何数组数据类型,并自动将多个参数提升为通用数据类型 |
anycompatiblenonarray | 通用 | 表示函数接受任何非数组数据类型,并自动将多个参数提升为通用数据类型 |
anycompatiblerange | 通用 | 表示函数接受任何范围数据类型,并自动将多个参数提升为通用数据类型 |
anycompatiblemultirange | 通用 | 表示函数接受任何多范围数据类型,并自动将多个参数提升为通用数据类型 |
多态参数和结果相互关联,并在解析调用多态函数的查询时解析为特定数据类型。如果有多个多态参数,则输入值的实际数据类型必须按如下所述进行匹配。如果函数的结果类型是多态的,或者它具有多态类型的输出参数,则这些结果的类型将按如下所述从多态输入的实际类型中推断出来。
对于“简单”多态类型系列,匹配和推断规则如下
声明为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) returns anyelement
。此声明将实际第一个参数限定为数组类型,并允许解析器从实际第一个参数的类型推断出正确的结果类型。另一个示例是,声明为f(anyarray) returns anyenum
的函数将仅接受枚举类型的数组。
在大多数情况下,解析器可以从同一系列中不同多态类型的参数推断出多态结果类型的实际数据类型;例如,可以从anyelement
推断出anyarray
,反之亦然。一个例外是,类型为anyrange
的多态结果需要一个类型为anyrange
的参数;无法从anyarray
或anyelement
参数推断出它。这是因为可能有多个具有相同子类型的范围类型。
请注意,anynonarray
和anyenum
并不表示单独的类型变量;它们与anyelement
类型相同,只是具有附加约束。例如,将函数声明为f(anyelement, anyenum)
等同于将其声明为f(anyenum, anyenum)
:两个实际参数必须是相同的枚举类型。
对于““common””多态类型系列,匹配和推断规则与““simple””系列大致相同,但有一个主要区别:参数的实际类型不必相同,只要它们可以隐式转换为一个公共类型即可。公共类型按照与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 ...
在此函数的实际调用中,前两个输入必须具有完全相同的类型。最后两个输入必须可提升为通用类型,但此类型不必与前两个输入的类型有任何关系。结果将具有最后两个输入的通用类型。
可变函数(采用可变数量的参数,如第 38.5.6 节中所示)可以是多态的:通过将其最后一个参数声明为VARIADIC``anyarray
或VARIADIC``anycompatiblearray
来实现这一点。在参数匹配和确定实际结果类型时,此类函数的行为与编写适当数量的anynonarray
或anycompatiblenonarray
参数相同。