↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 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 / 7.0 / 6.5 / 6.4
历史版本PostgreSQL 7.1 已于 2006 年 4 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

CREATE LANGUAGE

CREATE LANGUAGE — 为函数定义一种新语言

大纲

CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE 'langname'
    HANDLER call_handler
    LANCOMPILER 'comment'
  

输入

TRUSTED

TRUSTED指定该语言的调用处理器是安全的;也就是说,它不会为无特权用户提供任何绕过访问限制的功能。如果注册语言时省略这个关键字,则只有拥有 Postgres超级用户权限的用户能用这种语言创建新函数。

langname

新过程语言的名称。语言名不区分大小写。过程语言不能覆盖 Postgres的内建语言之一。

HANDLER call_handler

call_handler是一个先前已注册函数的名称,该函数将被调用来执行 PL 过程。

comment

LANCOMPILER参数是将被插入到新的 pg_language项的LANCOMPILER属性中的字符串。目前, Postgres完全不以任何方式使用这个属性。

输出

CREATE

如果语言成功创建,就返回此消息。

ERROR: PL handler function funcname() doesn't exist

如果找不到函数 funcname(),就返回此错误。

描述

使用CREATE LANGUAGE, Postgres用户可以向 Postgres注册一种新语言。随后,就可以用这种新语言定义函数和触发器过程。注册新语言的用户必须拥有 Postgres超级用户权限。

编写 PL 处理器

注意

在Postgres 7.1 及之后的版本中,调用处理器必须遵循"version 1"函数管理器接口,而不是旧式接口。

过程语言的调用处理器必须用 C 之类的编译语言编写,并作为不带参数、返回 opaque类型的函数注册到 Postgres中,这个类型是为未指定或未定义类型准备的占位类型。这可以防止调用处理器被当作函数从查询中直接调用。(不过,当要执行处理器所提供的语言中的某个 PL 函数时,实际调用中还是可以提供参数的。)

调用处理器的调用方式与其他任何函数相同:它接收一个指向 FunctionCallInfoData 结构的指针,其中包含参数值和被调用函数的信息,并且预期返回一个 Datum 结果(如果想返回 SQL NULL 结果,可能还要设置 FunctionCallInfoData 结构的isnull字段)。调用处理器与普通被调函数的区别在于,FunctionCallInfoData 结构的flinfo->fn_oid字段包含的是要调用的 PL 函数的 OID,而不是调用处理器自身的 OID。调用处理器必须用这个字段来确定要执行哪个函数。此外,所传递的参数列表是按照目标 PL 函数的声明(而不是调用处理器的声明)建立的。

获取pg_proc项并分析被调用过程的参数和返回类型,是调用处理器的责任。过程的 CREATE FUNCTION中的 AS 子句可以在pg_proc表项的prosrc属性中找到。它可以是过程语言自身的源文本(例如 PL/Tcl),可以是一个文件的路径名,也可以是任何能告诉调用处理器具体做什么的东西。

通常,同一个函数在一条 SQL 语句中会被调用多次。调用处理器可以利用flinfo->fn_extra字段来避免反复查找被调用函数的信息。该字段初始为 NULL,但调用处理器可以把它设置为指向关于该 PL 函数的信息。在后续调用中,如果flinfo->fn_extra已经非 NULL,就可以直接使用它并跳过信息查找步骤。调用处理器必须注意让flinfo->fn_extra指向至少能存活到当前查询结束的内存,因为 FmgrInfo 数据结构可能被保留那么久。一种做法是在flinfo->fn_mcxt指定的内存上下文中分配这些额外数据;这样的数据通常与 FmgrInfo 本身具有相同的生命期。但处理器也可以选择使用生存期更长的上下文,以便跨查询缓存函数定义信息。

当一个 PL 函数作为触发器被调用时,不会传递显式参数,但 FunctionCallInfoData 的context字段指向一个 TriggerData 节点,而不是像普通函数调用中那样为 NULL。PL 处理器应该为 PL 函数提供获取触发器信息的机制。

注意

使用CREATE FUNCTION创建函数。

使用DROP LANGUAGE删除过程语言。

参阅表pg_language以获得更多信息:

        Table "pg_language"
   Attribute   |  Type   | Modifier
---------------+---------+----------
 lanname       | name    |
 lanispl       | boolean |
 lanpltrusted  | boolean |
 lanplcallfoid | oid     |
 lancompiler   | text    |

   lanname   | lanispl | lanpltrusted | lanplcallfoid | lancompiler
-------------+---------+--------------+---------------+-------------
 internal    | f       | f            |             0 | n/a
 C           | f       | f            |             0 | /bin/cc
 sql         | f       | f            |             0 | postgres

过程语言的调用处理器通常必须用 C 编写,并根据它是链接进后端还是动态装载,注册为 'internal'或'C'语言。调用处理器不能使用旧式的'C'函数接口。

目前,过程语言的定义一旦创建就不能更改。

用法

这是一个用 C 编写的 PL 处理器模板:

#include "executor/spi.h"
#include "commands/trigger.h"
#include "utils/elog.h"
#include "fmgr.h"
#include "access/heapam.h"
#include "utils/syscache.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"

PG_FUNCTION_INFO_V1(plsample_call_handler);

Datum
plsample_call_handler(PG_FUNCTION_ARGS)
{
     Datum          retval;

     if (CALLED_AS_TRIGGER(fcinfo))
     {
          /*
           * Called as a trigger procedure
           */
          TriggerData    *trigdata = (TriggerData *) fcinfo->context;

          retval = ...
     } else {
          /*
           * Called as a function
           */

          retval = ...
     }

     return retval;
}
   

只需在省略号处再加上几千行代码,就能完成这个 PL 调用处理器。关于如何把它编译成可装载模块,见CREATE FUNCTION。

下面的命令随后注册这个示例过程语言:

CREATE FUNCTION plsample_call_handler () RETURNS opaque
    AS '/usr/local/pgsql/lib/plsample.so'
    LANGUAGE 'C';
CREATE PROCEDURAL LANGUAGE 'plsample'
    HANDLER plsample_call_handler
    LANCOMPILER 'PL/Sample';
   

兼容性

SQL92

CREATE LANGUAGE是 Postgres扩展。 SQL92中没有 CREATE LANGUAGE语句。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。