5.3. 函数 #
函数调用类型解析
在 pg_proc 系统目录中检查精确匹配。(涉及
unknown的情况在这一步永远找不到匹配。)寻找最佳匹配。
列出所有同名、参数个数相同且输入类型匹配或可以强制转换成匹配的函数。(为此目的,假定
unknown字面量可以转换成任何类型。)如果只有一个,就使用它;否则继续下一步。遍历所有候选,保留输入类型精确匹配最多的。如果没有任何精确匹配,则保留全部候选。如果只剩一个候选,就使用它;否则继续下一步。
遍历所有候选,保留输入类型精确匹配或二进制兼容匹配最多的。如果没有任何精确或二进制兼容匹配,则保留全部候选。如果只剩一个候选,就使用它;否则继续下一步。
遍历所有候选,保留在需要类型强制转换的最多个位置上接受首选类型的。如果没有任何候选接受首选类型,则保留全部候选。如果只剩一个候选,就使用它;否则继续下一步。
如果有输入参数是"unknown",检查其余候选在这些参数位置上接受的类型类别。在每个位置上,如果有候选接受 "string" 类别就选择该类别(这种偏向字符串的做法是恰当的,因为未知类型的字面量看起来确实像字符串)。否则,如果所有剩余候选接受相同的类型类别,就选择该类别;否则失败,因为没有更多线索就无法推断出正确的选择。还要注意是否有候选接受所选类别中的首选数据类型。现在丢弃不接受所选类型类别的操作符候选;此外,如果某个候选在给定的参数位置上接受首选类型,就丢弃在该参数上接受非首选类型的候选。
如果只剩一个候选操作符,就使用它。如果没有候选操作符或者不止一个候选操作符剩余,则失败。
如果找不到最佳匹配,看看这个函数调用是否是一个平凡的类型强制转换请求。当函数调用只有一个参数且函数名与某个数据类型的(内部)名相同时就是这种情况。此外,函数参数必须是未知类型的字面量或与该数据类型二进制兼容的类型。满足这些条件时,函数参数被强制转换为该数据类型。
5.3.1. 示例
5.3.1.1. 阶乘函数
pg_proc 目录中只定义了一个阶乘函数。因此下面的查询自动把 int2 参数转换为 int4:
tgl=> select int4fac(int2 '4');
int4fac
---------
24
(1 row)并且实际上被解析器变换为
tgl=> select int4fac(int4(int2 '4'));
int4fac
---------
24
(1 row)5.3.1.2. 子串函数
pg_proc 中声明了两个 substr 函数。但只有一个接受两个参数,类型是 text 和 int4。
如果用未指定类型的字符串常量调用,该类型会直接与唯一的候选函数类型匹配:
tgl=> select substr('1234', 3);
substr
--------
34
(1 row)如果该字符串被声明为 varchar 类型(例如它来自一张表时就是这种情况),则解析器会试图把它强制转换成 text:
tgl=> select substr(varchar '1234', 3);
substr
--------
34
(1 row)它被解析器变换成
tgl=> select substr(text(varchar '1234'), 3);
substr
--------
34
(1 row)注意
实际上,解析器知道 text 和 varchar
是"二进制兼容"的,即一个可以传给接受另一个的函数而不做任何物理转换。因此,这种情况下实际上不会插入显式的类型转换调用。
而且,如果用 int4 调用该函数,解析器会试图把它转换成 text:
tgl=> select substr(1234, 3);
substr
--------
34
(1 row)实际执行为
tgl=> select substr(text(1234), 3);
substr
--------
34
(1 row)这之所以成功,是因为系统目录中有一个转换函数 text(int4)。