Прежде всего нам нужно получить доступ к интерфейсуIMaster
. IMaster
— это основнойинтерфейс Firebird, необходимый для доступа ко всем остальныминтерфейсам. Поэтому существует особый способ доступа к нему —единственное, что нужно это использование простой функции OO API,называемой fb_get_master_interface()
. Эта функция не имеет параметрови всегда завершается успешно. Существует один и только один экземпляр IMaster
длякаждой клиентской библиотеки Firebird, поэтому не нужно заботиться обосвобождении памяти, используемой мастер-интерфейсом. Самый простой способ получить к нему доступиз вашей программы — использовать соответствующую глобальную или статическую переменную:
static IMaster* master = fb_get_master_interface();
Для многих методов, используемых в API Firebird, первым параметромявляется интерфейс IStatus
. Это логичнаязамена ISC_STATUS_ARRAY
, но работает отдельно с ошибками ипредупреждениями (не смешивая их в одном массиве), может содержать внутринеограниченное количество ошибок и (это важно, если вы планируетереализовать IStatus
самостоятельно) всегда сохраняет строки, на которыеон ссылается внутри интерфейса. Обычно для вызова других методовтребуется хотя бы один экземпляр IStatus
. Вы можете получить его изIMaster
:
IStatus* st = master->getStatus();
Если по какой-либо причине метод getStatus()
не работает (OOM дляпримера), то он возвращает NULL
— в этом случае очевидно, что мы неможем использовать общий метод для сообщений об ошибке, основанный наIStatus
.
Теперь мы рассмотрим первый интерфейс, напрямую связанный с обращениями кбазе данных. Это IProvider
-интерфейс,называемый таким образом, потому что именно этот интерфейс должен бытьреализован любым поставщиком в Firebird. В клиентской библиотекеFirebird есть собственная реализация IProvider
, которую необходимоиспользовать для запуска любых операций с базой данных. Чтобы получитьего, мы вызываем метод getDispatcher
интерфейса IMaster
:
IProvider* prov = master->getDispatcher();
При подключении к существующей базе данных или тем более при создании новой частобывает необходимо передать в вызов API множество дополнительных параметров(логин/пароль, размер страницы для новой базы и т.д.). Иметь отдельные параметрына уровне языка почти нереально — нам придется слишком часто модифицировать вызов,чтобы добавить новые параметры, и их количество будет очень большим,несмотря на то, что обычно их нужно передавать не слишком много.Поэтому для передачи дополнительных параметров используетсяспециальная структура данных в памяти, называемая блок параметров базыданных (database parameters block или DPB). Его формат чётко определён, иэто даёт возможность построить DPB байт за байтом. Однако гораздо прощеиспользовать специальный интерфейсIXpbBuilder
, упрощающий создание блоков различных параметров.Чтобы получить экземпляр IXpbBuilder
, необходимо знать об ещё одном универсальном интерфейсеFirebird API — IUtil
. Это своего родаконтейнер для вызовов, которые плохо подходят для размещения в другихместах. Итак, мы делаем следующее
IUtil* utl = master->getUtilInterface();
IXpbBuilder* dpb = utl->getXpbBuilder(&status, IXpbBuilder::DPB, NULL, 0);
Этот код создает пустой конструктор блоков параметров типа DPB. Теперьдобавление необходимого параметра в него тривиально:
dpb->insertInt(&status, isc_dpb_page_size, 4 * 1024);
будет создавать базу данных с размером страницы 4 Кб и значениями
dpb->insertString(&status, isc_dpb_user_name, "sysdba");
dpb->insertString(&status, isc_dpb_password, "masterkey");
смысл которых понятен.
Следующее специфично для C++: Мы почти готовы вызвать методcreateDatabase()
экземпляра IProvider
, но перед этим необходимо сказатьнесколько слов о концепции Status Wrapper (обёртка над статусом). StatusWrapper не является интерфейсом, это очень тонкая обёртка надинтерфейсом IStatus
. Она позволяет настраивать поведение C++ API(изменить способ обработки ошибок, возвращаемых в интерфейсе IStatus
).Первое время мы рекомендуем использовать ThrowStatusWrapper
, которыйвызывает исключение C++ каждый раз, когда в IStatus возвращается ошибка.
ThrowStatusWrapper status(st);
Теперь мы можем создать новую пустую базу данных:
IAttachment* att = prov->createDatabase(&status, "fbtests.fdb",
dpb->getBufferLength(&status), dpb->getBuffer(&status));
printf("Database fbtests.fdb created\n");
Обратите внимание, что мы не проверяем статус после вызова createDatabase()
,потому что в случае ошибки будет возбуждено исключение C++ или Pascal(поэтому в вашей программе очень полезно иметь try/catch/exceptсинтаксис). Мы также используем две новые функции из IXpbBuilder
—getBufferLength()
и getBuffer()
, которые извлекают данные из интерфейсав родном формате DPB. Как видите, нет необходимости явно проверять статусфункций, возвращая промежуточные результаты.
Отсоединение от только что созданной базы данных тривиально:
att->detach(&status);
Теперь осталось окружить все операторы блоком try
и написать обработчикв блоке catch
. При использовании ThrowStatusWrapper
, вы всегда должныперехватывать определённый в C++ API исключение класса FbException
,в Pascal вы также должны работать с классом FbException
. Блокобработки исключений в простейшем случае может выглядеть так:
catch (const FbException& error)
{
char buf[256];
utl->formatStatus(buf, sizeof(buf), error.getStatus());
fprintf(stderr, "%s\n", buf);
}
Обратите внимание, здесь мы используем ещё одну функцию изIUtil
— formatStatus()
. Она возвращаетв буфере текст, описывающим ошибку (предупреждение), сохранённую впараметре IStatus
.
Чтобы подключиться к существующей базе данных используйте методattachDatabase()
интерфейса IProvider
вместо createDatabase()
. Всепараметры одинаковы для обоих методов.
att = prov->attachDatabase(&status, "fbtests.fdb", 0, NULL);
В этом примере не использует никаких дополнительных параметров DPB.Учтите, что без логина/пароля любое удалённое подключение будетнеудачно, если не настроена доверительная аутентификация. Конечноинформация для логина может быть предоставлена окружением (впеременных ISC_USER
и ISC_PASSWORD
), так же как это было раньше.
Папка examples
содержит завершённые примеры, в том числе и примерысоздания базы данных — 01.create.cpp
и 01.create.pas
. При чтенииданного документа, полезно построить (build) примеры и попытатьсязапустить их.
Чтобы начать пользоваться сервисами (службами), прежде всего необходимоподключиться к менеджеру сервисов. Это делается с помощью методаattachServiceManager()
интерфейсаIProvider
. Этот метод возвращаетинтерфейс IService
, который позжеиспользуется для связи с сервисом. Чтобы подготовить SPB для подключенияк диспетчеру сервисов, вы можете использовать IXpbBuilder
:
IXpbBuilder* spb1 = utl->getXpbBuilder(&status, IXpbBuilder::SPB_ATTACH, NULL, 0);
spb1->insertString(&status, isc_spb_user_name, "sysdba");
spb1->insertString(&status, isc_spb_password, "masterkey");
и подключится:
IService* svc = prov->attachServiceManager(&status, "service_mgr",
spb1->getBufferLength(&status), spb1->getBuffer(&status));
Используя IService
, вы можете выполнять как доступные для служб действия— запускать службы, так и запрашивать различную информацию о запущенныхутилитах и сервере в целом. При запросе информации, есть одноограничение — формат блока параметров, используемый методом query()
, вFirebird 4 не поддерживается IXpbBuilder
. Вероятно, поддержка будетдобавлена в более поздних версиях, в Firebird 4 вам придется создавать ианализировать этот блок вручную. Формат этого блока повторяет старыйформат (используемый в ISC API) один в один.
Чтобы стартовать сервис, необходимо прежде всего создать соответствующийSPB:
IXpbBuilder* spb2 = utl->getXpbBuilder(&status, IXpbBuilder::SPB_START, NULL, 0);
и добавить к нему необходимые элементы. Например, для печати статистикишифрования для базы данных employee
в SPB следует поместить следующее:
spb2->insertTag(&status, isc_action_svc_db_stats);
spb2->insertString(&status, isc_spb_dbname, "employee");
spb2->insertInt(&status, isc_spb_options, isc_spb_sts_encryption);
После этого сервис можно запустить с использованием метода start()
интерфейса IService:
svc->start(&status, spb2->getBufferLength(&status), spb2->getBuffer(&status));
Многие запущенные службы (включая упомянутый здесь gstat) во времявыполнения возвращают текстовую информацию. Чтобы отобразить её,необходимо запросить эту информацию у запущенного сервиса построчно. Этоделается с помощью вызова метода query()
интерфейсаIService
с соответствующими блокамипараметров для приёма и отправки. Блок отправки может содержатьразличную вспомогательную информацию (например, тайм-аут запроса услужбы) или информацию, которая должна быть передана в служебнуюпрограмму stdin, или может быть пустым в простейшем случае. Блок приемадолжен содержать список тегов, которые вы хотите получать из службы. Длябольшинства утилит это единственный isc_info_svc_line
:
const unsigned char receiveItems1[] = {isc_info_svc_line};
Кроме того, для запроса этой информации для неё необходим буфер:
unsigned char results[1024];
После этих предварительных шагов мы готовы запросить информацию изсервиса в цикле (каждая строка возвращается в одном вызове query()
):
do
{
svc->query(&status, 0, NULL,
sizeof(receiveItems1), receiveItems1,
sizeof(results), results);
} while (printInfo(results, sizeof(results)));
В этом примере мы предполагаем, что функция printInfo()
возвращаетTRUE, пока сервис возвращает блок результатов, содержащий следующуювыходную строку, то есть до конца потока данных из сервиса. Форматблока результатов варьируется от сервиса к сервису, а некоторые сервисы,такие как gsec, создают исторические форматы, которые не являютсятривиальными для синтаксического анализа, но это выходит за рамки даннойглавы. Минимальный рабочий пример printInfo()
присутствует в примере09.service.cpp
.
Тот же метод запроса используется для извлечения информации о сервере,но в этом случае функция запроса не вызывается в цикле, т. е. буфердолжен быть достаточно большим, чтобы сразу вместить всю информацию. Этоне слишком сложно, так как обычно такие вызовы не возвращают многоданных. Как и в предыдущем случае, необходимо начать с того, чтобыразместить в блоке приема необходимые элементы — в нашем примере этоisc_info_svc_server_version
:
const unsigned char receiveItems2[] = {isc_info_svc_server_version};
Существующий буфер результатов из предыдущего вызова может бытьиспользован повторно. В данном случае цикл не требуется:
svc->query(&status, 0, NULL,
sizeof(receiveItems2), receiveItems2,
sizeof(results), results);
printInfo(results, sizeof(results));
После завершения сервисных задач не забудьте отключить сервис:
svc->detach(&status);
Только создание пустых баз данных определенно недостаточно для работы сРСУБД. Мы хотим иметь возможность создавать в базе данных различныеобъекты (например, таблицы и т. д.) и вставлять данные в эти таблицы. ВFirebird любая операция с базой данных выполняется под управлениемтранзакций. Поэтому прежде всего мы должны научиться стартоватьтранзакцию. Здесь мы не обсуждаем распределенные транзакции(поддерживаемые интерфейсом IDtc
), чтобыизбежать ненужных для большинства пользователей сложностей. Запуск нераспределенной транзакции очень прост и выполняется через интерфейсподключения:
ITransaction* tra = att->startTransaction(&status, 0, NULL);
В этом примере используются параметры транзакции по умолчанию — TPB непередается методу startTransaction()
. Если вам нужна транзакция спараметрами отличными от параметров по умолчанию, вы можете создатьсоответствующий IXpbBuilder
идобавить к нему необходимые элементы:
IXpbBuilder* tpb = utl->getXpbBuilder(&status, IXpbBuilder::TPB, NULL, 0);
tpb->insertTag(&status, isc_tpb_read_committed);
и передать готовый TPB в startTransaction()
:
ITransaction* tra = att->startTransaction(&status, tpb->getBufferLength(&status),
tpb->getBuffer(&status));
Интерфейс транзакции используется как параметр во множестве другихвызовах API, но сам он не выполняет никаких действий, кромефиксации/отката (commit/rollback) транзакции, может быть с сохранениемконтекста транзакции (retaining):
tra->commit(&status);
Вы можете посмотреть, как начинать и подтверждать транзакцию в примерах01.create.cpp
и 01.create.pas
.
После старта транзакции мы готовы выполнять наши первые SQL операторы.Используемый для этого метод execute()
вIAttachment является довольноуниверсальным, и может также использоваться для выполнения операторовSQL с входными и выходными параметрами (что типично для инструкцииEXECUTE PROCEDURE
), но сейчас мы будем использовать наиболее простую егоформу. Могут быть выполнены как DDL, так и DML операторы:
att->execute(&status, tra, 0, "create table dates_table (d1 date)",
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
tra->commitRetaining(&status);
att->execute(&status, tra, 0, "insert into dates_table values (CURRENT_DATE)",
SQL_DIALECT_V6, NULL, NULL, NULL, NULL);
Как вы видите, интерфейс транзакции является обязательным параметром дляметода execute()
(должен быть NULL
, только если вы выполняете инструкциюSET TRANSACTION
). Следующим параметром следует длина SQL оператора(может быть равна нулю, в этом случае используются правила C дляопределения длины строки), потом текст оператора и диалект SQL, которыйдолжен использоваться для него. Далее следует несколько NULL
которыеподставляются для описания метаданных, и буферов входных параметров ивыходных данных. Полное описание этого метода представлено в интерфейсеIAttachment
.
Существует два способа выполнения оператора с входными параметрами.Выбор правильного метода зависит от того, нужно ли вам выполнять егоболее одного раза, и знаете ли вы заранее формат параметров. Когда этотформат известен, и оператор нужно запускать только один раз, тогда выможете воспользоваться одиночным вызовом IAttachment::execute(). Впротивном случае сначала необходимо подготовить SQL-запрос, после чегоего можно выполнять многократно с различными параметрами.
Чтобы подготовить SQL оператор для выполнения, используйте методprepare()
интерфейса IAttachment
:
IStatement* stmt = att->prepare(&status, tra, 0,
"UPDATE department SET budget = ? * budget + budget WHERE dept_no = ?",
SQL_DIALECT_V6, IStatement::PREPARE_PREFETCH_METADATA);
Если вы не собираетесь использовать описание параметров из Firebird(т.е. вы можете предоставить эту информацию самостоятельно), используйтеIStatement::PREPARE_PREFETCH_NONE
вместоIStatement::PREPARE_PREFETCH_METADATA
— это немного снизитклиент/серверный трафик и сохранит ресурсы.
В ISC API структура XSQLDA
используется для описания формата параметровоператора. Новый API не использует XSQLDA
— вместо неё используетсяинтерфейс IMessageMetadata
.Набор входных параметров (а также запись, взятая из курсора) описываетсяв Firebird API таким же образом, далее называемый сообщением.IMessageMetadata
передаётся в качестве параметра в методы обменасообщениями между программой и движком базы данных. Существует многоспособов получить экземпляр IMessageMetadata, вот некоторые из них:
получить из IStatement
;
построить используяIMetadataBuilder
интерфейс;
иметь собственную реализацию этого интерфейса.
Получить метаданные из подготовленного запроса очень просто — методgetInputMetadata()
возвращает интерфейс, описывающий входное сообщение(т.е. параметры оператора), интерфейс, возвращаемый getOutputMetadata()
,описывает выходное сообщение (т.е. строку выбранных данных или значения,возвращаемые процедурой). В нашем случае мы можем сделать так:
IMessageMetadata* meta = stmt->getInputMetadata(&status);
Или мы можем построить сообщение метаданных самостоятельно. Для этогопрежде всего нам необходимо получить интерфейс построителя:
IMetadataBuilder* builder = master->getMetadataBuilder(&status, 2);
Второй параметр — это ожидаемое количество полей в сообщении, его можноизменить позже, т.е. он необходим только для оптимизации.
Теперь необходимо задать индивидуальные характеристики полей впостроителе. Минимально необходимыми являются типы полей и длина длястроковых полей:
builder->setType(&status, 0, SQL_DOUBLE + 1);
builder->setType(&status, 1, SQL_TEXT + 1);
builder->setLength(&status, 1, 3);
Новый API использует старые константы для типов SQL, наименьший бит, каки раньше, используется для обозначения возможности принимать null
значение. В некоторых случаях имеет смысл установить подтип (для BLOB),набор символов (для текстовых полей) или масштаб (для числовых полей).Наконец, пришло время получить экземпляр IMessageMetadata:
IMessageMetadata* meta = builder->getMetadata(&status);
Здесь мы не обсуждаем собственную реализацию IMessageMetadata
. Если вамэто интересно, то вы можете посмотреть пример 05.user_metadata.cpp
.
Итак, мы получили экземпляр описания метаданных входных параметров. Нодля работы с сообщением нам также необходим буфер. Размер буфераявляется одной из основных характеристик сообщений метаданных ивозвращается методом getMessageLength()
из IMessageMetadata
:
char* buffer = new char[meta->getMessageLength(&status)];
Чтобы иметь дело с отдельными значениями внутри буфера, смещение к нимдолжно быть принято в расчёт. IMessageMetadata знает о смещениях длявсех значений в сообщении, используя его, мы можем создавать указателина них:
double* percent_inc = (double*) &buffer[meta->getOffset(&status, 0)];
char* dept_no = &buffer[meta->getOffset(&status, 1)];
Кроме того, не забывайте установить NULL флаги:
short* flag = (short*)&buffer[meta->getNullOffset(&status, 0)];
*flag = 0;
flag = (short*) &buffer[meta->getNullOffset(&status, 1)];
*flag = 0;
После завершения манипуляций со смещениями, мы готовы получить значенияпараметров:
getInputValues(dept_no, percent_inc);
и выполнить подготовленный оператор:
stmt->execute(&status, tra, meta, buffer, NULL, NULL);
Два последних NULL
в параметрах предназначены для выходных сообщений иобычно используются для оператора EXECUTE PROCEDURE
.
Если вам не нужно получать метаданные из оператора и вы планируетевыполнить его только один раз, то вы можете выбрать более простой способ— используйте метод execute()
из интерфейсаIAttachment
:
att->execute(&status, tra, 0,
"UPDATE department SET budget = ? * budget + budget WHERE dept_no = ?",
SQL_DIALECT_V6, meta, buffer, NULL, NULL);
В этом случае вам вообще не нужно использоватьIStatement
.
Пример того, как выполнить оператор UPDATE
с параметрами, присутствует в02.update.cpp
, вы также увидите, как возбужденное исключение втриггере/процедуре может быть перехвачено в программе на C++.
Единственный способ получить строки данных, возвращаемых операторомSELECT
в OO API — это использовать интерфейсIResultSet
. Этот интерфейсвозвращается методом openCursor()
как в IAttachment
, так и в IStatement
.openCursor()
в большинстве аспектов похож на execute()
, и решение какимобразом открыть курсор (с использованием подготовленного оператора илинепосредственно из интерфейса подключения) то же. В примерах03.select.cpp
и 04.print_table.cpp
используются оба способа.Обратите внимание на одно отличие метода openCursor()
по сравнению сexecute()
— никто не передает буфер для выходного сообщения вopenCursor()
, он будет передан позже, когда данные будут извлечены изкурсора. Это позволяет открывать курсор с неизвестным форматом выходногосообщения (NULL
передается вместо выходных метаданных). В этом случаеFirebird использует формат сообщения по умолчанию, который может бытьзапрошен через интерфейс IResultSet
:
const char* sql = "select * from ..."; // some select statement
IResultSet* curs = att->openCursor(&status, tra, 0, sql, SQL_DIALECT_V6,
NULL, NULL, NULL, NULL, 0);
IMessageMetadata* meta = curs->getMetadata(&status);
Позже эти метаданные могут использоваться для выделения буфера дляданных и разбора извлечённых строк.
В качестве альтернативы можно сначала подготовить оператор, получитьметаданные из подготовленного оператора и после этого открыть курсор.Это предпочтительный способ, если вы предполагаете, что курсор будетоткрыт более одного раза.
IStatement* stmt = att->prepare(&status, tra, 0, sql, SQL_DIALECT_V6,
IStatement::PREPARE_PREFETCH_METADATA);
IMessageMetadata* meta = stmt->getOutputMetadata(&status);
IResultSet* curs = stmt->openCursor(&status, tra, NULL, NULL, NULL, 0);
Мы получили (тем или иным способом) экземпляр описания метаданныхвыходных полей (строк в наборе данных). Для работы с сообщением намтакже нужен буфер:
unsigned char* buffer = new unsigned char[meta->getMessageLength(&status)];
В IResultSet
есть много различных методов выборки, но когда курсороткрыт не с параметром SCROLL
, то работает только fetchNext()
, то естьможно перемещаться по записям только вперед. В дополнение к ошибкам ипредупреждениям в статусе метод fetchNext()
возвращает код завершения,который может иметь значения RESULT_OK
(когда буфер заполняетсязначениями для следующей строки) или RESULT_NO_DATA
(когда в курсоребольше строк не осталось). RESULT_NO_DATA
не является состоянием ошибки,это нормальное состояние после завершения метода, которое сигнализирует,что данных в курсоре больше нет. Если используется оболочка статуса(Status Wrapper), то исключение не бросается в случае возврата ошибки.Может быть возвращено еще одно значение — RESULT_ERROR
— оно означаетотсутствие данных в буфере и ошибки в статусе векторе. Метод fetchNext()
обычно вызывается в цикле:
while (curs->fetchNext(&status, buffer) == IStatus::RESULT_OK)
{
// row processing
}
То, что происходит при обработке строк, зависит от ваших потребностей.Для получения доступа к определённому полю следует использовать смещениеполя:
unsigned char* field_N_ptr = buffer + meta->getOffset(&status, n);
где n - номер поля в сообщении. Этот указатель должен быть присвоенсоответствующему типу, в зависимости от типа поля. Например, для поляVARCHAR
, следует использовать приведение к структуре vary:
vary* v_ptr = (vary*) (buffer + meta->getOffset(&status, n));
Теперь мы можем напечатать значение поля:
printf("field %s value is %*.*s\n",
meta->getField(&status, n),
v_ptr->vary_length,
v_ptr->vary_length,
v_ptr->vary_string);
Если вам нужна максимальная производительность, будет полезно кэшироватьнеобходимые значения метаданных, как это сделано в наших примерах03.select.cpp
и 04.print_table.cpp
.
Работа с данными с использованием смещений довольно эффективна, нотребует написания большого количества кода. В C++ эту проблему можнорешить с помощью шаблонов, но даже по сравнению с ними наиболее удобнымспособом работы с сообщением является представление его в родном (длязаданного языка) форме — структуре в C/C++, записи в Pascal и т. д.Конечно это работает только в том случае, если формат сообщения известензаранее. Для создания таких структур в C++ в Firebird существуетспециальный макрос FB_MESSAGE
.
FB_MESSAGE
имеет 3 аргумента: имя сообщения (структуры), тип обёрткистатуса (status wrapper) и список полей. Использование первого и второгоаргумента очевидно, список полей содержит пары (field_type, field_name)
,где field_type является одним из следующих:
FB_BIGINT
FB_BLOB
FB_BOOLEAN
FB_CHAR(len)
FB_DATE
FB_DECFLOAT16
FB_DECFLOAT34
FB_DOUBLE
FB_FLOAT
FB_INTEGER
FB_INTL_CHAR(len, charSet)
FB_INTL_VARCHAR(len, charSet)
FB_SCALED_BIGINT(x)
FB_SCALED_INTEGER(x)
FB_SCALED_SMALLINT(x)
FB_SMALLINT
FB_TIME
FB_TIME_TZ
FB_TIME_TZ_EX
FB_TIMESTAMP
FB_TIMESTAMP_TZ
FB_TIMESTAMP_TZ_EX
FB_VARCHAR(len)
В сгенерированной препроцессором структуре типы integer
и float
сопоставляются с соответствующими типами C, типы date
и time
— склассами FbDate
иFbTime
(все упомянутые здесь классынаходятся в пространстве имен Firebird), тип timestamp
— с классомFbTimestamp
, содержащим два публичныхчлена данных дату и время соответствующих классов, тип char
— соструктурой FbChar
и varchar
— со структуройFbVarChar
. Для каждого поля препроцессорсоздаст два члена данных — name для значения поля/параметра и nameNullдля индикатора NULL
. Конструктор сообщений имеет 2 параметра — указательна оболочку статуса (status wrapper) и главный интерфейс (masterinterface):
FB_MESSAGE(Output, ThrowStatusWrapper,
(FB_SMALLINT, relationId)
(FB_CHAR(31), relationName)
(FB_VARCHAR(100), description)
) output(&status, master);
Для статических сообщений использование FB_MESSAGE
является самым лучшимвыбором, в то же время они легко могут быть переданы в методы execute
,openCursor
и fetch
:
rs = att->openCursor(&status, tra, 0, sqlText,
SQL_DIALECT_V6, NULL, NULL, output.getMetadata(), NULL, 0);
и используется для работы со значениями отдельных полей:
while (rs->fetchNext(&status, output.getData()) == IStatus::RESULT_OK)
{
printf("%4d %31.31s %*.*s\n", output->relationId, output->relationName.str,
output->descriptionNull ? 0 : output->description.length,
output->descriptionNull ? 0 : output->description.length,
output->description.str);
}
Пример использования макроса FB_MESSAGE
для работы с сообщениямиприведен в примере 06.fb_message.cpp
.
Для BLOBs Firebird хранит в буфере сообщения идентификатор BLOB — 8байтовый объект, который должен быть выравнен по 4-байтной границе.Идентификатор имеет тип ISC_QUAD
. ИнтерфейсIAttachment
имеет 2 метода дляработы с BLOB — openBlob()
и createBlob()
, возвращающие интерфейсIBlob
и имеющие одинаковый наборпараметров, но выполняющие несколько разные действия: openBlob()
принимает BLOB идентификатор из сообщения и подготавливает BLOB длячтения, а createBlob()
создает новый BLOB, помещает его идентификатор всообщение и подготавливает BLOB для записи.
Для работы с BLOBs прежде всего необходимо включить в сообщение ихBLOB-идентификаторы. Если вы получите метаданные из поля движка Firebirdсоответствующего типа, то этот идентификатор уже будет присутствовать. Вэтом случае вы просто используете его смещение (при условии, чтопеременная blobFieldNumber
содержит номер поля BLOB) (и соответствующееNULL смещение для проверки NULL
или установки NULL флага) для полученияуказателя в буфере сообщений:
ISC_QUAD* blobPtr =
(ISC_QUAD*) &buffer[metadata->getOffset(&status, blobFieldNumber)];
ISC_SHORT* blobNullPtr =
(ISC_SHORT*) &buffer[metadata->getNullOffset(&status, blobFieldNumber)];
Если вы используете статические сообщениями макрос FB_MESSAGE
, то полеBLOB будет объявлено как тип FB_BLOB
:
FB_MESSAGE(Msg, ThrowStatusWrapper,
(FB_BLOB, b)
) message(&status, master);
ISC_QUAD* blobPtr = &message->b;
ISC_SHORT* blobNullPtr = &message->bNull;
Для создания нового BLOB, вызовите метод createBlob()
:
IBlob* blob = att->createBlob(status, tra, blobPtr, 0, NULL);
Последние два параметра требуются только в том случае, если вы хотитеиспользовать blob-фильтры или blob-поток, которые не рассматриваютсяздесь.
Теперь Blob интерфейс готов принять данные в BLOB. Используйте методputSegment()
для отправки данных в движок:
void* segmentData;
unsigned segmentLength;
while (userFunctionProvidingBlobData(&segmentData, &segmentLength))
blob->putSegment(&status, segmentLength, segmentData);
После отправки некоторых данных в BLOB не забудьте закрытьblob-интерфейс:
blob->close(&status);
Убедитесь, что null флаг не установлен (не требуется, если вы сбросиливесь буфер сообщений перед созданием BLOB):
*blobNullPtr = 0;
и сообщение, содержащее BLOB, может использоваться в операторе вставкиили обновления. После выполнения этого оператора новый BLOB будетсохранен в базе данных.
Чтобы прочитать blob, необходимо получить его идентификатор в сообщенииот ядра firebird. Это можно сделать с помощью методов fetch()
илиexecute()
. После этого используйте метод openBlob()
:
IBlob* blob = att->openBlob(status, tra, blobPtr, 0, NULL);
Blob интерфейс готов предоставить данные BLOB. Используйте методgetSegment()
для получения данных из движка:
char buffer[BUFSIZE];
unsigned actualLength;
for(;;)
{
switch (blob->getSegment(&status, sizeof(buffer), buffer, &actualLength))
{
case IStatus::RESULT_OK:
userFunctionAcceptingBlobData(buffer, actualLength, true);
continue;
case IStatus::RESULT_SEGMENT:
userFunctionAcceptingBlobData(buffer, actualLength, false);
continue;
default:
break;
}
}
Последний параметр в userFunctionAcceptingBlobData()
— это флагдостижения конца сегмента — когда getSegment()
возвращает код завершенияRESULT_SEGMENT
, о чём будет уведомлена функция (в последний параметрпередан false
), то есть этот сегмент прочитан не полностью, ипродолжение ожидается при следующем вызове.
Закончив работать с BLOB, не забудьте закрыть его:
blob->close(&status);
Поскольку Firebird 4.0 поддерживает пакетное выполнение операторов с входными параметрами, это означаетотправку более чем одного набора параметров при выполнении оператора. Пакетный интерфейс разработан (в первую очередь)для удовлетворения требований JDBC по пакетной обработке подготовленных операторов, но имеет ряд серьезных отличий:
как и все операции с данными в firebird ориентированы на сообщения, а не на одно поле;
в качестве важного расширения пакетный интерфейс поддерживает встроенное использование BLOB-объектов(особенно эффективно при работе с небольшими BLOB-объектами);
метод execute()
возвращает не простой массив целых чисел, а специальный интерфейс IBatchCompletionState
,который может (в зависимости от параметров создания пакета) содержать как информацию об обновлениях записей,так и в дополнение к флагу ошибки подробные векторы состояния для сообщений, вызвавших ошибки выполнения.
Интерфейс IBatch
(точно так же, как и IResultSet
)может быть создан двумя способами – с использованием интерфейса IStatement
илиIAttachment
, в обоих случаях вызывается метод createBatch()
соответствующего интерфейса.Во втором случае текст оператора SQL, который должен выполняться в пакете, передается непосредственно в createBatch()
.Настройка пакетной обработки осуществляется с помощью блока Batch parameters, формат которого более или менее похожна DPB v.2 – в начале тег (IBatch::CURRENT_VERSION
), за которым следует набор широких скоплений: тег 1 байт, длина 4 байта,значение указанной длины байт. Возможные теги описаны в пакетном интерфейсе.Самый простой (и рекомендуемый) способ создать блок параметров для пакетного создания — использоватьсоответствующий интерфейс IXpbBuilder
:
IXpbBuilder* pb = utl->getXpbBuilder(&status, IXpbBuilder::BATCH, NULL, 0);
pb->insertInt(&status, IBatch::RECORD_COUNTS, 1);
Использование такого блока параметров инструктирует пакет возвращать количество обновленных записей для каждого сообщения.
Чтобы создать пакетный интерфейс с нужными параметрами, передайте блок параметров в вызов createBatch()
:
IBatch* batch = att->createBatch(&status, tra, 0, sqlStmtText, SQL_DIALECT_V6, NULL,
pb->getBufferLength(&status), pb->getBuffer(&status));
В этом примере пакетный интерфейс создается с форматом сообщений по умолчанию,потому что вместо формата входных метаданных передается NULL
.
Для работы с созданным пакетным интерфейсом нам необходимо знать формат сообщений в нем.Его можно получить с помощью метода getMetadata()
:
IMessageMetadata* meta = batch->getMetadata(&status);
Конечно, если вы передали свой собственный формат сообщений в пакет, вы можете просто использовать его.
Далее я предполагаю, что существует некоторая функция fillNextMessage(unsigned char* data, IMessageMetadata* metadata)
и она может заполнить буфер data
в соответствии с переданным форматом metadata
. Для работы с сообщениями нам нужен буфер для данных:
unsigned char* data = new unsigned char[meta->getMessageLength(&status)];
Теперь мы можем добавить в пакет несколько сообщений с заполненными данными:
fillNextMessage(data, meta);
batch->add(&status, 1, data);
fillNextMessage(data, meta);
batch->add(&status, 1, data);
Альтернативный способ работы с сообщениями (с помощью макроса FB_MESSAGE
) присутствует в примере использованияпакетного интерфейса 11.batch.cpp
.
Наконец, пакет должен быть выполнен:
IBatchCompletionState* cs = batch->execute(&status, tra);
Мы запросили учет количества измененных (вставленных, обновленных или удаленных) записей для каждого сообщение.Чтобы распечатать его, мы должны использовать интерфейс IBatchCompletionState
.Определить общее количество сообщений, обработанных пакетом (оно может быть меньше количества сообщений,переданных в пакет, если произошла ошибка и не была включена опция возврата множества ошибок при пакетной обработке):
unsigned total = cs->getSize(&status);
Теперь выводим состояние каждого сообщения:
for (unsigned p = 0; p < total; ++p) printf("Msg %u state %d\n", p, cs->getState(&status, p));
Когда закончите анализ состояния завершения, не забудьте его удалить:
cs->dispose();
Полный пример печати содержимого IBatchCompletionState
находитсяв функции print_cs()
в примере 11.batch.cpp
.
Если по какой-то причине вы хотите сделать пакетные буферы пустыми, не выполняя их(т.е. подготовиться к обработке новой порции сообщений), используйте метод cancel()
:
batch->cancel(&status);
Как и у остальных наших интерфейсов доступа к данным, у IBatch
есть специальный метод для его закрытия:
batch->close(&status);
Вместо этого можно использовать стандартный вызов release()
, если вас не волнуют ошибки:
batch->release();
Описанные методы помогают реализовать все, что нужно для пакетных операций с подготовленными операторами в стиле JDBC.
Note
|
Замечание
JDBC не рекомендует использовать слишком большие пакеты, например, "Oracle рекомендует сохранять размеры пакетов в диапазоне от 50 до 100".Firebird поддерживает большие пакеты, но в любом случае должен ограничивать максимальный размер пакета — см. |
Можно добавить более одного сообщения за один вызов в пакет. При этом помните, что сообщения должны бытьправильно выровнены, чтобы эта функция работала правильно. Требуемое выравнивание и выровненный размер сообщениядолжны быть получены из интерфейса IMessageMetadata
, например:
unsigned aligned = meta->getAlignedLength(&status);
Позже этот размер пригодится при выделении массива сообщений и работе с ним:
unsigned char* data = new unsigned char[aligned * N]; // N is desired number of messages
for (int n = 0; n < N; ++n)
fillNextMessage(&data[aligned * n], meta);
batch->add(&status, N, data);
После этого может выполняться пакет или добавляться к нему следующая порция сообщений.
BLOBs в целом несовместимы с пакетами — пакет эффективен, когда нужно передать на сервер много мелких данных за один шаг,BLOBs рассматриваются как большие объекты, и поэтому в целом нет смысла использовать их в пакетах.Но на практике часто случается, что BLOB не слишком велики — и в этом случае использование традиционного BLOB API(создание BLOB, передача сегментов на сервер, закрытие BLOB, передача идентификатора BLOB в сообщении) убивает производительность,особенно при использовании через WAN. Поэтому в firebird пакет поддерживает передачу BLOB на сервер вместе с другими сообщениями.Чтобы использовать эту возможность, в первую очередь должна быть установлена политика использования BLOB-объектов длясоздаваемого пакета (как опция в блоке параметров):
pb->insertInt(&status, IBatch::BLOB_IDS, IBatch::BLOB_IDS_ENGINE);
В этом примере временные идентификаторы BLOB, необходимые для поддержания связи между BLOB и сообщением,в котором они используются, будут генерироваться движком firebird — это самое простое и довольно распространенное использование.Представьте, что сообщение описывается следующим образом:
FB_MESSAGE(Msg, ThrowStatusWrapper,
(FB_VARCHAR(5), id)
(FB_VARCHAR(10), name)
(FB_BLOB, desc)
) project(&status, master);
В этом случае, чтобы отправить сообщение, содержащее blob, на сервер, можно сделать что-то вроде этого:
project->id = ++idCounter;
project->name.set(currentName);
batch->addBlob(&status, descriptionSize, descriptionText, &project->desc);
batch->add(&status, 1, project.getData());
Если какой-то BLOB оказался достаточно большим, чтобы не поместиться в ваш существующий буфер,вы можете вместо перераспределения буфера использовать метод appendBlobData()
.Он добавляет больше данных к последнему добавленному BLOB.
batch->addBlob(&status, descriptionSize, descriptionText, &project->desc, bpbLength, bpb);
После добавления первой части BLOB получите следующую часть данных в descriptionText
, с размером descriptionSize
после чего:
batch->appendBlobData(&status, descriptionSize, descriptionText);
Это можно сделать в цикле, но будьте осторожны, чтобы не переполнить внутренние пакетные буферы — их размерконтролируется параметром BUFFER_BYTES_SIZE
при создании интерфейса IBatch
, но не может превышать 256 МБ(по умолчанию 16 МБ). Если вам нужно обработать такой большой BLOB (например, на фоне множества мелких — этим можнообъяснить использование пакетной обработки), просто используйте стандартный API IBlob
и метод registerBlob
интерфейса IBatch
.
Еще один возможный выбор политики BLOB — BLOB_IDS_USER
. Использование на первый взгляд не сильно меняется —перед вызовом addBlob()
правильный и уникальный для каждого пакета идентификатор должен быть помещен в память,на которую ссылается последний параметр. Конечно, тот же идентификатор должен быть передан в сообщении для BLOB.Принимая во внимание, что генерация BLOB-идентификаторов движком происходит очень быстро, такая политика может показаться бесполезной,но представьте случай, когда вы получаете BLOB и другие данные в относительно независимых потоках (например, в блоках файла),а некоторые хорошие идентификаторы уже присутствуют в них. В таком случае использование предоставленных пользователемидентификаторов BLOB может значительно упростить код.
Note
|
Обратите внимание
В отличие от BLOB-объектов, созданных с помощью обычного
|
Разумеется, переданный BPB может содержать и любые другие параметры создания BLOB. Как вы, возможно, уже заметили,вы также можете передать BPB напрямую в addBlob()
, но если большинство BLOB-объектов, которые вы собираетесь добавить,имеют одинаковый формат, отличный от формата по умолчанию, то использование setDefaultBpb()
немного более эффективно.Возвращаясь к сегментированным BLOB — вызов addBlob()
добавит первый сегмент в BLOB, последующие вызовы appendBlobData()
добавят дополнительные сегменты. Не забывайте, что размер сегмента ограничен 64Кб – 1
, попытка передать больше данныхза один вызов вызовет ошибку.
Следующий шаг - работа с существующими потоками BLOB для чего используется метод addBlobStream()
.Используя его, можно добавить более одного BLOB в пакет за один вызов. Поток BLOB — это последовательность BLOB,каждый из которых начинается с заголовка BLOB. Заголовок должен быть правильно выровнен — для этого в интерфейсе IBatch
предусмотрен специальный вызов:
unsigned alignment = batch->getBlobAlignment(&status);
Предполагается, что все компоненты потока BLOB в пакете должны быть выровнены как минимум по границе выравнивания,включая размер порций потока, передаваемых в addBlobStream()
, который должен быть кратен этому выравниванию.Заголовок содержит 3 поля: 8-байтовый идентификатор BLOB (должен быть ненулевым), 4-байтовый общий размер BLOB и 4-байтовый размер BPB.Общий размер BLOB-объекта включает в себя BPB внутри, т. е. всегда можно найти следующий BLOB-объект в потоке в байтразмера BLOB-объекта после заголовка (с учетом выравнивания). BPB (если присутствует, т.е. если размер BPB не равен нулю)помещается сразу после заголовка. После передачи данных BLOB-объекта BPB их формат зависит от типа BLOB-объекта —потокового или сегментированного. В случае потокового BLOB это простая последовательность байтов, имеющая размер blob-size – BPB-size
.С сегментированным BLOB-объектом все немного сложнее: данные BLOB-объекта представляют собой набор сегментов,где каждый сегмент имеет следующий формат: размер сегмента 2 байта (это должно быть выровнено по границе IBatch::BLOB_SEGHDR_ALIGN
),за которым следуют хранящиеся в нем 2 байта количества байт.
Когда в поток добавляется BLOB, его размер не всегда известен заранее. Чтобы не было слишком большого буферадля этого BLOB (помните, что размер должен быть указан в заголовке BLOB перед данными BLOB), можно использовать записьпродолжения BLOB. В заголовке BLOB вы оставляете размер BLOB со значением, известным при создании этого заголовка,и добавляете запись продолжения, которая имеет формат, абсолютно такой же, как и заголовок BLOB, но здесь идентификаторBLOB должен быть равен нулю, а размер BPB всегда также должен быть равен нулю. Обычно вам потребуется иметь одну записьпродолжения для каждого вызова addBlobStream()
.
Последний метод, используемый для работы с BLOB, стоит особняком от первых трех, которые передают данные BLOB вместес остальными пакетными данными — он необходим для регистрации в идентификаторе пакета BLOB, созданного с использованием стандартного BLOB API.Это может быть неизбежным, если нужно передать в пакет действительно большой BLOB. Не используйте идентификатор такогоBLOB в пакете напрямую — это приведет к ошибке недопустимого идентификатора BLOB во время пакетного выполнения. Вместо этого выполните:
batch->registerBlob(&status, &realId, &msg->desc);
Если политика BLOB заставляет механизм Firebird генерировать идентификаторы BLOB, этого кода достаточно,чтобы правильно зарегистрировать существующий BLOB в пакете. В других случаях вам нужно будет назначить правильный (из пакета POV) идентификатордля msg→desc
.
Почти все упомянутые методы используются в 11.batch.cpp
— используйте его, чтобы увидеть живой пример пакетной обработки в firebird.
Пару слов о доступе к пакетам из ISC API - можно выполнить подготовленный оператор ISC в пакетном режиме.Для поддержки этого добавлено две новые функций API, а именно fb_get_transaction_interface
иfb_get_statement_interface
, которые позволяют получить доступ к соответствующим интерфейсам,идентичным существующим дескрипторам ISC. Пример этого присутствует в 12.batch_isc.cpp
.
Интерфейс событий не был завершен в Firebird 4.0, мы ожидаем, что вследующей версии будет что-то более интересное. Минимальная существующаяподдержка выглядит следующим образом:IAttachment
содержит методqueEvents()
, который выполняет почти те же функции, что и вызовisc_que_events()
. Вместо пары параметров FPTR_EVENT_CALLBACK ast
иvoid* arg
, необходимых для вызова кода пользователя, когда в Firebirdпроисходит событие, используется интерфейс обратного вызоваIEventCallback
. Это традиционный подход, который помогает избежатьнебезопасных бросков из void* в пользовательской функции. Другое важноеразличие заключается в том, что вместо идентификатора события (видаобработчика) эта функция возвращает ссылку на интерфейсIEvents
, имеющий метод cancel()
,используемый для остановки ожидании события. В отличие отидентификатора, который уничтожается автоматически при поступлениисобытия, интерфейс не может быть уничтожен автоматически, если событиеполучено непосредственно перед вызовом метода cancel()
, то это вызоветsegfault из-за того, что интерфейс уже будет уничтожен. Поэтому послеполучения события интерфейс IEvents
должен быть явно освобождён. Это может быть сделано, например, прямоперед запросом события из очереди в следующий раз:
events->release();
events = NULL;
events = attachment->queEvents(&status, this, eveLen, eveBuffer);
Установка указателя интерфейса в NULL
полезна в случае возникновенияисключения в queEvents
. В других аспектах обработка событий неизменилась по сравнению с ISC API. Для получения дополнительнойинформации используйте наш пример 08.events.cpp
.
Чтобы написать плагин, нужно реализовать некоторые интерфейсы ипоместить вашу реализацию в динамическую библиотеку (.dll
в Windowsили .so
в Linux), которую называют модулем плагина или просто модулем.В большинстве случаев одиночный плагин размещается в динамическойбиблиотеке, но не обязательно. Один из этих интерфейсов —IPluginModule
— является модульным(как более или менее ясно из его имени), другие отвечают за плагин.Также каждый модуль плагина должен содержать специальнуюэкспортированную точку входа firebird_plugin()
, имя которой указано вфайле include/firebird/Interfaces.h
как FB_PLUGIN_ENTRY_POINT
.
В предыдущей части мы в основном описывали, как использоватьсуществующие интерфейсы, здесь основное внимание будет уделеносамостоятельной реализации интерфейсов. Разумеется, для этого можно инужно использовать уже существующие интерфейсы, общие для доступа кбазам данных Firebird (уже описанные) и некоторые дополнительныеинтерфейсы, специально предназначенные для плагинов.
Далее активно используется пример плагина шифрования базы данныхexamples/dbcrypt/DbCrypt.cpp
. Будет хорошей идеей собрать этот примерсамостоятельно и изучить его при чтении позже.
Плагины активно взаимодействуют со специальным компонентом Firebird,называемым диспетчером плагинов. В частности, менеджер плагинов должензнать, какие модули плагина были загружены и должен быть уведомлен, еслиоперационная система пытается выгрузить один из этих модулей без явнойкоманды диспетчера плагина (это может произойти прежде всего прииспользовании встроенного сервера (embedded) — когда в программевызывается exit()
или основная библиотека Firebird fbclient
выгружается). Основная задача интерфейса IPluginModule
— этоуведомление. Прежде всего, нужно решить — как определить, что модульбудет выгружен? Когда динамическая библиотека выгружается по какой-либопричине, выполняется множество зависимых от ОС действий, и некоторые изэтих действий могут использоваться для обнаружения этого факта впрограмме. При написании плагинов, распространяемых вместе с firebird,мы всегда используем вызов деструктора глобальной переменной. Большой«плюс» этого метода заключается в том, что он независим от ОС (хотячто-то вроде функции exit()
, возможно, также успешно используется). Ноиспользование деструктора позволяет легко сконцентрировать почти все,что связано с обнаружением выгрузки в одном классе, реализуя в то жевремя интерфейс IPluginModule
.
Минимальная реализация выглядит следующим образом:
class PluginModule : public IPluginModuleImpl<PluginModule, CheckStatusWrapper>
{
private:
IPluginManager* pluginManager;
public:
PluginModule()
: pluginManager(NULL)
{ }
~PluginModule()
{
if (pluginManager)
{
pluginManager->unregisterModule(this);
doClean();
}
}
void registerMe(IPluginManager* m)
{
pluginManager = m;
pluginManager->registerModule(this);
}
void doClean()
{
pluginManager = NULL;
}
};
Единственным членом данных является интерфейс диспетчера плагиновIPluginManager
. Он передаетсяфункции registerModule()
и сохраняется в приватной переменной, в то жевремя модуль регистрируется в диспетчере плагинов методом callModule()
ссобственным адресом в качестве единственного параметра. ПеременнаяpluginManager
не только сохраняет указатель на интерфейс, ноодновременно служит в качестве флага, что модуль зарегистрирован. Когдавызывается деструктор зарегистрированного модуля, он уведомляетдиспетчер плагинов о неожиданной выгрузке с помощью вызоваunregisterModule()
, передающим указатель на себя. Когда диспетчерплагинов будет регулярно выгружать модуль, то в первую очередь вызовметода doClean()
меняет состояние модуля на незарегистрированное, и этопозволяет избежать вызова unregisterModule()
, когда ОС выполняетфактическую выгрузку.
Реализовав интерфейс плагина IPluginModule
, мы встретились с первыминтерфейсом, необходимым для реализации плагинов — IPluginManager
. Онбудет активно использоваться позже, остальные члены этого класса вряд липотребуются вам после копирования в вашу программу. Просто не забудьтеобъявить глобальную переменную этого типа и вызвать функцию registerMe()
из FB_PLUGIN_ENTRY_POINT
.
Приступим к реализации самого плагина. Тип основного интерфейса зависитот типа плагина, что очевидно, но все они основаны на общем интерфейсеIPluginBase
с подсчётом ссылок, который выполняет общие для всехплагинов (и очень простые) задачи. Каждый плагин имеет некоторый (тоже сподсчётом ссылок) объект, которому принадлежит этот плагин. Чтобывыполнять интеллектуальное управление жизненным циклом плагинов, любойплагин должен иметь возможность хранить информацию о владельце исообщать её диспетчеру плагинов по запросу. Это означает, что каждыйплагин должен реализовывать два тривиальных метода setOwner()
иgetOwner()
, содержащиеся в интерфейсе IPluginBase
. Зависимые от типаплагина методы, безусловно, более интересны — они обсуждаются в частиописания интерфейсов.
Давайте рассмотрим типичную часть реализации любого плагина (здесь яспециально использую несуществующий тип SomePlugin
):
class MyPlugin : public ISomePluginImpl<MyPlugin, CheckStatusWrapper>
{
public:
explicit MyPlugin(IPluginConfig* cnf) throw()
: config(cnf), refCounter(0), owner(NULL)
{
config->addRef();
}
...
Конструктор получает в качестве параметра интерфейс конфигурацииплагина. Если вы собираетесь конфигурировать плагин каким-то образом, торекомендуется сохранить этот интерфейс в вашем плагине и использоватьего позже. Это позволит вам использовать общий стиль конфигурацииFirebird, позволяя пользователям иметь привычную конфигурацию и свести кминимуму написание кода. Конечно, при сохранении какого-либо ссылочногоинтерфейса лучше не забывать добавлять ссылку на него. Также не забудьтеустановить счетчик ссылок в 0 и владельца плагина в NULL
.
~MyPlugin()
{
config->release();
}
Деструктор освобождает конфигурационный интерфейс. Обратите внимание: мыне меняем счетчик ссылок нашего владельца, потому что он принадлежитнам, а не мы принадлежим ему.
// IRefCounted implementation
int release()
{
if (--refCounter == 0)
{
delete this;
return 0;
}
return 1;
}
void addRef()
{
++refCounter;
}
Абсолютно типичная реализация объекта с подсчётом ссылок.
// IPluginBase implementation
void setOwner(IReferenceCounted* o)
{
owner = o;
}
IReferenceCounted* getOwner()
{
return owner;
}
Как и было обещано, реализация IPluginBase
тривиальна.
// ISomePlugin implementation
// … here go various methods required for particular plugin type
private:
IPluginConfig* config;
FbSampleAtomic refCounter;
IReferenceCounted* owner;
};
В этом примере формальная часть реализации основного интерфейса плагиназавершена. После добавления специфичных для типа методов (и, возможно,написания кода, чтобы сделать их полезным), интерфейс готов.
Еще один интерфейс, необходимый для работы плагина —IPluginFactory
. Фабрика создаетэкземпляры плагина и возвращает их в диспетчер плагинов. Фабрика обычновыглядит так:
class Factory : public IPluginFactoryImpl<Factory, CheckStatusWrapper>
{
public:
IPluginBase* createPlugin(CheckStatusWrapper* status,
IPluginConfig* factoryParameter)
{
MyPlugin* p = new MyPlugin(factoryParameter);
p->addRef();
return p;
}
};
Здесь внимание следует уделить тому факту, что даже в случае, когда кодв функции может генерировать исключения (оператор new может бросать вслучае, когда память исчерпана), то не обязательно всегда вручнуюопределять блок try/catch — реализация интерфейсов Firebird делает этуработу за вас, в реализации IPluginFactory
эта обработка происходит вшаблоне IPluginFactoryImpl
. Обратите внимание, что обертки статуса поумолчанию выполняют полноценную обработку только для FbException
. Ноесли вы работаете над каким-то крупным проектом, то определите своюсобственную оболочку, в этом случае вы можете обрабатывать любой типисключения C++ и передавать полезную информацию об этом из своегоплагина.
Когда диспетчер плагинов загружает модуль плагина, он вызывает процедуруинициализации модуля — единственную экспортируемую функцию плагинаFB_PLUGIN_ENTRY_POINT
. Для написания кода ей понадобятся две глобальныепеременные — модуль плагина и фабрика плагинов. В нашем случае это:
PluginModule module;
Factory factory;
Если модуль содержит более одного плагина, вам понадобится фабрика длякаждого плагина.
Для FB_PLUGIN_ENTRY_POINT
мы не должны забывать, что она должна бытьэкспортирована из модуля плагина, для этого требуется учет некоторыхособенностей ОС. Мы делаем это, используя макрос FB_DLL_EXPORT
,определенный в examples/interfaces/ifaceExamples.h
. Если вы уверены,что используете плагин только для некоторых конкретных ОС, то вы можетесделать это место немного проще. В минимальном случае функция должнарегистрировать модуль и все фабрики в диспетчере плагинов:
extern "C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* master)
{
IPluginManager* pluginManager = master->getPluginManager();
module.registerMe(pluginManager);
pluginManager->registerPluginFactory(IPluginManager::TYPE_DB_CRYPT,
"DbCrypt_example",
&factory);
}
Прежде всего, мы вызываем недавно написанную нами функциюPluginModule::registerMe()
, которая сохраняет IPluginManager
длядальнейшего использования и регистрирует наш модуль плагина. Затемрегистрируем фабрику (или фабрики если в одном модуле будет несколькоплагинов). Мы должны передать правильный тип плагина (допустимые типыперечислены в интерфейсе IPluginManager
) и имя, под которым будетзарегистрирован плагин. В простейшем случае он должен совпадать с именемдинамической библиотеки модуля плагина. Это правило поможет вам ненастраивать плагин вручную в plugins.conf
.
Обратите внимание — в отличие от приложений плагины не должныиспользовать fb_get_master_interface()
для получения IMaster
. Вместоэтого следует использовать экземпляр, переданный вFB_PLUGIN_ENTRY_POINT
. Если вам нужен мастер-интерфейс в вашем плагине,позаботьтесь об его сохранении в этой функции.
В этом глоссарии мы не перечисляем интерфейсы, которые не используютсяактивно (например, IRequest
, необходимые в первую очередь для поддержкиустаревших запросов API ISC). Та же ссылка может быть получена изнекоторых методов (например, compileRequest()
в IAttachment
). Дляинтерфейсов/методов, имеющих прямой аналог в старом API, этот аналогбудет указан.
Интерфейс IAttachment
заменяет isc_db_handle
.
getInfo
void getInfo(StatusType* status,
unsigned itemsLength,
const unsigned char* items,
unsigned bufferLength,
unsigned char* buffer)
Заменяет isc_database_info()
.
startTransaction
ITransaction* startTransaction(StatusType* status,
unsigned tpbLength,
const unsigned char* tpb)
Частично заменяет isc_start_multiple()
, использует координатор, чтобызапустить более одной распределённой транзакции. Позволяет объединить 2транзакции в одну распределённую.
reconnectTransaction
ITransaction* reconnectTransaction(StatusType* status,
unsigned length,
const unsigned char* id)
Позволяет подключиться к транзакции в состоянии limbo. Параметр Idсодержит номер транзакции в сетевом формате заданной длины.
compileRequest
IRequest* compileRequest(StatusType* status,
unsigned blrLength,
const unsigned char* blr)
Поддержка ISC API.
transactRequest
void transactRequest(StatusType* status,
ITransaction* transaction,
unsigned blrLength,
const unsigned char* blr,
unsigned inMsgLength,
const unsigned char* inMsg,
unsigned outMsgLength,
unsigned char* outMsg)
Поддержка ISC API.
createBlob
IBlob* createBlob(StatusType* status,
ITransaction* transaction,
ISC_QUAD* id,
unsigned bpbLength,
const unsigned char* bpb)
Создает новый blob, сохраняет его идентификатор в id, заменяетisc_create_blob2()
.
openBlob
IBlob* openBlob(StatusType* status,
ITransaction* transaction,
ISC_QUAD* id,
unsigned bpbLength,
const unsigned char* bpb)
Открывает существующий blob, заменяет isc_open_blob2()
.
getSlice
int getSlice(StatusType* status,
ITransaction* transaction,
ISC_QUAD* id,
unsigned sdlLength,
const unsigned char* sdl,
unsigned paramLength,
const unsigned char* param,
int sliceLength,
unsigned char* slice)
Поддержка ISC API.
putSlice
void putSlice(StatusType* status,
ITransaction* transaction,
ISC_QUAD* id,
unsigned sdlLength,
const unsigned char* sdl,
unsigned paramLength,
const unsigned char* param,
int sliceLength,
unsigned char* slice)
Поддержка ISC API.
executeDyn
void executeDyn(StatusType* status,
ITransaction* transaction,
unsigned length,
const unsigned char* dyn)
Поддержка ISC API.
prepare
IStatement* prepare(StatusType* status,
ITransaction* tra,
unsigned stmtLength,
const char* sqlStmt,
unsigned dialect,
unsigned flags)
Заменяет isc_dsql_prepare()
. Дополнительный параметр flags позволяютконтролировать, какая информация будет предварительно загружена издвижка сразу (т.е. в одном сетевом пакете для удаленной операции).
execute
ITransaction* execute(StatusType* status,
ITransaction* transaction,
unsigned stmtLength,
const char* sqlStmt,
unsigned dialect,
IMessageMetadata* inMetadata,
void* inBuffer,
IMessageMetadata* outMetadata,
void* outBuffer)
Выполняет любую инструкцию SQL, за исключением возврата нескольких строкданных. Частичный аналог isc_dsql_execute2()
— вход и выход XSLQDAзаменены на входные и выходные сообщения с соответствующими буферами.
openCursor
IResultSet* openCursor(StatusType* status,
ITransaction* transaction,
unsigned stmtLength,
const char* sqlStmt,
unsigned dialect,
IMessageMetadata* inMetadata,
void* inBuffer,
IMessageMetadata* outMetadata,
const char* cursorName,
unsigned cursorFlags)
Выполняет оператор SQL, потенциально возвращающий несколько строкданных. Возвращает интерфейсIResultSet
, который используется дляизвлечения этих данных. Формат выходных данных определяется параметромoutMetadata
, при задании NULL
используется формат по умолчанию. ПараметрcursorName указывает имя открытого курсора (аналогisc_dsql_set_cursor_name()
). Параметр cursorFlags
необходим, чтобыоткрыть двунаправленный указатель курсора, для этого необходимо указатьзначение IStatement::CURSOR_TYPE_SCROLLABLE
.
queEvents
IEvents* queEvents(StatusType* status,
IEventCallback* callback,
unsigned length,
const unsigned char* events)
Заменяет вызов isc_que_events()
. Вместо функции обратного вызова сvoid*
параметром используется интерфейс обратного вызова.
cancelOperation
void cancelOperation(StatusType* status, int option)
Замена fb_cancel_operation()
.
ping
void ping(StatusType* status)
Проверяет состояния соединения. Если тест не удаётся, то единственнаявозможная операция с подключением — закрыть его.
getIdleTimeout
unsigned getIdleTimeout(StatusType* status)
Возвращает таймаут простоя соединения в секундах.
setIdleTimeout
void setIdleTimeout(StatusType* status, unsigned timeOut)
Устанавливает таймаут простоя соединения в секундах.
getStatementTimeout
unsigned getStatementTimeout(StatusType* status)
Возвращает таймаут выполнения запроса в миллисекундах.
setStatementTimeout
void setStatementTimeout(StatusType* status, unsigned timeOut)
Устанавливает таймаут выполнения запроса в миллисекундах.
createBatch
IBatch* createBatch(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par)
Подготавливает sqlStmt
и создает интерфейс IBatch
, готовый принять несколько наборов входных параметровв формате inMetadata
. Если оставить NULL
в inMetadata
, то пакет будет использовать формат по умолчанию для sqlStmt
.В функцию createBatch()
можно передать блок параметров, что позволит настроить поведение пакета.
createReplicator
IReplicator* createBatch(StatusType* status)
Создаёт экземпляр плагина репликации с интерфейсом IReplicator
.
detach
void detach(StatusType* status)
Отсоединяет от текущей базы данных. Заменяет isc_detach_database()
. В случае успеха освобождает интерфейс.
dropDatabase
void dropDatabase(StatusType* status)
Удаляет текущую базу данных. Заменяет isc_drop_database()
. В случае успеха освобождает интерфейс.
Интерфейс IDtc
— координатор распределенных транзакций. Используется длязапуска распределенной (работает с двумя или более подключениями)транзакции. В отличие от пред-FB3-подхода, когда распределеннаятранзакция должна запускаться таким образом с самого начала, координаторраспределенных транзакций Firebird 3 позволяет также присоединить ужезапущенные транзакции в единую распределенную транзакцию.
join
ITransaction* join(StatusType* status, ITransaction* one, ITransaction* two)
Объединяет 2 независимых транзакции в распределенную транзакцию. Приуспешном выполнении обе транзакции, переданные в join()
,освобождаются, а указатели на них больше не должны использоваться.
startBuilder
IDtcStart* startBuilder(StatusType* status)
Возвращает IDtcStart
интерфейс.
Интерфейс IDtcStart
— заменяет массив структур TEB (переданisc_start_multiple()
в ISC API). Этот интерфейс собирает подключения(и, вероятно, соответствующие TPB), для которых должна быть запущенараспределённая транзакция.
addAttachment
void addAttachment(StatusType* status, IAttachment* att)
Добавляет подключение, транзакция для него будет запущена с TPB поумолчанию.
addWithTpb
void addWithTpb(StatusType* status, IAttachment* att, unsigned length, const unsigned char* tpb)
Добавляет подключение и TPB, которые будут использоваться для запускатранзакции для этого подключения.
start
ITransaction* start(StatusType* status)
Начинает распределенную транзакцию для собранных подключений. При успехевозвращает интерфейс IDtcStart
.
Интерфейс IEventCallback
— заменяет функцию обратного вызова,используемую в вызове isc_que_events()
. Должен быть реализованпользователем для отслеживания событий с помощью методаIAttachment::queEvents()
.
eventCallbackFunction
void eventCallbackFunction(unsigned length, const unsigned char* events)
Вызывается каждый раз, когда происходит событие.
Интерфейс IEvents
— заменяет идентификатор события при работе смониторингом событий.
cancel
void cancel(StatusType* status)
Отменяет мониторинг событий, начатый в IAttachment::queEvents()
.
Интерфейс IFirebirdConf
— доступ к основной конфигурации Firebird.Используется как для конфигурации по умолчанию, заданной конфигурациейfirebird.conf
, так и для каждой базы данных, скорректированной спомощью database.conf
. Чтобы ускорить доступ к значениям конфигурации,вызовы, обращающиеся к фактическим значениям, используют целочисленныйключ вместо символьного имени параметра. Ключ стабилен во время работысервера (т. е. плагин может получить его один раз и использовать дляполучения значения параметров конфигурации для разных баз данных).
getKey
unsigned getKey(const char* name)
Возвращает ключ для заданного имени параметра. ~0 (все биты равны 1)возвращается в случае, когда такого параметра нет.
asInteger
ISC_INT64 asInteger(unsigned key)
Возвращает значение целочисленного параметра.
asString
const char* asString(unsigned key)
Возвращает значение строкового параметра
asBoolean
FB_BOOLEAN asBoolean(unsigned key)
Возвращает значение логического параметра. Стандартные аббревиатуры(1/true/t/yes/y) рассматриваются как true, все остальные — как false.
getVersion
unsigned getVersion(StatusType* status)
Возвращает версию диспетчера конфигурации, связанную с этим интерфейсом.Различные версии диспетчера конфигурации могут сосуществовать на одном сервере, например, когдастарый движок БД используется на современном сервере. Обратите внимание — ключи (см. getKey()
)разных версий не совпадают и при неправильном использовании всегда будут возвращать 0/nullptr/false.
Интерфейс IInt128
помогает работать со 128-битными целыми числами, которые используется в качестве базового типадля числовых и десятичных чисел с точностью более 18.
toString
void toString(StatusType* status, const FB_I128* from, int scale, unsigned bufferLength, char* buffer)
Преобразует 128-битное целое значение в строку с учетом масштаба.
fromString
void fromString(StatusType* status, int scale, const char* from, FB_I128* to)
Собирает 128-битное целое значение из строки с учетом масштаба.
IMaster
— основной интерфейс, с которого начинаются все операции сAPI-интерфейсом Firebird.
getStatus
IStatus* getStatus()
Возвращает экземпляр интерфейса IStatus
.
getDispatcher
IProvider* getDispatcher()
Возвращает экземпляр интерфейсаIProvider
, реализованный YValve(основной экземпляр поставщика).
getPluginManager
IPluginManager* getPluginManager()
Возвращает экземпляр интерфейсаIPluginManager
.
getTimerControl
ITimerControl* getTimerControl()
Возвращает экземпляр интерфейсаITimerControl
.
getDtc
IDtc* getDtc()
Возвращает экземпляр интерфейса IDtc
.
getUtilInterface
IUtil* getUtilInterface()
Возвращает экземпляр интерфейса IUtil
.
getConfigManager
IConfigManager* getConfigManager()
Возвращает экземпляр интерфейсаIConfigManager
.
Интерфейс MessageMetadata
— частичный аналог XSQLDA
(не содержит данныхсообщений, присутствует только информация о формате сообщения).Используется в вызовах, связанных с выполнением операторов SQL.
getCount
unsigned getCount(StatusType* status)
Возвращает количество полей/параметров в сообщении. Во всех вызовах,содержащих индексный параметр, это значение должно быть: 0 >= index < getCount()
.
getField
const char* getField(StatusType* status, unsigned index)
Возвращает имя поля.
getRelation
const char* getRelation(StatusType* status, unsigned index)
Возвращает имя отношения (из которого выбрано данное поле).
getOwner
const char* getOwner(StatusType* status, unsigned index)
Возвращает имя владельца отношения.
getAlias
const char* getAlias(StatusType* status, unsigned index)
Возвращает псевдоним поля.
getType
unsigned getType(StatusType* status, unsigned index)
Возвращает SQL тип поля.
isNullable
FB_BOOLEAN isNullable(StatusType* status, unsigned index)
Возвращает true
, если поле может принимать значение NULL
.
getSubType
int getSubType(StatusType* status, unsigned index)
Возвращает подтип поля BLOB (0 - двоичный, 1 - текст и т. д.).
getLength
unsigned getLength(StatusType* status, unsigned index)
Возвращает максимальную длину поля.
getScale
int getScale(StatusType* status, unsigned index)
Возвращает масштаб для числового поля.
getCharSet
unsigned getCharSet(StatusType* status, unsigned index)
Возвращает набор символов для символьных полей и текстового BLOB.
getOffset
unsigned getOffset(StatusType* status, unsigned index)
Возвращает смещение данных поля в буфере сообщений (используйте его длядоступа к данным в буфере сообщений).
getNullOffset
unsigned getNullOffset(StatusType* status, unsigned index)
Возвращает смещение NULL индикатора для поля в буфере сообщений.
getBuilder
IMetadataBuilder* getBuilder(StatusType* status)
Возвращает интерфейсIMetadataBuilder
,инициализированный метаданными этого сообщения.
getMessageLength
unsigned getMessageLength(StatusType* status)
Возвращает длину буфера сообщения (используйте его для выделения памятипод буфер).
getAlignment
unsigned getAlignment(StatusType* status)
Возвращает выравнивание в байтах.
getAlignedLength
unsigned getAlignedLength(StatusType* status)
Возвращает размер структуры метаданных после выравнивания.
Интерфейс IMetadataBuilder
— позволяет описать типы данных длясуществующих сообщений или создавать метаданные с самого начала.
setType
void setType(StatusType* status, unsigned index, unsigned type)
Устанавливает SQL тип поля.
setSubType
void setSubType(StatusType* status, unsigned index, int subType)
Устанавливает подтип BLOB поля.
setLength
void setLength(StatusType* status, unsigned index, unsigned length)
Устанавливает максимальную длину символьного поля.
setCharSet
void setCharSet(StatusType* status, unsigned index, unsigned charSet)
Устанавливает набор символов для символьного поля и текстового BLOB.
setScale
void setScale(StatusType* status, unsigned index, unsigned scale)
Устанавливает масштаб для числовых полей.
truncate
void truncate(StatusType* status, unsigned count)
Обрезает сообщение чтобы оно содержало не более count полей.
moveNameToIndex
void moveNameToIndex(StatusType* status, const char* name, unsigned index)
Реорганизует поля в сообщении — перемещает поле с именем name в заданноеположение.
remove
void remove(StatusType* status, unsigned index)
Удаляет поле.
addField
unsigned addField(StatusType* status)
Добавляет поле.
getMetadata
IMessageMetadata* getMetadata(StatusType* status)
Возвращает интерфейсIMessageMetadata
, построенныйэтим построителем.
setField
void setField(StatusType* status, unsigned index, const char* field)
Устанавливает имя поля/столбца.
setRelation
void setRelation(StatusType* status, unsigned index, const char* relation)
Устанавливает имя отношения для поля.
setOwner
void setOwner(StatusType* status, unsigned index, const char* owner)
Устанавливает имя владельца.
setAlias
void setAlias(StatusType* status, unsigned index, const char* alias)
Устанавливает псевдоним поля.
Интерфейс IOffsetsCallback
setOffset
void setOffset(StatusType* status, unsigned index, unsigned offset, unsigned nullOffset)
Уведомляет, что должны быть установлены смещения для поля/параметра синдексом index
. Должен быть реализован пользователем при реализацииинтерфейса MessageMetadata
и сиспользованием IUtil::setOffsets()
.
Интерфейс IBatch
— позволяет обрабатывать несколько наборов параметров при выполнении одного оператора.
add
void add(StatusType* status, unsigned count, const void* inBuffer)
Добавляет количество сообщений из inBuffer
в пакет. Общий размер сообщений, которые можно добавить в пакет,ограничен параметром TAG_BUFFER_BYTES_SIZE
при создании пакета.
addBlob
void addBlob(StatusType* status,
unsigned length, const void* inBuffer,
ISC_QUAD* blobId,
unsigned bpbLength, const unsigned char* bpb)
Добавляет в пакет один BLOB длиной length
байт из inBuffer
, идентификатор BLOB находится по адресу blobId
.Если большой двоичный объект должен быть создан с параметрами, отличными от параметров по умолчанию, то может бытьпередан BPB (формат соответствует формату, используемому в Attachment::createBlob
).Общий размер встроенных больших двоичных объектов, которые можно добавить в пакет (включая необязательные BPB,заголовки BLOB, размер сегментов с учётом выравнивания) ограничен параметром TAG_BUFFER_BYTES_SIZE
при создании пакета(влияет на все методы, ориентированные на BLOB, кроме registerBlob()
).
appendBlobData
void appendBlobData(StatusType* status, unsigned length, const void* inBuffer)
Расширяет последний добавленный BLOB: добавляет к нему байты длинной length
, взятые по адресу inBuffer
.
addBlobStream
addBlobStream(StatusType* status, unsigned length, const void* inBuffer)
Добавляет данные BLOB (это может быть несколько объектов или часть одного BLOB) в пакет. Заголовок каждого BLOB в потокевыравнивается по границе getBlobAlignment()
и содержит 3 поля: первое - 8-байтовый идентификатор BLOB (в формате ISC_QUAD
),второе - 4-байтная длина BLOB, третье - 4-байтная длина BPB. Заголовок большого двоичного объекта не должен пересекатьграницы буфера в этом вызове функции. Данные BPB помещаются сразу после заголовка, затем идут данные BLOB-объектов.Длина большого двоичного объекта включает BPB (если он присутствует). Все данные могут быть распределены междунесколькими вызовами addBlobStream()
. Данные BLOB-объекта, в свою очередь, могут быть структурированы в случаесегментированного BLOB-объекта, см. главу "Пакетное изменение данных".
registerBlob
void registerBlob(StatusType* status, const ISC_QUAD* existingBlob, ISC_QUAD* blobId)
Позволяет использовать в пакете BLOB, добавленные с помощью стандартного интерфейса IBlob
. Эта функция содержит 2параметра ISC_QUAD*
, важно их не смешивать – второй параметр (existingBlob
) является указателем на идентификатор BLOB,уже добавленный вне области действия пакета, третий (blobId
) указывает на идентификатор BLOB, который будет помещен в сообщение в этом пакете'.
execute
IBatchCompletionState* execute(StatusType* status, ITransaction* transaction)
Выполняет пакет с параметрами, переданными ему в сообщениях. Если параметр MULTIERROR
не установлен в блоке параметровпри создании пакета, выполнение пакета будет остановлено после первой ошибки, в режиме MULTIERROR
может произойтинеограниченное количество ошибок, после ошибки выполнение продолжается со следующего сообщения. Эта функция возвращаетинтерфейс IBatchCompletionState
, который содержит всю запрошеннуюинформацию о результатах выполнения пакета.
cancel
void cancel(StatusType* status)
Очищает буферы сообщений и BLOB, возвращая пакет в состояние, в котором он находился сразу после создания.Обратите внимание: интерфейс IBatch
с подсчетом ссылок не содержит какой-либо специальной функции для его закрытия,для этого используйте release()
.
getBlobAlignment
unsigned getBlobAlignment(StatusType* status)
Возвращает необходимое выравнивание для данных, помещаемых в буфер функцией addBlobStream()
.
getMetadata
IMessageMetadata* getMetadata(StatusType* status)
Возвращает формат метаданных, используемых в пакетных сообщениях.
setDefaultBpb
void setDefaultBpb(StatusType* status, unsigned parLength, const unsigned char* par)
Задает BPB, который будет использоваться для всех BLOB-объектов, в которых отсутствует BPB не по умолчанию.Должен вызываться перед добавлением любого сообщения или BLOB в пакет.
getInfo
void getInfo(StatusType* status,
unsigned itemsLength, const unsigned char* items,
unsigned bufferLength, unsigned char* buffer)
Запрашивает информацию о пакете.
Тег для блока параметров:
VERSION1
Теги для скоплений в блоке параметров:
TAG_MULTIERROR
(0/1) – может иметь более одного сообщения с ошибками;
TAG_RECORD_COUNTS
(0/1) - учет измененных записей по сообщениям;
TAG_BUFFER_BYTES_SIZE
(integer) - максимально возможный размер буфера на сервере (по умолчанию 16Мб, максимум 256Мб);
TAG_BLOB_POLICY
- политика, используемая для хранения BLOB-объектов;
TAG_DETAILED_ERRORS
(integer) - сколько векторов с подробной информацией об ошибках хранится в состоянии завершения (по умолчанию 64, максимум 256).
Политики, используемые для хранения BLOB:
BLOB_NONE
– нельзя использовать встроенные BLOB-объекты (registerBlob()
работает в любом случае);
BLOB_ID_ENGINE
- BLOB добавляются один за другим, BLOB-идентификаторы генерируются движком firebird;
BLOB_ID_USER
- BLOB добавляются один за другим, BLOB-идентификаторы генерируются пользователем;
BLOB_STREAM
- BLOB-объекты добавляются в поток.
Элементы, допустимые в вызове getInfo()
:
INF_BUFFER_BYTES_SIZE
– фактический максимально возможный размер буфера (устанавливается через TAG_BUFFER_BYTES_SIZE
);
INF_DATA_BYTES_SIZE
- размер уже добавленных сообщений;
INF_BLOBS_BYTES_SIZE
- размер уже добавленных BLOB;
INF_BLOB_ALIGNMENT
- требуемое выравнивание для данных BLOB (дублирует getBlobAlignment
).
Интерфейс IPluginConfig
— передается фабрике плагинов при созданииэкземпляра плагина (с конкретной конфигурацией).
getConfigFileName
const char* getConfigFileName()
Возвращает рекомендованное имя файла, в котором ожидается сохранениеконфигурации для плагина.
getDefaultConfig
IConfig* getDefaultConfig(StatusType* status)
Конфигурация плагина, загруженная по стандартным правилам.
getFirebirdConf
IFirebirdConf* getFirebirdConf(StatusType* status)
Возвращает главную конфигурацию Firebird с учётом настроек для базыданных, с которой будет работать новый экземпляр плагина.
setReleaseDelay
void setReleaseDelay(StatusType* status, ISC_UINT64 microSeconds)
Используемые плагином для настройки рекомендуемой задержки, в течениекоторой модуль плагина не будет выгружен менеджером плагинов послеосвобождения последнего экземпляра плагина из этого модуля.
Интерфейс IPluginFactory
— должен быть реализован автором плагина принаписании плагина.
createPlugin
IPluginBase* createPlugin(StatusType* status, IPluginConfig* factoryParameter)
Создает новый экземпляр плагина с переданной рекомендуемойконфигурацией.
Интерфейс IPluginManager
— API диспетчера плагинов.
registerPluginFactory
void registerPluginFactory(unsigned pluginType,
const char* defaultName,
IPluginFactory* factory)
Регистрирует именованную фабрику плагинов данного типа.
registerModule
void registerModule(IPluginModule* cleanup)
Регистрирует модуль плагина.
unregisterModule
void unregisterModule(IPluginModule* cleanup)
Разрегистрирует модуль плагина.
getPlugins
IPluginSet* getPlugins(StatusType* status,
unsigned pluginType,
const char* namesList,
IFirebirdConf* firebirdConf)
Возвращает интерфейс IPluginSet, предоставляющий доступ к спискуплагинов данного типа. Имена включенных плагинов берутся из namesList,если отсутствует (NULL), то из настроек конфигурации для данного типаpluginType
. Если указан параметр firebirdConf
, то он используется длявсех целей конфигурации (включая получение списка плагинов и переход кметоду PluginFactory::createPlugin()
), если отсутствует (NULL), тоиспользуется настройка по умолчанию (из firebird.conf
).
getConfig
IConfig* getConfig(StatusType* status, const char* filename)
Возвращает интерфейс IConfig для заданного имени файла конфигурации.Может использоваться плагинами для доступа к файлам конфигурации состандартным форматом, но не с именем по умолчанию.
releasePlugin
void releasePlugin(IPluginBase* plugin)
Освобождение данного плагина. Должен использоваться для плагинов вместопростой release()
из-за необходимости выполнять дополнительныедействия с владельцем плагина до фактического освобождения.
Константы, определенные интерфейсом IPluginManager
(типы плагинов):
TYPE_PROVIDER
TYPE_AUTH_SERVER
TYPE_AUTH_CLIENT
TYPE_AUTH_USER_MANAGEMENT
TYPE_EXTERNAL_ENGINE
TYPE_TRACE
TYPE_WIRE_CRYPT
TYPE_DB_CRYPT
TYPE_KEY_HOLDER
TYPE_REPLICATOR
Интерфейс IPluginModule
— представляет модуль плагина (динамическаябиблиотека). Должен быть реализован автором плагина в каждом модулеплагина (по одному экземпляру на модуль).
doClean
void doClean()
вызывается диспетчером плагинов перед нормальной выгрузкой модуляплагина.
Интерфейс IPluginSet — представляет собой набор плагинов данного типа.Обычно используется внутренним кодом Firebird, но рекомендуется дляиспользования в плагинах, загружающих другие плагины.
getName
const char* getName()
возвращает имя текущего плагина в наборе.
getModuleName
const char* getModuleName()
возвращает имя модуля текущего плагина в наборе (в простом случаесовпадает с именем плагина).
getPlugin
IPluginBase* getPlugin(StatusType* status)
возвращает экземпляр текущего плагина, возвращенный интерфейс долженбыть преобразован в основной интерфейс плагина запрошенного типа вметоде IPluginManager::getPlugins()
. Возвращает NULL
, если в наборебольше нет плагинов. Счётчик ссылок плагина, возвращаемого этойфункцией, увеличивается при возврате — не забудьте использовать методreleasePlugin()
интерфейсаIPluginManager для освобожденияплагинов, возвращаемых этим методом.
next
void next(StatusType* status)
устанавливает переключатель для перехода к следующему плагину из списка.
set
void set(StatusType* status, const char* list)
сбрасывает интерфейс: заставляет его работать со списком плагинов,предоставляемых параметром списка. Тип плагинов остается неизменным.
Интерфейс IPluginModule
— основной интерфейс для начала доступа к базеданных/сервису.
attachDatabase
IAttachment* attachDatabase(StatusType* status,
const char* fileName,
unsigned dpbLength,
const unsigned char* dpb)
Создаёт соединение с существующей базой данных. Заменяет isc_attach_database()
.
createDatabase
IAttachment* createDatabase(StatusType* status,
const char* fileName,
unsigned dpbLength,
const unsigned char* dpb)
Создаёт новую базу данных и возращает интерфейс соединения с ней. Заменяет isc_create_database()
.
attachServiceManager
IService* attachServiceManager(StatusType* status,
const char* service,
unsigned spbLength,
const unsigned char* spb)
Заменяет isc_service_attach()
.
shutdown
void shutdown(StatusType* status, unsigned timeout, const int reason)
Заменяет fb_shutdown()
.
setDbCryptCallback
void setDbCryptCallback(IStatus* status, ICryptKeyCallback* cryptCallback)
Устанавливает интерфейс обратного вызова шифрования базы данных, которыйбудет использоваться для последующих подключений к базе данных исервисам. См. … для подробностей.
Интерфейс IResultSet
— заменяет (с расширенной функциональностью)некоторые функции isc_stmt_handle
. Этот интерфейс возвращается вызовомopenCursor()
из IAttachment
илиIStatement
. Все вызовы fetch…
,кроме fetchNext()
, работают только для двунаправленного (открытого сфлагом CURSOR_TYPE_SCROLLABLE
) курсора.
fetchNext
int fetchNext(StatusType* status, void* message)
выбирает следующую запись, заменяет isc_dsql_fetch()
. Этот метод (идругие методы выборки) возвращает код завершенияStatus::RESULT_NO_DATA
при достижении EOF, и статусStatus::RESULT_OK
при успешном завершении.
fetchPrior
int fetchPrior(StatusType* status, void* message)
выбирает предыдущую запись.
fetchFirst
int fetchFirst(StatusType* status, void* message)
выбирает первую запись.
fetchLast
int fetchLast(StatusType* status, void* message)
выбирает последнюю запись.
fetchAbsolute
int fetchAbsolute(StatusType* status, int position, void* message)
получает запись по абсолютной позиции в наборе результатов.
fetchRelative
int fetchRelative(StatusType* status, int offset, void* message)
извлекает запись по положению относительно текущей.
isEof
FB_BOOLEAN isEof(StatusType* status)
проверка EOF.
isBof
FB_BOOLEAN isBof(StatusType* status)
проверка BOF.
getMetadata
IMessageMetadata* getMetadata(StatusType* status)
возвращает метаданные для сообщений в наборе результатов, особеннополезно, когда набор результатов открывается вызовомIAttachment::openCursor()
с параметром формата вывода метаданныхравным NULL
(это единственный способ получить формат сообщения в данномслучае).
close
void close(IStatus* status)
закрывает набор результатов, освобождает интерфейс в случае успеха.
Интерфейс IService
— заменяет isc_svc_handle
.
detach
void detach(StatusType* status)
Закрывает подключение к менеджеру сервисов, при успехе освобождаетинтерфейс. Заменяет isc_service_detach()
.
query
void query(StatusType* status,
unsigned sendLength,
const unsigned char* sendItems,
unsigned receiveLength,
const unsigned char* receiveItems,
unsigned bufferLength,
unsigned char* buffer)
Отправляет и запрашивает информацию в/из службы, при этом receiveItemsмогут использоваться как для запущенных служб, так и для полученияразличной информации по всему серверу. Заменяет isc_service_query()
.
start
void start(StatusType* status,
unsigned spbLength,
const unsigned char* spb)
Запускает утилиту в диспетчере служб. Заменяет isc_service_start()
.
Интерфейс IStatement
— заменяет (частично) isc_stmt_handle
.
getInfo
void getInfo(StatusType* status,
unsigned itemsLength,
const unsigned char* items,
unsigned bufferLength,
unsigned char* buffer)
Заменяет isc_dsql_sql_info()
.
getType
unsigned getType(StatusType* status)
Тип оператора, в настоящее время можно найти только в источникахfirebird в dsql/dsql.h
.
getPlan
const char* getPlan(StatusType* status, FB_BOOLEAN detailed)
Возвращает план выполнения оператора.
getAffectedRecords
ISC_UINT64 getAffectedRecords(StatusType* status)
Возвращает количество записей, которые затронуты оператором.
getInputMetadata
IMessageMetadata* getInputMetadata(StatusType* status)
Возвращает метаданные параметров.
getOutputMetadata
IMessageMetadata* getOutputMetadata(StatusType* status)
Возвращает метаданные значений выходных данных.
execute
ITransaction* execute(StatusType* status,
ITransaction* transaction,
IMessageMetadata* inMetadata,
void* inBuffer,
IMessageMetadata* outMetadata,
void* outBuffer)
Выполняет любую инструкцию SQL, за исключением тех, что возвращаютнескольких строк данных. Частичный аналог isc_dsql_execute2()
— вход ивыход XSLQDA
заменены на входные и выходные сообщения с соответствующимибуферами.
openCursor
IResultSet* openCursor(StatusType* status,
ITransaction* transaction,
IMessageMetadata* inMetadata,
void* inBuffer,
IMessageMetadata* outMetadata,
unsigned flags)
Выполняет оператор SQL, потенциально возвращающий несколько строкданных. Возвращает интерфейс IResultSet
, который должен использоватьсядля извлечения этих данных. Формат выходных данных определяетсяпараметром outMetadata
, если указано NULL
, то будет использоватьсяформат по умолчанию.
setCursorName
void setCursorName(StatusType* status, const char* name)
Заменяет isc_dsql_set_cursor_name()
.
free
void free(StatusType* status)
Уничтожает оператор, освобождает интерфейс в случае успеха.
getFlags
unsigned getFlags(StatusType* status)
Возвращает флаги, описывающие, как должен выполняться этот оператор,упрощенная замена метода getType()
.
getTimeout
unsigned getTimeout(StatusType* status)
Возвращает таймаут выполнения SQL запроса в миллисекундах.
setTimeout
unsigned setTimeout(StatusType* status)
Устанавливает таймаут выполнения SQL запроса в миллисекундах.
createBatch
IBatch* createBatch(StatusType* status,
IMessageMetadata* inMetadata,
unsigned parLength,
const unsigned char* par)
Создает интерфейс IBatch
для оператора SQL с входными параметрами, что позволяет выполнять этот операторс несколькими наборами параметров. Формат входных данных определяется параметром inMetadata
, оставив его NULL
,пакет использует формат по умолчанию из этого интерфейса. В функцию createBatch()
можно передать блок параметров,что позволит настроить поведение пакета.
Константы, определенные интерфейсом IStatement
Флаги IAttachment::prepare()
:
PREPARE_PREFETCH_NONE
— константа, чтобы пропускать флаги, значение0.
Следующие флаги могут быть объединены с помощью OR
для полученияжелаемого эффекта:
PREPARE_PREFETCH_TYPE
PREPARE_PREFETCH_INPUT_PARAMETERS
PREPARE_PREFETCH_OUTPUT_PARAMETERS
PREPARE_PREFETCH_LEGACY_PLAN
PREPARE_PREFETCH_DETAILED_PLAN
PREPARE_PREFETCH_AFFECTED_RECORDS
PREPARE_PREFETCH_FLAGS
(флаги возвращаемые методом getFlags()
)
Для наиболее часто используемых комбинаций флагов можно использоватьконстанты:
PREPARE_PREFETCH_METADATA
PREPARE_PREFETCH_ALL
Значения возвращаемые методом getFlags()
:
FLAG_HAS_CURSOR
— используйте openCursor()
для выполнения этогооператора, а не execute()
FLAG_REPEAT_EXECUTE
— когда подготовленный оператор можетвыполняться много раз с разными параметрами.
Флаги передаваемые в openCursor()
:
CURSOR_TYPE_SCROLLABLE
— открывается двунаправленный курсор.
Интерфейс IStatus
— заменяет ISC_STATUS_ARRAY
. Функциональностьрасширена — статус имеет отдельный доступ к векторам ошибок ипредупреждений, может содержать векторы неограниченной длины,самостоятельно хранит строки, используемые в векторах, не имеетнеобходимости в кольцевом буфере строк. В C++ IStatus
всегдаиспользуется в оболочке состояния, C++ API предоставляет две разныеоболочки, имеющие различное поведение, когда ошибка возвращается извызова API. Интерфейс сведен к минимуму (методы, такие какпреобразование его в текст, перемещены в интерфейсIUtil
), чтобы упростить его реализациюпользователями при необходимости.
init
void init()
очищает интерфейс, устанавливая его в исходное состояние.
getState
unsigned getState()
возвращает текущее состояние интерфейса, возвращаемые флаги могут бытьобъединены с помощью OR
.
setErrors2
void setErrors2(unsigned length, const intptr_t* value)
устанавливает содержимое вектора ошибок с длиной, явно указанной ввызове.
setWarnings2
void setWarnings2(unsigned length, const intptr_t* value)
устанавливает содержимое вектора предупреждений с длиной, явно указаннойв вызове.
setErrors
void setErrors(const intptr_t* value)
устанавливает содержимое вектора ошибок, длина определяется контекстомзначения.
setWarnings
void setWarnings(const intptr_t* value)
устанавливает содержимое вектора предупреждений, длина определяетсяконтекстом значения.
getErrors
const intptr_t* getErrors()
возвращает вектор ошибок.
getWarnings
const intptr_t* getWarnings()
возвращает вектор предупреждений.
clone
IStatus* clone()
создаёт клон текущего интерфейса.
Константы определённые в IStatus
Флаги, возвращаемые методом getState()
:
STATE_WARNINGS
STATE_ERRORS
Коды завершения:
RESULT_ERROR
RESULT_OK
RESULT_NO_DATA
RESULT_SEGMENT
IBatchCompletionState
— одноразовый интерфейс, всегда возвращаемый методом execute()
интерфейса IBatch
.Он содержит более или менее (в зависимости от параметров, переданных при создании IBatch
) подробную информациюо результатах выполнения пакета.
getSize
unsigned getSize(StatusType* status)
Возвращает общее количество обработанных сообщений.
getState
int getState(StatusType* status, unsigned pos)
Возвращает результат выполнения сообщения с номером pos
. При любой ошибке с сообщением это константа EXECUTE_FAILED
,возвращаемое значение в случае успеха зависит от наличия параметра RECORD_COUNTS
при создании пакета.Когда она присутствует и имеет ненулевое значение, возвращается количество записей, вставленных, обновленных или удаленныхво время обработки конкретного сообщения, иначе возвращается константа SUCCESS_NO_INFO
.
findError
unsigned findError(StatusType* status, unsigned pos)
Находит следующее (начинающееся с pos
) сообщение, обработка которого вызвала ошибку.При отсутствии такого сообщения возвращается константа NO_MORE_ERRORS
. Количество векторов состояния,возвращаемых в этом интерфейсе, ограничено значением параметра DETAILED_ERRORS
при создании пакета.
getStatus
void getStatus(StatusType* status, IStatus* to, unsigned pos)
Возвращает подробную информацию (полный вектор состояния) об ошибке, которая произошла при обработке сообщения pos
.Чтобы различать ошибки (в IBatch::execute()
или в IBatchCompletionState::getStatus()
), этот статус возвращаетсяв отдельном параметре to
, в отличие от ошибок в этом вызове, которые помещаются в параметр status
.
Специальные значения, возвращаемые getState()
:
EXECUTE_FAILED
— при обработке этого сообщения произошла ошибка;
SUCCESS_NO_INFO
— информация об обновлении записи не была собрана.
Специальное значение, возвращаемое findError()
:
NO_MORE_ERRORS
– больше нет сообщений с ошибками в этом пакете.
Интерфейс ITimer
— пользовательский таймер. Интерфейс обратного вызова,который должен быть реализован пользователем для использования таймераFirebird.
handler
void handler()
метод вызывается, когда таймер звонит (или когда сервер выключается).
Интерфейс ITimerControl
— очень простая и не слишком точная реализациятаймера. Прибыл сюда, потому что существующие таймеры очень зависимы отОС и могут использоваться в программах, которые требуют переносимости ине требуют действительно высокоточного таймера. В частности, выполнениеданного таймера может быть отложено, если другой не был завершен в тотмомент, когда данный таймер должен сигнализировать.
start
void start(StatusType* status, ITimer* timer, ISC_UINT64 microSeconds)
запуск ITimer
после сигнала (вмикросекундах, 10-6 секунд). Таймер будет разбужен только один разпосле этого вызова.
stop
void stop(StatusType* status, ITimer* timer)
остановка ITimer
. Не стоит останавливатьне запущенный таймер, что позволит избежать проблем с гонками междуstop()
и сигналом таймером.
Интерфейс ITransaction
— заменяет isc_tr_handle
.
getInfo
void getInfo(StatusType* status,
unsigned itemsLength,
const unsigned char* items,
unsigned bufferLength,
unsigned char* buffer)
заменяет isc_transaction_info()
.
prepare
void prepare(StatusType* status,
unsigned msgLength,
const unsigned char* message)
заменяет isc_prepare_transaction2()
.
commit
void commit(StatusType* status)
заменяет isc_commit_transaction()
.
commitRetaining
void commitRetaining(StatusType* status)
заменяет isc_commit_retaining()
.
rollback
void rollback(StatusType* status)
заменяет isc_rollback_transaction()
.
rollbackRetaining
void rollbackRetaining(StatusType* status)
заменяет isc_rollback_retaining()
.
disconnect
void disconnect(StatusType* status)
заменяет fb_disconnect_transaction()
.
join
ITransaction* join(StatusType* status, ITransaction* transaction)
соединяет текущую транзакцию и транзакцию, переданную как параметр вединую распределённую транзакцию (с использованием Dtc). При успешномвыполнении текущая транзакция и транзакция переданная в качествепараметра освобождаются и больше не должны использоваться.
validate
ITransaction* validate(StatusType* status, IAttachment* attachment)
этот метод используется для поддержки координатора распределенныхтранзакций.
enterDtc
ITransaction* enterDtc(StatusType* status)
этот метод используется для поддержки координатора распределенныхтранзакций.
Интерфейс IVersionCallback
— обратный вызов для IUtil::getFbVersion()
.
callback
void callback(StatusType* status, const char* text)
Вызывается движком firebird для каждой строки в многострочной версииотчета. Позволяет печатать эти строки одна за другой, помещать их в полесообщения в любом графическом интерфейсе и т. д.
Интерфейс IUtil
— различные вспомогательные методы, требуемые здесь илитам.
getFbVersion
void getFbVersion(StatusType* status,
IAttachment* att,
IVersionCallback* callback)
Строит длинный и красивый отчет о версии для firebird. Это можноувидеть в ISQL при вызове с ключом -Z
.
loadBlob
void loadBlob(StatusType* status,
ISC_QUAD* blobId,
IAttachment* att,
ITransaction* tra,
const char* file,
FB_BOOLEAN txt)
Загрузка BLOB из файла.
dumpBlob
void dumpBlob(StatusType* status,
ISC_QUAD* blobId,
IAttachment* att,
ITransaction* tra,
const char* file,
FB_BOOLEAN txt)
Сохраняет BLOB в файл.
getPerfCounters
void getPerfCounters(StatusType* status,
IAttachment* att,
const char* countersSet,
ISC_INT64* counters)
Получает статистику для данного подключения.
executeCreateDatabase
IAttachment* executeCreateDatabase(StatusType* status,
unsigned stmtLength,
const char* creatDBstatement,
unsigned dialect,
FB_BOOLEAN* stmtIsCreateDb)
Выполняет инструкцию CREATE DATABASE …
— трюк ISC с NULLдескриптором оператора не работает с интерфейсами.
decodeDate
void decodeDate(ISC_DATE date,
unsigned* year,
unsigned* month,
unsigned* day)
Заменяет isc_decode_sql_date()
.
decodeTime
void decodeTime(ISC_TIME time,
unsigned* hours,
unsigned* minutes,
unsigned* seconds,
unsigned* fractions)
Заменяет isc_decode_sql_time()
.
encodeDate
ISC_DATE encodeDate(unsigned year, unsigned month, unsigned day)
Заменяет isc_encode_sql_date()
.
encodeTime
ISC_TIME encodeTime(unsigned hours,
unsigned minutes,
unsigned seconds,
unsigned fractions)
Заменяет isc_encode_sql_time()
.
formatStatus
unsigned formatStatus(char* buffer, unsigned bufferSize, IStatus* status)
Заменяет fb_interpret()
. Размер буфера, переданного в этот метод, недолжен быть меньше 50 байт.
getClientVersion
unsigned getClientVersion()
Возвращает целое число, содержащее основную версию в байте 0 и младшуюверсию в байте 1.
getXpbBuilder
IXpbBuilder* getXpbBuilder(StatusType* status,
unsigned kind,
const unsigned char* buf,
unsigned len)
Возвращает интерфейс IXpbBuilder
.Допустимые kind
перечислены в IXpbBuilder
.
setOffsets
unsigned setOffsets(StatusType* status,
IMessageMetadata* metadata,
IOffsetsCallback* callback)
Устанавливает допустимые смещения вIMessageMetadata
. Выполняетвызовы для обратного вызова вIOffsetsCallback
для каждогополя/параметра.
getDecFloat16
IDecFloat16* getDecFloat16(StatusType* status)
Возвращает интерфейс IDecFloat16
.
getDecFloat34
IDecFloat34* getDecFloat34(StatusType* status)
Возвращает интерфейс IDecFloat34
.
decodeTimeTz
void decodeTimeTz(StatusType* status,
const ISC_TIME_TZ* timeTz,
unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions,
unsigned timeZoneBufferLength, char* timeZoneBuffer)
Декодирует время с часовым поясом.
decodeTimeStampTz
void decodeTimeStampTz(StatusType* status,
const ISC_TIMESTAMP_TZ* timeStampTz,
unsigned* year, unsigned* month, unsigned* day,
unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions,
unsigned timeZoneBufferLength, char* timeZoneBuffer)
Декодирует временную метку (дату-время) с часовым поясом.
encodeTimeTz
void encodeTimeTz(StatusType* status,
ISC_TIME_TZ* timeTz,
unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions,
const char* timeZone)
Кодирует время с часовым поясом.
encodeTimeStampTz
void encodeTimeStampTz(StatusType* status,
ISC_TIMESTAMP_TZ* timeStampTz,
unsigned year, unsigned month, unsigned day,
unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions,
const char* timeZone)
Кодирует временную метку (дату-время) с часовым поясом.
getInt128
IInt128* getInt128(StatusType* status)
Возвращает интерфейс IInt128
.
decodeTimeTzEx
void decodeTimeTzEx(StatusType* status,
const ISC_TIME_TZ_EX* timeTz,
unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions,
unsigned timeZoneBufferLength, char* timeZoneBuffer)
Декодирует время в расширенном формате с часовым поясом.
decodeTimeStampTzEx
void decodeTimeStampTzEx(StatusType* status,
const ISC_TIMESTAMP_TZ_EX* timeStampTz,
unsigned* year, unsigned* month, unsigned* day, unsigned* hours,
unsigned* minutes, unsigned* seconds, unsigned* fractions,
unsigned timeZoneBufferLength, char* timeZoneBuffer)
Декодирует временную метку (дату-время) в расширенном формате с часовым поясом.
Интерфейс IXpbBuilder
clear
void clear(StatusType* status)
Сбрасывает построитель в пустое состояние.
removeCurrent
void removeCurrent(StatusType* status)
Удаляет текущий clumplet.
insertInt
void insertInt(StatusType* status, unsigned char tag, int value)
Вставляет clumplet со значением, представляющим целое число в сетевомформате.
insertBigInt
void insertBigInt(StatusType* status, unsigned char tag, ISC_INT64 value)
Вставляет clumplet со значением, представляющим 64-битное целое число всетевом формате.
insertBytes
void insertBytes(StatusType* status, unsigned char tag, const void* bytes, unsigned length)
Вставляет clumplet со значением, содержащим переданные байты.
insertTag
void insertTag(StatusType* status, unsigned char tag)
Вставляет clumplet без значения.
isEof
FB_BOOLEAN isEof(StatusType* status)
Проверяет, нет ли текущего clumplet.
moveNext
void moveNext(StatusType* status)
Переходит к следующему clumplet.
rewind
void rewind(StatusType* status)
Переходит к первому clumplet.
findFirst
FB_BOOLEAN findFirst(StatusType* status, unsigned char tag)
Находит первый clumplet с данным тегом.
findNext
FB_BOOLEAN findNext(StatusType* status)
Находит следующий clumplet с заданным тегом.
getTag
unsigned char getTag(StatusType* status)
Возвращает тег для текущего clumplet.
getLength
unsigned getLength(StatusType* status)
Возвращает длину текущего значения clumplet.
getInt
int getInt(StatusType* status)
Возвращает значение текущего clumplet как целое.
getBigInt
SC_INT64 getBigInt(StatusType* status)
Возвращает значение текущего clumplet как 64-битное целое число.
getString
const char* getString(StatusType* status)
Возвращает значение текущего clumplet как указатель на нуль-терминальнуюстроку (указатель действителен до следующего вызова этого метода).
getBytes
const unsigned char* getBytes(StatusType* status)
Возвращает значение текущего clumplet как указатель на unsigned char
.
getBufferLength
unsigned getBufferLength(StatusType* status)
Возвращает длину блока параметров.
getBuffer
const unsigned char* getBuffer(StatusType* status)
Возвращает указатель на блок параметров.
Константы, определенные интерфейсом IXpbBuilder
Допустимые типы построителей:
BATCH
(IBatch parameters block)
BPB
(BLOB parameters block)
DPB
(database attachment parameters block)
SPB_ATTACH
(service attachment parameters block)
SPB_START
(start service parameters)
SPB_SEND
(send items in IService::query()
)
SPB_RECEIVE
(receive items in IService::query()
)
SPB_RESPONSE
(response from IService::query()
)
TPB
(transaction parameters block)
Алгоритмы, выполняющие шифрование данных для разных целей, хорошоизвестны на протяжении многих лет. Единственной "маленькой" типичнойпроблемой остается то, где можно получить секретный ключ, который будетиспользоваться этим алгоритмом. К счастью для шифрования сетевоготрафика есть одно хорошее решение — уникальный ключ шифрования долженбыть сгенерирован плагином аутентификации. По крайней мере, по умолчаниюплагин SRP может создать такой ключ. Этот ключ устойчив к атакам, в томчисле с помощью "человека в середине" (man-in-the-middle). Поэтому дляплагина шифрования сетевого трафика был выбран следующий способпредоставления ключей: получать его от плагина проверки подлинности(аутентификации). (В случае, если используемый плагин аутентификации неможет предоставить ключ, псевдоплагин может быть добавлен в спискиAuthClient и AuthServer для создания ключей, что-то вроде двухасимметричных пар приватного и публичного.)
Интерфейс ICryptKey
используется для хранения ключа, предоставленногоплагином аутентификации, и передает его в плагин шифрования сетевоготрафика. Этот интерфейс следует использовать следующим образом: когдаплагин аутентификации сервера или клиента готов предоставить ключ, то онзапрашивает IServerBlock
илиIClientBlock
для создания новогоинтерфейса ICryptKey
и хранит в нем ключ. Подходящий дляIWireCryptPlugin
тип ключабудет выбран Firebird и передан этому интерфейсу.
setSymmetric
void setSymmetric(StatusType* status,
const char* type,
unsigned keyLength,
const void* key)
сохраняет симметричный ключ заданного типа.
setAsymmetric
void setAsymmetric(StatusType* status,
const char* type,
unsigned encryptKeyLength,
const void* encryptKey,
unsigned decryptKeyLength,
const void* decryptKey)
сохраняет пару асимметричных ключей заданного типа.
getEncryptKey
const void* getEncryptKey(unsigned* length)
возвращает ключ для шифрования.
getDecryptKey
const void* getDecryptKey(unsigned* length))
возвращает ключ для дешифрирования (в случае симметричного ключаполучается тот же результат, что и getEncryptKey()
).
Интерфейс IWireCryptPlugin
является основным интерфейсом плагинасетевого шифрования. Как и любой другой такой интерфейс, он должен бытьреализован автором плагина.
getKnownTypes
const char* getKnownTypes(StatusType* status)
возвращает список допустимых ключей, разделённыхпробелами/табуляциями/запятыми.
setKey
void setKey(StatusType* status, ICryptKey* key)
плагин должен использовать ключ, переданный ему этим вызовом.
encrypt
void encrypt(StatusType* status,
unsigned length,
const void* from,
void* to)
шифрует пакет, который должен быть отправлен по сети.
decrypt
void decrypt(StatusType* status,
unsigned length,
const void* from,
void* to)
расшифровывает пакет, полученный из сети.
Плагин аутентификации содержит две требуемые части — клиентскую исерверную, а также может содержать связанную с ним третью часть —менеджер пользователей. В процессе аутентификации клиент Firebirdвызывает клиентский плагин и отправляет сгенерированные им данные насервер, затем сервер вызывает серверный плагин и отправляетсгенерированные им данные клиенту. Этот процесс повторяется до тех пор,пока оба плагина возвращают код AUTH_MORE_DATA
. AUTH_SUCCESS
,возвращенный на стороне сервера, означает успешную аутентификацию,AUTH_FAILED
с любой стороны — немедленное прерывание итеративногопроцесса и отказ, сообщаемый клиенту, AUTH_CONTINUE
означает, чтодолжен быть проверен следующий плагин из списка настроенных плагиновпроверки подлинности.
Нет выделенных примеров плагинов для аутентификации, но в исходных кодахfirebird в каталоге src/auth
можно найти плагин AuthDbg, с помощьюкоторого можно учиться на тривиальном примере (без сложных вычисленийкак, например, в Srp, и без вызовов сумасшедших функций WinAPI, таких,как в AuthSspi), как клиентская и серверная сторона выполняютаутентификацию (рукопожатие).
Интерфейс IWriter
— записывает блок параметров аутентификации.
reset
void reset()
очищает целевой блок.
add
void add(StatusType* status, const char* name)
добавляет имя логина.
setType
void setType(StatusType* status, const char* value)
устанавливает тип добавленного логина (пользователь, роль, группа ит.д.).
setDb
void setDb(StatusType* status, const char* value)
устанавливает базу данных безопасности, в которой была выполненааутентификация.
Интерфейс IBlob
заменяет isc_blob_handle
.
getInfo
void getInfo(StatusType* status,
unsigned itemsLength,
const unsigned char* items,
unsigned bufferLength,
unsigned char* buffer)
заменяет isc_blob_info()
.
getSegment
int getSegment(StatusType* status,
unsigned bufferLength,
void* buffer,
unsigned* segmentLength)
заменяет isc_get_segment()
. В отличие от него никогда не возвращаютсяошибки isc_segstr_eof
и isc_segment
(которые на самом деле неявляются ошибками), вместо этого возвращаются коды завершенияIStatus::RESULT_NO_DATA
и IStatus::RESULT_SEGMENT
, обычно возвращаетIStatus::RESULT_OK
.
putSegment
void putSegment(StatusType* status,
unsigned length,
const void* buffer)
заменяет isc_put_segment()
.
cancel
void cancel(StatusType* status)
заменяет isc_cancel_blob()
. В случае успеха освобождает интерфейс.
close
void close(StatusType* status)
заменяет isc_close_blob()
. В случае успеха освобождает интерфейс.
seek
int seek(StatusType* status,
int mode,
int offset)
заменяет isc_seek_blob()
.
Интерфейс IServerBlock
используется серверной частью модуляаутентификации для обмена данными с клиентом.
getLogin
const char* getLogin()
возвращает имя пользователя, переданное от клиента.
getData
const unsigned char* getData(unsigned* length)
возвращает данные аутентификации, переданные от клиента.
putData
void putData(StatusType* status, unsigned length, const void* data)
передаёт данные аутентификации клиенту.
newKey
ICryptKey* newKey(StatusType* status)
создаёт новый ключ шифрования и добавляет его в список доступных дляплагинов шифрования сетевого трафика.
Интерфейс IServer
является основным интерфейсом серверной части плагинааутентификации.
authenticate
int authenticate(StatusType* status,
IServerBlock* sBlock,
IWriter* writerInterface)
Выполняет один этап аутентификации. Обмен данными с клиентомосуществляется с использованием интерфейса sBlock
. Когда создаетсянекоторый элемент аутентификации, его следует добавить в блокаутентификации с помощью writerInterface
. Возможные значения возвратаопределяются в интерфейсе IAuth
.
setDbCryptCallback
void setDbCryptCallback(StatusType* status, ICryptKeyCallback* cryptCallback)
Устанавливает интерфейс обратного вызова шифрования базы данных, которыйбудет использоваться для последующих подключений к базе данных исервисам.
Интерфейс IClientBlock
используется клиентской стороной модуляаутентификации для обмена данными с сервером.
getLogin
const char* getLogin()
Возвращает имя пользователя, если оно присутствует в DPB.
getPassword
const char* getPassword()
Возвращает пароль, если он присутствует в DPB.
getData
const unsigned char* getData(unsigned* length)
Возвращает данные аутентификации, переданные с сервера.
putData
void putData(StatusType* status, unsigned length, const void* data)
Передаёт данные аутентификации на сервер.
newKey
ICryptKey* newKey(StatusType* status)
Создаёт новый ключ шифрования и добавляет его в список доступных дляплагинов шифрования сетевого трафика
getAuthBlock
IAuthBlock* getAuthBlock(StatusType* status)
Интерфейс IClient
является основным интерфейсом клиентской сторонымодуля аутентификации.
authenticate
int authenticate(StatusType* status,
IClientBlock* cBlock)
выполняет один этап аутентификации. Обмен данными с серверомосуществляется с использованием интерфейса cBlock
. Возможные значениявозврата определяются в интерфейсе IAuth
. AUTH_SUCCESS
обрабатываетсяклиентской стороной как AUTH_MORE_DATA
(т.е. клиент отправляетсгенерированные данные на сервер и ждет ответа от него).
Этот плагин активно связан с серверной частью проверки подлинности — онподготавливает список пользователей для плагина аутентификации. Длякаждого плагина проверки подлинности требуется менеджер пользователей —некоторые из них могут получить доступ к списку пользователей, созданныхс использованием не Firebird программного обеспечения (например,AuthSspi). Запись, описывающая пользователя, состоит из несколькихполей, и поддерживать выполнение нескольких операций, таких какдобавление пользователя, изменение пользователя, получение спискапользователей и т. д. Плагин должен уметь интерпретировать команды,полученные в интерфейсе IUser
.
Интерфейс IUserField
не используется как автономный интерфейс, онявляется базовым для ICharUserField
и IIntUserField
.
entered
int entered()
возвращает ненулевое значение, если было введено (присвоено) значениедля поля.
specified
int specified()
возвращает ненулевое значение, если для поля было присвоено значениеNULL
.
setEntered
void setEntered(StatusType* status, int newValue)
устанавливает entered флаг в 0 или ненулевое значение для поля. Нетспособа назначить NULL
для поля, потому что он никогда не требуется.NULL
, если они используются, назначаются реализациями интерфейсами и,следовательно, имеют полный доступ к их внутренним элементам.
Интерфейс ICharUserField
:
get
const char* get()
возвращает значение поля как C-строку (\0 терминальную).
set
void set(StatusType* status, const char* newValue)
присваивает значение полю. Устанавливает флаг entered в true.
Интерфейс IIntUserField
:
get
int get()
возвращает значение поля.
set
void set(StatusType* status, int newValue)
присваивает значение полю. Устанавливает флаг entered в true.
Интерфейс IUser
— это список методов доступа к полям, включенным взапись о пользователе.
operation
unsigned operation()
код операции (см. список ниже).
userName
ICharUserField* userName()
имя пользователя.
password
ICharUserField* password()
пароль.
firstName
ICharUserField* firstName()
это и 2 следующие компоненты полного имени пользователя.
lastName
ICharUserField* lastName()
middleName
ICharUserField* middleName()
comment
ICharUserField* comment()
комментарий (из SQL оператора COMMENT ON USER IS …
).
attributes
ICharUserField* attributes()
теги в форме tag1=val1, tag2=val2, …, tagN=valN
. Val может бытьпустым, что означает, что тег будет удален.
active
IIntUserField* active()
изменяет настройку ACTIVE/INACTIVE для пользователя.
admin
IIntUserField* admin()
устанавливает/отменяет права администратора для пользователя.
clear
void clear(StatusType* status)
устанавливает, что все поля не введены и не указаны.
Константы, определенные пользовательским интерфейсом — действующие кодыопераций.
OP_USER_ADD
— добавление пользователя.
OP_USER_MODIFY
— редактирование пользователя.
OP_USER_DELETE
— удаление пользователя.
OP_USER_DISPLAY
— отображение пользователя.
OP_USER_SET_MAP
— включение отображения администраторов Windows нароль RDB$ADMIN
.
OP_USER_DROP_MAP
— выключение отображения администраторов Windows нароль RDB$ADMIN
.
Интерфейс IListUsers
— это обратный вызов, используемый плагиномпроверки подлинности при запросе списка пользователей. Плагин заполняетинтерфейс IUser
для всех элементов всписке пользователей один за другим и для каждого пользователя вызываетметод list()
этого интерфейса.
list
void list(StatusType* status, IUser* user)
функция обратного вызова. Реализация может делать с полученными даннымито что хочет. Например, она может поместить данные из пользовательскогопараметра в выходной поток сервиса или разместить в специальных таблицахSEC$
группы.
Интерфейс ILogonInfo
содержит данные, переданные плагину управленияпользователями для подключения к базе данных безопасности сдействительными учётными данными.
name
const char* name()
возвращает имя пользователя текущего подключения.
role
const char* role()
возвращает активную роль текущего подключения.
networkProtocol
const char* networkProtocol()
возвращает сетевой протокол текущего подключения. В настоящее время неиспользуется плагинами.
remoteAddress
const char* remoteAddress()
возвращает удаленный адрес текущего подключения. В настоящее время неиспользуется плагинами.
authBlock
const unsigned char* authBlock(unsigned* length)
возвращает блок аутентификации текущего подключения. Если не NULLпереписывает имя пользователя.
Интерфейс IConfig
— общий интерфейс файла конфигурации.
find
IConfigEntry* find(StatusType* status, const char* name)
Находит запись по имени.
findValue
IConfigEntry* findValue(StatusType* status, const char* name, const char* value)
Находит запись по имени и значению
findPos
IConfigEntry* findPos(StatusType* status, const char* name, unsigned pos)
Находит запись по имени и позиции. Если файл конфигурации содержитстроки:
Db=DBA Db=DBB Db=DBC
вызов findPos(status, "Db", 2)
вернет запись со значением DBB.
Интерфейс IManagement
является основным интерфейсом плагина управленияпользователями.
start
void start(StatusType* status, ILogonInfo* logonInfo)
запускает плагин, при необходимости он подключается к базе данныхбезопасности для управления пользователями (использовать это или нет эторешение, зависящее от плагинов), используя учетные данные из logonInfo
.
execute
int execute(StatusType* status, IUser* user, IListUsers* callback)
выполняет команду, предоставляемую методом operation()
параметра user
.При необходимости будет использоваться интерфейс обратного вызова.Параметр callback
может иметь значение NULL
для команд, не требующихполучения списка пользователей.
commit
void commit(StatusType* status)
подтверждает изменения, выполненные вызовами метода execute()
.
rollback
void rollback(StatusType* status)
отменяет изменения, выполненные вызовами метода execute()
.
Возможность шифрования базы данных присутствовала в Firebird со времёнInterbase, но соответствующие места в коде были закомментированы.Реализация была сомнительной — ключ шифрования всегда отправлялся отклиента в DPB, не было сделано попыток скрыть его от внешнего мира, и непредлагалось путей для шифрования существующих баз данных. Firebird 3.0решает большинство проблем, за исключением, вероятно, худшей — какуправлять ключами шифрования. Мы предлагаем различные типы решений, ноони требуют усилий в плагинах, т. е. нет красивого способа работы сключами как, например, для плагинов шифрования сетевого трафика.
Перед запуском с собственным плагином шифрования базы данных следуетпринять во внимание следующее. Мы видим два основных случая для которыхиспользуется шифрование базы данных — во-первых, может оно потребоватьсяизбежать утечки данных, если сервер базы данных физически украден, аво-вторых, оно может использоваться для защиты данных в базе данных,которая распространяется вместе со специальным приложением, обращающимсяк этим данным. Требования к этим случаям совершенно разные. В первомслучае мы можем доверять серверу базы данных, что он не модифицирован,чтобы красть ключи, переданные в плагин безопасности, то есть мыожидаем, что этот ключ не будет отправлен на неподходящий сервер. Вовтором случае сервер может быть каким-то образом модифицирован для кражиключей (если они передаются из приложения в плагин через код сервера)или даже данных (в качестве последнего места для снятия дампов из кэша,где они находятся в не зашифрованном виде). Поэтому ваш плагин долженубедиться, что он работает с не измененными двоичными файлами Firebird ивашим приложением перед отправкой ключа в плагин, например, плагин можетпотребоваться от них какой-то цифровой подписи. Кроме того, еслииспользуется сетевой доступ к серверу, то хорошей идеей являетсяпроверка того, что сетевой канал зашифрован (разбор выводаIUtil::getFbVersion()
) или используется собственный ключ шифрования.Вся эта работа должна выполняться в плагине (и в приложении, работающимс ним), то есть алгоритм шифрования блока базы данных сам по себе можетоказаться наиболее простой частью плагина шифрования базы данных,особенно когда для него используется некоторая стандартная библиотека.
Интерфейс ICryptKeyCallback
должен обеспечивать передачу ключашифрования в плагин шифрования базы данных или плагин хранителя ключа.
callback
unsigned callback(unsigned dataLength,
const void* data,
unsigned bufferLength,
void* buffer)
при выполнении обратного вызова информация передается в обоихнаправлениях. Источник ключа получает dataLength
байт данных и можетотправлять bufferLength
байт в буфер. Возвращает фактическое количествобайтов, помещенных в буфер.
Интерфейс IDbCryptInfo
передается движку IDbCryptPlugin
. Плагин можетсохранить этот интерфейс и использовать, когда это необходимо, дляполучения дополнительной информации о базе данных.
getDatabaseFullPath
const char* getDatabaseFullPath(StatusType* status)
возвращает полное (включая путь) имя первичного файла базы данных.
Интерфейс IDbCryptPlugin
является основным интерфейсом плагинашифрования базы данных.
setKey
void setKey(StatusType* status,
unsigned length,
IKeyHolderPlugin** sources,
const char* keyName)
используется для предоставления информации плагину шифрования базыданных о ключе шифрования. Firebird никогда не передает ключи для этоготипа плагина напрямую. Вместо этого массивIKeyHolderPlugins
заданнойдлины передается в плагин шифрования, который должен получить от одногоиз них интерфейсICryptKeyCallback
и затемполучить ключ, используя его. Параметр keyName
— это имя ключа, котороебыло введено в операторе ALTER DATABASE ENCRYPT …
.
encrypt
void encrypt(StatusType* status,
unsigned length,
const void* from,
void* to)
шифрует данные перед записью блока в файл базы данных
decrypt
void decrypt(StatusType* status,
unsigned length,
const void* from,
void* to)
расшифровывает данные после чтения блока из файла базы данных.
setInfo
void setInfo(StatusType* status,
IDbCryptInfo* info)
в этом методе плагин шифрования обычно сохраняет информационныйинтерфейс для будущего использования.
Этот тип плагина необходим для разграничения функциональности — плагиншифрования базы данных имеет дело с фактическим шифрованием, держательключа решает вопросы, связанные с предоставлением ему ключа безопаснымспособом. Плагин может получить ключ из приложения или загрузить егокаким-либо другим способом (вплоть до использования флэш-устройства,вставленного в сервер при запуске Firebird).
Интерфейс IKeyHolderPlugin
является основным интерфейсом для плагинахранения ключей шифрования.
keyCallback
int keyCallback(StatusType* status,
ICryptKeyCallback* callback)
используется для передачи интерфейсаICryptKeyCallback
вподключение (если он предоставляется пользователем с вызовомIProvider::setDbCryptCallback()
). Этот вызов всегда выполняется в моментподключения к базе данных, и некоторые держатели ключа могут отклонитьподключение, если не был предоставлен удовлетворительный ключ.
keyHandle
ICryptKeyCallback* keyHandle(StatusType* status,
const char* keyName)
предназначен для непосредственного вызова интерфейсомIDbCryptPlugin
для полученияинтерфейса обратного вызова для именованного ключа из держателя ключа.Это позволяет использовать код Firebird с открытым исходным кодом так,чтобы никогда не касаться фактических ключей, избегая возможности кражиключа, изменяющим код Firebird. После получения интерфейсаICryptKeyCallback
плагиншифрования запускает обмен данными, используя его. Держатель ключа может(например) проверить цифровую подпись плагина шифрования перед отправкойему ключа, чтобы избежать использования модифицированного плагинашифрования, способного украсть секретный ключ.
useOnlyOwnKeys
FB_BOOLEAN useOnlyOwnKeys(StatusType* status)
информирует Firebird о том, будет ли использоваться ключ,предоставленный другим держателем ключа, или нет. Имеет смысл только дляSuperServer — только он может делиться ключами шифрования базы данныхмежду подключениями. Возвращая FB_TRUE
из этого метода, принудительнозаставляет Firebird убедиться, что этот конкретный держатель ключа (и,следовательно, связанное с ним подключение) предоставляет правильныйключ шифрования, прежде чем позволить ему работать с базой данных.
chainHandle
ICryptKeyCallback* chainHandle(StatusType* status)
поддержка цепочки держателей ключей. В некоторых случаях ключ долженпроходить через более чем один держатель ключа, прежде чем он достигнетплагина шифрования базы данных. Это необходимо (например) для поддержкиEXECUTE STATEMENT
в зашифрованной базе данных. Это всего лишь пример —цепочки также используются в некоторых других случаях. Интерфейсобратного вызова, возвращенный этим методом, может отличаться отвозвращаемого функцией keyHandle()
(см. выше). Как правило, он должениметь возможность дублировать ключи один в один, полученные изIKeyHolderPlugin
при вызове функции keyCallback()
.
Интерфейс IConfigManager
— общий интерфейс для доступа к различнымобъектам конфигурации.
getDirectory
const char* getDirectory(unsigned code)
Возвращает местоположение соответствующего каталога в текущем экземпляреFirebird. См. коды каталогов для этого вызова ниже.
getFirebirdConf
IFirebirdConf* getFirebirdConf()
Возвращает интерфейс для доступа к значениям конфигурации по умолчанию(из firebird.conf
).
getDatabaseConf
IFirebirdConf* getDatabaseConf(const char* dbName)
Возвращает интерфейс для доступа к конфигурации, специфичной для базыданных (берёт в расчёт firebird.conf
и соответствующую частьdatabase.conf
).
getPluginConfig
IConfig* getPluginConfig(const char* configuredPlugin)
Возвращает интерфейс для доступа к конфигурации именованного плагина.
getInstallDirectory
const char* getInstallDirectory()
Возвращает каталог, в котором установлен firebird.
getRootDirectory
const char* getRootDirectory()
Возвращает корневой каталог текущего экземпляра, в случае с единственнымэкземпляром обычно совпадает с каталогом установки.
getDefaultSecurityDb
const char* getDefaultSecurityDb()
Возвращает путь по умолчанию (т. е. без учета файлов конфигурации учетной записи) к базе данных безопасности,используемый в первую очередь для внутреннего использования, чтобы обеспечить правильный доступ к базе данныхбезопасности на сервере с несколькими провайдерами с нулевой конфигурацией.
Коды каталогов:
DIR_BIN — bin
(утилиты наподобие isql, gbak, gstat);
DIR_SBIN — sbin (fbguard и firebird сервер);
DIR_CONF — каталог файлов конфигурации (firebird.conf
,databases.conf
, plugins.conf
);
DIR_LIB — lib
(fbclient
, ib_util
);
DIR_INC — include
(ibase.h
, firebird/Interfaces.h
);
DIR_DOC — каталог документации;
DIR_UDF — UDF (ib_udf
, fbudf
);
DIR_SAMPLE — каталог примеров;
DIR_SAMPLEDB — каталог, где расположена база данных примеров(employee.fdb
);
DIR_HELP — qli help (help.fdb
);
DIR_INTL — каталог библиотек интернационализации (fbintl
);
DIR_MISC — различные файлы (как манифест деинсталлятора и другое);
DIR_SECDB — каталог, где расположена база данных безопасности(securityN.fdb
);
DIR_MSG — каталог, где расположен файл сообщений (firebird.msg
);
DIR_LOG — каталог, где расположен лог файл (firebird.log
);
DIR_GUARD — каталог, где расположена блокировка хранителя (fb_guard);
DIR_PLUGINS — директория плагинов ([lib]Engine12.\{dll|so}).
Интерфейс IConfigEntry
— представляет запись (Key = Values с возможнымиподзаголовками (подзаписями)) в файле конфигурации firebird.
getName
const char* getName()
Возвращает имя ключа.
getValue
const char* getValue()
Возвращает значение в качестве символьной строки.
getIntValue
ISC_INT64 getIntValue()
Обрабатывает значение как целое и возвращает его.
getBoolValue
FB_BOOLEAN getBoolValue()
Обрабатывает значение как boolean и возвращает его.
getSubConfig
IConfig* getSubConfig(StatusType* status)
Рассматривает подзаголовки как отдельный файл конфигурации и возвращаетинтерфейс IConfig
для него.
Интерфейс IDecFloat16
помогает работать с типом данных DECFLOAT(16)
.
toBcd
void toBcd(const FB_DEC16* from, int* sign, unsigned char* bcd, int* exp)
Преобразует десятичное значение с плавающей запятой в BCD.
toString
void toString(StatusType* status, const FB_DEC16* from, unsigned bufferLength, char* buffer)
Преобразует десятичное значение с плавающей запятой в строку.
fromBcd
void fromBcd(int sign, const unsigned char* bcd, int exp, FB_DEC16* to)
Собирает десятичное значение с плавающей запятой из BCD.
fromString
void fromString(StatusType* status, const char* from, FB_DEC16* to)
Собирает десятичное значение с плавающей запятой из строки.
Интерфейс IDecFloat34
помогает работать с типом данных DECFLOAT(34)
.
toBcd
void toBcd(const FB_DEC34* from, int* sign, unsigned char* bcd, int* exp)
Преобразует десятичное значение с плавающей запятой в BCD.
toString
void toString(StatusType* status, const FB_DEC34* from, unsigned bufferLength, char* buffer)
Преобразует десятичное значение с плавающей запятой в строку.
fromBcd
void fromBcd(int sign, const unsigned char* bcd, int exp, FB_DEC34* to)
Собирает десятичное значение с плавающей запятой из BCD.
fromString
void fromString(StatusType* status, const char* from, FB_DEC34* to)
Собирает десятичное значение с плавающей запятой из строки.
Note
|
Они находятся в специальном заголовке |
Следующие 3 класса используются для представления типов DATE
, TIME
иTIMESTAMP
(datetime) при использовании макроса FB_MESSAGE
. Членыструктуры данных, представляющие статическое сообщение, соответствуютполям типов FB_DATE/FB_TIME/ FB_TIMESTAMP, будут иметь тип одного изэтих классов. Для получения доступа к полям даты и времени в статическихсообщениях необходимо знать методы и члены класса (которые достаточносамо описательны, чтобы не описывать их здесь).
Методы класса FbDate
:
decode
void decode(IUtil* util,
unsigned* year,
unsigned* month,
unsigned* day)
getYear
unsigned getYear(IUtil* util)
getMonth
unsigned getMonth(IUtil* util)
getDay
unsigned getDay(IUtil* util)
encode
void encode(IUtil* util,
unsigned year,
unsigned month,
unsigned day)
Методы класса FbTime
:
decode
void decode(IUtil* util,
unsigned* hours,
unsigned* minutes,
unsigned* seconds,
unsigned* fractions)
getHours
unsigned getHours(IUtil* util)
getMinutes
unsigned getMinutes(IUtil* util)
getSeconds
unsigned getSeconds(IUtil* util)
getFractions
unsigned getFractions(IUtil* util)
encode
void encode(IUtil* util,
unsigned hours,
unsigned minutes,
unsigned seconds,
unsigned fractions)
Члены класса `FbTimestamp `:
date
FbDate date;
time
FbTime time;
Следующие два шаблона используются в статических сообщениях дляпредставления полей CHAR(N)
и VARCHAR(N)
.
template <unsigned N>
struct FbChar
{
char str[N];
};
template <unsigned N>
struct FbVarChar
{
ISC_USHORT length;
char str[N];
void set(const char* s);
};
В этом документе отсутствуют три типа плагинов — ExternalEngine
, Trace
и Replicator
.Информация о них будет доступна в следующем выпуске.