Utilisation de l'API MySQL avec Visual Basic

Romain Puyfoulhoux

Ce tutoriel est une adaptation d'un document écrit par LFE pour Borland C++ Builder. Il a pour but de montrer comment exploiter une connexion à une base de données MySQL, en utilisant uniquement l'API fournie avec MySQL. Le code a été écrit et testé avec Visual Basic 6 et MySQL version 3.23.49.

Pour une description des fonctions de l'API, je vous renvoie à la documentation fournie avec MySQL. ♪

- Titre : Utilisation de l'API MySQL avec Visual Basic

- Auteur : Romain Puyfoulhoux

- Parution : 4 janvier 2003

- Licence : Copyright (c) 2003 Romain Puyfoulhoux. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. Read the full license here : http://www.gnu.org/licenses/fdl.txt.

Sommaire

- I. Préparation

- II. Manipulation des pointeurs en Visual Basic

- III. Initialiser la connexion à MySQL

- IV. Fermer la connexion

- V. Se connecter à la base de données

- VI. Lister les tables dans la base de données

- VII. Accéder aux données de la table

- VIII. Lire la structure d'une table

- IX. Gestion des erreurs

- IX-A. Obtenir le code d'erreur

- IX-B. Obtenir un message décrivant l'erreur

I - Préparation

Vous devez tout d'abord recopier le fichier libmySQL.dll dans le répertoire windows. Ensuite il vous faut les déclarations des fonctions de l'API MySQL. Vous pouvez télécharger ma traduction des fichiers entêtes ici. Une fois le fichier .zip téléchargé, il vous suffit d'ajouter à votre projet les 3 modules contenus dans l'archive.

II - Manipulation des pointeurs en Visual Basic

Les fonctions de l'API Windows sont assez faciles à utiliser avec Visual Basic, car elles ne renvoient pas de pointeurs.
Mais la grande majorité des fonctions de l'API MySQL renvoient un pointeur, sur une structure ou sur une chaîne de caractères. VB ne permet pas de déclarer un pointeur sur une variable. Donc si nous avons besoin des champs de la structure renvoyée, ou de la chaîne de caractères, nous devons recopier la zone mémoire qui est pointée, dans une variable. Afin d'y parvenir, nous pouvons utiliser ces deux fonctions de l'API windows :

Private Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As Any, _
ByVal lpString2 As Any) As Long

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, _
Source As Any, ByVal Length As Long)

lstrcpy (lpString1, lpString2) recopie la chaîne qui est à l'adresse lpString2 dans la chaîne lpString1.

CopyMemory() recopie une zone mémoire dans une autre. Les paramètres sont :

- l'adresse de la zone mémoire de destination ;

- l'adresse de la zone mémoire à recopier ;

- le nombre d'octets à recopier.

Voyons comment récupérer une chaîne de caractères qui se trouve à une adresse donnée, à l'aide de lstrcpy() :

Private Function CopieChaine(ByVal adresse As Long) As String

Dim ret As String

If adresse > 0 Then
ret = Space(256)
lstrcpy ret, adresse
ret = Trim(ret)
If ret <> "" Then CopieChaine = left(ret, Len(ret) - 1)
End If

End Function

III - Initialiser la connexion à MySQL

Avant tout chose il est nécessaire d'initialiser l'accès à la DLL.

Dim pMySQL As Long

pMySQL = mysql_init(0)

Au retour, pMySQL contient l'adresse de la structure permettant l'interfaçage avec mySQL, ou 0 en cas d'erreur. Il est tout à fait possible d'avoir plusieurs connexions dans le même programme.

IV - Fermer la connexion

Dim pMySQL As Long

mysql_close (pMySQL)

mysql_close() ferme la connexion à la base de données et libère les ressources allouées lors de la création de la connexion.

V - Se connecter à la base de données

Dim pMySQL As Long

If mysql_real_connect(pMySQL, "127.0.0.1", "", "", "test", 0, "", 0) = 0 Then
' ...
' la connexion a échoué
' ...
Else
' la connexion a réussi

mysql_real_connect() ouvre la connexion à la base de données. Les paramètres sont :

- le handle de connexion ;

- l'adresse du serveur où mySQL est installé ;

- le nom de user ;

- le mot de passe ;

- le nom de la base de données ;

- le n° de port (0 indique que l'on utilise le port par défaut) ;

- le nom du pipe ou le socket qui sera utilisé (habituellement 0) ;

- des statuts permettant de configurer la connexion (habituellement 0).

Une valeur de retour nulle indique qu'une erreur s'est produite. Une valeur autre indique que la connexion est ouverte.

VI - Lister les tables dans la base de données

Private Sub EnumTables(pMySQL As Long)

Dim pMyROW As Long, myROW As Long, pMyRES As Long, i As Long

pMyRES = mysql_list_tables(pMySQL, "")

If (pMyRES <> 0) Then
For i = 0 To mysql_num_rows(pMyRES) - 1
pMyROW = mysql_fetch_row(pMyRES)
CopyMemory myROW, ByVal pMyROW, 4
ListBox1.AddItem CopieChaine(myROW)
Next
mysql_free_result (pMyRES)
End If

End Sub

mysql_list_tables() permet de lire le nom de toutes les tables de la base de données. Ses paramètres sont :

- le handle de connexion ;

- un masque permettant de filtrer les noms des tables à lire.

La valeur de retour est un handle vers le résultat de la requête, qui est un pointeur vers une structure MYSQL_RES. Si la requête échoue, la valeur de retour est nulle.

mysql_num_rows() renvoie le nombre d'enregistrements contenus dans le résultat.

mysql_fetch_row() permet d'accéder aux champs de l'enregistrement courant, et passe automatiquement à l'enregistrement suivant. En langage C, elle renvoie un tableau de chaînes de caractères, dont chaque élément contient la valeur d'un champ. Jetons un coup d'œil sur la déclaration de cette fonction en langage C :

typedef char **MYSQL_ROW;

MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result);

