Тема вызова внешних скриптов из СУБД не так уж нова, но часто остаётся за рамками технических решений, несмотря на свою простоту и изящность. Рассмотрим СУБД PostgreSQL (аналогичной функциональностью обладают OracleDB и MySQL). Иногда в процессе работы приложения может потребоваться обращаться к утилитам операционной системы, например, чтобы управлять подсистемами. Скажем, управлять записями в таблицах пакетного фильтра при изменении содержимого в БД. Также может потребоваться результаты выборки обрабатывать сложным образом, что не всегда удобно описывать в приложениях, работающих с базой (особенно, когда таких приложений несколько). Поэтому расскажу о стандартной возможности расширения языковых возможностей в PostgreSQL. Внимательный администратор обращал внимание на каталог databases/postgresql96-plperl в портах (ну или на наличие аналогичного пакета во всяких GNU/Linux-ах). Этот пакет позволяет нам создавать в БД дополнительные языки написания процедур, помимо PL/SQL, на котором описывать более-менее сложную логику -- не самое приятное занятие.
Давайте рассмотрим на примере двух кейсов. В первом кейсе БД является хранилищем системы тестирования и в ней есть табличка, в которой хранятся математические формулки, вводимые туда пользователями в ходе прохождения электронного тестирования. Задача состоит в том, чтобы найти в таблице все записи с некорректно расставленными скобками (для примера; в реальной системе там присутствует ещё несколько строк и одним запросом к БД можно получать все некорректные/корректные ответы. Ниже я привожу код, в котором создается БД с именем "test", создаётся в ней процедурный язык plperl, создаётся таблица для хранения математических выражений, заполняется тремя тестовыми выражениями. Далее создаётся функция, которая принимает текстовое поле и с помощью простого регулярного выражения проверяет корректность расстановки скобок в полученном текстовом поле. И приведён пример запроса, который из таблицы выбирает строки с некорректно расставленными скобками.
postgres=# create database test;
CREATE DATABASE
postgres=# \c test;
psql (9.3.15, server 9.3.5)
You are now connected to database "test" as user "pgsql".
test=# create language plperl;
CREATE LANGUAGE
test=# create table math (id integer, math text, primary key(id));
CREATE TABLE
test=# insert into math values(1, '((a + b) * c) / 2 = y');
INSERT 0 1
test=# insert into math values(2, 'z = sum[ lg(e + 2 ^ e) + (a / b) ^ 4 ]');
INSERT 0 1
test=# insert into math values(3, 'x = q + (w + z_ ^ e + t ^ 2');
INSERT 0 1
test=# create function brcheck (text) returns integer as $$
test$# return 0+($_[1] =~ /^[^][{}()]*(([({[])((?:[^][{}()]*+|(?1)))*(??{($0=$2)=~y|([{|)]}|;"\\$0"}))/);
test$# $$ language plperl;
CREATE FUNCTION
test=# select id, math from math where brcheck(math) = 0;
id | math
----+-----------------------------
3 | x = q + (w + z_ ^ e + t ^ 2
(1 row)
test=#
Во втором кейсе требуется уже менее безобидная задачка -- управление внешними утилитами. Это не так безопасно, поэтому необходимо создать другой язык: PL/PerlU, буква "U" -- от слова Unsafe. В примере я вызываю 'ls -la /', но можно вызвать и более суровые вещи, типа 'rm -rf /'. Также сразу рассмотрим, как можно получить из подобной функции возвращаемые значения.
test=# create function ls() returns setof text as $$
chomp(my@a = `ls -la /`);
return \@a;
$$ language plperlu;
CREATE FUNCTION
test=# select * from ls();
ls
------------------------------------------------------------------
total 59
drwxr-xr-x 20 root wheel 26 May 19 09:22 .
drwxr-xr-x 20 root wheel 26 May 19 09:22 ..
-r--r--r-- 1 root wheel 6195 Jan 25 2016 COPYRIGHT
...
Таким образом, мы покрыли практически все необходимые функциональные возможности программирования внутри БД, которые часто рационально использовать вместо огорода костылей на PHP.