SQL是一种强类型语言。也就是说,每一个数据项都有一个关联的数据类型,用于确定它的行为和允许的使用方式。PostgreSQL 具有一个可扩展类型系统,该系统比其他SQL实现更通用且更灵活。因此,PostgreSQL 中的大部分类型转换行为由通用规则而非特殊启发式信息决定。这样即使使用用户定义的类型,也可以使用混合类型表达式。
PostgreSQL 扫描器/解析器将词法元素分为五个基本类别:整数、非整数数字、字符串、标识符和关键字。大多数非数字类型常量首先归类为字符串。SQL语言定义允许使用字符串指定类型名称,这种机制可以在 PostgreSQL 中用来让解析器开始沿着正确的路径进行解析。例如,查询
SELECT text 'Origin' AS "label", point '(0,0)' AS "value"; label | value --------+------- Origin | (0,0) (1 row)
有两个文本常量,类型分别为 text
和 point
。如果字符串文本没有指定类型,则会最初分配一个占位符类型 unknown
,之后将按照如下所述在后续的阶段中进行解析。
在 PostgreSQL 解析器中共有四个基本SQL构造需要不同的类型转换规则
PostgreSQL 类型的系统主要围绕着一组丰富的函数进行构建。函数可以有一个或多个参数。由于 PostgreSQL 允许函数重载,所以函数名称本身并不能唯一地标识要调用的函数;解析器必须基于所提供参数的数据类型来选择正确的函数。
PostgreSQL 允许使用前缀(一个参数)运算符和中缀(两个参数)运算符的表达式。与函数一样,运算符也可以重载,所以存在选择正确的运算符的同样的问题。
SQL INSERT
和 UPDATE
语句将表达式的结果放在表中。语句中的表达式必须与目标列的类型相匹配并可能转换为其类型。
UNION
、CASE
及类似构造由于联合化 SELECT
语句中的所有查询结果必须以一组列出现,因此每个 SELECT
子句的结果类型必须匹配并转换为一组统一类型。类似地,CASE
构造的结果表达式必须转换为公共类型,以便整个 CASE
表达式拥有已知的输出类型。一些其它构造,例如 ARRAY[]
和 GREATEST
和 LEAST
函数,同样需要确定几个子表达式的公共类型。
系统目录存储有关在哪些数据类型之间存在哪种转换(或转换)以及如何执行这些转换的信息。用户可以使用 CREATE CAST 命令添加额外的转换。(这通常与定义新数据类型结合来完成。内置类型之间的转换集已经过精心构造,最好不要对其进行更改。)
解析器提供的另外一个启发式方法,提高了确定隐式强制转换类型组中适当强制转换行为的能力。数据类型分成几个基本类型范畴,包括 boolean
、numeric
、string
、bitstring
、datetime
、timespan
、geometric
、network
,以及用户自定义类型。(有关列表,请参见表 51.65;但请注意,也可以创建自定义类型范畴。)在每个范畴中,可以有一个或多个首选类型,当有多种可能的类型可供选择时,首选这些类型。通过仔细选择首选类型和可用的隐式强制转换,可以通过有用的方式解决歧义表达式(具有多个候选解析解决方案的表达式)。
所有类型转换规则的设计都考虑了几个原则
隐式转换绝不应带来令人惊讶或无法预测的结果。
如果查询不需要隐式类型转换,则解析器或执行器不应有额外开销。也就是说,如果查询格式正确,并且类型已匹配,那么查询应执行而不必在解析器中花费额外时间,并且在查询中不引入不必要的隐式转换调用。
此外,如果查询通常需要对某个函数执行隐式转换,并且然后用户使用正确的参数类型定义了一个新函数,那么解析器应使用此新函数,并且不再执行隐式转换以使用旧函数。