2025年9月25日: PostgreSQL 18 发布!
支持的版本: 当前 (18) / 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 表示函数没有副作用。除了通过返回值外,它不透露有关其参数的任何信息。例如,一个函数在某些参数值下抛出错误消息而不是其他参数值,或者在任何错误消息中包含参数值,则不是 leakproof 的。这会影响系统如何执行对使用 security_barrier 选项创建的视图或启用行级安全策略的表执行查询。系统将首先强制执行来自安全策略和安全屏障视图的条件,然后再执行用户提供的来自查询本身的、包含非 leakproof 函数的条件,以防止数据意外泄露。被标记为 leakproof 的函数和运算符被假定为可信的,并且可能在安全策略和安全屏障视图中的条件之前执行。此外,不带参数或未从安全屏障视图或表中传递任何参数的函数不需要被标记为 leakproof 即可在安全条件之前执行。请参阅 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)或对设置进行了持久性更改,则应将函数标记为 parallel unsafe。如果它们访问临时表、客户端连接状态、游标、预编译语句或后端本地的杂项状态(系统无法在并行模式下同步,例如 setseed 只能由组长执行,因为其他进程的更改不会反映在领导者中),则应将其标记为 parallel restricted。总的来说,如果一个函数被标记为 safe,但实际上是 restricted 或 unsafe,或者被标记为 restricted,但实际上是 unsafe,那么在并行查询中使用它时,可能会导致错误或产生错误的结果。C 语言函数理论上可能表现出完全未定义的行为,如果标记错误,因为系统无法保护自己免受任意 C 代码的影响,但在大多数情况下,结果不会比任何其他函数更糟。如有疑问,应将函数标记为 UNSAFE,这是默认设置。

COST execution_cost

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

ROWS result_rows

一个正数,表示规划器应期望函数返回的行数。这仅在函数被声明为返回集合时才允许。默认假定为 1000 行。

SUPPORT support_function

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

configuration_parameter
value

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

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

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

definition

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

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

obj_file, link_symbol

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

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

sql_body

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

RETURN expression

或一个块

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

这类似于将函数主体文本写成字符串常量(参见上面的definition),但有一些区别:此形式仅适用于 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 替换现有函数时,对更改参数名称有限制。您不能更改已分配给任何输入参数的名称(尽管您可以为以前没有名称的参数添加名称)。如果存在多个输出参数,则不能更改输出参数的名称,因为这会改变描述函数结果的匿名复合类型的列名。这些限制是为了确保函数现有的调用在替换后不会停止工作。

如果一个函数被声明为 STRICT 并带有 VARIADIC 参数,则 strictness 检查会测试该变长数组整体是否为非 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 子句,或者 SET 子句只提到 admin,那么函数可能会被创建名为 pwds 的临时表所颠覆。

如果 security definer 函数打算创建角色,并且它以非超级用户的身份运行,那么 createrole_self_grant 也应该使用 SET 子句设置为一个已知值。

需要注意的另一点是,默认情况下,新创建函数的执行权限授予给 PUBLIC(有关更多信息,请参阅 第 5.8 节)。通常您希望限制 security definer 函数的使用仅限于某些用户。要做到这一点,您必须撤销默认的 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;

兼容性

CREATE FUNCTION 命令在 SQL 标准中定义。 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。

提交更正

如果您在文档中看到任何不正确、与您对特定功能的使用经验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。