您的位置:寻梦网首页编程乐园数据库PostgreSQL 7.2 Documentation

5.3. 操作符

一次操作符调用的操作数类型是按照下面的过程解析的. 请注意这个过程受被调用操作符的优先级的间接影响. 参阅 Section 1.4 获取更多信息.

操作符类型解析

  1. pg_operator 系统表里找出准确的匹配.

    1. 如果一个双目操作符的一个参数是 unknown , 则在本次检查中假设其与另一个参数类型相同. 其他涉及 unknown 的情况绝不会在这一步找到匹配.

  2. 寻找最优匹配.

    1. 生成一个同名的操作符的列表:它们的输入类型匹配或者可以转换成匹配的。 (假定 unknown 文本可以为此目的转换成任何类型) 如果只有一个,用之,否则继续下一步.

    2. 遍历所有候选操作符,保留那些输入类型有最多准确匹配的. 如果没有完全准确匹配的操作符,保留所有候选. 如果只有一个,用之,否则继续下一步.

    3. 遍历所有候选操作符,保留那些输入类型有最多准确匹配或者有二进制兼容匹配的. 如果没有完全准确匹配而且也没有二进制兼容匹配的操作符,保留所有候选. 如果只有一个,用之,否则继续下一步.

    4. 遍历所有候选操作符,保留那些需要类型转换时最多位置接受优选类型的. 如果没有接受优选类型的操作符,则保留所有候选. 如果只有一个,用之,否则继续下一步.

    5. 如果任何输入参数是 "unknown" ,检查剩下的候选操作符对应参数位置的 类型表.如果任何候选操作符接受 "string" 类型,则在那些位置选 "string" 类型(这个假设认为 string 是合适的,因为 unknown 类型文本确实象 string). 否则,如果所有剩下的候选操作符接受相同的类型,选择该类型; 否则抛出一个错误,因为在没有更多线索的条件下不能导出正确的选择. 还要注意是否有哪个候选操作符在选出的类型表中有优选类型. 现在抛弃不接受选定的类型表的候选操作符;然后, 如果任意候选操作符在某个给定的参数位置接受一个优选类型, 则抛弃那些在该参数位置接受非优选类型的候选操作符.

    6. 如果只剩下一个操作符,用之. 如果还有超过一个的候选操作符或是没有候选操作符,则产生一个错误.

例子

Example 5-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)

注意: 最后的形式最高效,因为不用调用函数做隐含类型转换. 这对小查询没有什么影响,但可能对那些操 作大表的查询的性能产生较大影响.

Example 5-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)

本例中对类型任何初始提示,因为查询中没有声明任何类型. 因此,分析器查找所有参数可以同时接受字符串类和位串类的候选操作符. 因为在可用时字串类是优选,所以选择该表, 于是字串的 "优选类型" text ,作为解析未知类型文本的声明类型.

Example 5-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 '44' ! 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 '44' as int8) ! as "factorial";
      factorial
---------------------
 2673996885588443136
(1 row)