Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ
Шрифт:
typedef struct paramdsc {
unsigned char dsc_dtype;
signed char dsc_scale;
ISC_OSHORT dsc_length;
short dsc_sub_type;
ISC_USHORT dsc_flags;
unsigned char *dsc_address;
} PARAMDSC;
Самое важное поле в структуре, конечно, dsc_dtype, потому что оно ответственно за трансляцию родных типов данных Firebird в типы данных включающего языка.
! ! !
СОВЕТ. Claudio Valderrama С., который выполнил реализацию передачи через дескриптор, представил детальное описание этого процесса в статье "Using descriptors with UDFs" (Использование
. ! .
Функции UDF, которые принимают параметры BLOB, требуют для обработки специальной структуры данных, BLOB передается по ссылке в управляющей структуре BLOB, описанной в разд. "Написание функций BLOB".
К типам данных возвращаемых значений применяются те же самые ограничения, что и к входным параметрам: типы данных включающего языка должны соответствовать типам данных Firebird. Например, объявление в С для функции FN_ABSO возвращает значение типа double, который корреспондирует с типом данных DOUBLE PRECISION в Firebird.
По умолчанию возвращаемые значения передаются по ссылке. Числовые значения могут также возвращаться по значению, хотя это и не очень хороший метод, и он не рекомендован. Для возврата числового параметра по значению включите необязательное ключевое слово BY VALUE после возвращаемого значения при объявлении UDF в базе данных.
В UDF необходимо использовать типы данных включающего языка как для входных, так и для выходных значений. Firebird должен иметь возможность выполнить трансляцию между объявленным типом и типом данных SQL. В случае строк входной строкой UDF является тип CSTRING С заданной максимальной длиной в байтах, CSTRING используется для трансляции входных типов CHAR и VARCHAR В строку языка С, завершающуюся нулем, для обработки и для возвращения строки языка С переменной длины, завершающуюся нулем, для автоматического преобразования в Firebird в типы CHAR или VARCHAR. В случае других включающих языков убедитесь, что ваша функция возвращает строки, завершающиеся нулем.
При объявлении UDF, которая возвращает строку языка С, CHAR или VARCHAR, В объявление должно быть добавлено ключевое слово FREE_IT для освобождения памяти, используемой для возвращаемого значения, если она была выделена с помощью функции ib_util_malloc.
Соглашение о вызовах определяет, как вызывается функция и как передаются параметры. Функция, получающая вызов, должна быть совместима с соглашением о вызове CDECL, используемым в Firebird. В функциях на языке С при использовании соглашения о вызове CDECL в объявление функции должно быть добавлено зарезервированное слово cdeci. В языке Pascal используйте cdeci.
Вот пример на языке С, где задается CDECL:
ISC_TIMESTAMP* cdeci addmonth(ISC_TIMESTAMP *preTime)
{
// здесь тело функции
}
В реализации Суперсервера в Firebird сервер выполняется как один многопоточный процесс. Это означает, что вам нужно проявлять некоторую осторожность при использовании способов выделения и освобождения
* Функции UDF должны выделять память с использованием функции ib_utii_ maiioc из библиотеки ib_util, а не с помощью статических массивов.
* Выделенная динамически память не освобождается автоматически, пока процесс не завершится. Вы должны использовать зарезервированное слово FREE IT при объявлении UDF в базе данных (DECLARE EXTERNAL FUNCTION).
* Статические переменные не сохраняются в потоке. Пользователи, выполняющие параллельно одну и ту же UDF, будут конкурировать, если они обратятся к одному пространству статической памяти. Неразумно использовать статические переменные, если вы не можете гарантировать, что только один пользователь в каждый конкретный момент времени будет обращаться к этой функции.
Если вы не можете исключить возвращаемый указатель на статические данные, вы не должны использовать FREE_IT.
Функция 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); }
При распределении памяти под возвращаемые значения для обеспечения потокобезопасности и переносимости следует использовать функцию 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.