要在 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 手册页中 Variable "%s" will not stay shared
和 Variable "%s" is not available
的条目,或者在 Internet 上搜索 “perl nested named subroutine”。
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 中将显示为 “undefined”。上面的函数定义对于空输入不会表现得很好(事实上,它会表现得好像它们是零)。我们可以将 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!可以通过使用 “transform”(请参阅 CREATE TRANSFORM)来改进这种情况。bool_plperl
扩展提供了合适的转换。要使用它,请安装扩展
CREATE EXTENSION bool_plperl; -- or bool_plperlu for PL/PerlU
然后,将 TRANSFORM
函数属性用于接受或返回 bool
的 PL/Perl 函数,例如
CREATE FUNCTION perl_and(bool, bool) RETURNS bool TRANSFORM FOR TYPE bool AS $$ my ($a, $b) = @_; return $a && $b; $$ LANGUAGE plperl;
应用此转换后,Perl 会将 bool
参数视为 1
或空,因此分别为 true 或 false。如果函数结果为 bool
类型,则根据 Perl 是否会将返回值评估为 true 来确定它是 true 还是 false。对于在函数内部执行的 SPI 查询的布尔查询参数和结果(第 43.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();
声明的结果数据类型中任何未出现在哈希中的列都将作为空值返回。
类似地,过程的输出参数可以作为哈希引用返回
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
。
如果您发现文档中的任何内容不正确、与您使用特定功能的体验不符或需要进一步澄清,请使用 此表单报告文档问题。