支持的版本: 当前 (17) / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

CREATE FUNCTION

CREATE FUNCTION — 定义一个新函数

概要

CREATE [ OR REPLACE ] FUNCTION
    name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )
    [ RETURNS rettype
      | RETURNS TABLE ( column_name column_type [, ...] ) ]
  { LANGUAGE lang_name
    | TRANSFORM { FOR TYPE type_name } [, ... ]
    | WINDOW
    | { IMMUTABLE | STABLE | VOLATILE }
    | [ NOT ] LEAKPROOF
    | { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }
    | { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }
    | PARALLEL { UNSAFE | RESTRICTED | SAFE }
    | COST execution_cost
    | ROWS result_rows
    | SUPPORT support_function
    | SET configuration_parameter { TO value | = value | FROM CURRENT }
    | AS 'definition'
    | AS 'obj_file', 'link_symbol'
    | sql_body
  } ...

描述

CREATE FUNCTION 定义一个新函数。CREATE OR REPLACE FUNCTION 将创建一个新函数,或替换现有定义。要能够定义一个函数,用户必须拥有该语言的 USAGE 权限。

如果包含模式名称,则会在指定的模式中创建函数。否则,它会在当前模式中创建。新函数的名称不得与同一模式中具有相同输入参数类型的任何现有函数或过程匹配。但是,具有不同参数类型的函数和过程可以共享一个名称(这称为重载)。

要替换现有函数的当前定义,请使用 CREATE OR REPLACE FUNCTION。不能以这种方式更改函数的名称或参数类型(如果尝试这样做,实际上会创建一个新的、不同的函数)。此外,CREATE OR REPLACE FUNCTION 不允许您更改现有函数的返回类型。要执行此操作,您必须删除并重新创建该函数。(当使用 OUT 参数时,这意味着您不能更改任何 OUT 参数的类型,除非删除该函数。)

当使用 CREATE OR REPLACE FUNCTION 替换现有函数时,该函数的所有权和权限不会更改。所有其他函数属性都将分配命令中指定或暗示的值。您必须拥有该函数才能替换它(包括作为拥有角色的成员)。

如果您删除然后重新创建函数,则新函数与旧函数不是同一个实体;您将必须删除引用旧函数的现有规则、视图、触发器等。使用 CREATE OR REPLACE FUNCTION 更改函数定义,而不会破坏引用该函数的对象。此外,ALTER FUNCTION 可用于更改现有函数的大多数辅助属性。

创建函数的用户将成为该函数的所有者。

要能够创建函数,您必须对参数类型和返回类型具有 USAGE 权限。

有关编写函数的更多信息,请参阅 第 36.3 节

参数

name

要创建的函数的名称(可选的模式限定)。

argmode

参数的模式:INOUTINOUTVARIADIC。如果省略,则默认值为 IN。只有 OUT 参数可以跟随 VARIADIC 参数。此外,OUTINOUT 参数不能与 RETURNS TABLE 表示法一起使用。

argname

参数的名称。某些语言(包括 SQL 和 PL/pgSQL)允许您在函数体中使用该名称。对于其他语言,输入参数的名称只是额外的文档,就函数本身而言;但是,您可以在调用函数时使用输入参数名称来提高可读性(请参阅 第 4.3 节)。在任何情况下,输出参数的名称都很重要,因为它定义了结果行类型中的列名。(如果省略输出参数的名称,系统将选择默认列名。)

argtype

函数的参数的数据类型(可选的模式限定),如果有的话。参数类型可以是基本类型、复合类型或域类型,或者可以引用表列的类型。

根据实现语言,可能还允许指定诸如 伪类型 之类的类型,例如 cstring。伪类型表示实际参数类型要么未完全指定,要么超出了普通 SQL 数据类型的范围。

列的类型通过写入 table_name.column_name%TYPE 来引用。使用此功能有时可以帮助使函数独立于表定义的更改。

default_expr

如果未指定参数,则用作默认值的表达式。该表达式必须可强制转换为参数的参数类型。只有输入(包括 INOUT)参数才能具有默认值。具有默认值的参数之后的所有输入参数也必须具有默认值。

rettype

