25.3. 描述 #
25.3.1. PL/Perl 函数和参数
要用 PL/Perl 语言创建函数,使用标准的语法
CREATE FUNCTIONfuncname(argument-types) RETURNSreturn-typeAS ' # PL/Perl function body ' LANGUAGE plperl;
PL/PerlU 与此相同,只是语言应指定为
plperlu。
函数体是普通的 Perl 代码。参数和结果的处理与任何其他 Perl 子例程一样:参数通过 @_ 传入,结果值用 return 或作为函数中最后求值的表达式返回。例如,一个返回两个整数值中较大者的函数可以这样定义:
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS '
if ($_[0] > $_[1]) { return $_[0]; }
return $_[1];
' LANGUAGE plperl;
如果把一个 NULL 传给函数,参数值在 Perl 中将显示为“未定义”。上面的函数定义对 NULL 输入表现不太好(事实上,它会把它们当作零来处理)。我们可以在函数定义中加上 WITH (isStrict),让 PostgreSQL
做更合理的事情:如果传入 NULL,函数根本不会被调用,而是自动返回 NULL
结果。另一种做法是在函数体内检查未定义的输入。例如,假设我们希望 perl_max
在一个参数为空、另一个非空时返回非空的那个参数,而不是返回 NULL:
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS '
my ($a,$b) = @_;
if (! defined $a) {
if (! defined $b) { return undef; }
return $b;
}
if (! defined $b) { return $a; }
if ($a > $b) { return $a; }
return $b;
' LANGUAGE plperl;
如上所示,要让 PL/Perl 函数返回 NULL,就返回一个未定义的值。无论函数是否为 strict,都可以这样做。
复合类型的参数以哈希的引用形式传给函数。哈希的键是该复合类型的属性名。下面是一个例子:
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;
目前不支持返回复合类型的结果值。
提示
由于函数体是作为 SQL 字符串字面量传给 CREATE FUNCTION 的,你必须转义 Perl 源码中的单引号和反斜线,通常像上例那样将它们加倍。另一种可行的方法是使用 Perl 的扩展引号函数(q[]、qq[]、qw[])来避免写单引号。
下面是一个由于安全原因不允许文件系统操作而不能工作的函数例子:
CREATE FUNCTION badfunc() RETURNS integer AS '
open(TEMP, ">/tmp/badfile");
print TEMP "Gotcha!\n";
return 1;
' LANGUAGE plperl;这个函数的创建会成功,但执行它不会成功。
注意,如果同一个函数是由超级用户用语言
plperlu 创建的,执行就会成功。
25.3.2. PL/Perl 中的数据值
提供给
PL/Perl 函数脚本的参数值只是转换为文本形式的输入参数(就像它们被
SELECT 语句显示出来一样)。反过来,return
命令接受任何作为函数声明的返回类型可接受输入格式的字符串。因此,PL/Perl
程序员可以像操作纯文本一样操作数据值。
25.3.3. 从 PL/Perl 访问数据库
从
Perl 函数访问数据库本身可以通过实验性模块 DBD::PgSPI(也可在 CPAN
镜像站点获取)完成。该模块提供了一个名为
$pg_dbh 的符合 DBI 的数据库句柄,可以用正常的 DBI 语法执行查询。
PL/Perl 本身目前只提供一个额外的 Perl 命令:
eloglevel,msg发出一条日志或错误消息。可能的级别有
DEBUG、NOTICE和ERROR。DEBUG和NOTICE只是把给定的消息发送到 postmaster 日志(对NOTICE而言还会发送给客户端)。ERROR引发一个错误条件:函数的进一步执行被放弃,当前事务被中止。
25.3.4. 缺失的特性
PL/Perl 函数不能直接相互调用(因为它们是 Perl 内部的匿名子例程)。目前也没有办法让它们共享全局变量。
PL/Perl 目前不能用于编写触发器函数。
DBD::PgSPI 或类似的能力应当被集成进标准 PostgreSQL 发行版。