Для создания функции на языке PL/Perl используется стандартный CREATE FUNCTION синтаксис:
CREATE FUNCTIONимя_функции(типы_аргументов) RETURNSтип_возвращаемого_значения-- здесь могут быть указаны атрибуты функции AS $$ # здесь располагается тело функции PL/Perl $$ LANGUAGE plperl;
Тело функции представляет собой обычный код на языке Perl. Фактически связующий код PL/Perl оборачивает его в подпрограмму Perl. Функция PL/Perl вызывается в скалярном контексте, поэтому она не может возвращать список. Возврат нескалярных значений (массивов, записей и наборов строк) может осуществляться посредством возврата ссылки, как описано ниже.
В процедуре PL/Perl любое возвращаемое значение из кода Perl игнорируется.
PL/Perl также поддерживает анонимные блоки кода, вызываемые с помощью DO команды:
DO $$
# код PL/Perl
$$ LANGUAGE plperl;
Анонимный блок кода не принимает аргументов, а любое возвращаемое им значение игнорируется. В остальном его поведение идентично поведению функции.
Использование именованных вложенных подпрограмм в Perl представляет опасность, особенно если они обращаются к лексическим переменным в объемлющей области видимости. Так как функция PL/Perl оборачивается в подпрограмму, любая именованная подпрограмма, помещённая внутрь неё, становится вложенной. Как правило, гораздо безопаснее создавать анонимные подпрограммы, вызываемые по ссылке на код (coderef). Для получения дополнительной информации см. разделы Variable "%s" will not stay shared и
Variable "%s" is not available в
perldiag страницу справочного руководства man или выполните поиск в Интернете по «perl nested named subroutine».
Синтаксис команды CREATE FUNCTION CREATE FUNCTION команда требует, чтобы тело функции было представлено в виде строковой константы. Обычно наиболее удобно использовать долларовое цитирование (см. Раздел 2.1.1.2.4) для строковой константы.
В случае использования синтаксиса строк с экранированием (escape string syntax) E'',
необходимо удваивать любые одиночные кавычки (') и обратные косые черты
(\), используемые в теле функции
(см. Раздел 2.1.1.2.1).
Обработка аргументов и результатов осуществляется так же, как и в любой другой подпрограмме 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 обратно в кодировку базы данных.
Если значение NULL в SQL передается в функцию,
значение аргумента будет представлено как «undefined» в языке Perl. Приведенное выше определение функции будет работать не вполне корректно при наличии входных значений null (фактически, они будут восприниматься как нули). Можно добавить параметр STRICT к определению функции, чтобы
Digital Q.DataBase сделать её поведение более логичным:
если передается значение null, функция вообще не будет вызвана,
а автоматически вернет результат null. Кроме того, можно предусмотреть проверку неопределенных входных аргументов в теле функции. Например,
предположим, что требуется, чтобы функция perl_max с
одним аргументом null и одним значимым аргументом возвращала этот аргумент,
а не значение null:
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;
Как было показано выше, для возврата значения NULL из функции на языке PL/Perl следует возвращать неопределённое значение. Это можно сделать независимо от того, определена ли функция как строгая (STRICT) или нет.
Любой аргумент функции, не являющийся ссылкой, представляет собой строку, представленную в стандартном Digital Q.DataBase
внешнем текстовом представлении для соответствующего типа данных. При использовании обычных числовых или текстовых типов Perl обрабатывает данные корректно, и разработчику обычно не требуется об этом беспокоиться. Однако в других случаях аргумент необходимо преобразовать в форму, более удобную для работы в Perl. Например, decode_bytea
функция может применяться для преобразования аргумента типа bytea в двоичные данные в исходном виде (без экранирования).
Аналогично, значения, возвращаемые в Digital Q.DataBase
должны быть представлены во внешнем текстовом формате. Например, для
encode_bytea функции может применяться
экранирование двоичных данных в возвращаемом значении типа bytea.
Одним из наиболее важных случаев являются логические значения. Как было
указано выше, поведение по умолчанию для bool значений предполагает их
передачу в Perl в виде текста, то есть либо 't'
или 'f'. Это создает проблему, так как Perl не будет
интерпретировать 'f' как ложное значение! Ситуацию можно улучшить
путем использования «трансформации» (см.
CREATE TRANSFORM). Соответствующие трансформации предоставляются
расширением bool_plperl extension. Для его использования установите
расширение:
CREATE EXTENSION bool_plperl; -- или bool_plperlu для 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 или пустые, что корректно соответствует логическим значениям true или false. Если результат функции имеет тип bool, значение будет истинным (true) или ложным (false) в зависимости от того, как Perl интерпретирует возвращаемое значение. Аналогичные преобразования также применяются к логическим аргументам и результатам запросов через интерфейс SPI, выполняемых внутри функции (Раздел 5.8.3.1).
Perl может возвращать Digital Q.DataBase массивы как ссылки на массивы Perl. Ниже приведен пример:
CREATE OR REPLACE function returns_array()
RETURNS text[][] AS $$
return [['a"b','c,d'],['e\\f','g']];
$$ LANGUAGE plperl;
select returns_array();
Perl передает Digital Q.DataBase массивы как специальный («blessed»)
PostgreSQL::InServer::ARRAY объект. Данный объект может рассматриваться как ссылка на массив или как строка, что обеспечивает обратную совместимость для выполнения кода на Perl, написанного для Digital Q.DataBase версий ниже 9.1. Например:
CREATE OR REPLACE FUNCTION concat_array_elements(text[]) RETURNS TEXT AS $$
my $arg = shift;
my $result = "";
return undef if (!defined $arg);
# как ссылка на массив
for (@$arg) {
$result .= $_;
}
# также работает как строка
$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 => 'Привет', f1 => 1, f3 => 'world'};
$$ LANGUAGE plperl;
SELECT * FROM perl_row();
Любые столбцы объявленного типа данных результата, отсутствующие в хэше, будут возвращены как значения NULL.
Аналогичным образом, выходные аргументы процедур могут быть возвращены в виде ссылки на хеш:
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 => 'Привет', f3 => 'World' });
return_next({ f1 => 2, f2 => 'Привет', f3 => 'PostgreSQL' });
return_next({ f1 => 3, f2 => 'Привет', 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 => 'Привет', f3 => 'World' },
{ f1 => 2, f2 => 'Привет', f3 => 'PostgreSQL' },
{ f1 => 3, f2 => 'Привет', f3 => 'PL/Perl' }
];
$$ конструкция LANGUAGE plperl;
команда SELECT * FROM perl_set();
При необходимости использования strict прагмы в коде существует несколько вариантов. Для временного глобального использования можно выполнить SET
plperl.use_strict в значение true.
Это затронет последующие компиляции PL/Perl
функций, но не те функции, что уже были скомпилированы в текущем сеансе.
Для постоянного глобального использования можно установить данный параметр plperl.use_strict
в значение true в postgresql.conf файле.
Для постоянного использования в конкретных функциях можно просто указать:
use strict;
в начале тела функции.
Прагма функция, функционал, функциональность прагма также доступна для использования если версия Perl — 5.10.0 или выше.