返回数据类型(可选的模式限定)。返回类型可以是基本类型、复合类型或域类型,或者可以引用表列的类型。根据实现语言,可能还允许指定诸如 伪类型 之类的类型,例如 cstring。如果该函数不应返回值,请指定 void 作为返回类型。

当存在 OUTINOUT 参数时,可以省略 RETURNS 子句。如果存在,则它必须与输出参数暗示的结果类型一致:如果有多个输出参数,则为 RECORD,或者与单个输出参数的类型相同。

SETOF 修饰符表示该函数将返回一组项,而不是单个项。

列的类型通过写入 table_name.column_name%TYPE 来引用。

column_name

RETURNS TABLE 语法中输出列的名称。这实际上是声明命名 OUT 参数的另一种方式,只是 RETURNS TABLE 也暗示 RETURNS SETOF

column_type

RETURNS TABLE 语法中输出列的数据类型。

lang_name

实现该函数的语言的名称。它可以是 sqlcinternal 或用户定义的过程语言的名称,例如 plpgsql。如果指定了 sql_body,则默认值为 sql。将名称用单引号括起来已被弃用,并且需要大小写匹配。

TRANSFORM { FOR TYPE type_name } [, ... ] }

列出函数调用应应用的转换。转换在 SQL 类型和特定于语言的数据类型之间进行转换;请参阅 CREATE TRANSFORM。过程语言的实现通常具有内置类型的硬编码知识,因此无需在此处列出。如果过程语言的实现不知道如何处理类型,并且没有提供转换,它将回退到用于转换数据类型的默认行为,但这取决于实现。

WINDOW

WINDOW 表示该函数是窗口函数,而不是普通函数。这目前仅对用 C 编写的函数有用。替换现有函数定义时无法更改 WINDOW 属性。

IMMUTABLE
STABLE
VOLATILE

这些属性告知查询优化器有关该函数的行为。最多可以指定一个选择。如果未出现这些属性,则默认假设为 VOLATILE

IMMUTABLE 表示该函数无法修改数据库,并且在给定相同参数值时始终返回相同的结果;也就是说,它不会进行数据库查找或以其他方式使用未直接存在于其参数列表中的信息。如果给定此选项,则使用全常量参数对函数的任何调用都可以立即替换为函数值。

STABLE 表示该函数无法修改数据库,并且在单个表扫描中,它将始终为相同的参数值返回相同的结果,但其结果可能会在 SQL 语句之间发生变化。对于其结果取决于数据库查找、参数变量(例如当前时区)等的函数,这是一个合适的选择。(它不适合希望查询当前命令修改的行的 AFTER 触发器。)另请注意,current_timestamp 函数系列符合稳定条件,因为它们的值在事务中不会更改。

VOLATILE 表示即使在单个表扫描中,函数值也可能会发生变化,因此无法进行任何优化。在这种意义上,相对较少的数据库函数是不稳定的;一些示例包括 random()currval()timeofday()。但请注意,任何具有副作用的函数都必须分类为不稳定,即使其结果非常可预测,以防止优化掉调用;一个示例是 setval()

有关更多详细信息,请参阅 第 36.7 节

LEAKPROOF

LEAKPROOF 表示该函数没有副作用。它不会通过返回值以外的任何方式泄露其参数的任何信息。例如,如果一个函数针对某些参数值抛出错误消息,而针对其他参数值不抛出错误消息,或者在任何错误消息中包含参数值,则该函数不是无泄漏的。这会影响系统如何针对使用 security_barrier 选项创建的视图或启用行级安全性的表执行查询。系统会在查询本身包含非无泄漏函数之前,强制执行安全策略和安全屏障视图中的条件,以防止意外暴露数据。标记为无泄漏的函数和运算符被认为是可信任的,可以在执行安全策略和安全屏障视图中的条件之前执行。此外,不接受参数或不从安全屏障视图或表传递任何参数的函数,不必标记为无泄漏即可在安全条件之前执行。请参阅 CREATE VIEW第 39.5 节。此选项只能由超级用户设置。

CALLED ON NULL INPUT
RETURNS NULL ON NULL INPUT
STRICT

CALLED ON NULL INPUT (默认) 表示当它的某些参数为 null 时,该函数将正常调用。然后,函数作者有责任在必要时检查 null 值并做出适当的响应。

