FirebirdSQL logo

Utilisation des Services

Pour commencer à utiliser les services, vous devez d’abord vous connecter au gestionnaire de services. Cela se fait à l’aide de la méthode attachServiceManager() de l’interface IProvider. Cette méthode renvoie l’interface IService, qui est ensuite utilisée pour communiquer avec le service. Pour préparer le SPB à se connecter au Service Manager, vous pouvez utiliser 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");

et connectez-vous :

IService* svc = prov->attachServiceManager(&status, "service_mgr",
    spb1->getBufferLength(&status), spb1->getBuffer(&status));

À l’aide de IService, vous pouvez effectuer des actions disponibles pour les services, telles que l’exécution de services, ainsi que demander diverses informations sur les utilitaires en cours d’exécution et du serveur dans son ensemble. Lors de la demande d’informations, il y a une limitation : le format du bloc de paramètres utilisé par la méthode query() n’est pas pris en charge par IXpbBuilder dans Firebird 4. Le support sera probablement ajouté dans les futurs versions, dans Firebird 4 vous devrez créer et analyser ce bloc manuellement. Le format de ce bloc rdt identique à l’ancien format (utilisé dans l’API ISC) un pour un.

Pour démarrer le service, vous devez d’abord créer le SPB approprié :

IXpbBuilder* spb2 = utl->getXpbBuilder(&status, IXpbBuilder::SPB_START, NULL, 0);

et y ajouter les éléments nécessaires. Par exemple, pour imprimer les statistiques de chiffrement de la base de données « employé » dans SPB, vous devez mettre ce qui suit :

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);

Après cela, le service peut être démarré à l’aide de la méthode start() de l’interface IService :

svc->start(&status, spb2->getBufferLength(&status), spb2->getBuffer(&status));

De nombreux services en cours d’exécution (y compris le gstat mentionné ici) renvoient des informations textuelles au moment de l’exécution. Pour l’afficher, vous devez demander ces informations au service en cours d’exécution ligne par ligne. Pour ce faire, appelez la méthode query() de l’interface IService avec les blocs de paramètres appropriés pour la réception et l’envoi. Le bloc d’envoi peut contenir diverses informations auxiliaires (par exemple, un délai d’expiration de la demande du service) ou des informations qui doivent être transmises à l’utilitaire stdin, où il peut être vide dans le cas le plus simple. Le bloc d’ingestion doit contenir une liste des balises que vous souhaitez recevoir du service. Pour la plupart des services publics, il s’agit de la seule « isc_info_svc_line » :

const unsigned char receiveItems1[] = {isc_info_svc_line};

De plus, il a besoin d’une mémoire tampon pour demander ces informations :

unsigned char results[1024];

Après ces étapes préliminaires, nous sommes prêts à demander des informations au service dans une boucle (chaque ligne est retournée en un seul appel à query()) :

do
{
    svc->query(&status, 0, NULL,
               sizeof(receiveItems1), receiveItems1,
               sizeof(results), results);
} while (printInfo(results, sizeof(results)));

Dans cet exemple, nous supposons que la fonction printInfo() renvoie TRUE tant que le service renvoie un bloc de résultat contenant la ligne de sortie suivante, c’est-à-dire jusqu’à la fin du flux de données du service. Le format du bloc de résultat varie d’un service à l’autre, et certains services, tels que gsec, créent des formats historiques qui ne sont pas triviaux pour l’analyse, mais qui dépassent le cadre de ce chapitre. L’exemple de travail minimal printInfo() est présent dans l’exemple 09.service.cpp.

La même méthode de requête est utilisée pour récupérer des informations sur le serveur, mais dans ce cas, la fonction de requête n’est pas appelée dans une boucle, c’est-à-dire que le tampon doit être suffisamment grand pour contenir toutes les informations à la fois. Ce n’est pas trop difficile, car ces appels ne renvoient généralement pas beaucoup de données. Comme dans le cas précédent, vous devez commencer par placer les éléments nécessaires dans le bloc d’accueil — dans notre exemple, il s’agit de isc_info_svc_server_version :

const unsigned char receiveItems2[] = {isc_info_svc_server_version};

Un tampon de résultat existant d’un appel précédent peut être réutilisé. Dans ce cas, vous n’avez pas besoin d’une boucle :

svc->query(&status, 0, NULL,
           sizeof(receiveItems2), receiveItems2,
           sizeof(results), results);

printInfo(results, sizeof(results));

Une fois les tâches de service terminées, n’oubliez pas de désactiver le service :

svc->detach(&status);

Utilisation des transactions

La création de bases de données vides n’est certainement pas suffisante pour travailler avec un SGBDR. Nous voulons être en mesure de créer divers objets dans la base de données (par exemple, des tables, etc.) et d’insérer des données dans ces tables. Dans Firebird, toute opération de base de données est transactionnelle. Par conséquent, tout d’abord, nous devons apprendre à démarrer une transaction. Nous ne parlons pas ici de transactions distribuées (prises en charge par l’interface IDtc) afin d’éviter une complexité inutile pour la plupart des utilisateurs. Le démarrage d’une transaction non distribuée est très simple et se fait via l’interface de connexion :

ITransaction* tra = att->startTransaction(&status, 0, NULL);

Dans cet exemple, les paramètres de transaction par défaut sont utilisés : le TPB n’est pas transmis à la méthode startTransaction(). Si vous avez besoin d’une transaction avec des paramètres autres que la valeur par défaut, vous pouvez créer un IXpbBuilder correspondant et y ajouter les éléments nécessaires :

IXpbBuilder* tpb = utl->getXpbBuilder(&status, IXpbBuilder::TPB, NULL, 0);
tpb->insertTag(&status, isc_tpb_read_committed);

et passez le TPB terminé à startTransaction() :

ITransaction* tra = att->startTransaction(&status, tpb->getBufferLength(&status),
    tpb->getBuffer(&status));

L’interface de transaction est utilisée comme paramètre dans de nombreux autres appels d’API, mais elle ne fait rien d’autre que valider/annuler la transaction, tout en conservant le contexte de transaction :

tra->commit(&status);

Vous pouvez voir comment démarrer et confirmer une transaction dans les exemples 01.create.cpp ou en Pascal 01.create.pas.