# 创建函数

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
  } ...

# 描述

创建函数定义了一个新函数。创建或替换函数将创建一个新函数,或替换现有定义。为了能够定义一个函数,用户必须拥有用法语言的特权。

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

要替换现有函数的当前定义,请使用创建或替换函数.无法以这种方式更改函数的名称或参数类型(如果您尝试过,您实际上会创建一个新的、不同的函数)。还,创建或替换函数不会让您更改现有函数的返回类型。为此,您必须删除并重新创建该函数。(使用时出去参数,这意味着您不能更改任何类型出去参数,除非删除函数。)

什么时候创建或替换函数用于替换现有函数,函数的所有权和权限不会改变。所有其他功能属性都分配了命令中指定或隐含的值。您必须拥有要替换它的功能(这包括成为拥有角色的成员)。

如果您删除然后重新创建一个函数,则新函数与旧函数不是同一个实体;您将不得不删除引用旧功能的现有规则、视图、触发器等。采用创建或替换函数在不破坏引用该函数的对象的情况下更改函数定义。还,改变功能可用于更改现有函数的大部分辅助属性。

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

为了能够创建一个函数,你必须有用法参数类型和返回类型的特权。

参考第 38.3 节有关写入函数的更多信息。

# 参数

姓名

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

参数模式

参数的模式:,出去,进出, 或者杂音.如果省略,则默认为.仅有的出去参数可以遵循杂音一。还,出去进出参数不能与回报表符号。

参数名称

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

参数类型

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

根据实现语言,它也可能被允许指定“伪类型”,例如字符串.伪类型表示实际参数类型要么未完全指定,要么超出普通 SQL 数据类型集。

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

default_expr

如果未指定参数,则用作默认值的表达式。表达式必须强制转换为参数的参数类型。仅输入(包括进出) 参数可以有一个默认值。具有默认值的参数之后的所有输入参数也必须具有默认值。

重新输入

返回数据类型(可选模式限定)。返回类型可以是基类型、复合类型或域类型,也可以引用表列的类型。根据实现语言,它也可能被允许指定“伪类型”,例如字符串.如果函数不应该返回值,请指定空白作为返回类型。

当有出去要么进出参数,回报子句可以省略。如果存在,它必须与输出参数隐含的结果类型一致:记录如果有多个输出参数,或者与单个输出参数的类型相同。

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

列的类型通过写来引用*表名*.*列名*%类型.

列名

输出列的名称回报表句法。这实际上是另一种声明命名的方式出去参数,除了回报表也暗示回报设定.

列类型

中输出列的数据类型返回表语法。

郎朗的名字

实现函数的语言的名称。有可能sql,c,内部的,或用户定义的过程语言的名称,例如。,plpgsql.默认值为sql如果*sql_体*是指定的。不推荐使用单引号将名称括起来,需要大小写匹配。

转换{FOR TYPE*输入你的名字* } [, ... ] }

列出应该应用哪些转换函数调用。转换SQL类型和特定语言的数据类型;看见创建转换.过程语言实现通常具有内置类型的硬编码知识,因此这里不需要列出这些类型。如果过程语言实现不知道如何处理类型,并且没有提供转换,那么它将退回到转换数据类型的默认行为,但这取决于实现。

表示该函数是一个窗口函数而不是简单的函数。这目前只对用C编写的函数有用替换现有函数定义时无法更改属性。

不变的
稳定的
不稳定的

这些属性通知查询优化器函数的行为。最多可以指定一个选项。如果这些都没有出现,不稳定的这是默认的假设。

不变的指示函数无法修改数据库,并且在给定相同的参数值时始终返回相同的结果;也就是说,它不进行数据库查找,也不使用参数列表中没有直接显示的信息。如果给出了这个选项,任何带有常量参数的函数调用都可以立即替换为函数值。

稳定的指示函数无法修改数据库,并且在一次表扫描中,它将一致地为相同的参数值返回相同的结果,但其结果可能会在SQL语句中发生变化。对于结果依赖于数据库查找、参数变量(如当前时区)等的函数,这是一个合适的选择(不适用于之后希望查询由当前命令修改的行的触发器。)还要注意当前时间戳函数族符合稳定条件,因为它们的值在事务中不会改变。

不稳定的指示即使在一次表扫描中函数值也可以更改,因此无法进行优化。在这个意义上,相对较少的数据库函数是不稳定的;例如随机的, currval(), 每日时间.但请注意,任何具有副作用的函数都必须分类为volatile,即使其结果是可预测的,以防止调用被优化;例如setval().

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

防漏的

防漏的表示该功能没有副作用。除了返回值之外,它不显示关于其参数的任何信息。例如,如果函数为某些参数值而不是其他参数值抛出错误消息,或者在任何错误消息中包含参数值,则该函数不是防泄漏的。这会影响系统对使用创建的视图执行查询的方式安全屏障选项或启用了行级安全性的表。系统将在用户从查询本身提供的任何包含非防泄漏功能的条件之前,强制执行安全策略和安全屏障视图中的条件,以防止数据意外泄露。标记为防泄漏的函数和运算符被认为是可信的,并且可以在安全策略和安全屏障视图中的条件出现之前执行。此外,不接受参数或未从security barrier视图或表中传递任何参数的函数不必标记为防泄漏,以便在安全条件之前执行。看见创建视图第41.5节。此选项只能由超级用户设置。

调用空输入
输入为NULL时返回NULL
严格的

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

输入为NULL时返回NULL严格的指示每当函数的任何参数为null时,该函数始终返回null。如果指定了此参数,则在存在空参数时不执行该函数;相反,会自动假定结果为空。

[外部]安全调用程序
[外部]安全定义器

