Создание базы данных и соединение с существующей базой данных
Прежде всего нам нужно получить доступ к интерфейсу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) примеры и попытатьсязапустить их.