Создание собственных функций

Мы не будем подробно останавливаться на всех особенностях создания пользовательских функций, поскольку данный механизм достаточно прост, однако продемонстрируем написание и подключение одной функции на примере. В качестве средства разработки мы будем использовать Borland Delphi. Для примера также будет применяться стандартная база данных EMPLOYEE.GDB. В нашем примере мы создадим функцию, которая будет преобразовывать строку к верхнему регистру. Подобная функция может оказаться полезной, если вы не задали опцию COLLATE для ваших строковых полей. Кроме того, работа со строковыми параметрами, как правило, вызывает наибольшее количество вопросов при создании пользовательских функций. Разумеется, мы исходим из предположения, что вы знакомы с принципом создания DLL при помощи Delphi.

library TestUDF;

uses SysUtils;

function malloc(Size: Integer): Pointer; cdecl; external

'msvcrt.dll';

function StrUpperCase(sz: PChar): PChar; cdecl; export;

var Tmp: string;

begin

Tmp := AnsiUpperCase(sz);

Result := malloc(length(Tmp) + 1);

StrPCopy(Result, Tmp); end; exports

StrUpperCase; begin end.

Динамическая библиотека экспортирует только одну функцию: StrUpperCase. Для передачи строковых параметров, равно как и результата функции, использу­ется тип Pchar, т. е. динамическая строка, ограниченная символами #0. Смысл кода нашей функции очевиден: мы приводим строку sz к верхнему регистру, ис­пользуя стандартную функцию AnsiUpperCase. Данная функция корректно рабо­тает с русскими буквами, если в системе установлена русская кодовая страница. После этого выделяем память для результирующей переменной, используя malloc - стандартную функцию Windows. Остается только скопировать значение временной переменной Tmp в переменную Result. Скомпилируйте библиотеку и поместите полученный файл TestUDF.dll в нужный каталог. Если вы исполь­зуете InterBase 6.x или его клоны, то это каталог \Udf, который находится в ка­талоге установки сервера. Необходимо зарегистрировать функцию в базе дан­ных. Для регистрации необходимо выполнить команду DECLARE EXTERNAL j FUNCTION, которая имеет следующий синтаксис.

DECLARE EXTERNAL FUNCTION name [datatype | CSTRING (int)

[, datatype CSTRING (int) ...] ]

RETURNS {datatype [BY VALUE] | CSTRING (int)} [FREE_IT]

ENTRY_POINT 'entryname' .

MODULE_NAME 'modulename';

Параметр name - это имя пользовательской функции внутри базы данных.Он не обязательно должен совпадать с реальным названием функции в DLL.Параметр datatype определяет тип параметров. На параметры накладываются следующие ограничения:

• все параметры передаются по ссылке;

• выходной параметр (значение функции) может возвращаться по значению;

• параметры не могут быть массивами.

Если вы хотите применять строковые параметры, то вы должны использовать тип CSTRING. В скобках необходимо указать максимальную длину строки. Еcли строка является результатом функции, она всегда передается по ссылке, а не по значению. Параметр FREE_IT указывает InterBase, что после выполнения функции необходимо автоматически освободить память, выделенную для параметров. Очевидно, данная опция нужна только в том случае, если наша библиотека сама вы­делила память под какие-либо параметры функции.

В параметре entryname необходимо указывать название функции в DLL, ко­торую мы собственно и хотим декларировать как пользовательскую функцию.

В параметре modulename необходимо указать название файла DLL, в котором находится декларируемая функция пользователя.

Стоит заметить, что параметры entryname и modulename регистрочувствительные.

Таким образом, чтобы добавить нашу функцию в базу данных, нам необхо­димо выполнить следующую команду.

DECLARE EXTERNAL FUNCTION USTRUPPERCASE cstring(254)

RETURNS cstring(254) FREE_IT ENTRY_POINT 'StrUpperCase' MODULE_NAME 'TestUDF.dll1

После этого мы сможем использовать новую функцию USTRUPPERCASE в любом SQL-запросе. Например, мы можем проверить, как работает функция на следующем запросе.

SELECT USTRUPPERCASE(DEPARTMENT) FROM DEPARTMENT

Запрос вернет названия отделов из таблицы DEPARTMENT (рис. 1.5).

Заключение

Мы рассмотрели на примере, как можно расширять набор доступных SQL-функций при помощи механизма User Defined Functions. Имея этот простой, но очень мощный механизм, вы сможете сделать обработку бизнес-правил в ва­ших базах данных гораздо более эффективно и удобно. В сущности, механизм пользовательских функций InterBase имеет только одно серьезное ограничение -он не позволяет обрабатывать NULL-параметры. В остальном функциональность пользовательских "расширений" SQL зависит только от ваших потребностей.

Широкий выбор UDF-библиотек, а также более подробную информацию об их использовании и разработке всегда можно найти на сайтах www.InterBase-world.com и www.ibase.ru.