CREATE FUNCTION 语句(概述)

CREATE FUNCTION 语句用于在数据库服务器中注册用户定义的函数。 您可以在此声明中注册的每种功能都有单独的描述。

外部标量
更改开始该函数是用编程语言编写的,并返回标量值。 外部可执行程序(包)与函数的各种属性一起在数据库服务器中注册。 每次调用该函数时,程序包都会执行一次或多次。 参见 CREATE FUNCTION语句(外部标量函数 )。更改结束
外部表
更改开始该功能是用编程语言编写的。 每次启动函数时,它都会返回一个表,该表是从子选择开始的,每次返回一行。 外部可执行程序(包)与函数的各种属性一起在数据库服务器中注册。 每次调用该函数时,程序包都会执行一次或多次。 参见 CREATE FUNCTION语句(外部表函数 )。更改结束
有源
更改开始该功能通过调用服务器上存在的另一个函数(内置、外部、SQL或源代码)来实现。 该函数继承了基础源函数的属性。 源函数没有关联的包。 参见 CREATE FUNCTION语句(源函数 )。更改结束
SQL 标量
该函数仅以SQL语句编写,并返回一个标量值。 SQL标量函数的主体是用SQL过程语言(SQL PL)编写的。 函数及其各种属性在当前服务器上定义。
更改开始Db2 支持两种类型的SQL标量函数,内联和编译:
  • 内联SQL标量函数包含一个RETURN语句,用于返回简单表达式的值。 该函数不作为查询的一部分调用,而是将函数RETURN语句中的表达式复制(内联)到查询本身中。 因此,内联SQL标量函数不会生成包。
  • 编译的SQL标量函数支持更广泛的功能,包括所有SQL PL语句。 为编译的SQL标量函数生成一个包。 它包含函数的主体,包括控制语句。 它可能还包含由 Db2 生成的语句。 每次调用该函数时,程序包都会执行一次或多次。
更改结束

更改开始当处理 SQL 标量函数的 CREATE FUNCTION 语句时, Db2 会尝试创建内联 SQL 标量函数。 如果无法创建内联函数, Db2 将尝试创建一个已编译的SQL标量函数。 有关这些类型的函数的语法和规则的更多信息,请参阅 CREATE FUNCTION 语句(内联 SQL 标量函数)CREATE FUNCTION 语句(编译 SQL 标量函数)更改结束

更改开始要确定创建的是哪种类型的SQL标量函数,请参阅 SYSIBM.SYSROUTINES 目录表的INLINE列。 更改结束

SQL 表
更改开始该函数仅以SQL RETURN语句的形式编写,并返回一组行。 SQL表函数的主体是用SQL过程语言编写的。 该功能与各种属性一起在当前服务器上定义。 该函数不作为查询的一部分调用。 相反,函数的RETURN语句中的表达式被复制(内联)到查询本身中。 因此,不会为SQL表函数生成包。 参见 CREATE FUNCTION语句(SQL表函数 )。更改结束

所有CREATE FUNCTION类型的说明

创建各种功能时,应考虑以下因素:

车主特权:
对于除源函数以外的所有函数,所有者有权执行该函数(EXECUTE权限),并可以将这些权限授予他人。 更多信息,请参阅 GRANT语句(函数或过程权限 )。 有关对象所有权的更多信息,请参阅授权、特权、权限、掩码和对象所有权
选择架构和功能名称:

名称、模式名称、参数数量和每个参数的数据类型(不考虑数据类型的任何长度、精度、比例、子类型或编码方案属性)的组合不能识别当前服务器上存在的用户定义的函数。 如果函数有超过30个参数,则仅使用前30个参数来确定函数是否唯一。

如果每个函数的签名是唯一的,则可以为多个函数使用相同的名称。

  • 功能名称的无限定形式不得为以下任何系统保留关键字,即使您将其指定为分隔标识符:
    ALL                     LIKE                     UNIQUE
    AND                     MATCH                    UNKNOWN
    ANY                     NOT                      =
    BETWEEN                 NULL                     ¬=
    DISTINCT                ONLY                     <
    EXCEPT                  OR                       <=
    EXISTS                  OVERLAPS                 ¬<
    FALSE                   SIMILAR                  >
    FOR                     SOME                     >=
    FROM                    TABLE                    ¬>
    IN                      TRUE                     <>
    IS                      TYPE                                          

更改开始如果权限集包含 SYSADM 或 SYSCTRL 权限,则架构名称可以是“SYSTOOLS”或“SYSFUN”。 否则,模式名称不得以“SYS”开头,除非模式名称为“SYSADM”。更改结束

