Почему эта хранимая процедура 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)
  1. Почему Eval обходит автоматический use utf8?

  2. Почему 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 файл.

Надеюсь, это кому-нибудь поможет.

Другие вопросы по тегам