10.3. 函数

被一个函数调用引用的特定函数使用下面步骤来决定。

函数类型解析

  1. pg_proc系统目录中选择考虑的函数。 如果使用一个不合格的模式的函数名称,那么考虑到的函数是那些可以在当前搜索路 径(查阅Section 5.7.3)中匹配名称和现有的参数数量的函数。 如果给定的是一个合格的函数名称,那么只考虑在指定的模式中的函数。

    1. 如果搜索路径里发现多个参数类型相同的函数,那么只考虑最早在搜索路径中出现的那个。 不同参数类型的函数被平等对待,不受搜索路径位置的影响。

    2. 如果使用一个VARIADIC数组参数声明一个函数,并且调用不使用关键字VARIADIC, 那么该函数被作为是否数组参数被一个或更多它元素类型的事件,需要去匹配调用。 这样的扩展函数之后或许会有对于一些非可变参数函数有效的相同的参数类型。 在这种情况下,使用在搜索路径中出现比较早的函数,或者如果两个函数在相同的模式中,那么首选非可变的一个。

    3. 考虑使用有默认参数值的函数来匹配任何省略了零或者多个默认表参数位置的调用。 如果有更多的超出一个的函数匹配一个调用,那么使用最早出现在搜索路径中的那个。 如果在同一个相同的在非默认位置的参数类型的模式中有两个或者更多的这样的函数(他们有 不同的默认参数设置或许是可能的),系统将不能确定去选择哪个,并且如此一个"模糊的函数调用" 错误导致是否可以发现更匹配的调用。

  2. 检查函数正确地接受了输入参数类型。如果存在一个(在所考虑的函数的设置中可以仅有一个精确匹配),那么使用它。 (在该步骤中该情况涉及的未知将永不匹配)

  3. 如果没有发现精确匹配,那么查看调用函数是否作为一个特定的转换访问类型出现。 如果函数调用仅有一个参数并且函数名和一些数据类型名相同,那么该情况将会发生。 并且,函数参数不能是一个未知类型的文字,或者是一个以数据类型命名的可强迫的二进制类型, 或者是一个可以被转换为以类型的I/O命名的数据类型(也就是,转换要么是那样要么是来在标准字符类型中的一个)。 当遇到这些条件的时候,函数调用被当做CAST规格的一个格式来看。 [1]

  4. 查找最佳匹配。

    1. 丢弃候选函数 输入类型不匹配且不能转换(使用一个隐式变换转换)匹配。 为了这个目的,unknown文字是假定的转换为任何形式。 如果仅有一个候选项,那么使用它;或者继续下一步。

    2. 通过所有候选项并保持在输入类型中的最佳匹配。 (为达到该目的,域被认为和它们的基础类型一样。) 如果没有精确匹配那么保持所有候选项。 如果仅有一个候选项,那么使用它;或者继续下一步。

    3. 通过所有候选项并保持那些接受优先类型(输入数据类型的类型分类)在大多数类型转换被访问位置。 如果没有可以接受的首选类型那么保持所有的候选项。 如果仅有一个候选项,那么使用它;或者继续下一步。

    4. 如果输入参数是未知,那么通过剩下的候选项检查在那些参数位置上接受的类型类别。 在每一个位置上,如果任何候选项接受类别那么选择string类。 (这个偏向于字符串是恰当的,因为一个未知类型文字看起来像字符。) 否则,如果所有剩余的候选项接受相同的类型类别,那么选择那个类别; 否则将失败因为在缺乏更多的提示时不能推断出正确的选择。 现在,丢弃的候选项不接受选择类型分类。 此外,如果在那样的分类中任何一个候选项接受一个首选的类型,那么丢弃的候选项为那个参数接受非首选类型。

    5. 如果仅有一个候选项,那么使用它。 如果没有候选项或多于一个的首选项,那么将会失败。

注意,对于操作符和函数类型解析来说"最佳匹配"规则是完全相同的。 下面是一些例子。

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

只有一个带有两个参数的取整函数; 它携带一个参数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);

Note: 解析器从系统表pg_cast中解析到textvarchar类型是兼容二进制的, 意思是它可以被转化成一个接受其它不做屋里转换的函数。 因此,在这种情况下调用的类型转换没有真正地插入。

并且,如果该函数被一个integer类型的参数调用,那么解析器将试图转换其为text

SELECT substr(1234, 3);
ERROR:  函数substr(integer, integer)不存在
HINT: 没有函数匹配所给的名称和参数类型。你或许需要添加明确的类型。

由于integer类型不会隐含地转换为text所以它不能正常工作。 在一个明确的情况下它才会工作,然而:

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

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

Notes

[1]

该步的原因是在那些没有一个实际的类型转换函数的情况下支持函数风格浇铸规格。 如果有一个类型转换函数,那么在它的输出类型之后按惯例命名,并且不需要有一个特殊情况。 查阅CREATE CAST获取更多的说明。