Почему эта хранимая процедура postgres хочет `использовать utf8`?
Я столкнулся с особенностью хранимой процедуры plperl на Postgres 9.2 с Perl 5.12.4.
Любопытное поведение можно воспроизвести с помощью этого "сломанного" 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, который, как говорят, единственный раз, когда нужноuse utf8
,Во всяком случае, я мог бы ожидать
eval
версия, чтобы сломать безuse utf8
в случае, когда входные данные для скрипта содержали не-ASCII-значения. (Дальнейшее тестирование показывает, что передача не ASCII-значений в bar() действительно приводит к сбою eval с той же ошибкой)
Обратите внимание, что многие установки Postgres автоматически загружают utf8 при запуске интерпретатора perl. Это значение по умолчанию в 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
ДЕЛАТЬ
Но не так на машине, демонстрирующей странное поведение:
ПРЕДУПРЕЖДЕНИЕ: Carp.pm, Carp/Heavy.pm, Exporter.pm, feature.pm, overload.pm, overloading.pm, strict.pm, vars.pm, warnings.pm, warnings/register.pm
КОНТЕКСТ: блок анонимного кода PL/Perl
ДЕЛАТЬ
Этот вопрос не о том, как заставить мою целевую машину автоматически загружать utf8; Я знаю, как это сделать. Мне любопытно, почему это кажется необходимым в первую очередь.
2 ответа
В версии, которая терпит неудачу, вы выполняете
$re = ''.qr/\b($re)\b/i
В успешной версии вы выполняете
$re = ''.qr/\b(foo)\b/i
Похоже, qr// нуждается в utf8.pm, когда шаблон был скомпилирован как шаблон Unicode (что бы это ни значило), но последний не скомпилирован как шаблон Unicode.
Ошибка загрузки utf8.pm связана с ограничениями, накладываемыми безопасным отсеком, созданным plperl.
Исправление заключается в загрузке модуля за пределы безопасного отсека.
Обходной путь должен использовать более эффективный
$re = '(?^u:\\b(?i:'.$re.')\\b)';
У меня была та же проблема, и я исправил ее, добавив
plperl.on_init = 'use utf8; use re; package utf8; require "utf8_heavy.pl";'
в postgresql.conf
файл.
Надеюсь, это кому-нибудь поможет.