安全调用程序指示将以调用该函数的用户的权限执行该函数。这是默认值。安全定义者指定使用拥有该函数的用户的权限执行该函数。

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

平行的

平行不安全指示函数不能以并行模式执行,并且SQL语句中存在此类函数会强制执行串行执行计划。这是默认设置。并行限制指示该功能可以并行模式执行,但执行仅限于并行组长。平行保险箱表示该功能可以在并行模式下安全运行,不受限制。

如果函数修改任何数据库状态,或对事务进行更改(例如使用子事务),或访问序列或试图对设置进行持久更改(例如。,塞特瓦尔)。如果它们访问临时表、客户端连接状态、游标、准备好的语句或系统无法在并行模式下同步的其他后端本地状态(例如。,种子只能由组长执行,因为其他流程所做的更改不会反映在组长中)。一般来说,如果函数在被限制或不安全时被标记为安全,或者在实际上不安全时被标记为受限制,则在并行查询中使用时可能会抛出错误或产生错误答案。理论上,C语言函数如果标记错误,可能会表现出完全未定义的行为,因为系统无法保护自己免受任意C代码的攻击,但在大多数情况下,结果不会比任何其他函数更糟。如果有疑问,功能应标记为不安全的,这是默认值。

费用 执行成本

一个正数,给出函数的估计执行成本,单位为中央处理器_操作人员_费用.如果函数返回一个集合,这是每返回一行的成本。如果未指定成本,则C语言和内部函数假设为1个单位,所有其他语言的函数假设为100个单位。较大的值会导致规划人员试图避免过于频繁地评估函数。

结果_行

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

支持 支持功能

应用程序的名称(可选架构限定)计划者支持功能用于此功能。看见第38.11节详细信息。您必须是超级用户才能使用此选项。

配置参数
价值

这个设置子句使指定的配置参数在输入函数时设置为指定的值,然后在函数退出时恢复为以前的值。从当前设置保存当前参数的值创建函数作为输入函数时应用的值执行。

如果设置子句附加到一个函数,然后是设置本地在函数内部为同一变量执行的命令仅限于函数:配置参数的先前值仍在函数退出时恢复。然而,一个普通的设置命令(无地方的)覆盖设置条款,就像它对前一个设置本地命令:除非回滚当前事务,否则该命令的效果将在函数退出后持续。

看见设置第20章有关允许的参数名称和值的详细信息。

释义

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

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

*obj_文件*, *链接符号*

这种形式的子句用于在C语言源代码中的函数名与SQL函数名不相同时动态加载的C语言函数。绳子*obj_文件包含已编译C函数的共享库文件的名称,并被解释为负载命令绳子链接符号*是函数的链接符号,即C语言源代码中函数的名称。如果省略了链接符号,则假定它与所定义的SQL函数的名称相同。所有函数的C名称必须不同,因此必须为重载的C函数指定不同的C名称(例如,将参数类型用作C名称的一部分)。

重复时创建函数调用引用同一个对象文件,每个会话只加载一次该文件。要卸载和重新加载文件(可能在开发期间),请启动一个新会话。

sql_体

尸体语言SQL作用这可以是单个语句

RETURN expression

还是一个街区

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

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

# 超载

PostgreSQL允许函数超载; 也就是说,相同的名称可以用于几个不同的函数,只要它们具有不同的输入参数类型。无论您是否使用它,在一些用户不信任其他用户的数据库中调用函数时,此功能都需要采取安全预防措施;看见第10.3节.

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

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

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

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

电话傅(10)将由于应调用哪个函数的模糊性而失败。

# 笔记

可以使用完整的SQL类型语法来声明函数的参数和返回值。但是,括号中的类型修饰符(例如,类型的精度字段数字的)被丢弃创建函数例如创建函数foo(varchar(10))。。。创建函数foo(varchar)。。。.

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

如果函数被声明严格的用一个可变的参数,严格性检查测试变量数组作为一个整体是非空的。如果数组中有空元素,则仍将调用该函数。

# 例子

使用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);

返回多列的另一种方法是使用桌子功能:

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);

然而桌子函数与前面的示例不同,因为它实际上返回设置记录的数量,而不仅仅是一张记录。

#安全定义者安全运行

因为安全定义者函数是以拥有它的用户的权限执行的,需要注意确保函数不会被滥用。为了安全,搜索_路径应设置为排除不受信任用户可写的任何架构。这可以防止恶意用户创建对象(例如,表、函数和运算符),从而屏蔽该函数要使用的对象。在这方面特别重要的是临时表模式,默认情况下首先搜索临时表模式,通常任何人都可以写入临时表模式。通过强制最后搜索临时模式,可以获得安全的安排。要做到这一点,请写pg_温度作为最后一项搜索路径.此功能说明了安全使用:

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;

此函数的目的是访问表管理pwds.但是没有设置子句,或带有设置只提及的条款管理,可以通过创建名为pwds.

在PostgreSQL 8.3版本之前设置子句不可用,因此旧函数可能包含相当复杂的保存、设置和恢复逻辑搜索路径这个设置子句更容易用于此目的。

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

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;

# 兼容性

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

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

  • 或者替换是一个PostgreSQL扩展。

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

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

  • 这个一套修饰符是PostgreSQL的扩展。

  • 只有SQL是一种标准化的语言。

  • 除此之外的所有其他属性调用空输入输入为NULL时返回NULL没有标准化。

  • 为了…的身体语言SQL函数,SQL标准只指定*sql_体*类型

    易于理解的语言SQL函数的编写方式既符合标准,又便于其他实现。使用高级功能、优化属性或其他语言的更复杂的函数必然在很大程度上特定于PostgreSQL。

# 另见

改变功能, 下降函数, 授予, 负载, 撤销