Читать интересную книгу Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ - Хелен Борри

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 164 165 166 167 168 169 170 171 172 ... 238

Параметры, не являющиеся BLOB или массивами, передаются функциям UDF либо по ссылке[144] с использованием типов данных включающего языка, допускающих преобразование в соответствующие типы данных Firebird, либо через дескриптор, используя предварительно определенную структуру, которая описывает тип данных Firebird во включающем языке. Может быть принято до десяти параметров, соответствующих любому типу данных Firebird за исключением массива или элемента массива. Если UDF возвращает BLOB, то количество входных параметров ограничивается девятью.

В качестве примера передачи параметров по ссылке можно рассмотреть объявление функции в языке С FN_ABSO, которая принимает один параметр, имеющий в С тип double. Когда вызывается FN_ABS(), ей должен передаваться параметр, имеющий в SQL тип данных DOUBLE PRECISION.

Передача параметров через дескриптор появилась в Firebird 1.0, что позволяет передавать родные типы данных Firebird. Для некоторых внешних функций это упрощает обработку параметров NOLL и дает возможность перекрывать объявления. Структуру дескриптора параметра можно найти в ibase.h:

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) на http:// www.cvalde.net/document/using_descriptors_with_udfs.htm.

. ! .

Параметры BLOB

Функции 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, а также при объявлении 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.

Создание управляющей структуры BLOB

Управляющая структура BLOB является структурой языка С, определенной в функциональном модуле в виде typedef. Программисты должны описать такую управляющую структуру на языке С, т. е. должны написать следующее:

typedef struct blob {

short (*blob_get_segment)();

isc_blob_handle blob_handle;

long number_segments;

long max_seglen;

long total_size;

void (*blob_put_segment)();

} *Blob;

Табл. 36.1 описывает поля в управляющей структуре BLOB.

Таблица 36.1. Поля в управляющей структуре BLOB[145]

Поле

Описание

blob get segment

NULL, если внешняя функция не принимает BLOB в качестве входного аргумента. Иначе это поле является указателем на функцию, которая вызывается для чтения сегмента BLOB. Данная функция получает четыре аргумента: дескриптор BLOB, адрес буфера для сегмента BLOB, размер буфера и адрес переменной для хранения размера сегмента BLOB

1 ... 164 165 166 167 168 169 170 171 172 ... 238
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ - Хелен Борри.
Книги, аналогичгные Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ - Хелен Борри

Оставить комментарий