35.2. PostgreSQL类型系统

PostgreSQL数据类型可以分为基本类型、复合类型、域、伪类型。

35.2.1. 基本类型

基本类型是那些在SQL语言层次更低级别(通常是C语言)上实现的类型(比如int4类型), 它们通常与抽像数据类型对应。PostgreSQL对这些数据类型只能通过用户提供的函数来操作, 并且对这些数据类型行为的理解只限于用户所描述的范围。基本类型进一步分成标量和数组类型。 对于每种标量类型,系统都会自动创建一个对应的数组类型,可以保存该标量类型的变长数组。

35.2.2. 复合类型

复合类型(或者说行类型)是用户创建表时创建的。 也可以用CREATE TYPE创建一个"独立的"、没有关联表的复合类型。 复合类型只是一个带着相关字段名称的基本类型的列表。 复合类型的数值是一行字段值或者一条字段值组成的记录。 用户可以从SQL查询里访问其字段。 参考第 8.16 节获取更多复合类型的相关信息。

35.2.3. 域

域基于一种特定的基本类型,从很多角度来看,它们也可以和其对应的基本类型交换。 但是,域可以有约束,把它的有效值限制在其对应的基本类型的有效值范围的一个子集中。

域可以使用SQL命令CREATE DOMAIN创建。 它们的创建和使用不在本章讨论。

35.2.4. 伪-类型

有一些用于特殊目的"伪类型"。伪类型不能作为表的字段类型, 也不能作为复合类型的属性,但是它们可以用于声明函数的参数和结果类型。 这样就在类型系统里提供了一个标识特殊类型函数的机制。 表 8-24列出了现有的伪类型。

35.2.5. 多态类型

anyelement,anyarray, anynonarray, anyenum, 和anyrange是五种特别有趣的伪类型,它们被称作多态类型。 任何用这些类型定义的函数就叫做多态函数。 一种多态函数可以在许多不同的数据类型上操作, 它们根据调用中实际传递进来的数据类型判断具体的类型。

多态参数和结果是相互绑定的,并且在分析查询调用的函数时解析成特定的数据类型。 每个声明成anyelement的位置(参数或者返回类型)都允许拥有一个特定的实际数据类型, 但是在任何给定的调用过程中,它们都必须是同样的类型。 每个声明为anyarray的位置都可以是任何数组数据类型,类似的,声明为anyrange的位置 也必许都是同样的类型。而且,如果有些位置声明为anyarray而其它位置声明为anyelement, 那么在anyarray位置上的类型必须是元素类型与那些出现在anyelement位置上的类型相同的数组。 类似的,如果有声明为anyrange的位置而且其他的声明为anyelement,那么 在anyrange位置上的类型必须是子类型与那些出现在anyelement位置上类型相同 的范围。anynonarray实际上被看做anyelement, 但却多一个约束:实际类型必须不能是一个数组类型。 anyenum实际上被看做anyelement,但却多一个约束: 实际类型必须是一个枚举类型。

因此,如果多个参数位置声明为多态类型,其实际效果是只允许某些实际参数类型的组合出现。 比如,一个函数声明为equal(anyelement, anyelement)将接受任何两个输入值,只要它们的数据类型相同。

如果一个函数的返回值声明为多态类型,那么至少有一个参数位置也是多态的, 并且提供给参数的类型决定本次调用实际返回的类型。比如,如果没有数组下标机制, 那么我们可以定义一个实现下标的函数subscript(anyarray, integer) returns anyelement。 这个声明约束第一个实际参数是一个数组类型,并且允许分析器从第一个参数的实际类型推导出正确的返回类型。 声明为一个f(anyarray) returns anyenum的函数的另一个例子只接受枚举类型的数组。

需要注意的是,anynonarrayanyenum不代表不同的类型变量; 它们是与anyelement相同的类型,只有一个额外的约束。 例如,声明一个函数为f(anyelement, anyenum) 等同于声明它为f(anyenum, anyenum): 两个实际参数必须是相同的枚举类型。

一个可变参数函数(其使用一个可变数目的参数,如第 35.4.5 节中描述) 可以是多态的: 可以通过声明它的最后一个参数为VARIADIC anyarray来实现。 为了实现参数匹配并决定实际结果类型, 这样一个函数的行为等同于将anynonarray参数写一个合适的数目。