10.3. 函数

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

函数参数类型解析

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

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

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

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

  4. 查找最优的匹配

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

    2. 遍历所有候选函数,保留那些在输入类型上有最多准确匹配的。 (在这种场合下域被认为和其基本类型一样。) 如果没有一个有准确匹配,则保留全部。 如果只剩下一个,用之;否则继续下一步。

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

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

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

请注意,"最佳匹配" 规则对操作符和对函数的类型分析都是一样的。 下面是一些例子。

Example 10-4. 圆整函数参数类型解析

只有一个round函数有两个参数。(第一个参数是numeric, 第二个是 integer。)所以下面的查询自动把第一个类型为 integer 的参数转换成 numeric

SELECT round(4, 4);

 round
--------
 4.0000
(1 row)

实际上它被分析器转换成:

SELECT round(CAST (4 AS numeric), 4);

因为带小数点的数值常量初始时被赋予 numeric 类型,因此下面的查询将不需要类型转换,并且可能会略微高效一些:

SELECT round(4.0, 4);

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

有好几个 substr 函数,其中一个接受类型 textinteger。如果用一个未声明类型的字串常量调用它, 系统将选择接受优选 string类型(也就是类型 text)的候选函数。

SELECT substr('1234', 3);

 substr
--------
     34
(1 row)

如果该字符串声明为类型 varchar, 就像大多数从表中取来的数据一样,分析器将试着将其转换成 text

SELECT substr(varchar '1234', 3);

 substr
--------
     34
(1 row)

被分析器转换后实际上变成:

SELECT substr(CAST(varchar '1234' AS text), 3);

 substr
--------
     34
(1 row)

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

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

SELECT substr(1234, 3);

 substr
--------
     34
(1 row)

实际上是这样执行的

SELECT substr(CAST(1234 AS text), 3);

 substr
--------
     34
(1 row)

这种自动转换能够成功是因为存在一个从 integertext 的隐含转换可以调用。