我在带有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)
  • 为什么eval绕过自动use utf8
  • 为什么一开始甚至需要use utf8?我的代码不在UTF8中,它被称为only time one should use utf8

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

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



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



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

    最佳答案

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

    $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)';
    

    关于perl - 为什么此postgres存储过程想要 `use utf8`?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20355007/

    10-15 13:03