CREATE FUNCTION — 定义一个新函数
CREATE [ OR REPLACE ] FUNCTIONname
( [ [argmode
] [argname
]argtype
[ { DEFAULT | = }default_expr
] [, ...] ] ) [ RETURNSrettype
| RETURNS TABLE (column_name
column_type
[, ...] ) ] { LANGUAGElang_name
| TRANSFORM { FOR TYPEtype_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 } | COSTexecution_cost
| ROWSresult_rows
| SUPPORTsupport_function
| SETconfiguration_parameter
{ TOvalue
| =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
参数的模式:IN
、OUT
、INOUT
或 VARIADIC
。如果省略,默认为 IN
。只有 OUT
参数可以跟在 VARIADIC
参数之后。此外,OUT
和 INOUT
参数不能与 RETURNS TABLE
语法一起使用。
argname
参数的名称。某些语言(包括 SQL 和 PL/pgSQL)允许您在函数体中使用名称。对于其他语言,输入参数的名称仅作为额外的文档,就函数本身而言;但您可以在调用函数时使用输入参数名称来提高可读性(参见 第 4.3 节)。无论如何,输出参数的名称很重要,因为它定义了结果行类型中的列名。(如果您为输出参数省略了名称,系统将选择一个默认列名。)
argtype
函数参数的数据类型(可选择模式限定),如果有的话。参数类型可以是基本类型、复合类型或域类型,或者可以引用表列的类型。
根据实现语言,也可能允许指定“伪类型”,例如 cstring
。伪类型表示实际参数类型要么不完全指定,要么不在普通 SQL 数据类型集合之外。
通过写入
来引用列的类型。使用此功能有时可以帮助函数独立于表定义的变化。table_name
.column_name
%TYPE
default_expr
如果未指定参数,则用作默认值的表达式。该表达式必须可强制转换为参数的参数类型。只有输入(包括 INOUT
)参数可以有默认值。具有默认值的参数后面的所有输入参数也必须具有默认值。
rettype
返回数据类型(可选择模式限定)。返回类型可以是基本类型、复合类型或域类型,或者可以引用表列的类型。根据实现语言,也可能允许指定“伪类型”,例如 cstring
。如果函数不应返回值,则将 void
指定为返回类型。
当存在 OUT
或 INOUT
参数时,可以省略 RETURNS
子句。如果存在,它必须与输出参数所隐含的结果类型一致:如果是多个输出参数,则为 RECORD
,或者与单个输出参数的类型相同。
SETOF
修饰符表示函数将返回一个项集,而不是单个项。
通过写入
来引用列的类型。table_name
.column_name
%TYPE
column_name
RETURNS TABLE
语法中输出列的名称。这实际上是声明一个命名的 OUT
参数的另一种方式,除了 RETURNS TABLE
也隐含了 RETURNS SETOF
。
column_type
RETURNS TABLE
语法中输出列的数据类型。
lang_name
函数实现的语言名称。它可以是 sql
、c
、internal
,或者是用户定义的存储过程语言的名称,例如 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 INPUT
或 STRICT
表示当任何参数为 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
命令一样:此类命令的效果将在函数退出后持续存在,除非当前事务被回滚。
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 ATOMICstatement
;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 INPUT
和 RETURNS NULL ON NULL INPUT
外,所有其他属性均未标准化。
对于 LANGUAGE SQL
函数的主体,SQL 标准仅指定 sql_body
形式。
简单的 LANGUAGE SQL
函数可以以一种既符合标准又可移植到其他实现的方式编写。使用高级功能、优化属性或其他语言的更复杂的函数必然会在很大程度上特定于 PostgreSQL。
如果您在文档中看到任何不正确、与您对特定功能的使用经验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。