2024年9月26日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不支持的版本: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()。但请注意,任何具有副作用的函数都必须被归类为 volatile,即使其结果相当可预测,以防止调用被优化掉;一个例子是 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 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_filelink_symbol

当 C 语言源代码中的函数名称与 SQL 函数的名称不同时,此形式的 AS 子句用于动态加载的 C 语言函数。字符串 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类型语法允许用于声明函数的参数和返回值。但是,CREATE FUNCTION 会丢弃带括号的类型修饰符(例如,类型 numeric 的精度字段)。因此,例如 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 子句,或者 SET 子句仅提及 admin,则可以通过创建一个名为 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。

提交更正

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