Domino goes mySQL

Blaz a écrit le Mercredi 10 Décembre 2003 à 20:06:48

Voilà un problème auquel nous sommes tous un jour confronté : faire communiquer domino et une base de données relationnelles. (dans mon cas mySQL).
Et en général, commence une longue quête vers la Connaissance.
Donc autant vous faire partager ce que je sais, vous gagnerez du temps. Par contre, je ne prétend pas être exhaustif et je vous conseille vivement de lire la documentation.

Il existe plusieurs solutions Lotus pour la connexion domino->SGBD-r, comme LEI ou DECS ou des produits "add-on" spécifiques. Mais, LEI et DECS ont chacun leurs inconvénients et tout le monde n'a pas le budget pour des "add-on".

En fait, j'avais besoin de pouvoir exporter mes données notes vers une base de données relationnelles. Ce qui dans mon cas, signifait que je devais pouvoir insérer des données dans mon sgbd-r et pouvoir en récupérer le cas échéant pour ne pas ré-insérer deux fois la même choses.
Donc pour faire simple, j'avais besoin d'un bout de programme capable de gérer tous les types de requêtes (insert, update, delete,select).

1 - librairie LSX-LC

Commence la Quête. Après avoir erré de longues heures à travers les documentations, les forums, après avoir frôlé la folie dans les solitudes glacées de l'incompréhension, j'ai trouvé un début de piste. La librairie LSX-LC dont la documentation se trouve dans le répertoire HELP de la racine du serveur.
Cette librairie contient toutes les fonctions nécessaires pour se connecter à une base de données. C'est l'accès quasi universel en lotusscript.

Petit bémol tout de même :
domino en version R5 n'a que quelques drivers natifs : oracle, sybase, DB2 et ODBC. Donc dans mon cas, passage obligé par ODBC. Ce qui veut dire, qu'avant de se lancer dans la programmation, il faut configurer un accès ODBC pour chaque base de données relationnelles. Par ailleurs, ODBC doit être installé et configuré sur la machine qui exécute le script.
Pour les systèmes d'exploitation, et les gens qui ne supportent pas ODBC, il existe une autre solution : l'agent java. En effet, on peut implémenter du java dans domino, donc vous pouvez utiliser JDBC.

2 - tir de requête

Pour en revenir à mon problème, il me fallait une sous-routine capable d'éxécuter des requêtes SQL et de renvoyer un résultat intelligible pour le reste du programme.
C'est un choix personnel, mais j'ai préféré garder tout ce qui concerne l'accès aux données SQL dans la sous routine et celle-ci renvoie un tableau à deux dimensions.

Dans un agent , mettre dans la catégorie "options" :

1 UseLsx "lsxlc"

On importe la librairie de script lsxlc.

Dans la catégorie "initialize" :

1 Dim lc_session as New LCsession
2 Dim source as new LCconnection("odbc2")
3 Dim requete as String
4 Dim unTableauResultat() as String

5 lc_session.clearStatus
6 source.server="maSourceODBC"
7 source.userID="monLogin"
8 source.password="monPassword"
9 source.connect

10 requete="SELECT nom,prenom,mail FROM maTable WHERE ville='paris' "

11 Call tirDeRequete(source,requete,tableauResult)

12 source.disconnect

Ici on va créer la connexion entre domino et odbc (ligne 2) puis l'initialiser (l 6 à 9). En ligne 11, on appelle la sous routine en passant en paramètres, la source de connexion, la requete SQL et le array qui contiendra le résultat de la requête. L'avantage de passer la source en paramètres est de pouvoir travailler avec plusieurs sources ODBC dans le même agent. De même pour l'argument array, cela permet de conserver le résultat de requêtes précédentes.
En ligne 12, on ferme la connexion. On peut s'en passer dans la mesure ou quand l'agent se termine, la connexion se termine aussi.

1 Sub tirDeRequete(source As LCconnection, requete As String, tableau() As String )

2 On Error Goto hellTir

3 Dim nbLignesAffectees,nbLignes,nbCols,posSelect As Integer
4 Dim unChamp As LCfield
5 Dim resultSet As New LCFieldList

6 nbLignes=0
7 posSelect=Instr(1,Lcase(requete),"select",5)

8 nbLignesAffectees=source.execute(requete,resultSet)

9 If(nbLignesAffectees> 0) And ( posSelect>0 And posSelect<7 ) Then
10
11
nbCols=resultSet.FieldCount
While (source.fetch(resultSet)>0)
12
13
  Redim Preserve tableau(0 To nbCols-1, 0 To nbLignes)
