Connexion à MySQL en C

Publié le 1 janvier 2011

Sommaire

Introduction

Dans cet article, je vais montrer comment faire une connexion MySQL en utilisation l’API MySQL en C (informations sur cette page : http://dev.mysql.com/doc/refman/5.0/fr/c.html).

Ces fonctions peuvent être utile quand on récupère beaucoup de données très bas niveau (données système, données de capteurs) et que l’on veut les insérer directement dans une base de données.

Le langage permet des performances bien plus avancées que d’autres langages, mais celui-ci étant “bas-niveau” il apporte également un niveau de complexité supplémentaire.

On privilégiera donc ce langage pour l’import massif de données sans modification, ou des mises à jours massives de la base de données.

Données utiles aux fonctions

Tout d’abord, il faut inclure les entêtes des fonctions MySQL de l’API :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <winsock.h> (sous Windows)
#include <mysql/mysql.h>

Winsock.h est utile si l’on compile le code sous Windows. Il est possible que le fichier d’entête mysql.h soit dans un sous dossier mysql ou MYSQL, ce qui fait une différence puisque le langage est sensible à la casse.

Puis nous allons nous attarder aux directives pré-processeur, qui vont nous servir de constantes (ce ne sont pas de réelles constantes puisqu’elles n’utilisent pas le mot clé const et elles ne sont pas typées) :

// Directives pré-processeur
#define DB_HOST "127.0.0.1"
#define DB_USER "root"
#define DB_PASSWORD "nopwd";
#define DB_BASE "mydb";

Ces directives serviront à la connexion à la base de données.

Maintenant nous nous intéressons à la collecte des données que l’on va récupérer lorsque nous effectuons un SELECT en base :

// Structure des données SQL
typedef struct {
	unsigned int nbLine;
	unsigned int nbColumn;
	char ***data;
}sqlData;

Les données retournées par la structure MySQL sous de la forme d’un triple pointeur ! C’est-à-dire que si l’on s’intéresse aux jeux de résultats sortant d’une base SQL, c’est une matrice, avec des colonnes (les champs) et les lignes (chaque enregistrement retourné). De plus toutes ces données sont retournées sous forme d’un pointeur, ce qui en fait un triple pointeur. Nous collectons donc, le nombre de colonnes et le nombre de lignes pour le parcours des données et les données retournées.

Afin d’avoir un code propre (pour créer un fichier db.h par exemple), nous créons nos prototypes (entêtes de fonction):

// Prototypes
MYSQL* dbInitialisation(void);
void* dbRequestWithoutResult(MYSQL *m, char requete[]);
sqlData* dbRequestWithResult(MYSQL *m, char requete[]);
void dbClose(MYSQL *m);

Les noms des fonctions parlent d’eux mêmes.

Fonction d’initialisation et de fermeture

Voici la fonction d’initialisation de la connexion à la base MySQL :

/**
  * Initialisation connection MYSQL
  */
MYSQL *dbInitialisation(void) {
        // Déclaration du pointeur de structure de type MYSQL
        MYSQL *mysqlStruct = NULL;
 
        // Initialisation de MySQL
        mysqlStruct = mysql_init(mysqlStruct);
 
        if (mysqlStruct = mysql_real_connect(mysqlStruct, DB_HOST, DB_USER, DB_PASSWORD, DB_BASE, 3306, NULL, 0)) { 
            return mysqlStruct;
	}
	else {
            printf("Erreur | Connexion MySQL impossible ! -> %s\n", mysql_error(mysql));		
            return NULL;
	}
}

Deux fonctions fournies par l’API, mysql_init() et mysql_real_connect(). La première fonction initialise un objet MySQL. La seconde fonction effectue la connexion au serveur de base de données.

/**
 * Fermeture connection MYSQL
 */
void dbClose(MYSQL *m) {
    mysql_close(m);    
}

La fonction mysql_close() ferme l’objet MySQL initialisé, il faut absolument libérer la mémoire prise par cet objet.

Fonction de récupération d’un jeu de données

Voici la fonction permettant par exemple de faire un SELECT en base :

/**
  * Fonction requête avec jeu de résultat MYSQL
  */
sqlData* dbRequestWithResult(MYSQL *aMysqlStruct, char aRequest[]) {
    if(mysql_query(aMysqlStruct, aRequest) != 0) {
    printf("Erreur : %s\n\n", mysql_error(aMysqlStruct));
    exit (1);
    }
    /* Déclaration des variables */
 
    // Déclaration des pointeurs de structure
    MYSQL_RES *resultat = NULL;
    MYSQL_ROW row = NULL;
 
    unsigned int uiNbChamps = 0;
    unsigned int uiNbData = 0;
    unsigned long *lengths;
 
    // On mets le jeu de résultat dans le pointeur result
    resultat = mysql_store_result(m);
 
    uiNbChamps = mysql_num_fields(resultat); // Nombre de champs
    uiNbData = mysql_num_rows(resultat); // Nombre d'enregistrements
 
    // Allocation de mémoire des données retournées
    sqlData *dataResult = (sql_data *)malloc(sizeof(sqlData));
    dataResult->nbColumn = uiNbChamps;
    dataResult->nbLine = uiNbData;
 
    char ***column = (char ***) calloc(uiNbData, sizeof(char));
    unsigned int countLine = 0;
 
    // Tant qu'il y a encore un résultat ...
    while ((row = mysql_fetch_row(resultat))) {
        column[countLine] = (char **) calloc(num_champs, sizeof(char));
 
        for(unsigned int i = 0; i < num_champs; i++) {
            column[countLine][i] =(char *)malloc(sizeof(char)*400);
            strcpy(colonne[countLine][i], row[i]);
        }
        countLine++;
    }
    dataResult->data = column;
    mysql_free_result(result);
}

On effectuera la connexion à la base avec la fonction mysql_query(), la syntaxe est plus ou moins la même qu’en PHP, au détail prêt que le lien avec la connexion MySQL ici est un pointeur sur l’objet MySQL.

Pour résumer l’algorithme :

  • on envoie la requête
  • on récupère le résultat avec mysql_store_result()
  • sur ce résultat on récupère les lignes et les colonnes
  • on crée notre objet sqlData et on stocke dans les colonnes et les lignes
  • ensuite tant que l’on a des résultats on forge dans notre structure les données sous forme de chaîne de caractère.
  • on retourne le résultat
  • on vide le résultat de l’objet Mysql.

Fonction d’envoi de requête sans jeu de données

Voici la fonction qui permet d’envoyer une requête SQL sans jeu de retour (INSERT, UPDATE, DELETE par exemple) :

/**
  * Fonction requête sans jeu de résultat MYSQL
  */
void* dbRequestWithoutResult(MYSQL *aMysqlStruct, char aRequest[]) {
    if(mysql_query(aMysqlStruct, aRequest) != 0) {
        printf("Erreur : %s\n\n", mysql_error(aMysqlStruct));
        exit (1);
    }
}

Celle-ci est plus pour mettre en forme les fonctions par type d’utilisation plus qu’autre chose, puisqu’elle ne fait que l’action mysql_query().

Exemple d’utilisation

/** 
  * Exemple d'utilisation dans un programme principal (main)
  */
int main(void) {
    // Création de la connexion à la base
    MYSQL *mysqlConnect = dbInitialisation();
 
    // Requête qui retourne un résultat (type SELECT)
    dbRequestWithResult(mysqlConnect,"SELECT * FROM app_news");
 
    // Requête qui ne retourne aucun résultat (type UPDATE, DELETE)
    dbRequestWithoutResult(mysqlConnect,"UPDATE app_news SET app_news.test1=20");
 
    // Fermeture de la connexion à la base
    dbClose(mysqlConnect);
 
    return 0;
}

Voici un petit exemple d’utilisation des fonctions vues plus haut.