支持的版本:当前 (17) / 16 / 15 / 14 / 13
开发版本:devel
不支持的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4

36.2. PostgreSQL 类型系统 #

PostgreSQL 数据类型可以分为基本类型、容器类型、域和伪类型。

36.2.1. 基本类型 #

基本类型是指那些像 integer 这样的类型,它们是在SQL语言级别之下实现的(通常使用 C 等低级语言)。它们通常对应于通常所说的抽象数据类型。PostgreSQL 只能通过用户提供的函数来操作此类类型,并且仅在用户描述它们的程度内了解此类类型的行为。内置的基本类型在第 8 章中进行了描述。

枚举(enum)类型可以被认为是基本类型的一个子类别。主要区别在于它们可以使用简单的SQL命令来创建,而无需任何低级编程。有关更多信息,请参阅第 8.7 节

36.2.2. 容器类型 #

PostgreSQL 有三种 容器 类型,它们是包含其他类型的多个值的类型。这些类型是数组、复合类型和范围。

数组可以保存多个相同类型的值。为每个基本类型、复合类型、范围类型和域类型自动创建一个数组类型。但是,没有数组的数组。就类型系统而言,多维数组与一维数组相同。有关更多信息,请参阅第 8.15 节

当用户创建表时,就会创建复合类型或行类型。也可以使用 CREATE TYPE 来定义没有关联表的 独立 复合类型。复合类型只是一个带有相关字段名称的类型列表。复合类型的值是一行或一条记录的字段值。有关更多信息,请参阅第 8.16 节

范围类型可以保存两个相同类型的值,这两个值是范围的下限和上限。范围类型是用户创建的,尽管存在一些内置的范围类型。有关更多信息,请参阅第 8.17 节

36.2.3. 域 #

域基于特定的底层类型,并且在许多情况下可以与其底层类型互换。但是,域可以具有约束,这些约束将域的有效值限制为底层类型允许的子集。域是使用SQLCREATE DOMAIN 命令创建的。有关更多信息,请参阅第 8.18 节

36.2.4. 伪类型 #

有一些用于特殊用途的 伪类型。伪类型不能作为表的列或容器类型的组成部分出现,但是它们可以用来声明函数的参数和结果类型。这在类型系统中提供了一种机制来识别特殊的函数类。表 8.27 列出了现有的伪类型。

36.2.5. 多态类型 #

一些特别值得关注的伪类型是多态类型,它们用于声明多态函数。这种强大的功能允许单个函数定义对许多不同的数据类型进行操作,具体的(多个)数据类型由特定调用中实际传递给它的数据类型确定。多态类型显示在表 36.1中。它们的一些使用示例出现在第 36.5.11 节中。

表 36.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 的位置和其他声明为 anyelementanyarray 的位置,则 anyrange 位置中的实际范围类型必须是一个范围,其子类型与 anyelement 位置中出现的类型相同,并且与 anyarray 位置的元素类型相同。如果存在声明为 anymultirange 的位置,则它们的实际多范围类型必须包含与声明为 anyrange 的参数匹配的范围,以及与声明为 anyelementanyarray 的参数匹配的基本元素。

因此,当多个参数位置被声明为多态类型时,最终的效果是只允许实际参数类型的某些组合。例如,声明为 equal(anyelement, anyelement) 的函数将接受任何两个输入值,只要它们是相同的数据类型即可。

当函数的返回值被声明为多态类型时,必须至少有一个参数位置也是多态的,并且为多态参数提供的实际数据类型决定了该调用的实际结果类型。例如,如果还没有数组下标机制,可以定义一个实现下标的函数,如 subscript(anyarray, integer) returns anyelement。这个声明约束了第一个实际参数必须是数组类型,并允许解析器从第一个实际参数的类型推断出正确的结果类型。另一个例子是,声明为 f(anyarray) returns anyenum 的函数将只接受枚举类型的数组。

在大多数情况下,解析器可以从同一家族中不同多态类型的参数推断出多态结果类型的实际数据类型;例如,可以从 anyelement 推导出 anyarray,反之亦然。一个例外是,类型为 anyrange 的多态结果需要一个类型为 anyrange 的参数;它不能从 anyarrayanyelement 参数推导出来。这是因为可能存在具有相同子类型的多个范围类型。

请注意,anynonarrayanyenum 并不代表单独的类型变量;它们与 anyelement 类型相同,只是增加了额外的约束。例如,将函数声明为 f(anyelement, anyenum) 等同于将其声明为 f(anyenum, anyenum):两个实际参数都必须是相同的枚举类型。

对于多态类型的“公共”家族,匹配和推导规则与“简单”家族大致相同,但有一个主要区别:参数的实际类型不需要完全相同,只要它们可以隐式转换为单个公共类型。公共类型的选择遵循与 UNION 和相关构造相同的规则(请参见 第 10.5 节)。公共类型的选择考虑了 anycompatibleanycompatiblenonarray 输入的实际类型,anycompatiblearray 输入的数组元素类型,anycompatiblerange 输入的范围子类型,以及 anycompatiblemultirange 输入的多范围子类型。如果存在 anycompatiblenonarray,则公共类型必须是非数组类型。一旦确定了公共类型,anycompatibleanycompatiblenonarray 位置的参数将自动转换为该类型,anycompatiblearray 位置的参数将自动转换为该类型的数组类型。

由于在仅知道其子类型的情况下无法选择范围类型,因此使用 anycompatiblerange 和/或 anycompatiblemultirange 需要所有使用该类型声明的参数都具有相同的实际范围和/或多范围类型,并且该类型的子类型与所选的公共类型一致,这样就不需要对范围值进行类型转换。与 anyrangeanymultirange 一样,将 anycompatiblerangeanymultirange 用作函数结果类型需要有一个 anycompatiblerangeanycompatiblemultirange 参数。

请注意,没有 anycompatibleenum 类型。这种类型不会非常有用,因为通常没有任何隐式转换为枚举类型的类型转换,这意味着没有办法为不同的枚举输入解析公共类型。

简单”和“公共”多态家族代表了两组独立的类型变量。例如,考虑

CREATE FUNCTION myfunc(a anyelement, b anyelement,
                       c anycompatible, d anycompatible)
RETURNS anycompatible AS ...

在实际调用此函数时,前两个输入必须具有完全相同的类型。后两个输入必须可以提升为公共类型,但此类型不必与前两个输入的类型有任何关系。结果将具有后两个输入的公共类型。

可变参数函数(接受可变数量参数的函数,如 第 36.5.6 节 中所示)可以是多态的:这是通过将其最后一个参数声明为 VARIADIC anyarrayVARIADIC anycompatiblearray 来实现的。为了进行参数匹配和确定实际结果类型,此类函数的行为与您编写了适当数量的 anynonarrayanycompatiblenonarray 参数相同。

提交更正

如果您在文档中发现任何不正确、与您使用特定功能的经验不符或需要进一步澄清的内容,请使用此表单报告文档问题。