Соглашения о вызовах
Соглашение о вызовах определяет, как вызывается функция и как передаются параметры. Функция, получающая вызов, должна быть совместима с соглашением о вызове CDECL, используемым в Firebird. В функциях на языке С при использовании соглашения о вызове CDECL в объявление функции должно быть добавлено зарезервированное слово cdeci. В языке Pascal используйте cdeci.
Вот пример на языке С, где задается CDECL:
ISC_TIMESTAMP* cdeci addmonth(ISC_TIMESTAMP *preTime)
{
// здесь тело функции
}
Вопросы поточной обработки
В реализации Суперсервера в Firebird сервер выполняется как один многопоточный процесс. Это означает, что вам нужно проявлять некоторую осторожность при использовании способов выделения и освобождения памяти при кодировании UDF, а также при объявлении UDF. При использовании памяти в одном процессе в многопоточной архитектуре необходимо рассмотреть некоторые вопросы.
* Функции UDF должны выделять память с использованием функции ib_utii_ maiioc из библиотеки ib_util, а не с помощью статических массивов.
* Выделенная динамически память не освобождается автоматически, пока процесс не завершится. Вы должны использовать зарезервированное слово FREE IT при объявлении UDF в базе данных (DECLARE EXTERNAL FUNCTION).
* Статические переменные не сохраняются в потоке. Пользователи, выполняющие параллельно одну и ту же UDF, будут конкурировать, если они обратятся к одному пространству статической памяти. Неразумно использовать статические переменные, если вы не можете гарантировать, что только один пользователь в каждый конкретный момент времени будет обращаться к этой функции.
Если вы не можете исключить возвращаемый указатель на статические данные, вы не должны использовать FREE_IT.
Библиотека ib_util
Функция ib utii maiioc находится в вашем каталоге Firebird /lib, в совместно используемой библиотеке ib util.so в POSIX, ib_util.dll в Windows и ib utii.sl в HP-UX. Прототип функции для С и Pascal содержится в каталоге /include в файлах ib util.h и ib util.pas соответственно.
Указатели на переменные в Классическом сервере
При не поточном использовании Классического сервера вы можете возвращать глобальный указатель. В следующем примере функции FN LOWERO массив должен быть глобальным, чтобы исключить выход за пределы контекста:
char buffer[256];
char *fn_lower(char *ups) {
return (buffer); }
Создание UDF, защищенных от утечки памяти
При распределении памяти под возвращаемые значения для обеспечения потокобезопасности и переносимости следует использовать функцию ib_ut.ii_maiioc(). Вместе с ней нужно применять также ключевое слово FREE_IT В предложении RETURNS при объявлении функции, которая возвращает динамически создаваемые объекты.
В следующем примере сервер Firebird освободит буфер, если UDF была определена с зарезервированным словом FREE IT. Обратите внимание, что этот пример использует функцию Firebird ib_utii_maiioc() для выделения памяти:
char *fn_lower(char *ups) {
char *buffer = (char *) ib util_malloc(256);
return (buffer); }
Вот ее объявление:
DECLARE EXTERNAL FUNCTION lowercase VARCHAR (25 6)
RETURNS CSTRING(256) FREE_IT
ENTRY POINT 'fn lower' MODULE_NAME 'ib_udf';
! ! !
ПРИМЕЧАНИЕ. Память должна освобождаться той же библиотекой времени выполнения, которая выделяла эту память.
. ! .
Замечания по компиляции и компоновке
Когда модуль UDF готов, компилируйте его обычным образом в объектный или библиотечный формат.
Включите ibase.h или его эквивалент, если вы используете в нем объявления типов.
Если сборка выполняется статически, свяжите модуль с клиентской библиотекой Firebird, если вы обращаетесь к какой-либо функции библиотеки Firebird. Для Microsoft Visual C/C++ библиотеки fbclient ms.lib и ib_util_ms.lib могут быть найдены в каталоге Firebird /lib.
Изменение библиотеки функций
Для включения UDF в существующий модуль внешней функции добавьте файл, содержащий объектный код новой UDF, и перекомпилируйте как обычно. Некоторые платформы позволяют добавлять объектные файлы непосредственно в существующие библиотеки. Относительно подробностей посмотрите документацию по компилятору и редактору связей для конкретной платформы.
Для удаления функции следуйте инструкциям редактора связей по удалению объектов из библиотеки. Удаление функции из библиотеки не удаляет ее объявления из базы данных - используйте для этого DROP EXTERNAL FUNCTION.
Написание функции BLOB
Функции BLOB отличаются от других внешних функций, потому что им передаются указатели па управляющие структуры BLOB, а не на фактические данные. Функция не может открывать и закрывать BLOB, а вместо этого вызывает функции API для выполнения доступа к BLOB.
Читать дальше