Функции и аргументы PL/Perl
Эта страница переведена при помощи нейросети GigaChat.
Чтобы создать функцию на языке PL/Perl, используйте стандартную синтаксис CREATE FUNCTION:
CREATE FUNCTION funcname (argument-types)
RETURNS return-type
-- function attributes can go here
AS $$
# PL/Perl function body goes here
$$ LANGUAGE plperl;
Тело функции представляет собой обычный код Perl. Фактически, код PL/Perl оборачивает его внутри подпрограммы Perl. Функция PL/Perl вызывается в скалярном контексте, поэтому она не может возвращать список. Можно вернуть нескалярные значения (массивы, записи и наборы), возвращая ссылку, как описывается ниже.
В процедуре PL/Perl любое возвращаемое значение из кода Perl игнорируется.
PL/Perl также поддерживает анонимные блоки кода, вызываемые с помощью оператора DO:
DO $$
# PL/Perl code
$$ LANGUAGE plperl;
Анонимный блок кода не получает никаких аргументов, и любое значение, которое он может вернуть, игнорируется. В остальном он ведет себя точно так же как функция.
Использование именованных вложенных подпрограмм опасно в Perl, особенно если они ссылаются на лексические переменные во внешней области видимости. Поскольку функция PL/Perl обернута в подпрограмму, любая именованная подпрограмма, помещенная внутрь нее, будет вложенной. Как правило, гораздо безопаснее создавать анонимные подпрограммы, которые вызываются через coderef
. Для получения дополнительной информации см. записи для «Variable "%s" will not stay shared» и «Variable "%s" is not available» на странице руководства perldiag, или выполните поиск в Интернете по запросу «вложенная именованная подпрограмма perl».
Синтаксис команды CREATE FUNCTION
требует, чтобы тело функции было написано как строковая константа. Обычно удобнее всего использовать долларовую нотацию (см. раздел «Константы строковых литералов с долларовой кавычкой») для строковой константы. Если решено использовать синтаксис строки с экранированием E''
, нужно удвоить любые одинарные кавычки ('
) и обратные слэши (\
), используемые в теле функции (см. раздел «Строковые константы»).
Аргументы и результаты обрабатываются так же, как и в любой другой подпрограмме Perl: аргументы передаются в @_
, а значение результата возвращается с помощью return
или как последнее выражение, оцениваемое в функции.
Например, функция, возвращающая большее из двух целых значений, может быть определена следующим образом:
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
if ($_[0] > $_[1]) { return $_[0]; }
return $_[1];
$$ LANGUAGE plperl;
Аргументы будут преобразованы из кодировки базы данных в UTF-8 для использования внутри PL/Perl, а затем обратно из UTF-8 в кодировку базы данных при возврате.
Если значение SQL NULL
передается функции, значение аргумента будет отображаться как неопределенное в Perl. Приведенное выше определение функции не будет вести себя очень хорошо с пустыми входами (фактически, она будет действовать так, как будто они равны нулю). Можно было бы добавить STRICT
к определению функции, чтобы заставить PostgreSQL делать что-то более разумное: если передается нулевое значение, функция вообще не вызывается, но просто возвращает нулевой результат автоматически. В качестве альтернативы можем проверить наличие неопределенных входных данных в теле функции. Например, предположим, что хотели perl_max
с одним нулевым и одним ненулевым аргументом вернуть ненулевой аргумент, а не нулевое значение:
CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
my ($x, $y) = @_;
if (not defined $x) {
return undef if not defined $y;
return $y;
}
return $x if not defined $y;
return $x if $x > $y;
return $y;
$$ LANGUAGE plperl;
Как показано выше, чтобы вернуть значение SQL NULL
из функции PL/Perl, верните неопределенное значение. Это можно сделать независимо от того, является ли функция строгой или нет.
Все, что находится в аргументе функции и не является ссылкой, представляет собой строку, которая находится в стандартной PostgreSQL внешней текстовой форме представления для соответствующего типа данных. В случае обычных числовых или текстовых типов Perl просто сделает все правильно, и программисту обычно не придется об этом беспокоиться. Однако в других случаях аргумент должен быть преобразован в форму, более удобную для использования в Perl. Например, функция decode_bytea
может использоваться для преобразования аргумента типа bytea
в нескорректированный двоичный код.
Аналогично, значения, передаваемые обратно в PostgreSQL, должны находиться во внешнем формате текстового представления. Например, функцию encode_bytea
можно использовать для экранирования двоичных данных для возвращаемого значения типа bytea
.
Один случай, который особенно важен, – это логические значения. Как уже было сказано, поведение по умолчанию для значений bool
заключается в том, что они передаются в Perl в виде текста, таким образом, либо 't'
, либо 'f'
. Это проблематично, поскольку Perl не будет рассматривать 'f'
как ложь! Можно улучшить ситуацию, используя «преобразование» (см. CREATE TRANSFORM). Соответствующие преобразования предоставляются расширением bool_plperl
. Чтобы его использовать, установите расширение:
CREATE EXTENSION bool_plperl; -- or bool_plperlu for PL/PerlU
Затем используйте атрибут функции TRANSFORM
для функции PL/Perl, которая принимает или возвращает bool
, например:
CREATE FUNCTION perl_and(bool, bool) RETURNS bool
TRANSFORM FOR TYPE bool
AS $$
my ($a, $b) = @_;
return $a && $b;
$$ LANGUAGE plperl;
Когда это преобразование применяется, аргументы bool
будут восприниматься Perl как 1
или пустые, таким образом, правильно истинные или ложные. Если результат функции имеет тип bool
, он будет истинным или ложным в зависимости от того, оценит ли Perl возвращаемое значение как истинное. Аналогичные преобразования также выполняются для логических аргументов запроса и результатов запросов SPI, выполняемых внутри функции (раздел «Доступ к базе данных из PL/Perl»).
Perl может возвращать массивы PostgreSQL как ссылки на массивы Perl. Пример:
CREATE OR REPLACE function returns_array()
RETURNS text[][] AS $$
return [['a"b','c,d'],['e\\f','g']];
$$ LANGUAGE plperl;
select returns_array();
Perl передает массивы PostgreSQL как объект, сопоставленный с PostgreSQL::InServer::ARRAY
. Этот объект может рассматриваться как ссылка на массив или строку, что позволяет коду Perl, написанному для версий PostgreSQL ниже 9.1, работать без проблем. Например:
CREATE OR REPLACE FUNCTION concat_array_elements(text[]) RETURNS TEXT AS $$
my $arg = shift;
my $result = "";
return undef if (!defined $arg);
# as an array reference
for (@$arg) {
$result .= $_;
}
# also works as a string
$result .= $arg;
return $result;
$$ LANGUAGE plperl;
SELECT concat_array_elements(ARRAY['PL','/','Perl']);
Многомерные массивы представлены как ссылки на массивы меньшей размерности, что является обычным делом для каждого программиста Perl.
Аргументы составного типа передаются функции как ссылки на хеши. Ключами хеш-таблицы являются имена атрибутов составного типа. Пример:
CREATE TABLE employee (
name text,
basesalary integer,
bonus integer
);
CREATE FUNCTION empcomp(employee) RETURNS integer AS $$
my ($emp) = @_;
return $emp->{basesalary} + $emp->{bonus};
$$ LANGUAGE plperl;
SELECT name, empcomp(employee.*) FROM employee;
Функция PL/Perl может возвращать составной тип результата с использованием того же подхода: вернуть ссылку на хеш, который имеет необходимые атрибуты. Например:
CREATE TYPE testrowperl AS (f1 integer, f2 text, f3 text);
CREATE OR REPLACE FUNCTION perl_row() RETURNS testrowperl AS $$
return {f2 => 'hello', f1 => 1, f3 => 'world'};
$$ LANGUAGE plperl;
SELECT * FROM perl_row();
Любые столбцы в объявленном типе результирующих данных, которые отсутствуют в хеше, будут возвращаться как нулевые значения.
Аналогично, выходные аргументы процедур могут быть возвращены как ссылка на хеш:
CREATE PROCEDURE perl_triple(INOUT a integer, INOUT b integer) AS $$
my ($a, $b) = @_;
return {a => $a * 3, b => $b * 3};
$$ LANGUAGE plperl;
CALL perl_triple(5, 10);
Функции PL/Perl также могут возвращать наборы либо скалярных, либо композитных типов. Обычно требуется возвращать строки одну за другой, чтобы ускорить время запуска и избежать постановки всей результирующей выборки в память. Можно сделать это с помощью return_next
как показано ниже. Обратите внимание, что после последнего return_next
нужно поставить либо return
или (лучше) return undef
.
CREATE OR REPLACE FUNCTION perl_set_int(int)
RETURNS SETOF INTEGER AS $$
foreach (0..$_[0]) {
return_next($_);
}
return undef;
$$ LANGUAGE plperl;
SELECT * FROM perl_set_int(5);
CREATE OR REPLACE FUNCTION perl_set()
RETURNS SETOF testrowperl AS $$
return_next({ f1 => 1, f2 => 'Hello', f3 => 'World' });
return_next({ f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' });
return_next({ f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' });
return undef;
$$ LANGUAGE plperl;
Для небольших наборов результатов можно вернуть ссылку на массив, который содержит либо скаляры, ссылки на массивы или ссылки на хеши для простых типов, типов массивов и составных типов соответственно. Вот несколько простых примеров возврата всего результирующего набора в виде ссылки на массив:
CREATE OR REPLACE FUNCTION perl_set_int(int) RETURNS SETOF INTEGER AS $$
return [0..$_[0]];
$$ LANGUAGE plperl;
SELECT * FROM perl_set_int(5);
CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testrowperl AS $$
return [
{ f1 => 1, f2 => 'Hello', f3 => 'World' },
{ f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' },
{ f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' }
];
$$ LANGUAGE plperl;
SELECT * FROM perl_set();
Если нужно использовать strict
pragma с кодом, есть несколько вариантов. Для временного глобального использования можно SET
plperl.use_strict
установить значение true. Это повлияет на последующие компиляции функций PL/Perl, но не на функции, уже скомпилированные в текущем сеансе. Для постоянного глобального использования можно установить plperl.use_strict
равным true в файле postgresql.conf
.
Для постоянного использования в определенных функциях можно просто вставить в верхней части функции:
use strict;
Прагма feature
также доступна для использования, если версия Perl равна или выше 5.10.0.