7.3. 函数 #
函数调用的参数类型按下列步骤解析。
函数参数类型解析
从
pg_proc系统目录中选择要考虑的函数。如果使用的是未限定的函数名,所考虑的函数是当前搜索路径中可见的名称和参数个数都合适的函数(见第 2.8.3 节)。如果给出的是限定的函数名,则只考虑指定模式中的函数。如果搜索路径中找到多个参数类型完全相同的函数,只考虑路径中最早出现的那一个。参数类型不同的函数则不受搜索路径位置影响,处于同等地位。
检查是否存在一个恰好接受输入参数类型的函数。如果存在(在被考虑的函数集合中至多只有一个精确匹配),就使用它。(涉及
unknown的情况在这一步永远找不到匹配。)如果找不到精确匹配,看看这个函数调用是否是一个平凡的类型强制转换请求。当函数调用只有一个参数且函数名与某个数据类型的(内部)名相同时就是这种情况。此外,函数参数必须是未知类型的字面量或与该数据类型二进制兼容的类型。满足这些条件时,函数参数被强制转换为该数据类型,不会有任何显式的函数调用。
寻找最佳匹配。
丢弃输入类型不匹配且不能(用隐式强制转换函数)转换成匹配的候选函数。为此目的,假定
unknown字面量可以转换成任何类型。如果只剩一个候选,就使用它;否则继续下一步。遍历所有候选,保留输入类型精确匹配最多的。如果没有任何精确匹配,则保留全部候选。如果只剩一个候选,就使用它;否则继续下一步。
遍历所有候选,保留输入类型精确匹配或二进制兼容匹配最多的。如果没有任何精确或二进制兼容匹配,则保留全部候选。如果只剩一个候选,就使用它;否则继续下一步。
遍历所有候选,保留在需要类型强制转换的最多个位置上接受首选类型的。如果没有任何候选接受首选类型,则保留全部候选。如果只剩一个候选,就使用它;否则继续下一步。
如果有输入参数是
unknown,检查其余候选在这些参数位置上接受的类型类别。在每个位置上,如果有候选接受string类别就选择该类别(这种偏向字符串的做法是恰当的,因为未知类型的字面量看起来确实像字符串)。否则,如果所有剩余候选接受相同的类型类别,就选择该类别;否则失败,因为没有更多线索就无法推断出正确的选择。还要注意是否有候选接受所选类别中的首选数据类型。现在丢弃不接受所选类型类别的候选;此外,如果某个候选在给定的参数位置上接受首选类型,就丢弃在该参数上接受非首选类型的候选。如果只剩一个候选操作符,就使用它。如果没有候选操作符或者不止一个候选操作符剩余,则失败。
Examples
例 7.4. 阶乘函数参数类型解析
pg_proc 目录中只定义了一个
int4fac 函数。因此下面的查询自动把 int2 参数转换为 int4:
tgl=> SELECT int4fac(int2 '4');
int4fac
---------
24
(1 row)并且实际上被解析器变换为
tgl=> SELECT int4fac(int4(int2 '4'));
int4fac
---------
24
(1 row)例 7.5. substr 函数类型解析
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)。