↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1
历史版本PostgreSQL 7.3 已于 2007 年 11 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

7.2. 操作符 #

操作符调用的操作数类型按下面的 过程解析。注意这个过程间接受 所涉操作符优先级的影响。更多信息见 第 1.1.6 节。

操作数类型解析

  1. 从 pg_operator 系统 目录中选择要考虑的操作符。如果使用的是未限定的 操作符名(通常情况),所考虑的操作符 是当前搜索路径中可见的名称和参数个数都 合适的操作符(见 第 2.8.3 节)。 如果给出的是限定的操作符名,则只考虑指定 模式中的操作符。

    1. 如果搜索路径中找到多个参数类型完全相同的操作符,只考虑路径中最早出现的那一个。参数类型不同的操作符则不受搜索路径位置影响,处于同等地位。

  2. 检查是否存在一个恰好接受输入参数类型的操作符。如果存在(在被考虑的操作符集合中至多只有一个精确匹配),就使用它。

    1. 如果二元操作符的一个参数是 unknown 类型, 那么在这一步检查中假定它与另一个参数的类型 相同。其他涉及 unknown 的情况在这一步 永远找不到匹配。

  3. 寻找最佳匹配。

    1. 丢弃输入类型不匹配且不能(用隐式强制转换函数) 转换成匹配的候选操作符。 为此目的,假定 unknown 字面量 可以转换成任何类型。如果只剩一个 候选,就使用它;否则继续下一步。

    2. 遍历所有候选,保留输入类型精确匹配 最多的。如果没有任何精确匹配,则保留全部 候选。如果只剩一个候选,就使用它;否则继续下一步。

    3. 遍历所有候选,保留输入类型精确匹配或二进制 兼容匹配最多的。如果没有任何精确或二进制 兼容匹配,则保留全部候选。 如果只剩一个候选,就使用它;否则继续下一步。

    4. 遍历所有候选,保留在需要类型强制转换的最多个 位置上接受首选类型的。 如果没有任何候选接受首选类型,则保留全部候选。 如果只剩一个候选,就使用它;否则继续下一步。

    5. 如果有输入参数是 “unknown”,检查其余 候选在这些参数位置上接受的类型 类别。在每个位置上,如果有候选接受 "string" 类别就选择该类别(这种偏向字符串的 做法是恰当的,因为未知类型的字面量看起来 确实像字符串)。否则,如果所有剩余候选 接受相同的类型类别,就选择该 类别;否则失败,因为没有更多线索就无法 推断出正确的选择。还要注意是否有候选接受所选类别中的 首选数据类型。现在丢弃不接受所选类型 类别的操作符候选;此外,如果某个候选在给定的参数 位置上接受首选类型,就丢弃在该参数上 接受非首选类型的候选。

    6. 如果只剩一个候选操作符,就使用它。如果没有候选操作符或者不止一个候选操作符剩余,则失败。

Examples

例 7.1. 指数操作符类型解析

目录中只定义了一个取幂 运算符,它接受 double precision 类型的参数。 扫描器给这个查询表达式的两个 参数都赋予了初始类型 integer:

tgl=> SELECT 2 ^ 3 AS "Exp";
 Exp
-----
   8
(1 row)

于是解析器对两个操作数都做类型转换,查询 等价于

tgl=> SELECT CAST(2 AS double precision) ^ CAST(3 AS double precision) AS "Exp";
 Exp
-----
   8
(1 row)

或

tgl=> SELECT 2.0 ^ 3.0 AS "Exp";
 Exp
-----
   8
(1 row)

注意

最后这种形式的开销最小,因为没有调用任何函数来做 隐式类型转换。这对小查询不是问题,但可能 影响涉及大表的查询的性能。


例 7.2. 字符串连接操作符类型解析

类字符串的语法既用于处理字符串类型,也用于 处理复杂的扩展类型。 未指定类型的字符串会与可能的操作符候选 匹配。

一个参数未指定类型的例子:

tgl=> SELECT text 'abc' || 'def' AS "Text and Unknown";
 Text and Unknown
------------------
 abcdef
(1 row)

在这种情况下,解析器会查看是否存在一个两边参数都接受text的操作符。既然存在,它就会假定第二个参数应解释为text类型。

未指定类型上的串接:

tgl=> SELECT 'abc' || 'def' AS "Unspecified";
 Unspecified
-------------
 abcdef
(1 row)

这种情况下没有关于使用哪个类型的初始提示,因为查询中 没有指定类型。于是解析器查找所有候选操作符, 发现有候选既接受 string 类别也接受 bit-string 类别的输入。由于 string 类别可用时会被优先选择, 就选择了该类别,然后把字符串的 “首选类型” text 用作解析未知 字面量的具体类型。


例 7.3. 绝对值与阶乘操作符的类型解析

PostgreSQL 运算符目录中前缀运算符 @ 有若干条目,它们为各种数值数据类型实现 绝对值操作。其中一个 条目面向 float8 类型,它是数值类别中的首选 类型。因此,PostgreSQL 遇到非数值输入时会使用那个条目:

tgl=> select @ text '-4.5' as "abs";
 abs
-----
 4.5
(1 row)

这里系统在应用选中的运算符之前做了一次隐式的 text 到 float8 转换。我们可以验证用的是 float8 而 不是别的类型:

tgl=> select @ text '-4.5e500' as "abs";
ERROR:  Input '-4.5e500' is out of range for float8

另一方面,后缀运算符 !(阶乘) 只为整数数据类型定义,不为 float8 定义。因此,如果我们 用 ! 尝试类似的情形,会得到:

tgl=> select text '20' ! as "factorial";
ERROR:  Unable to identify a postfix operator '!' for type 'text'
        You may need to add parentheses or an explicit cast

这是因为系统无法决定几个可能的 ! 运算符中应该首选哪个。我们可以用 显式转换来帮它解决:

tgl=> select cast(text '20' as int8) ! as "factorial";
      factorial
---------------------
 2432902008176640000
(1 row)

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。