10.1. 概述
SQL是一种强类型语言。也就是说,每个数据项都有一个相关的数据类型,数据类型决定其行为和允许的用法。 PostgreSQL有一个可扩展的类型系统,该系统比其它SQL实现更具通用和灵活。因而,PostgreSQL中大多数类型转换行为是由通用规则来管理的,而不是 ad hoc 启发式规则。这种做法允许使用混合类型表达式,即便是其中包含用户定义的类型。
PostgreSQL扫描器/解析器只将词法元素分解成五个基本种类:整数、非整数数字、字符串、标识符、关键字。大多数非数字类型常量首先被分类为字符串。SQL语言定义允许将类型名指定为字符串, 这个机制被PostgreSQL用于保证解析器沿着正确的方向运行。例如,查询:
SELECT text 'Origin' AS "label", point '(0,0)' AS "value";
label | value
--------+-------
Origin | (0,0)
(1 row)
有两个文字常量,类型分别为text
和point
。如果一个串文字没有指定类型,初始将被分配一个占位符类型unknown
,该类型将在下文描述的后续阶段被解析。
在SQL解析器里,有四种基本的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
和用户自定义(可参阅表 52.63中的列表;但需要注意的是 也可以创建自定义的类型分类)。在每个分类中,可以有一个或多个 首选类型 , 当存在类型选择时,这个是更好的选择。利用精心选择的首选类型和可用的隐式造型, 我们可以确保有歧义的表达式(那些有多个候选解析方案的表达式)可以用一种有用的方式来处理。
所有类型转换规则都是建立在下面几个基本原则上的:
-
隐式转换决不能有意外的或不可预见的输出。
-
如果一个查询不需要隐式类型转换,解析器或执行器不应该有额外的开销。也就是说,如果一个查询是结构良好的并且类型已经匹配,则查询不应该在解析器里耗费额外的时间执行,也不会在查询中引入不必要的隐式类型转换调用。
-
另外,如果一个查询通常要求为某个函数进行隐式类型转换,而用户定义了一个有正确参数类型的新函数, 解析器应该使用新函数并不再做隐式转换来使用旧函数。