On this page
44.1. PL/Perl 函数和参数
要使用 PL/Perl 语言创建函数,请使用标准的CREATE FUNCTION语法:
CREATE FUNCTION funcname (argument-types) RETURNS return-type AS $$
# PL/Perl function body
$$ LANGUAGE plperl;
该函数的主体是普通的 Perl 代码。实际上,PL/Perl 粘合代码将其包装在 Perl 子例程中。 PL/Perl 函数在标量上下文中被调用,因此它无法返回列表。您可以通过返回引用来返回非标量值(数组,记录和集合),如下所述。
PL/Perl 还支持用DO语句调用的匿名代码块:
DO $$
# PL/Perl code
$$ LANGUAGE plperl;
匿名代码块不接收任何参数,并且它可能返回的任何值都将被丢弃。否则,它的行为就像一个函数。
Note
在 Perl 中使用命名嵌套子例程是危险的,特别是如果它们在封闭范围内引用词法变量时,则尤其如此。由于 PL/Perl 函数包含在子例程中,因此您放置在其中的任何命名子例程都将被嵌套。通常,创建通过代码引用调用的匿名子例程要安全得多。有关更多信息,请参见 perldiag 手册页中Variable "%s" will not stay shared
和Variable "%s" is not available
的条目,或在 Internet 上搜索“ perl 嵌套命名子例程”。
CREATE FUNCTION
命令的语法要求将函数主体编写为字符串常量。通常,对字符串常量使用美元引号(请参见Section 4.1.2.4)最方便。如果选择使用转义字符串语法E''
,则必须将函数主体中使用的任何单引号('
)和反斜杠(\
)都加倍(请参见Section 4.1.2.1)。
参数和结果的处理方式与任何其他 Perl 子例程相同:参数在@_
中传递,结果值以return
或作为函数中最后一个求值的表达式返回。
例如,返回两个整数值中较大的一个的函数可以定义为:
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
if ($_[0] > $_[1]) { return $_[0]; }
return $_[1];
$$ LANGUAGE plperl;
Note
参数将从数据库的编码转换为 UTF-8 以在 PL/Perl 中使用,然后在返回时从 UTF-8 转换回数据库编码。
如果将 SQL 空值传递给函数,则参数值在 Perl 中将显示为“未定义”。上面的函数定义在 Importing 为 null 时表现不佳(实际上,它们的行为就好像它们是零)。我们可以在函数定义中添加STRICT
以使 PostgreSQL 做一些更合理的事情:如果传递了 null 值,则该函数将根本不会被调用,而只会自动返回 null 结果。另外,我们可以检查函数体中是否有未定义的 Importing。例如,假设我们希望perl_max
带有一个 null 和一个 nonnull 参数,以返回 nonnull 参数而不是 null 值:
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
my ($x, $y) = @_;
if (not defined $x) {
return undef if not defined $y;
return $y;
}
return $x if not defined $y;
return $x if $x > $y;
return $y;
$$ LANGUAGE plperl;
如上所示,要从 PL/Perl 函数返回 SQL 空值,请返回未定义的值。无论功能是否严格,都可以这样做。
函数参数中没有引用的任何内容都是字符串,该字符串位于相关数据类型的标准 PostgreSQL 外部文本表示形式中。对于普通的数字或文本类型,Perl 只会做正确的事,而程序员通常不必担心。但是,在其他情况下,需要将参数转换为 Perl 中更可用的形式。例如,decode_bytea
函数可用于将bytea
类型的参数转换为未转义的二进制文件。
同样,传回 PostgreSQL 的值必须采用外部文本表示格式。例如,encode_bytea
函数可用于为类型为bytea
的返回值转义二进制数据。
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();
Perl 将 PostgreSQL 数组作为有福的PostgreSQL::InServer::ARRAY
对象传递。该对象可以视为数组引用或字符串,从而可以与为运行低于 9.1 的 PostgreSQL 版本编写的 Perl 代码向后兼容。例如:
CREATE OR REPLACE FUNCTION concat_array_elements(text[]) RETURNS TEXT AS $$
my $arg = shift;
my $result = "";
return undef if (!defined $arg);
# as an array reference
for (@$arg) {
$result .= $_;
}
# also works as a string
$result .= $arg;
return $result;
$$ LANGUAGE plperl;
SELECT concat_array_elements(ARRAY['PL','/','Perl']);
Note
多维数组以对每个 Perl 程序员都通用的方式表示为对低维引用数组的引用。
复合类型参数作为对哈希的引用传递给函数。哈希键是组合类型的属性名称。这是一个例子:
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();
如果您希望在代码中使用strict
编译指示,则可以选择几种方法。对于临时的全局使用,您可以SET
plperl.use_strict
为 true。这将影响 PL/Perl 函数的后续编译,但不会影响当前会话中已编译的函数。对于永久的全局使用,您可以在postgresql.conf
文件中将plperl.use_strict
设置为 true。
对于特定功能的永久使用,您可以简单地 Importing:
use strict;
在功能主体的顶部。
如果您的 Perl 版本为 5.10.0 或更高版本,feature
编译指示也可用于use
。