10.3. Functions

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

功能类型解析

当通过限定名称[9]调用在架构中发现的可变参数函数时,这会造成安全隐患,该函数允许不受信任的用户创建对象。恶意用户可以控制并执行任意 SQL 函数,就像执行它们一样。替换带有VARIADIC关键字的呼叫,可以绕过此危险。填充VARIADIC "any"参数的调用通常没有包含VARIADIC关键字的等效公式。为了安全地发出这些调用,函数的架构必须仅允许受信任的用户创建对象。

通过合格名称[9]调用架构中允许不信任用户创建对象的任何函数时,这会造成可用性危害。恶意用户可以使用现有功能的名称创建功能,复制该功能的参数并附加具有默认值的新颖参数。这排除了对原始函数的新调用。为了避免这种危险,请将函数放置在仅允许受信任用户创建对象的架构中。

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

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

只有一个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);

实施例 10.7. 可变参数功能

CREATE FUNCTION public.variadic_example(VARIADIC numeric[]) RETURNS int
  LANGUAGE sql AS 'SELECT 1';
CREATE FUNCTION

此函数接受但不要求 VARIADIC 关键字。它允许整数和数字参数:

SELECT public.variadic_example(0),
       public.variadic_example(0.0),
       public.variadic_example(VARIADIC array[0.0]);
 variadic_example | variadic_example | variadic_example
------------------+------------------+------------------
                1 |                1 |                1
(1 row)

但是,第一个和第二个调用将使用更特定的功能(如果有):

CREATE FUNCTION public.variadic_example(numeric) RETURNS int
  LANGUAGE sql AS 'SELECT 2';
CREATE FUNCTION

CREATE FUNCTION public.variadic_example(int) RETURNS int
  LANGUAGE sql AS 'SELECT 3';
CREATE FUNCTION

SELECT public.variadic_example(0),
       public.variadic_example(0.0),
       public.variadic_example(VARIADIC array[0.0]);
 variadic_example | variadic_example | variadic_example
------------------+------------------+------------------
                3 |                2 |                1
(1 row)

给定默认配置,并且只有第一个功能存在,因此第一个和第二个调用是不安全的。任何用户都可以通过创建第二个或第三个函数来拦截它们。通过完全匹配参数类型并使用VARIADIC关键字,第三次调用是安全的。

实施例 10.8. 子字符串函数类型解析

有多个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:  function substr(integer, integer) does not exist
HINT:  No function matches the given name and argument types. You might need
to add explicit type casts.

这不起作用,因为integer没有对text的隐式转换。显式强制转换将起作用,但是:

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

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

[9]使用非模式限定的名称不会引起危险,因为包含允许不信任用户创建对象的架构的搜索路径不是安全模式使用模式

[10]此步骤的原因是在没有实际的强制转换功能的情况下支持函数样式的强制转换规范。如果存在强制转换功能,则通常按其输出类型命名,因此无需特殊情况。有关其他 Comment,请参见CREATE CAST

上一章 首页 下一章