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

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
历史版本PostgreSQL 8.1 已于 2010 年 11 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

第 38 章 PL/Perl - Perl 过程语言

PL/Perl 是一种可加载的过程语言,可以用 Perl 编程语言编写 PostgreSQL 函数。

使用 PL/Perl 的主要好处,是可以在存储函数中使用 Perl 提供的多种“字符串处理”操作符和函数。与使用 PL/pgSQL 提供的字符串函数和控制结构相比,用 Perl 解析复杂字符串可能更容易。

要在某个特定数据库中安装 PL/Perl,使用 createlang plperl dbname。

提示

如果把某种语言安装到template1中,之后创建的所有数据库都会自动安装该语言。

注意

使用源码包的用户必须在安装过程中专门启用 PL/Perl 的构建(更多信息见 第 14 章)。使用二进制包的用户可能会在单独的 子包中找到 PL/Perl。

38.1. PL/Perl 函数和参数 #

要用 PL/Perl 语言创建一个函数,可使用标准的 CREATE FUNCTION语法:

CREATE FUNCTION funcname (argument-types) RETURNS return-type AS $$
    # PL/Perl 函数体
$$ LANGUAGE plperl;

函数的主体就是普通的 Perl 代码。事实上,PL/Perl 的粘合代码会把它 包裹在一个 Perl 子程序中。PL/Perl 函数必须总是返回一个标量值。 如下文所述,可以通过返回引用来返回更复杂的结构(数组、记录和 集合)。绝不要返回列表。

注意

在 Perl 中使用命名嵌套子程序是有危险的,特别是当它们引用外层作用域 中的词法变量时。因为 PL/Perl 函数被包装成一个子程序,任何放在其中的 命名子程序都会成为嵌套子程序。一般来说,创建通过代码引用 (coderef)调用的匿名子程序会安全得多。更多细节见 perldiag 手册页。

CREATE FUNCTION 命令的语法要求函数体写成一个 字符串常量。通常对该字符串常量使用美元引用(见 第 4.1.2.2 节)最方便。如果选择使用常规的 单引号字符串常量语法,就必须对函数体中用到的单引号 (')和反斜线(\)进行转义, 通常是把它们写成双份(见 第 4.1.2.1 节)。

参数和结果的处理与其他 Perl 子程序一样:参数通过 @_ 传入,结果值通过 return 返回,或者作为函数中最后一个被求值的表达式返回。

例如,一个返回两个整数值中较大值的函数可以定义为:

CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
    if ($_[0] > $_[1]) { return $_[0]; }
    return $_[1];
$$ LANGUAGE plperl;

如果一个 SQL 空值被传给一个函数,在 Perl 中该参数值将呈现为“未定义”。上述函数定义对于 空值输入的行为并不理想(实际上,它会把它们当作零)。我们可以在函数 定义中添加 STRICT,让 PostgreSQL 采取更合理的做法:如果传入空值, 函数将根本不会被调用,而是自动返回空值结果。另一种方式是在函数体中 检查未定义输入。例如,假设我们希望在 perl_max 的两个参数中一个为空值、另一个非空值时,返回非空值参数而不是空值:

CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
    my ($x,$y) = @_;
    if (! defined $x) {
        if (! defined $y) { return undef; }
        return $y;
    }
    if (! defined $y) { return $x; }
    if ($x > $y) { return $x; }
    return $y;
$$ LANGUAGE plperl;

如上所示,要从 PL/Perl 函数返回 SQL 空值,就返回一个未定义值。 无论函数是否为严格函数,都可以这样做。

Perl 可以把 PostgreSQL 数组返回为对 Perl 数组的引用。这里有一个示例:

CREATE OR REPLACE function returns_array()
RETURNS text[][] AS $$
    return [['a"b','c,d'],['e\\f','g']];
$$ LANGUAGE plperl;

select returns_array();

复合类型参数被作为哈希的引用传递给函数。哈希的键是复合类型的 属性名。这里是一个示例:

CREATE TABLE employee (
    name text,
    basesalary integer,
    bonus integer
);

CREATE FUNCTION empcomp(employee) RETURNS integer AS $$
    my ($emp) = @_;
    return $emp->{basesalary} + $emp->{bonus};
$$ LANGUAGE plperl;

SELECT name, empcomp(employee.*) FROM employee;

PL/Perl 函数也可以用相同的方法返回复合类型:返回一个具有所需属性的 哈希的引用。例如:

CREATE TYPE testrowperl AS (f1 integer, f2 text, f3 text);

CREATE OR REPLACE FUNCTION perl_row() RETURNS testrowperl AS $$
    return {f2 => 'hello', f1 => 1, f3 => 'world'};
$$ LANGUAGE plperl;

SELECT * FROM perl_row();

在声明的结果数据类型中,凡是哈希中未出现的列都将作为空值返回。

PL/Perl 函数还可以返回标量类型或复合类型的集合。通常会希望逐行返回, 这既能缩短启动时间,也能避免把整个结果集排入内存。如下所示, 可以用 return_next 实现这一点。注意,在最后一次 return_next 之后,必须写上 return 或者(更好)return undef。

CREATE OR REPLACE FUNCTION perl_set_int(int)
RETURNS SETOF INTEGER AS $$
    foreach (0..$_[0]) {
        return_next($_);
    }
    return undef;
$$ LANGUAGE plperl;

SELECT * FROM perl_set_int(5);

CREATE OR REPLACE FUNCTION perl_set()
RETURNS SETOF testrowperl AS $$
    return_next({ f1 => 1, f2 => 'Hello', f3 => 'World' });
    return_next({ f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' });
    return_next({ f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' });
    return undef;
$$ LANGUAGE plperl;

对于较小的结果集,可以返回一个数组引用,其中对简单类型、数组类型 和复合类型分别包含标量、数组引用或哈希引用。下面是把整个结果集 作为数组引用返回的几个简单示例:

CREATE OR REPLACE FUNCTION perl_set_int(int) RETURNS SETOF INTEGER AS $$
    return [0..$_[0]];
$$ LANGUAGE plperl;

SELECT * FROM perl_set_int(5);

CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testrowperl AS $$
    return [
        { f1 => 1, f2 => 'Hello', f3 => 'World' },
        { f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' },
        { f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' }
    ];
$$ LANGUAGE plperl;

SELECT * FROM perl_set();

PL/Perl 目前对域类型没有完整支持:它把域同其底层 标量类型一样对待。这意味着与域关联的约束不会被强制执行。这对函数 参数来说不是问题,但如果你把一个 PL/Perl 函数声明 为返回域类型,就会存在隐患。

如果希望在代码中使用 strict 编译指示,最简单的 方法是把 SET plperl.use_strict 设为真。该参数影响后续编译的 PL/Perl 函数,但不会影响当前会话中已经 编译的函数。要在 PL/Perl 装载之前设置该 参数,必须先把 “plperl” 加入 postgresql.conf 中的 custom_variable_classes 列表。

使用 strict 编译指示的另一种方法是把:

use strict;

放在函数体中。

提交更正

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