一次操作符调用的操作数类型是按照下面的过程解析的. 请注意这个过程受被调用操作符的优先级的间接影响. 参阅 Section 1.1.6 获取更多信息.
操作符类型解析
从 pg_operator 系统表中 选出要考虑的操作符.如果使用了一个不带修饰的操作符名 (常见的状况),那么认为该操作符是那些在当前的搜索路径中 名字和参数个数正确的函数(参阅 Section 2.8.3). 如果给出一个带修饰的操作符名,那么只考虑指明的大纲中的操作符.
如果搜索路径中找到了多个相同参数类型的操作符,那么只考虑 最早出现在路径中的.但是不同参数类型的操作符将以相同的基础 进行考虑,而不管它们在路径中的位置如何.
检查一个操作符是否刚好接受输入参数类型. 如果存在一个(在考虑的操作符中,可能只存在一个精确匹配的), 则用之.
如果一个双目操作符的一个参数是 unknown, 则在本次检查中假设其与另一个参数类型相同. 其他涉及 unknown 的情况绝不会在这一步找到匹配.
寻找最优匹配.
抛弃那些输入类型不匹配并且也不能强制转换 (使用隐含转换函数)成匹配的候选操作符. unknown 文本在这种情况下被认为是 可疑转换成任何东西.如果只剩下一个候选项,用之; 否则继续下一步.
遍历所有候选操作符,保留那些输入类型有最多准确匹配的. 如果没有完全准确匹配的操作符,保留所有候选. 如果只有一个,用之,否则继续下一步.
遍历所有候选操作符,保留那些输入类型有最多准确匹配或者有二进制兼容匹配的. 如果没有完全准确匹配而且也没有二进制兼容匹配的操作符,保留所有候选. 如果只有一个,用之,否则继续下一步.
遍历所有候选操作符,保留那些需要类型转换时最多位置接受优选类型的. 如果没有接受优选类型的操作符,则保留所有候选. 如果只有一个,用之,否则继续下一步.
如果任何输入参数是 "unknown",检查剩下的候选操作符对应参数位置的 类型表.如果任何候选操作符接受 "string" 类型,则在那些位置选 "string" 类型(这个假设认为 string 是合适的,因为 unknown 类型文本确实象 string). 否则,如果所有剩下的候选操作符接受相同的类型,选择该类型; 否则抛出一个错误,因为在没有更多线索的条件下不能导出正确的选择. 还要注意是否有哪个候选操作符在选出的类型表中有优选类型. 现在抛弃不接受选定的类型表的候选操作符;然后, 如果任意候选操作符在某个给定的参数位置接受一个优选类型, 则抛弃那些在该参数位置接受非优选类型的候选操作符.
如果只剩下一个操作符,用之. 如果还有超过一个的候选操作符或是没有候选操作符,则产生一个错误.
Example 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)
注意: 最后的形式最高效,因为不用调用函数做隐含类型转换. 这对小查询没有什么影响,但可能对那些操 作大表的查询的性能产生较大影响.
Example 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)
本例中对类型任何初始提示,因为查询中没有声明任何类型. 因此,分析器查找所有参数可以同时接受字符串类和位串类的候选操作符. 因为在可用时字串类是优选,所以选择该表, 于是字串的"优选类型", text,作为解析未知类型文本的声明类型.
Example 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 '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)