要创建 PL/Perl 语言中的函数,请使用标准 CREATE FUNCTION 语法
CREATE FUNCTIONfuncname(argument-types) RETURNSreturn-type-- function attributes can go here AS $$ # PL/Perl function body goes here $$ LANGUAGE plperl;
函数的主体是普通的 Perl 代码。事实上,PL/Perl 粘合代码将其包装在 Perl 子例程中。PL/Perl 函数在标量上下文中调用,因此它不能返回列表。您可以通过返回引用(如下所述)来返回非标量值(数组、记录和集合)。
在 PL/Perl 过程中,将忽略 Perl 代码中的任何返回值。
PL/Perl 还支持使用 DO 语句调用的匿名代码块
DO $$
# PL/Perl code
$$ LANGUAGE plperl;
匿名代码块不接收任何参数,并且它可能返回的任何值都将被丢弃。否则,它的行为就像一个函数。
在 Perl 中使用已命名的嵌套子例程很危险,尤其是当它们引用封闭作用域中的词法变量时。由于 PL/Perl 函数封装在一个子例程中,因此你放在其中的任何已命名子例程都将被嵌套。通常,创建匿名子例程并通过代码引用调用它们要安全得多。有关更多信息,请参阅 perldiag 手册页中 变量“%s”不会保持共享 和 变量“%s”不可用 的条目,或在互联网上搜索 “perl 嵌套已命名子例程”。
CREATE FUNCTION 命令的语法要求函数体写为字符串常量。通常最方便的是对字符串常量使用美元引用(请参阅 第 4.1.2.4 节)。如果你选择使用转义字符串语法 E'',则必须对函数体中使用的任何单引号 (') 和反斜杠 (\) 加倍(请参阅 第 4.1.2.1 节)。
参数和结果的处理方式与任何其他 Perl 子例程一样:参数在 @_ 中传递,结果值通过 return 返回或作为函数中计算的最后一个表达式返回。
例如,可以将返回两个整数值中较大值的一个函数定义为
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
if ($_[0] > $_[1]) { return $_[0]; }
return $_[1];
$$ LANGUAGE plperl;
参数将从数据库的编码转换为 UTF-8 以在 PL/Perl 中使用,然后在返回时从 UTF-8 转换回数据库编码。
如果将 SQL 空值传递给函数,则该参数值在 Perl 中将显示为 “未定义”。上述函数定义在处理空输入时不会表现得很理想(事实上,它会将空输入当作零)。我们可以向函数定义中添加 STRICT,以使 PostgreSQL 执行更合理的操作:如果传递空值,则根本不会调用函数,而只会自动返回空结果。或者,我们可以在函数体中检查未定义的输入。例如,假设我们希望 perl_max 在一个空参数和一个非空参数的情况下返回非空参数,而不是空值
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 的返回值的二进制数据。
一个特别重要的情况是布尔值。正如刚刚所述,bool 值的默认行为是将它们作为文本传递给 Perl,因此可能是 't' 或 'f'。这存在问题,因为 Perl 不会将 'f' 视为 false!可以通过使用 “转换” 来改善情况(请参见 CREATE TRANSFORM)。bool_plperl 扩展提供了合适的转换。要使用它,请安装该扩展
CREATE EXTENSION bool_plperl; -- or bool_plperlu for PL/PerlU
然后,对采用或返回 bool 的 PL/Perl 函数使用 TRANSFORM 函数属性,例如
CREATE FUNCTION perl_and(bool, bool) RETURNS bool TRANSFORM FOR TYPE bool AS $$ my ($a, $b) = @_; return $a && $b; $$ LANGUAGE plperl;
应用此转换后,Perl 会将 bool 参数视为 1 或空,因此正确地为真或假。如果函数结果为 bool 类型,则根据 Perl 是否将返回的值评估为真来确定其为真或假。对于布尔查询参数和函数内部执行的 SPI 查询的结果,也会执行类似的转换(第 45.3.1 节)。
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']);
多维数组表示为对低维数组引用的引用,这是每个 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();
声明的结果数据类型中不存在哈希中的任何列都将作为 null 值返回。
类似地,过程的输出参数可以作为哈希引用返回
CREATE PROCEDURE perl_triple(INOUT a integer, INOUT b integer) AS $$
my ($a, $b) = @_;
return {a => $a * 3, b => $b * 3};
$$ LANGUAGE plperl;
CALL perl_triple(5, 10);
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。
对于在特定函数中永久使用,您可以简单地放置
use strict;
在函数体的顶部。
如果您的 Perl 是 5.10.0 或更高版本,feature 编译指示也可用于 use。
如果您在文档中看到任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。