我在使用Postgres 9.2和Perl 5.12.4中的plperl存储过程时发现了一个奇怪的问题。
这种奇怪的行为可以使用以下“错误”的存储过程进行复现:
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 格式,据说只有在这种情况下才需要使用use utf8
。如果有什么问题,我可能希望
eval
版本在没有use utf8
的情况下出现错误,比如输入脚本包含非 ASCII 值的情况。(进一步测试表明将非 ASCII 值传递给 bar() 确实会导致 eval 失败并显示相同的错误)
请注意,许多 Postgres 安装程序会在 perl 解释器启动时自动加载 'utf8'。至少在 Debian 中,通过执行
DO 'elog(WARNING, join ", ", sort keys %INC)' language plperl;
可以证明这一点:
WARNING: 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
CONTEXT: PL/Perl anonymous code block
DO
但在表现奇怪的机器上并非如此:
WARNING: Carp.pm, Carp/Heavy.pm, Exporter.pm, feature.pm, overload.pm, overloading.pm, strict.pm, vars.pm, warnings.pm, warnings/register.pm
CONTEXT: PL/Perl anonymous code block
DO
这个问题不是关于如何让我的目标机器自动加载 utf8;我知道如何做。我想知道为什么似乎首先需要这样做。
\
,因此无法正常工作。您还应该转义第二个$
。 - ikegami$
不应该被转义,但是对于\
字符的好召唤;现在我得到了正确的输出,这使问题更加神秘。 - Jonathan Hall$
,则会在$re='/; system("rm -rf /"); qr/';
中失败。注入错误! - ikegami$
也会导致 eval 以同样的方式失败。嗯。 - Jonathan Hallqr//
或eval()
的字符串类型非常聪明。默认情况下,$re是一个Unicode字符串(按照Perl的默认设置),因此在执行qr
时会相应地表现。 - Jonathan Hall