我在使用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;
:所证明的那样
警告: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;我知道该怎么做。我很好奇为什么它首先似乎是必要的。
答案 0 :(得分:4)
在失败的验证中,你正在执行
$re = ''.qr/\b($re)\b/i
在成功的版本中,您正在执行
$re = ''.qr/\b(foo)\b/i
当模式被编译为Unicode模式(无论这意味着什么)时,听起来像qr //需要utf8.pm,但后者不会编译为Unicode模式。
无法加载utf8.pm是由于plperl创建的Safe隔离区施加的限制。
修复方法是将模块加载到安全隔间外。
解决方法是使用效率更高的
$re = '(?^u:\\b(?i:'.$re.')\\b)';
答案 1 :(得分:0)
我有同样的问题,我通过添加
修复了它username.github.io/project_name
到plperl.on_init = 'use utf8; use re; package utf8; require "utf8_heavy.pl";'
档。
我希望这会对某人有所帮助。