定义参数
函数的输入参数在括号内以列表形式指定。

一个函数可以没有输入参数。 在这种情况下,必须指定一组空括号,例如:

CREATE FUNCTION WOOFER()

函数结果的类型在函数的 RETURNS 子句中指定。

为参数选择数据类型:
当您为函数选择输入和输出参数的数据类型时,请考虑可能会影响参数值的提升规则。 (参见数据类型推广 )。 例如,作为函数输入参数之一的常量可能具有与函数所期望的数据类型不同的内置数据类型,更重要的是,它可能无法转换为函数所期望的数据类型。 根据推广规则,请考虑使用以下数据类型作为参数:
  • INTEGER代替SMALLINT
  • DOUBLE代替REAL
  • VARCHAR代替CHAR
  • VARGRAPHIC代替GRAPHIC
  • VARBINARY代替BINARY

为了在非 Db2 for z/OS® 平台之间实现功能的可移植性,请不要使用以下数据类型,因为它们在不同平台上的表现可能有所不同:

  • Float。 请使用DOUBLE或REAL。
  • 数值。 请改用 DECIMAL。

有关内置数据类型的说明,请参阅 CREATE TABLE 语句中的数据类型built-in-type 的说明。

指定AS LOCATOR作为参数:
传递定位符而不是值可以减少函数传入或传出的字节数。 当参数值非常大时,此功能非常有用。 AS LOCATOR子句指定传递参数值的定位符,而不是实际值。 仅当参数具有LOB数据类型或基于LOB数据类型的独特类型时,且仅当JAVA语言无效时,才指定AS LOCATOR。

AS LOCATOR子句对确定数据类型是否可以提升没有影响,对函数解析中使用的函数签名也没有影响。

对于源函数或 SQL 函数,不得指定 AS LOCATOR。

如果函数定义为“无 SQL”,则不能指定 AS LOCATOR。

