# 10.3.功能

函数调用引用的特定函数使用以下过程确定。

函数类型解析

  1. 从列表中选择要考虑的功能pg_程序系统目录。如果使用了非模式限定的函数名,则考虑的函数是那些具有匹配名称和参数计数的函数,它们在当前搜索路径中可见(请参见第5.9.3节)。如果给定了限定函数名,则只考虑指定架构中的函数。

    1. 如果搜索路径找到多个参数类型相同的函数,则只考虑路径中最早出现的函数。不管搜索路径位置如何,不同参数类型的函数都是在平等的基础上考虑的。

    2. 如果函数是用可变的数组参数,调用不使用可变的关键字,则该函数将被视为数组参数被其元素类型的一个或多个匹配项替换,以匹配调用。在这种扩展之后,函数的有效参数类型可能与一些非变量函数相同。在这种情况下,使用搜索路径中较早出现的函数,或者如果两个函数在同一个模式中,则首选非变量函数。

      这会在通过限定名称呼叫时造成安全隐患[10],一个在模式中发现的变量函数,允许不受信任的用户创建对象。恶意用户可以控制并执行任意SQL函数,就像您执行了它们一样。替换带有可变的关键字,它绕过了这种危险。呼叫填充可变“任意”参数通常没有包含可变的关键词。为了安全地发出这些调用,函数的模式必须只允许受信任的用户创建对象。

    3. 具有参数默认值的函数被视为与忽略零个或多个可默认参数位置的任何调用相匹配。如果有多个这样的函数与一个调用匹配,则使用搜索路径中最早出现的函数。如果在同一模式中有两个或多个这样的函数,且在非默认位置具有相同的参数类型(如果它们具有不同的可默认参数集,这是可能的),系统将无法确定首选哪个,因此如果找不到与调用更好的匹配,将导致“模糊函数调用”错误。

      这会在通过限定名称呼叫时造成可用性风险[10],在模式中找到的允许不受信任的用户创建对象的任何函数。恶意用户可以使用现有函数的名称创建函数,复制该函数的参数并附加具有默认值的新参数。这就排除了对原始函数的新调用。为了防止这种危险,将函数放在只允许受信任用户创建对象的模式中。

  2. 检查函数是否完全接受输入参数类型。如果存在一个(在考虑的函数集中只能有一个精确匹配),请使用它。当通过限定名呼叫时,缺少精确匹配会造成安全隐患[10],在模式中找到的一个函数,允许不受信任的用户创建对象。在这种情况下,可以使用参数强制进行精确匹配。(涉及未知的在这一步中永远找不到匹配项。)

  3. 如果没有找到精确匹配,请查看函数调用是否为特殊类型转换请求。如果函数调用只有一个参数,且函数名与某些数据类型的(内部)名称相同,则会发生这种情况。此外,函数参数必须是未知类型文字,或者是可二进制强制为命名数据类型的类型,或者是可通过应用该类型的I/O函数转换为命名数据类型的类型(即,转换为或从标准字符串类型之一转换)。当满足这些条件时,函数调用被视为铸造规格[11]

  4. 寻找最佳匹配。

    1. 放弃输入类型不匹配且无法转换(使用隐式转换)以匹配的候选函数。未知的为了这个目的,文字被认为可以转换成任何东西。如果只剩下一名候选人,就使用它;否则继续下一步。

    2. 如果任何输入参数属于域类型,则在所有后续步骤中将其视为域的基类型。这确保了域的行为与它们的基类型类似,以实现不明确的函数解析。

    3. 仔细检查所有候选人,并保留那些在输入类型上最精确匹配的候选人。如果没有完全匹配的候选人,则保留所有候选人。如果只剩下一名候选人,就使用它;否则继续下一步。

    4. 浏览所有候选项,并将那些接受首选类型(输入数据类型的类型类别)的候选项保留在需要进行类型转换的大多数位置。保留所有候选人,如果没有人接受首选类型。如果只剩下一名候选人,就使用它;否则继续下一步。

    5. 如果有输入参数未知的,检查其余候选人在这些论点位置接受的类型类别。在每个位置,选择一串类别如果任何候选人接受该类别。(这种对字符串的偏向是适当的,因为未知类型的文字看起来像字符串。)否则,如果所有剩余的候选对象都接受相同的类型类别,请选择该类别;否则就会失败,因为没有更多的线索就无法推断出正确的选择。现在放弃不接受所选类型类别的候选项。此外,如果任何候选者接受该类别中的首选类型,则放弃接受该参数的非首选类型的候选者。如果没有人通过这些测试,就保留所有候选人。如果只剩下一名候选人,就使用它;否则继续下一步。

    6. 如果两者都有未知的已知类型参数,所有已知类型参数都具有相同的类型,假设未知的参数也是这种类型的,并检查哪些候选者可以在未知的-论点立场。如果只有一个候选人通过了这项测试,就使用它。否则,失败。

请注意,运算符和函数类型解析的“最佳匹配”规则是相同的。下面是一些例子。

例10.6.舍入函数参数类型解析

只有一个圆形的具有两个参数的函数;它需要类型为的第一个参数数字的还有第二个类型的参数整数。因此,下面的查询会自动转换类型为的第一个参数整数数字的:

SELECT round(4, 4);

 round
### Note

The parser learns from the `pg_cast` catalog that`text` and `varchar`are binary-compatible, meaning that one can be passed to a function that
accepts the other without doing any physical conversion. Therefore, no
type conversion call is really inserted in this case.

And, if the function is called with an argument of type `integer`,
the parser will try to convert that to `text`:

选择substr(1234,3);错误:函数substr(整数,整数)不存在提示:没有与给定名称和参数类型匹配的函数。您可能需要添加显式类型转换。

 This does not work because `integer` does not have an implicit cast
to `text`. An explicit cast will work, however:

选择substr(CAST(1234为文本),3);

substr