7.3. 函数

函数调用的参数类型是用下面的步骤来解析的.

函数参数类型解析

  1. pg_proc 系统表中选择要考虑的函数. 如果使用了未经修饰的名字,那么则认为该函数是那些在当前搜索路径中 可见的,拥有正确名字和参数个数的函数(参阅 Section 2.8.3). 如果给出了一个带修饰的函数名,那么只考虑在声明的大纲中的函数.

    1. 如果在搜索路径中找到多个函数有相同的参数类型, 那么只考虑出现在搜索路径最前面的那个.但是有 不同参数类型的函数都以相同基础看待,而不管它们 在搜索路径中的位置.

  2. 找一个刚好接受完全一致的输入参数类型的函数. 如果存在这么一个(在考虑的函数集中可能只存在一个),用之. (涉及到 unknown 类型的情况下在本步骤不会找到任何匹配.)

  3. 如果没有找到准确的匹配,则看看函数调用是否明显需要 一个简单的类型转换.如果函数调用只有一个参数并且函数名与某些数据类型 的(内部)名称相同,那么就会出现这种情况.另外,该函数的参数必须是 一个未知类型的文本或者与命名数据类型二进制兼容.如果符合这些条件, 则该函数参数在不做任何明确函数调用的情况下转换成这个命名的数据类型.

  4. 查找最优的匹配

    1. 抛弃那些输入类型不匹配并且也不能强制转换 (使用隐含转换函数)成匹配的候选操作符. unknown 文本在这种情况下被认为是 可疑转换成任何东西.如果只剩下一个候选项,用之; 否则继续下一步.

    2. 遍历所有候选函数,保留那些在输入类型上有最多准确匹配的. 如果没有一个有准确匹配,则保留全部. 如果只剩下一个,用之;否则继续下一步.

    3. 遍历所有候选函数,保留那些在输入类型上有最多准确匹配的 或者在输入类型上有二进制兼容匹配的. 如果没有一个有准确匹配,则保留全部. 如果只剩下一个,用之;否则继续下一步.

    4. 遍历所有候选函数,保留那些在最多需要类型转换的参数位置上 接受优选类型的函数. 如果没有哪个候选函数接受优选类型,则保留全部. 如果只剩下一个,用之;否则继续下一步.

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

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

例子

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

Example 7-5. 子字串函数类型解析

pg_proc里定义了两个 substr 函数. 但是,其中只有一个使用两个参数,参数类型分别是 textint4

如果调用时其中一个字符串常量的类型不明确,其类型直接与唯一的候选函数匹配:

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)

Note: 实际上,分析器知道 textvarchar二进制兼容的,意思是说其中一个可以传递给一个接受另外一个的函数 而不需要做任何物理转换.因此,在这种情况下,实际上没有做任何明确的 类型转换.

而且,如果以 int4为参数调用函数,分析器将试图将其转换成 text

tgl=> SELECT substr(1234, 3);
 substr
--------
     34
(1 row)

实际上是这样执行的

tgl=> SELECT substr(text(1234), 3);
 substr
--------
     34
(1 row)

这样可以运行是因为在系统表里面有一个转换函数 text(int4).