RETURNS NULL ON NULL INPUTSTRICT 表示只要它的任何参数为 null,该函数始终返回 null。如果指定此参数,则在存在 null 参数时不会执行该函数;而是自动假定为 null 结果。

[EXTERNAL] SECURITY INVOKER
[EXTERNAL] SECURITY DEFINER

SECURITY INVOKER 表示该函数应以调用它的用户的权限执行。这是默认设置。SECURITY DEFINER 指定该函数应以拥有它的用户的权限执行。有关如何安全地编写 SECURITY DEFINER 函数的信息,请参见下文

关键字 EXTERNAL 允许用于 SQL 一致性,但它是可选的,因为与 SQL 不同,此功能适用于所有函数,而不仅仅是外部函数。

PARALLEL

PARALLEL UNSAFE 表示该函数不能在并行模式下执行;SQL 语句中存在这样的函数会强制执行串行执行计划。这是默认设置。PARALLEL RESTRICTED 表示该函数可以在并行模式下执行,但只能在并行组的领导进程中执行。PARALLEL SAFE 表示该函数可以在并行模式下安全运行,没有任何限制,包括在并行工作进程中。

如果函数修改任何数据库状态、更改事务状态(除了使用子事务进行错误恢复之外)、访问序列(例如,通过调用 currval)或对设置进行持久性更改,则应将其标记为并行不安全。如果函数访问临时表、客户端连接状态、游标、预处理语句或系统无法在并行模式下同步的杂项后端本地状态(例如,setseed 只能由组领导执行,因为另一个进程所做的更改不会反映在领导中),则应将其标记为并行受限。一般来说,如果一个函数被标记为安全,但实际上是受限的或不安全的,或者它被标记为受限,但实际上是不安全的,那么当在并行查询中使用时,它可能会抛出错误或产生错误的答案。C 语言函数理论上可能会表现出完全未定义的行为(如果标记错误),因为系统无法保护自己免受任意 C 代码的侵害,但在最可能的情况下,结果不会比任何其他函数更糟糕。如果有疑问,应将函数标记为 UNSAFE,这是默认设置。

COST 执行_成本

一个正数,给出函数的估计执行成本,单位为 cpu_operator_cost。如果函数返回一个集合,则这是每个返回行的成本。如果未指定成本,则对于 C 语言和内部函数假定为 1 个单位,对于所有其他语言的函数假定为 100 个单位。较大的值会导致规划器尝试避免不必要地频繁评估函数。

ROWS 结果_行

一个正数,给出规划器应预期函数返回的估计行数。仅当声明函数返回集合时才允许这样做。默认假设为 1000 行。

SUPPORT 支持_函数

用于此函数的规划器支持函数的名称(可选地使用模式限定)。有关详细信息,请参阅 第 36.11 节。您必须是超级用户才能使用此选项。

配置_参数

SET 子句会导致在进入函数时将指定的配置参数设置为指定的值,然后在函数退出时将其恢复为之前的值。SET FROM CURRENT 将在执行 CREATE FUNCTION 时当前参数的值保存为进入函数时要应用的值。

如果 SET 子句附加到函数,则在函数内为同一变量执行的 SET LOCAL 命令的效果仅限于该函数:配置参数的先前值仍然在函数退出时恢复。但是,普通的 SET 命令(不带 LOCAL)会覆盖 SET 子句,就像它对先前的 SET LOCAL 命令一样:此命令的效果在函数退出后仍然存在,除非当前事务回滚。

有关允许的参数名称和值的更多信息,请参阅 SET第 19 章

定义

定义函数的字符串常量;其含义取决于语言。它可以是内部函数名称、对象文件的路径、SQL 命令或过程语言中的文本。

使用美元引号(请参阅 第 4.1.2.4 节)来编写函数定义字符串,而不是使用普通的单引号语法,通常很有帮助。如果没有美元引号,则必须通过将函数定义中的任何单引号或反斜杠加倍来进行转义。

obj_file链接_符号

