Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ
Шрифт:
Для включения UDF в существующий модуль внешней функции добавьте файл, содержащий объектный код новой UDF, и перекомпилируйте как обычно. Некоторые платформы позволяют добавлять объектные файлы непосредственно в существующие библиотеки. Относительно подробностей посмотрите документацию по компилятору и редактору связей для конкретной платформы.
Для удаления функции следуйте инструкциям редактора связей по удалению объектов из библиотеки. Удаление функции из библиотеки не удаляет ее объявления из базы данных - используйте для этого DROP EXTERNAL FUNCTION.
Функции 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 |
blob handle | Требуемое поле. Это дескриптор BLOB, который уникально идентифицирует BLOB, передаваемый функции или возвращаемый функцией |
number segments | NULL, если внешняя функция не принимает BLOB в качестве входного аргумента. В противном случае задает общее количество сегментов в BLOB |
max seglen | NULL, если внешняя функция не принимает BLOB в качестве входного аргумента. В противном случае задает в байтах размер наибольшего передаваемого сегмента |
total size | NULL, если внешняя функция не принимает BLOB в качестве входного аргумента. В противном случае задает в байтах фактический размер всего BLOB как единого целого |
blob_put segment | NULL, если внешняя функция не принимает BLOB в качестве входного аргумента. В противном случае содержит указатель на функцию, которая вызывается для записи сегмента в BLOB. Эта функция принимает три аргумента: дескриптор BLOB, адрес буфера, содержащего данные для записи в BLOB, и размер в байтах записываемых данных |
145
Определена в ibase.h как blobcallback (структурный тип) и BLOBCALLBACK (указатель на структурный тип). Это объявление дает полное определение для функций чтения/записи указателей, которые упрощают использование их в современных компиляторах. См. также примечания перед объявлением в ibase.h.
Функция BLOB объявляется в базе данных с использованием DECLARE EXTERNAL FUNCTION с тем отличием, что тип ее объявления помещается перед ключевым словом RETURNS в качестве последнего аргумента в списке параметров вместо возвращаемого значения. Для аргумента RETURNS используйте ключевое слово PARAMETER и порядковый номер последнего параметра. Например, следующий оператор объявляет функцию BLOB, biob_pius_biob в модуле внешних функций с именем MyExtLib:
DECLARE EXTERNAL FUNCTION blob_plus_blob
Blob,
Blob,
Blob
RETURNS PARAMETER 3
ENTRY_POINT 'blob_concat' MODULE_NAME 'MyExtLib';
Учебник по написанию внешних функций доступен на сайте сообщества Firebird. Множество толковых статей можно найти в базах знаний и через поисковые машины.
Фильтры BLOB
В главе 12 мы коснулись специального типа внешних функций, которые могут быть использованы в Firebird для преобразования данных BLOB между двумя форматами, способными представлять совместимые данные. Фильтры BLOB являются определенными пользователем служебными подпрограммами на стороне сервера - фактически, специализированными UDF - способными получать данные BLOB В одном формате, преобразовывать их и возвращать в виде BLOB другого формата. Один раз скомпилированный и объявленный в базе данных, фильтр BLOB может быть использован в обычных операторах DML в клиентских приложениях, хранимых процедурах, триггерах и в isql.
В SQL Firebird фильтр BLOB распознается по его подтипу SUB_TYPE. Вы уже хорошо знакомы с двумя подтипами: 0 (для BLOB любого формата) и 1 (для неформатированного или минимально форматированного текста). Они предварительно определены внутренне вместе с множеством других, которые все являются положительными числами, их Firebird использует внутренне для метаданных и синтаксического разбора. Другие фильтры BLOB определяются пользователем, и могут иметь любое отрицательное число в качестве своего подтипа.
Сервер Firebird не имеет никакого "внутреннего знания" о том, что хранится (или может храниться) в BLOB заданного подтипа: ноль или меньше нуля. Задача приложения - обеспечить, чтобы вход и выход соответствовали целям подтипов, и какие фильтры BLOB будут написаны для их обработки.
Пары фильтров BLOB могут быть использованы для управления полезным диапазоном обычных преобразований данных, требуемых вашим приложениям, приведем примеры.
* Упаковка и распаковка данных. Один подтип хранит упакованные данные, в то время как другой обрабатывает их в распакованном виде. Фильтр BLOB может быть разработан для получения BLOB подтипа 1 (неизвестный формат) и преобразования его в сжатый формат (например, zip или гаг) и распаковки его для обработки как
SUB_TYPE 0.
* Вы можете использовать один подтип для хранения собственного кода приложения и другие для специфического системного кода и фильтр BLOB для добавления системных дополнений в собственный код, когда он требуется в запросе.
* Вы можете иметь подтип для хранения текста формата XML и фильтры BLOB для трансформации его в заданные выходные форматы - HTML, RTF, PDF, файлы UNIX, формат текстового процессора - для вывода в виде другого подтипа.
Возможности фильтров BLOB в Firebird позволяют уменьшить "разбухание", связанное с преобразованием данных для внешних процессоров. Преобразование кода в подпрограмме фильтра может быть настолько простым или сложным, насколько это требуется. Фильтры при необходимости могут вызывать другие модули, предоставляя в ваше распоряжение возможность включения существующих конвертирующих подпрограмм в ваши операции на сервере. Поскольку сам сервер имеет дело лишь с входом и выходом, в то время как ваш код фильтра поддерживается внешне, ваши фильтры могут быть изменены с учетом новейших технологий без воздействия на сервер.
Написание фильтров BLOB
Написание фильтров BLOB требует точно таких же усилий по управлению памятью и потоками, а также того же порядка действий, что и другие внешние функции, а именно:
1. Напишите фильтры и скомпилируйте их в объектные коды.
2. Создайте совместно используемую библиотеку фильтров (совместно используемый объект или DLL).
3. Сконфигурируйте сервер Firebird, чтобы он знал, где отыскать библиотеку во время выполнения.
4. Используйте DECLARE FILTER для объявления фильтров в базе данных.
5. Объявите столбцы в таблицах для хранения BLOB С тем подтипом, который "известен" фильтру.
6. Пишите приложения или модули PSQL, которым требуется фильтрация.
Объявление фильтров BLOB
На уровне базы данных фильтр распознается при объявлении метаданных с использованием следующего синтаксиса:
DECLARE FILTER <имя-фильтра>
INPUT_TYPE <подтип>
/* идентифицирует подтип конвертируемого объекта */