Расширение PostgreSQL
В листинге 7.48 приведена пара очень простых функций, написанных на языке С. Первая функция, is_zero(int), возвращает true (1), если при вызове ей был передан аргумент 0; в противном случае возвращается false (0). Вторая функция, is_zero_two(int .int), возвращает true, если хотя бы один из переданных аргументов равен нулю.
Листинг 7.48. Функции на языке С.
/* is_zero.c * Простейшие проверочные функции */ int is_zero(int); int is_zero_two(int .int): int is_zero(int incoming) { /* Вернуть true, если аргумент равен 0. */ if (incoming == 0) return 1; else return 0: } int is_zero_two(int left, int right) { /* Вернуть true, если хотя бы один из аргументов равен 0. */ if (left – 0 || right == 0) return 1: else return 0; }
Внимание
В этот простейший пример не были включены заголовочные файлы PostgreSQL. В данном случае они не нужны из-за очевидного соответствия между типами данных С и SQL. Более реальные примеры с использованием внутреннего интерфейса API PostgreSQL и структур данных находятся во вложенном каталоге contrib исходного каталога PostgreSQL.
В листинге 7.49 файл is_zero.c компилируется с ключом – shared, а полученный общий модуль создается в файле is_zero.so. Путь к файлу передается в определении функции в команде CREATE FUNCTION; атрибут LANGUAGE сообщает, что функция написана на языке С.
Листинг 7.49. Создание функции на языке С.
[jworsley@cmd ~]$ gcc – shared is_zero.c – о is_zero.so [jworsley@cmd – ]$ psql – U manager booktown Welcome to psql .the PostgreSQL interactive terminal. Type: \copyright for distribution terms \h for help with SQL commands \? for help on internal slash commands \g or terminate with semicolon to execute query \q to quit booktown-* CREATE FUNCTION is_zero(int4) RETURNS Boolean booktown-l AS '/home/jworsley/is_zero.so' LANGUAGE 'C'; CREATE
Команда CREATE FUNCTION в листинге 7.49 создает функцию с именем is_zero(), которая получает один аргумент типа int4 и возвращает значение типа boolean. В объявление включена ссылка на функцию С с именем is_zero(int), реализованную в объектном модуле /home/jworsley/is_zero.so (поскольку в языке С нет типа boolean, PostgreSQL приходится преобразовывать целочисленное значение, возвращаемое функцией, к логическому типу). При этом число 0 преобразуется в false, a 1 – в true.
По умолчанию PostgreSQL ищет в общем модуле функцию с тем же именем, с которым она создается в PostgreSQL. Такой способ подходит для функции is_zero(integer), имя которой соответствует откомпилированному символическому имени функции is_zero(int) в файле is_zero.so. Для предотвращения конфликтов имен вторая функция в общем объектном модуле определяется с сигнатурой is_zero_two(int.int). Чтобы ассоциировать ее с перегруженной функцией PostgreSQL, получающей два аргумента вместо одного, имя функции С в виде строковой константы передастся после пути к файлу общего модуля.
Имя указывается без круглых скобок и без перечисления аргументов, а от пути к файлу оно отделяется запятой:
CREATE FUNCTION имя ([ тип_аргумента [….] ]) RETURNS тип_возвращаемого_значения AS 'определение'. 'имя_в_объектном_файле' LANGUAGE 'С' [ WITH (атрибут [….]) ]
В листинге 7.50 подгружается тот же общий модуль, но на этот раз перегруженная функция PostgreSQL ассоциируется с функций С is_zero_two.
Листинг 7.50. Перегрузка функции С.
booktown=# CREATE FUNCTION is_zero(int4 .int4) RETURNS Boolean booktown-# AS '/home/jworsley/is_zero.so'. 'is_zero_two' booktown-* LANGUAGE 'C': CREATE