当 C 语言源代码中的函数名称与 SQL 函数的名称不同时,此形式的 AS 子句用于动态可加载的 C 语言函数。字符串 obj_file 是包含编译后的 C 函数的共享库文件的名称,并且其解释方式与 LOAD 命令相同。字符串 链接_符号 是函数的链接符号,即 C 语言源代码中函数的名称。如果省略链接符号,则假定它与正在定义的 SQL 函数的名称相同。所有函数的 C 名称必须不同,因此必须为重载的 C 函数提供不同的 C 名称(例如,使用参数类型作为 C 名称的一部分)。

当重复的 CREATE FUNCTION 调用引用同一对象文件时,该文件每个会话仅加载一次。要卸载并重新加载文件(可能在开发期间),请启动一个新会话。

sql_body

LANGUAGE SQL 函数的主体。它可以是单个语句

RETURN expression

或一个块

BEGIN ATOMIC
  statement;
  statement;
  ...
  statement;
END

这类似于将函数主体的文本编写为字符串常量(请参阅上面的 定义),但有一些差异:此形式仅适用于 LANGUAGE SQL,字符串常量形式适用于所有语言。此形式在函数定义时解析,字符串常量形式在执行时解析;因此,此形式不支持多态参数类型和在函数定义时无法解析的其他构造。此形式跟踪函数和函数主体中使用的对象之间的依赖关系,因此 DROP ... CASCADE 将正常工作,而使用字符串文字的形式可能会留下悬空的函数。最后,此形式与 SQL 标准和其他 SQL 实现更加兼容。

重载

PostgreSQL 允许函数重载;也就是说,只要它们具有不同的输入参数类型,就可以对多个不同的函数使用相同的名称。无论是否使用它,此功能在数据库中调用函数时都需要安全预防措施,在这些数据库中,某些用户不信任其他用户;请参阅 第 10.3 节

如果两个函数具有相同的名称和 输入 参数类型,则认为它们是相同的,忽略任何 OUT 参数。因此,例如,这些声明冲突

CREATE FUNCTION foo(int) ...
CREATE FUNCTION foo(int, out text) ...

具有不同参数类型列表的函数在创建时不会被视为冲突,但是如果提供了默认值,则它们在使用时可能会冲突。例如,请考虑

CREATE FUNCTION foo(int) ...
CREATE FUNCTION foo(int, int default 42) ...

由于应该调用哪个函数的不明确性,调用 foo(10) 将失败。

备注

完整的SQL类型语法允许用于声明函数的参数和返回值。但是,带括号的类型修饰符(例如,类型 numeric 的精度字段)会被 CREATE FUNCTION 丢弃。因此,例如,CREATE FUNCTION foo (varchar(10)) ...CREATE FUNCTION foo (varchar) ... 完全相同。

使用 CREATE OR REPLACE FUNCTION 替换现有函数时,更改参数名称存在限制。您不能更改已分配给任何输入参数的名称(尽管您可以将名称添加到以前没有名称的参数)。如果存在多个输出参数,则不能更改输出参数的名称,因为这会更改描述函数结果的匿名复合类型的列名。进行这些限制是为了确保在替换函数时,对该函数的现有调用不会停止工作。

如果使用 VARIADIC 参数声明函数 STRICT,则严格性检查会测试可变参数数组作为一个整体是否为非 null。如果数组具有 null 元素,仍将调用该函数。

示例

使用 SQL 函数添加两个整数

CREATE FUNCTION add(integer, integer) RETURNS integer
    AS 'select $1 + $2;'
    LANGUAGE SQL
    IMMUTABLE
    RETURNS NULL ON NULL INPUT;

用更符合 SQL 标准的风格编写的同一函数,使用参数名称和未加引号的主体

CREATE FUNCTION add(a integer, b integer) RETURNS integer
    LANGUAGE SQL
    IMMUTABLE
    RETURNS NULL ON NULL INPUT
    RETURN a + b;

PL/pgSQL 中,使用参数名称递增整数

CREATE OR REPLACE FUNCTION increment(i integer) RETURNS integer AS $$
        BEGIN
                RETURN i + 1;
        END;
$$ LANGUAGE plpgsql;

返回包含多个输出参数的记录

CREATE FUNCTION dup(in int, out f1 int, out f2 text)
    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
    LANGUAGE SQL;

