pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
SQL语句可能有意或无意地要求在同一表达式中混用不同的数据类型。PostgreSQL提供了丰富的机制来求值这类混合类型表达式。
在很多情况下,用户不需要了解类型转换机制的 细节。但 PostgreSQL 所做的隐式转换会影响查询的结果。必要时,用户或程序员可以 用显式类型转换来定制 这些结果。
本章介绍PostgreSQL的类型转换机制和约定。有关特定数据类型以及允许使用的函数和操作符的更多信息,请参阅第 8 章和第 9 章中的相关章节。
SQL 是一种强类型语言。也就是说,每个数据项 都有一个相关联的数据类型,它决定了该数据项的行为和允许的用法。 PostgreSQL 拥有一个可扩展的类型系统, 比其他 SQL 实现更加通用和灵活。 因此,PostgreSQL 中大部分类型转换行为 应当由一般规则而不是ad hoc(特定)启发式规则支配, 以使混合类型表达式即使在有用户定义类型时也有 意义。
PostgreSQL 的扫描器/解析器只把词法 元素解码成五种基本类别:整数、浮点数、字符串、 名字和关键字。大多数非数值类型 的常量最初被归类为 字符串。SQL 语言定义允许用字符串指定类型 名,这一机制可以用来让解析器走上正确的 路径。例如,查询
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和ARRAY结构由于联合起来的 SELECT 语句的所有查询结果 必须出现在一组列中,每个 SELECT 子句结果的类型必须匹配并转换成统一的集合。 类似地,CASE 结构的各分支表达式必须 转换成公共类型,使 CASE 表达式整体 有已知的输出类型。ARRAY 结构 也是如此。
系统目录保存了哪些数据类型之间存在哪些类型转换,以及如何执行这些转换的信息。用户还可以使用CREATE CAST命令添加额外的类型转换。(这通常与定义新数据类型一并完成。内置类型之间的类型转换集合经过精心设计,最好不要改动。)
解析器还提供了一个附加的启发式规则,以便对SQL标准类型做出更好的猜测。系统定义了若干基本的类型分类:boolean、numeric、string、bitstring、datetime、timespan、geometric、network以及用户定义类型。除用户定义分类外,每个分类都有一个或多个首选类型,存在歧义时会优先选择它们。在用户定义分类中,每个类型自己的首选类型就是它自己。因此,当存在多个可能的内置类型时,有歧义的表达式(即存在多个候选解析方案的表达式)常常仍能被解析;但当存在多个用户定义类型选择时,则会报错。
所有类型转换规则都以以下几个原则为基础:
隐式转换绝不应产生令人意外或无法预测的结果。
解析器没有关于用户定义类型的先验知识,这类类型在类型层次结构中应当处于“更高”的位置。在混合类型的表达式中,原生类型应当总是被转换为用户定义类型(当然,仅在确有必要转换时)。
用户定义类型彼此之间没有关联。目前,PostgreSQL除了对内置类型的硬编码启发式规则,以及基于可用函数和类型转换的隐式关系外,并没有关于类型之间关系的信息可用。
如果查询不需要隐式类型转换,解析器和执行器就不应承担额外开销。也就是说,如果查询本身书写正确且类型已经匹配,那么执行时不应让解析器额外耗时,也不应在查询中引入不必要的隐式类型转换调用。
此外,如果某个查询通常需要先对参数做隐式类型转换才能调用某个函数,而此后用户又定义了一个参数类型正确的新函数,那么解析器应改为使用这个新函数,而不再通过隐式转换去调用旧函数。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。