运算符表达式中具体绑定的物理运算符通过以下标准化决议流程确定(该过程受运算符优先级的约束,参见 Section 4.1.6):
运算符类型推导流程
从系统目录 pg_operator 中检索待选运算符。如果使用的是未带模式前缀的名称(绝大多数场景),候选池为当前搜索路径下名称匹配且入参个数相符的所有可见运算符。若使用了带模式限定的前缀名,则仅检索指定模式下的运算符。
寻找与传入实参类型完全精确匹配的运算符。如果存在(在有效候选集中至多只能存在一个完全匹配),直接选用该运算符。在模式限定调用时缺乏精确匹配可能引发安全隐患[8]。
在二元运算符调用中,如果其中一个参数为 unknown 占位符类型,在此步骤中暂且假定其类型与另一个已知参数完全相同。
若一个参数为 unknown 类型而另一个参数为 domain 类型,检查是否存在两端均精确匹配该域基类型的运算符。
若无精确匹配,寻找最佳匹配运算符:
剔除那些实参类型无法通过隐式类型转换与之匹配的候选者。unknown 字面量在此步骤中假定可转换为任何类型。如果筛选后仅剩唯一的候选者,直接采用;否则进入下一步。
遍历所有候选者,优先保留在实参类型上精确匹配项最多的候选。
遍历所有候选者,优先保留在需要类型转换的位置上能接受该类别首选类型(preferred type)最多的候选。如果仅剩唯一样本,直接采用;否则继续。
若参数包含 unknown,如果候选者支持字符串类别,优先选定 string 类别。
如果同时存在 unknown 与已知类型的参数,假定 unknown 参数与已知参数具有相同类型并做最终匹配。
Example 10.1. 平方根运算符类型推导
标准系统目录中只定义了一个一元前缀平方根运算符(|/),其接收的参数类型为 double precision。在此查询中:
SELECT |/ 40 AS "square root of 40"; square root of 40 ------------------- 6.324555320336759 (1 row)
词法分析器最初赋予整型字面量 40 以 integer 类型,解析器根据上述规则自动将其隐式转换为 double precision,查询等价于:
SELECT |/ CAST(40 AS double precision) AS "square root of 40";
Example 10.2. 字符串拼接运算符类型推导
对于包含未定类型的字符串拼接表达式:
SELECT text 'abc' || 'def' AS "text and unknown"; text and unknown ------------------ abcdef (1 row)
解析器发现存在接收两个 text 参数的拼接运算符,因此自动将未定类型的字面量 'def' 决议为 text 类型。