For i=1 To nbCols
14
15
    Set unChamp=resultSet.getField(i)
tableau(i-1,nbLignes)=unChamp.text(0)
16
17
  Next
nbLignes=nbLignes+1
18 Wend
19 Else Then
20
21
Redim tableau(0 To 0, 0 To 0)
tableau(0,0)=nbLignesAffectees
22 End If

23 Exit Sub

24 hellTir:
25
26
27
28
Print "REQUETE : " & requete & " >> " & Error$ & " à la ligne" & Erl()
Redim tableau(0 To 0, 0 To 0)
tableau(0,0)="0"
Exit Sub
29 End Sub

En ligne 7, la variable posSelect va contenir la position éventuelle du mot select dans la requête.
En effet, c'est seulement dnas le cas d'une requête SQL type select que l'on va "dépiler" le resultset avec la commande fetch.
En ligne 8, la requete est exécutée; la commande execute renvoie le nombre de lignes affectées par la requête SQL.
En ligne 9, on vérifie qu'il y a un résultat de requête (le nombre de lignes affectées est supérieur à 0) et que la requête est de type insert (la position du mot insert doit être comprise entre 0 et 7 dans la requête SQL)

Le resultset (déclaré ligne 5) peut être assimilé à un tableau de données. Une ligne représente une ligne de table et chaque colonne représente une donnée pour une ligne.
On récupère le nombre de colonnes (ligne 10).
A la ligne 11, on commence la boucle sur toutes les lignes du resultset et en ligne 12 on redimensionne le array en ajoutant une ligne.
En ligne 13 , on boucle sur toutes les colonnes du resultset et on les intègre à l'array (ligne 15).
En ligne 21, on traite le cas ou la requête SQL n'est pas de type insert. Dans ce cas on affecte à l'array le nombre de lignes affectées.
En cas d'erreur, le message s'affiche en ligne 24 à 28 et le tableau est renvoyé avec 0 comme valeur.

Pour résumer, dans le cas d'un insert, delete ou update réussi, le tableau renvoyé contient le nombre de lignes affectés (unTableau(0,0)=12 par exemple).
Dans le cas d'un select, le tableau contient les données.
Si la requête n'a eu aucun effet sur la base ou n'a rien sélectionné, le tableau contient 0. (unTableau(0,0)=0).

3 - inversion

Ca a l'air simple comme ça, mais il existe une petite subtilité. Avec DominoR5, les arrays multidimensionnels ne peuvent être retaillés que sur la première dimension. Ce qui , dans notre cas pose problème, car à chaque fois qu'on ajoute une ligne, c'est la première dimension qui est agrandie.
Conséquence : les lignes deviennent des colonnes et vice versa.

Si mon resultSet contient 5 lignes et que ma requete demandait trois colonnes
j'obtiens un tableau de données de 3 lignes et de 5 colonnes.

RESULTSET
  nom prenom mail
1 dupont jean jean@dupont.fr
2 lajoie robert robert@lajoie.com
3 boudiou janine jboudiou@wana.net
4 tubal arthur a.tubal@glop.fr
5 crozet carole ccrozet@shiva.com



Mais du fait du redimensionnement uniquement sur la première dimension, le tableau renvoyé par la routine tirDeRequete aura cette forme :
UNTABLEAU()
  1 2 3 4 5
nom dupont lajoie boudiou tubal crozet
prenom jean robert janine arthur carole
mail jean@dupont.fr robert@lajoie.com jboudiou@wana.net a.tubal@glop.fr ccrozet@shiva.com

Donc pour obtenir le mail de jean dupont on fait : unTableau(3,1). Dans le tableau retourné par la fonction, le premier indice représente le type d'info (nom, prenom ou mail) et le deuxième le numéro de "lignes" (1,2,3,4 ou 5).

4 - stabilité et bugs possibles
J'ai fait tourner cette fonction pour exporter ma base domino vers mySQL. Ce qui représente environ 400 000 INSERT et 120 000 SELECT au total. L'opération entière a été effectuée en une heure et demi (mais plusieurs autres traitements avaient lieu entre chaque INSERT).
L'agent n'a pas planté, la consommation de mémoire est restée stable et je n'ai pas rencontré de String overflow. C'est à dire, que le tableau retourné est capable d'appréhender des textes de grandes longueurs. Dans mon cas, ce sont des pages HTML entières qui étaient contenues dans le tableau pendant l'opération d'import et je n'ai pas rencontré de souci.