SELECT * FROM dup(42);

你可以使用显式命名的复合类型以更详细的方式做同样的事情。

CREATE TYPE dup_result AS (f1 int, f2 text);

CREATE FUNCTION dup(int) RETURNS dup_result
    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
    LANGUAGE SQL;

SELECT * FROM dup(42);

另一种返回多列的方式是使用 TABLE 函数。

CREATE FUNCTION dup(int) RETURNS TABLE(f1 int, f2 text)
    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
    LANGUAGE SQL;

SELECT * FROM dup(42);

然而,TABLE 函数与前面的示例不同,因为它实际上返回的是一个记录集合,而不仅仅是一条记录。

安全地编写 SECURITY DEFINER 函数

由于 SECURITY DEFINER 函数是以其所有者的权限执行的,因此需要注意确保该函数不会被滥用。为了安全起见,search_path 应该被设置为排除任何不受信任用户可写的模式。这可以防止恶意用户创建对象(例如,表、函数和运算符)来掩盖函数打算使用的对象。在这方面,临时表模式尤其重要,默认情况下会首先搜索它,并且通常任何人都可以写入。通过强制最后搜索临时模式,可以获得安全的安排。为此,请将 pg_temp 作为 search_path 中的最后一个条目。这个函数说明了安全用法:

CREATE FUNCTION check_password(uname TEXT, pass TEXT)
RETURNS BOOLEAN AS $$
DECLARE passed BOOLEAN;
BEGIN
        SELECT  (pwd = $2) INTO passed
        FROM    pwds
        WHERE   username = $1;

        RETURN passed;
END;
$$  LANGUAGE plpgsql
    SECURITY DEFINER
    -- Set a secure search_path: trusted schema(s), then 'pg_temp'.
    SET search_path = admin, pg_temp;

此函数的目的是访问表 admin.pwds。但是如果没有 SET 子句,或者只有提到 adminSET 子句,可以通过创建一个名为 pwds 的临时表来破坏该函数。

如果安全定义器函数打算创建角色,并且它以非超级用户的身份运行,则应使用 SET 子句将 createrole_self_grant 也设置为已知值。

另一个需要记住的点是,默认情况下,新创建的函数的执行权限授予 PUBLIC(有关更多信息,请参阅第 5.8 节)。通常,您希望将安全定义器函数的使用限制为仅某些用户。为此,您必须撤销默认的 PUBLIC 权限,然后有选择地授予执行权限。为了避免新函数对所有人可访问的情况,请在单个事务中创建它并设置权限。例如:

BEGIN;
CREATE FUNCTION check_password(uname TEXT, pass TEXT) ... SECURITY DEFINER;
REVOKE ALL ON FUNCTION check_password(uname TEXT, pass TEXT) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION check_password(uname TEXT, pass TEXT) TO admins;
COMMIT;

兼容性

SQL 标准中定义了 CREATE FUNCTION 命令。PostgreSQL 实现可以以兼容的方式使用,但有许多扩展。相反,SQL 标准指定了一些在 PostgreSQL 中未实现的 可选功能。

以下是重要的兼容性问题:

  • OR REPLACE 是 PostgreSQL 的扩展。

  • 为了与其他一些数据库系统兼容,argmode 可以写在 argname 之前或之后。但只有第一种方式符合标准。

  • 对于参数默认值,SQL 标准仅指定带有 DEFAULT 关键字的语法。带有 = 的语法在 T-SQL 和 Firebird 中使用。

  • SETOF 修饰符是 PostgreSQL 的扩展。

  • 只有 SQL 被标准化为一种语言。

  • 除了 CALLED ON NULL INPUTRETURNS NULL ON NULL INPUT 之外的所有其他属性均未标准化。

  • 对于 LANGUAGE SQL 函数的主体,SQL 标准仅指定 sql_body 形式。

简单的 LANGUAGE SQL 函数可以使用既符合标准又可移植到其他实现的方式编写。使用高级功能、优化属性或其他语言的更复杂函数必然会在很大程度上特定于 PostgreSQL。

提交更正

如果您在文档中发现任何不正确的内容,与特定功能的体验不符,或者需要进一步说明,请使用此表单来报告文档问题。