版本:
目录导航

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. 多态类型

名称家族描述
anyelementSimple表示函数接受任何数据类型
anyarraySimple表示函数接受任何数组数据类型
anynonarraySimple表示函数接受任何非数组数据类型
anyenumSimple表示函数接受任何枚举数据类型 (参见 第 8.7 节)
anyrangeSimple表示函数接受任何范围数据类型 (参见 第 8.17 节)
anymultirangeSimple表示函数接受任何多范围数据类型 (参见 第 8.17 节)
anycompatibleCommon表示函数接受任何数据类型,并自动将多个参数提升为公共数据类型
anycompatiblearrayCommon表示函数接受任何数组数据类型,并自动将多个参数提升为公共数据类型
anycompatiblenonarrayCommon表示函数接受任何非数组数据类型,并自动将多个参数提升为公共数据类型
anycompatiblerangeCommon表示函数接受任何范围数据类型,并自动将多个参数提升为公共数据类型
anycompatiblemultirangeCommon表示函数接受任何多范围数据类型,多个参数自动提升到公共数据类型

多态参数和结果是相互关联的,并且它们在解析调用多态函数的查询时被决定到一种特定的数据类型。 当存在多个多态参数时,输入值的实际数据类型必须匹配如下所述。 如果函数的结果类型是多态的,或者它具有多态类型的输出参数,则这些结果的类型是根据下面所描述的多态输入的实际类型推导出来的。

对于多态类型的 simple 家族,匹配和推导规则是这样工作的:

每一个被声明为anyelement的位置(参数或返回值)被允许具有任意特定的实际数据类型,但是在任何给定的查询中它们必须全部是相同的实际类型。 每一个被声明为anyarray的位置可以有任意数组数据类型,但是相似地,它们必须全部具有相同类型。 并且类似地,被声明为anyrange的位置必须全部是相同的范围类型。 对于anymultirange也是同样的。

此外,如果有位置被声明为anyarray并且其他位置被声明为anyelementanyarray位置中的实际数组类型必须是一个数组,该数组的元素都是出现在anyelement位置的同一种类型。 anynonarray被当做和anyelement相同,但是增加了额外的约束要求实际类型不能是一种数组类型。 anyenum被当做和anyelement相同,但是增加了额外的约束要求实际类型必须是一种枚举类型。

相似地,如果有位置被声明为anyrange并且其他位置被声明为anyelementanyarrayanyrange位置的实际范围类型必须是一个范围,该范围的子类型是出现在anyelement位置的同一种类型,并且与anyarray位置的元素类型相同。 如果有位置声明为anymultirange,它们的实际多范围类型必须包含匹配anyrange声明参数的范围,并且基本元素匹配参数声明的anyelementanyarray

因此,当使用一种多态类型声明了多于一个参数位置,有效效果是只有实际参数类型的某些组合才被允许。例如,一个被声明为equal(anyelement, anyelement)的函数将接受任意两个输入值,只要它们是同一种数据类型。

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

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

注意anynonarrayanyenum并不表示独立的类型变量,它们是和anyelement相同的类型,只是有一个额外的约束。例如,将一个函数声明为f(anyelement, anyenum)等效于把它声明为f(anyenum, anyenum):两种实际参数必须是相同的枚举类型。

对于多态类型的common家族,匹配和推断规则工作与simple家族相同,有一个主要区别: 参数的实际类型不需要相同,只要可以隐式地将它们转换为单一的公共类型就可以。 公共类型的选择遵循与UNION和相关结构相同的规则(参见第 10.5 节)。 公共类型的选择考虑了anycompatibleanycompatiblenonarray输入的实际类型,anycompatiblearray输入的数组元素类型,以及anycompatiblerange输入中的范围子类型,还有anycompatiblemultirange输入的多范围子类型。 如果存在anycompatiblenonarray,那么公共类型必须是非数组类型。 一旦识别了公共类型,anycompatibleanycompatiblenonarray位置中的参数将自动转换到该类型,并且anycompatiblearray位置的参数将自动转换到该类型的数组类型。

因为不可能选择只知道子类型的范围类型,使用anycompatiblerange和/或anycompatiblemultirange需要使用该类型声明的所有参数具有相同的实际范围和/或多范围类型, 这种类型的子类型与所选的公共类型一致,这样就不需要对范围值进行强制转换。 与anyrangeanymultirange一样,使用anycompatiblerangeanymultirange作为函数结果类型需要有一个anycompatiblerangeanycompatiblemultirange参数。

注意,没有anycompatibleenum类型。 这样的类型不是很有用,因为通常没有任何隐式的枚举类型的强制转换,这意味着无法为不同的枚举输入解析通用类型。

simplecommon 多态家族代表两组独立的类型变量。考虑例如

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

在此函数的实际调用中,前两个输入必须具有完全相同的类型。 最后两个输入必须提升为一个通用类型,但是这个类型不需要与前两个输入的类型有任何关系。结果将具有最后两个输入的共同类型。

一个可变函数(可以有可变数量的参数,如第 38.5.6 节中所述)能够是多态的: 这可以通过声明其最后一个参数为VARIADIC anyarrayVARIADIC anycompatiblearray来实现。 为了匹配和确定实际结果类型的参数,这样一种函数的行为和写了合适数量的anynonarrayanycompatiblenonarray参数是一样的。