En C, un tableau de chaînes de caractères est un pointeur vers un pointeur sur une chaîne de caractères. Le tableau est en fait une chaîne unique, contenant les différentes chaînes juxtaposées, chaque chaîne se terminant par un caractère nul.

En VB, nous récupérons avec CopyMemory() le pointeur sur la chaîne de caractères, et enfin la chaîne de caractères elle-même avec la fonction CopieChaine(), que nous avons écrite précédemment. Ici chaque enregistrement ne contient qu'un seul champ.

Une fois que l'on n'a plus besoin du résultat de la requête, il ne faut pas oublier de libérer les ressources en appelant la fonction mysql_free_result().

VII - Accéder aux données de la table

Private Sub LitEnregistrements(pMySQL As Long)

Dim pMyROW As Long, myROW As Long, pLengths As Long, pMyRES As Long
Dim i As Long, j As Long, nbFields As Long, lengths() As Long, texte As String

If (mysql_query(pMySQL, "select * from tTest") = 0) Then

pMyRES = mysql_store_result(pMySQL)

If (pMyRES <> 0) Then

nbFields = mysql_num_fields(pMyRES)
If nbFields > 0 Then

ReDim lengths(0 To nbFields - 1)
For i = 0 To mysql_num_rows(pMyRES) - 1

pMyROW = mysql_fetch_row(pMyRES)
CopyMemory myROW, ByVal pMyROW, 4

pLengths = mysql_fetch_lengths(pMyRES)
CopyMemory lengths(0), ByVal pLengths, 4 * nbFields

For j = 0 To nbFields - 1
texte = Space(lengths(j))
lstrcpy texte, myROW
myROW = myROW + lengths(j) + 1
ListBox1.AddItem texte
Next
Next
End If
End If
mysql_free_result (pMyRES)
End If

End Sub

La fonction mysql_query() exécute une requête, et renvoie 0 si la requête a abouti.
Pour accéder au résultat de la requête, il est nécessaire d'appeler la fonction mysql_store_result(). Celle-ci renvoie un handle vers le résultat de la requête, qui est un pointeur vers une structure MYSQL_RES, ou 0 en cas d'erreur.

Nous pouvons ensuite lire les données. Vous voyez que la boucle qui est chargée de parcourir les enregistrements est ici plus complexe. Ceci vient du fait que nous avons plusieurs champs. mysql_fetch_row() nous renvoie la valeur des champs, juxtaposés dans une chaîne de caractères unique. Nous ne pouvons pas lire toute la chaîne de caractères en une seule fois. Car avec lstrcpy(), nous récupèrerons que le premier élément. Et avec CopyMemory(), nous devons connaître le nombre d'octets à lire.

La solution à notre problème est la fonction mysql_fetch_lengths(), qui renvoie un tableau contenant la longueur des différents champs.
Nous pouvons alors lire la valeur de chaque champ, un par un, en nous déplaçant dans la chaîne de caractères unique, et en copiant le nombre d'octets nécessaires à chaque fois. Le schéma ci-dessous montre un exemple de ce que l'on peut obtenir.

VIII - Lire la structure d'une table

Private Sub LitStructure(pMySQL As Long)

Dim pMyROW As Long, pMyRES As Long, pMyFields As Long, myFields() As MYSQL_FIELD
Dim aStr As String, CountFields As Integer, i As Integer

If (mysql_query(pMySQL, "select * from pet") = 0) Then

pMyRES = mysql_store_result(pMySQL)

If (pMyRES <> 0) Then

CountFields = mysql_num_fields(pMyRES)

If (CountFields > 0) Then

pMyFields = mysql_fetch_fields(pMyRES)
ReDim myFields(0 To CountFields - 1)
CopyMemory myFields(0), ByVal pMyFields, Len(myFields(0)) * CountFields

For i = 0 To CountFields - 1
aStr = "Le champ " & CopieChaine(myFields(i).name) & " est du type " & _
myFields(i).type
ListBox1.AddItem (aStr)
Next
End If
mysql_free_result (pMyRES)
End If
End If

End Sub

La fonction mysql_fetch_fields() renvoie un tableau de structures MYSQL_FIELD, dont chaque élément représente un champ de la table.
Les attributs de la structure MYSQL_FIELD sont les informations relatives à un champ.

IX - Gestion des erreurs

IX-A - Obtenir le code d'erreur

Dim myErrorCode As Long

myErrorCode = mysql_errno(pMySQL)

mysql_errno() renvoie le n° de l'erreur survenue lors du dernier appel à l'API, pour la connexion donnée. Une valeur nulle indique qu'il n'y a pas eu d'erreur.

IX-B - Obtenir un message décrivant l'erreur

Dim pMyErrorMsg As Long, myErrorMsg As String

pMyErrorMsg = mysql_error(pMySQL)
myErrorMsg = CopieChaine(pMyErrorMsg)

mysql_error() renvoie un message décrivant l'erreur survenue lors du dernier appel à l'API, pour la connexion donnée. Un message vide indique qu'il n'y a pas eu d'erreur.