使用 TABLE LIKE 名称 AS LOCATOR 子句定义的函数注意事项:
如果函数定义时带有表参数( TABLE LIKE 姓名 AS LOCATOR 如果在 CREATE FUNCTION 语句中指定了 CLASSIFICATION 子句来指示输入参数之一是转换表,那么任何指定参数列表作为变更的一部分的 ALTER FUNCTION 语句都无法更改该函数。 例如,在添加或替换函数版本时,需要将参数列表作为常规规范的一部分。 在这种情况下,必须放弃该功能,然后重新创建。
确定架构中功能的唯一性:
在目前的服务器上,每个函数的函数签名(即限定函数名称与输入参数的数量和数据类型相结合)必须是唯一的。 如果函数有超过30个输入参数,则仅使用前30个参数的数据类型来确定唯一性。 这意味着两个不同的方案可以包含具有相同名称的函数,这些函数具有相同的数据类型,适用于所有相应的数据类型。 但是,一个单一的架构不能包含多个具有相同名称且对应数据类型相同的功能。

在确定对应的数据类型是否匹配时, Db2 不会考虑任何长度、精度或比例属性。 Db2 将数据类型的同义词视为匹配项。 例如,REAL和FLOAT,DOUBLE和FLOAT被视为匹配。 因此,CHAR(8)和CHAR(35)被视为相同,DECIMAL(11,2)、DECIMAL(4,3)、DECFLOAT(16)和DECFLOAT(34)、TIMESTAMP(6)和TIMESTAMP(9)、TIMESTAMP(6) WITH TIME ZONE和TIMESTAMP(9) WITH TIME ZONE也是如此。 此外,字符和图形类型以及时间戳类型被认为是相同的。 例如,以下类型被视为同一类型:CHAR和GRAPHIC、VARCHAR和VARGRAPHIC、CLOB和DBCLOB、TIMESTAMP WITHOUT TIME ZONE和TIMESTAMP WITH TIME ZONE。 CHAR(13)和GRAPHIC(8)被视为同一类型。 如果创建的函数的签名与现有用户定义的函数(具有相同名称和架构)的签名重复,则返回错误。

假设在同一个模式中执行以下语句来创建四个函数。 第二和第四句语句失败,因为它们创建的函数与第一和第三句语句创建的函数重复。

  CREATE FUNCTION PART (INT, CHAR(15)) …
  CREATE FUNCTION PART (INTEGER, CHAR(40)) …
  CREATE FUNCTION ANGLE (DECIMAL(12,2)) …
  CREATE FUNCTION ANGLE (DEC(10,7)) …
为函数指定一个特定的名称:
当定义具有相同名称和架构(具有不同参数列表)的多重功能时,建议同时指定一个特定的名称。

特定名称可用于唯一标识功能,例如在搜索、删除或评论功能时。 但是,不能通过其特定名称来调用该函数。

特定名称隐式或显式地由模式名称限定。 如果在CREATE FUNCTION中未指定模式名称,则该名称与函数名称(function-name)的显式或隐式模式名称相同。 如果指定了模式名称,则该名称必须与函数名称的显式或隐式模式名称相同。 名称(包括架构名称)不得识别当前服务器上存在的其他函数或过程的具体名称。

如果没有指定SPECIFIC子句,则生成一个特定的名称。

扩展或覆盖内置功能
除非需要扩展或覆盖内置功能,否则不建议将用户定义的外部函数与内置函数重名。

如果您确实打算创建一个与内置函数同名的函数,请注意保持其函数签名唯一。 如果您的函数与内置函数的相应参数具有相同的名称和数据类型,但实现不同的逻辑,当使用不正确的函数名称调用该函数时, Db2 可能会选择错误的函数。 例如,如果新函数的模式出现在SQL路径中,且位于系统模式之前,则 Db2 可能会选择用户定义的函数,而不是内置函数。 使用非限定名称的应用程序,如果之前使用该名称的内置函数成功,则可能会失败。 如果 Db2 选择内置函数而不是内置函数,它也可能看起来运行成功,但结果却不同。 这种情况可能发生在动态 SQL 语句中,也可能发生在静态 SQL 语句被重新编译时。

扩展现有内置功能
创建一个与内置函数同名的用户自定义函数,并赋予其唯一的函数签名。 例如,可能需要用户定义的函数,类似于内置函数ROUND,该函数接受不同的类型MONEY作为输入,而不是内置的数字类型。 在这种情况下,名为ROUND的新用户定义函数的签名与内置ROUND函数支持的所有函数签名不同。
超越内置功能:
创建与内置函数同名的用户自定义函数,并为其指定签名。 新函数与内置函数的相应参数具有相同的名称和数据类型,但逻辑不同。

例如,使用不同的四舍五入规则可能比内置的ROUND函数更有用。 在这种情况下,名为ROUND的新用户定义函数的签名将与内置ROUND函数支持的签名相同。

另一个覆盖内置函数的情形是,当参数不是内置数据类型时,使用其功能。 您可以定义一个源函数,该函数接受用户定义的数据类型参数并将其传递给底层内置函数,而不是将参数明确转换为内置数据类型。 源函数是指引用内置函数或其他用户定义的函数。 有关有源函数的更多信息,请参阅 CREATE FUNCTION 语句(有源函数)

DISTINCT关键字可以传递给调用用户定义的函数,该函数源自内置聚合函数之一。 例如,假设MY_AVG是一个用户定义的函数,它基于内置的AVG函数。 用户自定义函数可通过“MY_AVG (DISTINCT expression )”调用。这会导致使用DISTINCT关键字调用内置的AVG函数。

特殊功能注册
调用者的特殊寄存器的设置由调用时的函数继承,并在返回调用者时恢复。 特殊寄存器可以在执行SQL语句的功能中更改,但这些更改不会影响调用者。
函数中的全局变量:
函数中引用的全局变量的内容是从调用环境继承的。
用户自定义功能指定的可滚动光标:
使用可滚动光标,一行内容可以多次获取。 因此,如果滚动光标的 SELECT 语句在选择列表中调用了一个不确定的函数,则一行数据可能会被多次提取,每次提取的结果都不同。 同样,如果滚动光标的 SELECT 语句调用了一个使用外部操作定义的用户定义函数,则每次获取时都会执行该操作。
安全功能注意事项:
为了创建安全函数,安全管理员通常会检查函数访问的数据,确保其安全,并向当前需要创建安全用户定义函数权限的人员授予CREATE_SECURE_OBJECT权限。 在创建函数后,他们从函数所有者那里撤销了CREATE_SECURE_OBJECT权限。

源函数不能创建为安全函数。

如果行权限或列掩码定义引用了用户定义的函数,则该用户定义的函数必须是安全的,因为敏感数据可能会作为参数传递给该函数。 DSN_FUNCTION_TABLE中的SECURE列指示用户定义的函数是否被视为安全。

如果一个安全的用户定义函数调用其他用户定义函数,则 Db2 不会验证这些嵌套的用户定义函数是否具有SECURED属性。 如果这些嵌套函数可以访问敏感数据,安全管理员必须确保这些函数被允许访问敏感数据,并确保为这些函数的任何更改建立变更控制审核程序。