Un des bugs que vous risquez de rencontrer le plus souvent concernent les guillemets et autres apostrophes. N'oubliez pas d'ajouter un slash devant chaque apostrophe ou guillemets dans les requêtes.
Par ailleurs, il semble que sous notes, de temps en temps, l'apostrophe classique (code ASCII : 39 ) soit remplacé par un autre apostrophe dont la forme est légèrement différente (code ASCII : 146 ). Si a l'oeil nu, il est difficile de faire la différence (surtout avec des petites polices), une fois transféré dnas mySQL (pour les autres bases je ne sais pas), on voit très bien la différence. L'apostrophe classique s'affiche sans problème mais à la place du "faux apostrophe" on voit s'afficher un caractère bizarre : Æ
Là aussi, il sera nécessaire de mettre en place une sous routine de rechercher/remplacer.

Enfin, chose curieuse, (qui n'arrive que sur mon poste apparament) , quand ma requête select ne renvoie aucun résultat, la sous routine tirDeRequete plante à la ligne 8 avec comme message :
" A fixed-length stream requires a non-zero length "
Dans la mesure ou de toute façon le tableau est renvoyé avec zéro comme valeur, celà n'affecte pas le reste du programme. Je n'ai jamais vraiment cherché à corriger cette erreur (manque de temps) alors si vous trouvez la solution, écrivez-moi.

5 - environnement

Mon domino est un R5.0.9a et mon SGBD-r est un mySQL 4.0.13. Ils sont tous les deux installés sur la même machine.
La machine serveur est un PC pentium III 667MHz avec 256 Mo de RAM. Le système d'exploitation est Windows NT Server SP6

Commentaire(s)

Re: Domino goes mySQL

darwah-group.com le 07/07/2004 15:41:22

Je ne sais pas encore si ca marche, mais j'ai changé un peu, car il y avait une erreur :

- il faut lire 'Call tirDeRequete (source,requete,untableauResultat)' à l'avant dernière ligne.

Re: Domino goes mySQL

artacus le 11/06/2004 19:35:54

Pour ma part, je ne suis même pas en mesure de faire uselsx "lsxlc" et ce, mêm si la libraire se trouve bel et bien dans le répertoire de l''aplication !!??

Re: Domino goes mySQL

Rapha■l le 17/06/2005 23:31:07

mille mercis pour ce bout de codes avec les explications; cela m'a permis d'optimiser mes requ■tes sur les bases mySQL centralis■es et de gagner du temps.

Cela fonctionne comme un charme.

A bient■t,

Rapha■l

Re: Domino goes mySQL

toome le 05/12/2005 17:23:11

Bonjour,

je vois que vous êtes des maitres en dev Lotus !! moi jsui entrain de soufrir avec ça !!

je veux me connecter ç une base Oracle en passant par les objets LC, jusque là ça marche, j'arrive à requter la base, ok tant mieux... mais je veux appeler des procédures stockées..et là ça foire...j'ai vu un code sur l'aide de Domino Designer, j'ai rien compris, il y a eu des champs d'entrée et de sortie lors de l'appel à la procedures, bref, je patine.

Aurez-vous une idées sur comment appeler une proc stock pour insertion, selection et update des données d'une BD oracle ??

merci d'avance

Re: Domino goes mySQL

Olivier@Dominux le 06/12/2005 10:49:29

@Toome : je te suggères de poser ta question dans le forum. { Link }

Re: Domino goes mySQL

toome le 09/12/2005 13:38:44

j'ai posté ici :

{ Link }

mais apparament IBM paie les gens pour qu'ils ne fassent pas beaucoup de forum pas beaucoup de doc, peu de réponse !!!

là je commence à perdre espoire !!

t'as des liens? des forums ? des doc? des livres à recommander?

jveux acheter le livre d'IBM : Domino Designer 6 ou 7 mais en Français et j'ai pas trouvé !!

Re: Domino goes mySQL

Olivier@Dominux le 10/12/2005 19:13:58

Malheureusement pour toi, les ressources françaises sont rares. Tu peux utiliser le forum de référence anglais { Link } sur lequel tu auras certainement plus de retour pour ton type de problème.

encore des galères

Vilain Mamuth le 20/05/2011 17:21:32

un grand merci pour ton article, je m'obstinais bêtement à vouloir mettre un nom de serveur dans la propriété "server".... qu'est ce qu'on peut être borné parfois....

Ajouter un commentaire





Se souvenir de mes informations?



Les balises HTML ne sont pas permises dans les commentaires. Pour faire un lien, il suffit de donner l'URL, préfixée par http://.