FirebirdSQL logo

Accès à la base de données

Création d’une base de données et connexion à une base de données existante

Tout d’abord, nous devons accéder à l’interface IMaster. IMaster est l’interface principale de Firebird, nécessaire pour accéder à toutes les autres interfaces. Par conséquent, il existe un moyen simple d’y accéder – la seule chose qui est nécessaire est d’utiliser une fonction de l’API OO appelée fb_get_master_interface(). Cette fonction n’a pas de paramètres et réussit toujours. Il n’y a qu’une seule instance de IMaster pour chaque bibliothèque cliente Firebird, il n’y a donc pas besoin de s’inquiéter de libérer de la mémoire utilisée par l’interface maître. Le moyen le plus simple d’y accéder à partir de votre programme est d’utiliser la variable globale ou statique appropriée :

static IMaster* master = fb_get_master_interface();

Pour la plupart des méthodes utilisées dans l’API OO de Firebird, le premier paramètre est IStatus. Il s’agit d’un remplacement logique de ISC_STATUS_ARRAY, mais il fonctionne différement avec les erreurs et les avertissements (sans les mélanger dans le même tableau), peut contenir un nombre illimité d’erreurs, et (c’est important si vous envisagez d’implémenter IStatus vous-même) stocke toujours les chaînes auxquelles il fait référence à l’intérieur de l’interface. Habituellement, au moins une instance de IStatus est nécessaire pour appeler d’autres méthodes. Vous pouvez l’obtenir à partir de iMaster :

IStatus* st = master->getStatus();

Si, pour une raison quelconque, la méthode getStatus() ne fonctionne pas (OOM par exemple), alors elle retourne NULL – auquel cas il est évident que nous ne pouvons pas utiliser une méthode générique pour les messages d’erreur basée sur IStatus.

Nous allons maintenant nous intéresser à la première interface, qui est directement liée à l’accès à la base de données. Il s’agit de l’interface IProvider, ainsi nommée parce que c’est l’interface que tout fournisseur dans Firebird devrait implémenter. La bibliothèque cliente Firebird possède sa propre implémentation de IProvider qui doit être utilisée pour exécuter toutes les opérations de base de données. Pour l’obtenir, nous appelons la méthode getDispatcher de l’interface IMaster :

IProvider* prov = master->getDispatcher();

Lors de la connexion à une base de données existante, ou encore plus lors de la création d’une nouvelle base de données, il est souvent nécessaire de passer de nombreux paramètres supplémentaires à l’appel de l’API (login/mot de passe, taille de page pour la nouvelle base de données, etc.). Il est presque impossible d’avoir des paramètres séparés au niveau de l’appel : nous devrons modifier l’appel trop souvent pour ajouter de nouveaux paramètres, et le nombre de paramètres peut être très important, même si vous n’avez généralement pas besoin d’en passer beaucoup.Par conséquent, une structure de données en mémoire spéciale appelée bloc de paramètres de base de données (DPB) est utilisée pour transmettre des paramètres supplémentaires. Son format est clairement défini, ce qui permet de construire des blocs de paramètres DPB octets par octets. Cependant, il est beaucoup plus facile d’utiliser une interface spéciale IXpbBuilder, ce qui facilite la création de blocs de divers paramètres.Pour obtenir une instance de IXpbBuilder, vous devez connaître une autre API générique de Firebird — IUtil. C’est une sorte de conteneur pour les appels qui ne se prêtent pas bien à d’autres endroits. Donc, ce que nous faisons, c’est

IUtil* utl = master->getUtilInterface();
IXpbBuilder* dpb = utl->getXpbBuilder(&status, IXpbBuilder::DPB, NULL, 0);

Ce code crée un constructeur de bloc de paramètres vide de type DPB. Maintenant, l’ajout du paramètre nécessaire est trivial :

dpb->insertInt(&status, isc_dpb_page_size, 4 * 1024);

créera une base de données avec une taille de page de 4 Ko et des valeurs dont le sens est clair.

dpb->insertString(&status, isc_dpb_user_name, "sysdba");
dpb->insertString(&status, isc_dpb_password, "masterkey");

Ce qui suit est spécifique à C++ : Nous sommes presque prêts à appeler la méthode createDatabase() de l’instance IProvider, mais avant cela, nous devons dire quelques mots sur le concept du Status Wrapper. Le Status Wrapper n’est pas une interface, c’est un wrapper très fin sur l’interface IStatus. Il permet de personnaliser le comportement de l’API C++ (changer la façon dont les erreurs retournées dans l’interface IStatus sont gérées).Dans un premier temps, nous vous recommandons d’utiliser ThrowStatusWrapper, qui lève une exception C++ chaque fois qu’une erreur est renvoyée dans IStatus.

ThrowStatusWrapper status(st);

Nous pouvons maintenant créer une nouvelle base de données vide :

IAttachment* att = prov->createDatabase(&status, "fbtests.fdb",
    dpb->getBufferLength(&status), dpb->getBuffer(&status));
printf("Database fbtests.fdb created\n");

Notez que nous ne vérifions pas l’état après avoir appelé createDatabase(), car si une erreur se produit, une exception C++ ou Pascal sera levée (il est donc très utile d’avoir la syntaxe try/catch/except dans votre code). Nous utilisons également deux nouvelles fonctions de IXpbBuildergetBufferLength() et getBuffer(), qui extraient les données de l’interface au format DPB natif. Comme vous pouvez le voir, il n’est pas nécessaire de vérifier explicitement l’état des fonctions en renvoyant des résultats intermédiaires.

La fermeture de la base de données nouvellement créée est trivial :

att->detach(&status);

Il ne reste plus qu’à entourer toutes les instructions d’un bloc try et à écrire un gestionnaire dans le bloc catch. Lorsque vous utilisez ThrowStatusWrapper, vous devez toujours intercepter la classe FbException définie dans l’API C++, en Pascal, vous devez également travailler avec la class FbException. Dans le cas le plus simple, le bloc de gestion des exceptions peut ressembler à ceci :

catch (const FbException& error)
{
    char buf[256];
    utl->formatStatus(buf, sizeof(buf), error.getStatus());
    fprintf(stderr, "%s\n", buf);
}

Notez qu’ici nous utilisons une autre fonction de IUtilformatStatus(). Il renvoie dans le tampon buf le texte décrivant l’erreur (avertissement) stocké dans le paramètre IStatus.

Pour vous connecter à une base de données existante, utilisez la méthode attachDatabase() de l’interface IProvider au lieu de createDatabase(). Tous les paramètres sont les mêmes pour les deux méthodes.

att = prov->attachDatabase(&status, "fbtests.fdb", 0, NULL);

Dans cet exemple, il n’utilise aucun paramètre DPB supplémentaire. Gardez à l’esprit que sans identifiant/mot de passe, toute connexion à distance échouera si l’authentification de confiance n’est pas configurée. Bien entendu, les informations de connexion peuvent être fournies par l’environnement (dans les variables ISC_USER et ISC_PASSWORD), comme c’était le cas auparavant.

Le dossier examples contient des exemples terminés, y compris des exemples de création d’une base de données, 01.create.cpp et en Pascal 01.create.pas. Lors de la lecture de ce document, il est utile de créer soit même les exemples et d’essayer de les exécuter.