PostgreSQL数据类型被划分为基础类型、组合类型、域和伪类型。
基础类型是那些被实现在SQL语言层面之下的类型(通常用一种底层语言,如 C),例如int4
。它们通常对应于常说的抽象数据类型。PostgreSQL只能通过由用户提供的函数在这类类型上操作,并且只能理解到用户描述这种类型行为的程度。基础类型会被进一步划分为标量和数组类型。对于每一种标量类型,会自动创建一个相应的数组类型,它能够保存该标量类型的可变尺寸的数组。
只要用户创建一个表,就会创建组合类型或者行类型。也可以使用CREATE TYPE来定义一个没有关联表的“stand-alone”组合类型。一个组合类型只是一个具有相关域名称的类型列表。一个组合类型的值是一个行或者域值记录。用户可以访问来自SQL查询的组成域。更多关于组合类型的信息请参考第 8.16 节。
一个域是基于一种特定基础类型的,并且出于很多目的它可以与其基础类型互换。不过,一个域能够具有约束来限制它的合法值于其底层基础类型允许值的一个子集。
可以使用SQL命令CREATE DOMAIN创建域。本章不会讨论它们的创建和使用。
有一些用于特殊目的“伪类型”。伪类型不能作为表列或者组合类型的属性出现,但是它们能被用于声明函数的参数和结果类型。这在类型系统中提供了一种机制来标识函数的特殊分类。表 8.25列出了现有的伪类型。
特别让人感兴趣的五种伪类型是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
的函数将只接受枚举类型的数组。
注意anynonarray
和anyenum
并不表示独立的类型变量,它们是和anyelement
相同的类型,只是有一个额外的约束。例如,将一个函数声明为f(anyelement, anyenum)
等效于把它声明为f(anyenum, anyenum)
:两种实际参数必须是相同的枚举类型。
一个可变函数(可以有可变数量的参数,如第 37.4.5 节中所述)能够是多态的:这可以通过声明其最后一个参数为VARIADIC
anyarray
来实现。为了匹配和决定实际结果类型的参数,这样一种函数的行为和写了合适数量的anynonarray
参数是一样的。