5

我在使用 Perl 5.12.4 的 Postgres 9.2 上的 plperl 存储过程中遇到了一个特殊性。

可以使用这个“破碎”的 SP 来重现奇怪的行为:

CREATE FUNCTION foo(VARCHAR) RETURNS VARCHAR AS $$
    my ( $re ) = @_;
    $re = ''.qr/\b($re)\b/i;
    return $re;
$$ LANGUAGE plperl;

执行时:

# select foo('foo');
ERROR:  Unable to load utf8.pm into plperl at line 3.
BEGIN failed--compilation aborted.
CONTEXT:  PL/Perl function "foo"

但是,如果我将qr//操作移到 eval 中,它会起作用:

CREATE OR REPLACE FUNCTION bar(VARCHAR) RETURNS VARCHAR AS $$
    my ( $re ) = @_;
    eval "\$re = ''.qr/\\b($re)\\b/i;";
    return $re;
$$ LANGUAGE plperl;

结果:

# select bar('foo');
       bar       
-----------------
 (?^i:\b(foo)\b)
(1 row)
  1. 为什么评估绕过自动use utf8

  2. 为什么use utf8甚至首先需要?我的代码不是 UTF8,据说这是唯一一次应该use utf8.

    如果有的话,如果脚本的输入包含非 ASCII 值,我可能希望eval版本在没有 的情况下中断。use utf8(进一步的测试表明,将非 ASCII 值传递给 bar() 确实会导致 eval 失败并出现相同的错误)


请注意,许多 Postgres 安装会在 perl 解释器启动时自动加载“utf8”。这至少在 Debian 中是默认设置,如下所示DO 'elog(WARNING, join ", ", sort keys %INC)' language plperl;

警告:Carp.pm、Carp/Heavy.pm、Exporter.pm、feature.pm、overload.pm、strict.pm、unicore/Heavy.pl、unicore/To/Fold.pl、unicore/lib/Perl/SpacePer。 pl、utf8.pm、utf8_heavy.pl、vars.pm、warnings.pm、warnings/register.pm
上下文:PL/Perl 匿名代码块
DO

但在展示奇怪行为的机器上却不是这样:

警告:Carp.pm、Carp/Heavy.pm、Exporter.pm、feature.pm、overload.pm、overloading.pm、strict.pm、vars.pm、warnings.pm、warnings/register.pm
上下文:PL/Perl匿名代码块
DO

这个问题不是关于如何让我的目标机器自动加载 utf8;我知道该怎么做。我很好奇为什么它似乎首先是必要的。

4

2 回答 2

4

在失败的版本中,你正在执行

$re = ''.qr/\b($re)\b/i

在成功的版本中,您正在执行

$re = ''.qr/\b(foo)\b/i

当模式被编译为 Unicode 模式(无论这意味着什么)时,听起来 qr// 需要 utf8.pm,但后者没有被编译为 Unicode 模式。


无法加载 utf8.pm 是由于 plperl 创建的安全隔间所施加的限制。

解决方法是将模块加载到保险箱外。

解决方法是使用更有效的

$re = '(?^u:\\b(?i:'.$re.')\\b)';
于 2013-12-03T15:56:53.627 回答
1

我有同样的问题,我通过添加来解决它

plperl.on_init = 'use utf8; use re; package utf8; require "utf8_heavy.pl";'

postgresql.conf归档。

我希望这会对某人有所帮助。

于 2015-10-21T03:19:02.150 回答