Bases de données
Introduction
Ce chapitre aborde les bases de données. Vous ferez un peu d’astronomie avec ses recettes car il s’agit de stocker, puis d’obtenir, grâce aux bases de données, des objets célestes du catalogue de Messier. Nous avons choisi les bases de données PostgreSQL, MySQL, SQLite et celles compatibles avec le protocole ODBC.
Les recettes de ce chapitre travaillent avec des chaînes de caractères. Comme dans le chapitre "Protocoles réseau", nous avons besoin d’un type plus adapté que char* à leur traitement. Aussi, nous reprenons le type string_t que nous avons utilisé dans le chapitre cité précédemment. Nous indiquons à nouveau la définition de ce type ci-dessous. Veuillez vous référer à ce même chapitre pour les fonctions relatives à ce type (string_new(), string_free() et string_ajout()).
typedef struct
{
char *str; /* chaîne */
int size; /* Taille de l'espace alloué */
int len; /* Longueur de la chaîne */
} string_t;
Effectuer une requête sur un serveur PostgreSQL
Problème
Vous voulez vous connecter à un serveur PostgreSQL et gérer vos données.
Solution
Utilisez la bibliothèque libpq fournie avec PostgreSQL pour vous connecter et envoyer vos requêtes au serveur.
Discussion
Effectuer une requête sur un serveur PostgreSQL s’effectue en quatre étapes.
Étape 1 : se connecter au serveur
Tout d’abord, connectez-vous au serveur avec PQsetdbLogin(). La fonction suivante utilise celle-ci en mettant quelques paramètres à NULL pour utiliser les valeurs par défaut. Elle vérifie si la connexion a bien été effectuée. Le code retour, dont le type est PGconn*, et que nous nommerons identifiant de connexion, est un ensemble opaque de paramètres nécessaire à toutes les actions ultérieures sur le serveur, comme un descripteur de fichiers pour des fichiers.
PGconn *
pg_connexion (const char *serveur, const char *db, const char *user,
const char *pwd)
{
PGconn *pgh;
/* Connexion à la base. */
pgh = PQsetdbLogin (serveur, NULL, NULL, NULL, db, user, pwd);
if (CONNECTION_BAD == PQstatus (pgh))
{
fprintf (stderr, "Échec de la connexion à %s\n", db);
fprintf (stderr, "%s", PQerrorMessage (pgh));
PQfinish (pgh);
return NULL;
}
return pgh;
}
Étape 2 : effectuer une requête SQL
Deuxièmement, effectuez votre requête avec PQexec() qui prend l’identifiant de connexion et une requête SQL en argument. Nous pouvons utiliser la fonction suivante pour toute requête simple, à savoir toute requête qui ne retourne pas de résultat :
int
pg_requete_simple (PGconn * pgh, const char *requete)
{
PGresult *pgr;
ExecStatusType status;
/* Requête au serveur. */
pgr = PQexec (pgh, requete);
/* Obtention de l'état de la requête pour tester si une erreur
* est survenue.
*/
status = PQresultStatus (pgr);
if (PGRES_COMMAND_OK != status)
{
char *s;
fprintf (stderr, "Échec : '%s' %s\n", requete,
((s = PQcmdStatus (pgr)) ? s : "OK"));
PQfinish (pgh);
return...
Effectuer une requête sur un serveur MySQL
Problème
Vous voulez vous connecter à un serveur MySQL et gérer vos données.
Solution
Utilisez la bibliothèque libmysqlclient fournie avec MySQL pour vous connecter et envoyer vos requêtes au serveur.
Discussion
Effectuer une requête sur un serveur MySQL s’effectue en quatre étapes.
Étape 1 : se connecter au serveur
En premier lieu, connectez-vous au serveur avec mysql_real_connect(). La fonction suivante, sur le même modèle que celle de la recette précédente, utilise celle-ci en mettant quelques paramètres à zéro ou NULL pour utiliser les valeurs par défaut. Contrairement à de nombreuses fonctions de connexion comme fopen(), gzopen() ou PQsetdbLogin() qui allouent l’espace mémoire pour stocker l’identifiant de connexion, nous devons réaliser cette tâche nous-même au préalable, grâce à mysql_init(). Notre fonction vérifie ensuite si la connexion a bien été effectuée. Elle renvoie, en guise de code retour, cet identifiant de connexion de type MYSQL*, tout aussi opaque que celui de PostgreSQL ou qu’un descripteur de fichiers.
MYSQL *
my_connexion (const char *serveur, const char *db, const char *user,
const char *pwd)
{
MYSQL *myh;
/* Initialisation de myh. */
if (NULL == (myh = mysql_init (NULL)))
{
fprintf (stderr, "Mémoire insuffisante\n");
exit (EXIT_FAILURE);
}
/* Connexion à la base. */
if (NULL ==
mysql_real_connect (myh, serveur, user, pwd, db, 0, NULL, 0))
{
fprintf (stderr, "Échec de la connexion à %s\n", db);
fprintf (stderr, "%s", mysql_error (myh));
free (myh);
return NULL;
}
return myh;
}
Étape 2 : effectuer une requête SQL
Deuxièmement, effectuez votre requête avec mysql_query() (ou mysql_real_query()) qui prend l’identifiant de connexion et une requête SQL en argument (ainsi que la longueur de la requête pour mysql_real_query()). Nous pouvons utiliser la fonction suivante pour toute requête simple, à savoir toute requête qui ne retourne pas de résultat :
int
my_requete_simple...
Effectuer une requête sur une base de données SQLite3
Problème
Vous voulez gérer les données contenues dans une base SQLite3.
Solution
Utilisez la bibliothèque libsqlite3 pour vous connecter à la base et effectuer vos requêtes.
Discussion
Une base SQLite3 a la particularité d’être contenue dans un fichier qui porte le même nom. Le moteur de base de données SQLite3 est une bibliothèque, libsqlite3, qu’il est possible d’utiliser avec l’interface utilisateur en ligne de commande sqlite3 ou, comme décrit ici, via l’API C. Cette implémentation du moteur de base de données présente l’avantage de n’avoir rien à configurer, rien à maintenir ou à administrer. C’est aussi son objectif. En contrepartie, certaines fonctionnalités sont absentes de SQLite3, comme la gestion des utilisateurs ou possibilité de se connecter à distance à la base (en TCP/IP par exemple).
Effectuer une requête dans une base SQLite3 s’effectue en quatre étapes.
Étape 1 : ouvrir la base
Se connecter à une base SQLite3 revient à ouvrir le fichier qui la contient, avec sqlite3_open(). Elle prend en argument le nom du fichier contenant la base du même nom, suivie d’un pointeur vers un descripteur de base de données de type sqlite3 passé par référence. Elle renvoie SQLITE_OK si tout s’est bien passé.
sqlite3 *
sqlite_connexion (char *db)
{
sqlite3 *dbh;
if (SQLITE_OK != sqlite3_open (db, &dbh))
{
fprintf (stderr, "Impossible d'ouvrir la base (%s)\n",
sqlite3_errmsg (dbh));
return (NULL);
}
return (dbh);
}
Étape 2 : effectuer une requête SQL
Il existe trois façons d’effectuer une requête SQL dans une base SQLite3 :
-
avec sqlite3_exec() ;
-
avec sqlite3_get_table() ;
-
avec sqlite3_prepare_v2() et sqlite3_step().
Avec sqlite3_exec(), vous exécutez une requête dont le résultat est traité par une fonction de rappel que vous indiquez en argument. Cette façon est la plus pratique lorsque vous n’attendez pas de résultat de votre requête (CREATE TABLE ou INSERT par exemple). Si vous attendez un résultat...
Effectuer une requête sur un serveur de bases de données compatible ODBC
Problème
Vous voulez vous connecter à un serveur compatible ODBC et gérer vos données.
Solution
Utilisez une bibliothèque ODBC comme unixODBC sur Unix pour vous connecter et envoyer vos requêtes au serveur.
Discussion
Le sigle ODBC signifie Open DataBase Connectivity. L’API ODBC, normalisée par les organismes ISO et ANSI, fut implémentée en premier par Microsoft. Elle existe maintenant entre autres pour les plates-formes Unix, OS/2 et Macintosh. Une base de données est dite ODBC lorsqu’il existe un moyen de stocker et d’obtenir des données en effectuant des requêtes SQL grâce à l’API ODBC. Ainsi, de nombreuses bases, dont PostgreSQL, MySQL, Oracle, Sybase, et aussi OpenOffice.org et MSAccess, aussi surprenant que cela puisse être, sont des bases ODBC. Il existe en effet un pilote ODBC pour la bibliothèque unixODBC pour s’y connecter.
Contrairement à une base de données relationnelle comme PostgreSQL ou MySQL, la connexion via ODBC ne s’effectue pas à une base sur un serveur, mais à une source de données. Pour configurer celle-ci, vous devez vous référer à la documentation de votre bibliothèque. Sur un système Unix, avec la bibliothèque unixODBC, il s’agit de modifier les fichiers /etc/odbcinst.ini et /etc/odbc.ini. Dans la suite de la recette, nous supposerons que vous avez défini une source Messier.
Pour effectuer une requête sur un serveur avec l’API ODBC, nous suivons les quatre étapes suivantes.
Étape 1 : se connecter à la source de données
La connexion à la source de données n’est pas aussi triviale qu’une ouverture de fichier. En effet, vous devez initialiser un identifiant de connexion avant de pouvoir réaliser celle-ci. Pour cela, une variable définissant l’environnement ODBC vous sera demandée et il faudra l’avoir préparée. La connexion elle-même s’effectue donc en quatre étapes :
-
1. Initialisation de l’environnement ODBC avec SQLAllocHandle() ;
-
2. Choix du numéro de version d’ODBC avec SQLSetEnvAttr() ;
-
3. Initialisation de l’identifiant de connexion avec...