Использование сервисов
Чтобы начать пользоваться сервисами (службами), прежде всего необходимоподключиться к менеджеру сервисов. Это делается с помощью метода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);