SQL 查询可能(有意无意地)要求在同一表达式里混合不同的数据类型. Postgres 在计算混合类型表达式方面有许多扩展性很强的功能。
在大多数情况下,用户不需要明白类型转换机制的细节. 但是,由 Postgres 所进行的隐含的类型转换会对查询的结果产生明显的影响,这些影响又可以由用 户或程序员通过明确的类型转换进行剪裁利用.
本章介绍 Postgres类型转换的传统和机制。 关于特定的类型和函数及操作符的进一步信息,请参考用户手册和程序员手册有关章节。
在程序员手册里有关于隐含类型转换的具体算法的更详细的介绍.
SQL 是强类型语言。 也就是说,每一数据都与一个决定其特性和用法的数据类型相联。 Postgres 有一个可扩展的数据类型系统, 该系统比其他 RDBMS 对应 系统的实现更具通用性和灵活性。 因而,Postgres 大多数类型转换的特性应该是由通用规则来管理的, 而不是由专门搜索方法来分析混合类型表达式的含义, 即便是用户定义的类型也应该如此。
Postgres 扫描/分析器只将词法元素分解成五个基本种类: 整数(integers),浮点数(floats), 字符串(strings),名字(names)和关键字 (keywords). 大多数扩展的类型首先表征为字符串(strings). SQL 语言的定义允许将类型名声明为字符串,这个机制被 Postgres用于令分析器沿着正确 的方向运行.例如,下面查询
tgl=> SELECT text 'Origin' AS "Label", point '(0,0)' AS "Value"; Label | Value --------+------- Origin | (0,0) (1 row)有两个字符串(strings)类型 text 和 point. 如果类型没有声明, (该类型)先被初始化成一个拥有存储空间的 unknown(未知)类型, 该类型将在后面描述的晚期阶段分析.
在 Postgres 分析器里, 有四种基本的 SQL 元素需要独立的类型转换规则:
Postgres 允许表达式里使用双目操作符(两个参数), 也允许使用左目或右目操作符(单目操作符,一个参数).
多数 Postgres 类型系统是建筑在一套丰富的函数上的. 任何查询中调用的函数的参数,不管是一个还是多个,必须符合该函数在系统表里的定义.因为 Postgres 允许函数重载, 所以函数名自身并不唯一地标识将要调用的函数 --- 分析器必须以 函数提供的参数的类型为基础选择正确的函数.
SQL INSERT 和 UPDATE 语句将表达式结果放入表中. 查询表达式的类型必须和 insert 语句的目标列一致或者是(可能需要)转换成一致的.
因为 UNION SELECT 语句的所有查询结果必须在一列里显示出来, 所以每个 SELECT 子句中的元素类型必须相互匹配并转换成一套统一类型. 类似,一个 CASE 构造的结果表达式必须转换成统一的类型, 这样 CASE 表达式自身作为整体有一种已知输出类型.
许多通用的类型转换规则使用建立在 Postgres 函数和操作符系统表基础上的简单转换来实现. 在转换规则中包括了一些启发方法,以便更好的支持 SQL92 标准中一些传统的内部类型,像 smallint,integer,和 float.
Postgres 分析器的习惯是: 所有类型转换函数接受一个类型是源类型的参数,该参数与目标类型同名. 任何符合这一标准的函数都被认为是一个有效的转换函数, 因而可以被分析器当作转换函数使用.这个简单的假设令分析器在不需要写硬代 码的基础上就可以充分利用类型转换的能力, 也让用户定义的类型可以透明地使用同一特性.
分析器中还有一个搜索器用于更好地猜测 SQL 标准类型的确切特性. 分析器里定义了几种类型范畴: 布尔(boolean),字符串(string), 数字(numeric),日期时间(datetime),时间跨度(timespan), 几何(geometric)网络,和用户定义(user-defined). 除用户定义类型外, 每种类型都有一种优选类型用于解决类型定义歧义的问题. 每一个"用户定义"的类型就是其自身的"优选类型",所以那些含混不清的 表达式(在分析结果中有多种可能的表达式) 如果有多个内件类型的时候则可以正确分析,但如果有多个用户定义类型 可选,则会抛出错.
所有类型转换规则都是建立在下面几个基本原则上的:
隐含转换决不能有奇怪的或不可预见的输出.
用户定义类型,因为分析器对其没有预先的认识,在类型级别中应该级别较"高". 在混合类型的表达式里,内部类型总是应该转换成用户定义类型. (当然只是在必须转换的时候).
用户定义类型是不相关的.当前,Postgres 除了用于内部数据类型的硬代码搜索器和以系统表中现有函数为基础的 隐含类型关系外,没有任何可用于处理类型间关系的信息。
如果一个查询不需要隐含的类型转换,分析器或执行器不应该进行更多的额外操作. 这就是说,任何一个类型匹配, 格式清晰的查询不应该在分析器里耗费更多的时间,也不应该做任何不必要的类型转换.
另外,如果一个查询通常使用某个函数进行隐含类型转换, 而用户明确定义了一个有正确参数的函数,解释器应该 使用新函数取代原先旧函数的隐含操作。