De Eric
ROUMEGOU
ALL Rigts
reserved © 2003
WinDev®, WebDev® et HyperFile® sont des marques déposées par PC
SOFT.
Utiliser les accès natifs
avec Windev7.5.
Se rendre indépendant de la
base comme des accès utilisés
Quelques
techniques de programmation
Lire les données de la
requête
Inutile de revenir sur les nombreux débats entre moteur HyperFile et SGBD. Comme toujours en matière d’informatique, il y a des avantages, des inconvénients, des afficionados et des détracteurs pour chaque solution.
Pour ma part, je m’oriente systématiquement vers les SGBD standards du marché pour des questions de performances, d’ouverture et de pérennité. Choisir un SGBD, c’est la garantie de pouvoir utiliser n’importe quel outil de développement ou produit du marché.
Et quand - c’est l’objet de ce travail- je peux à tout moment changer de SGBD en fonction des besoins, d’un existant, de contraintes économiques sans rien modifier à mes applications, je me félicite d’avoir opté pour des standards.
J’ai découvert ces accès en 2003 et depuis je les utilise comme beaucoup d’autres développeurs de la communauté. J’ai pu apprécier la qualité de ces produits et surtout la disponibilité et la réactivité de leurs auteurs.
Ce sont des solutions très sérieuses car fiables et économiques.
Pour plus d’informations, je vous renvoie au site dédié à ces accès
Je les ai beaucoup utilisés avec des bases de données Oracle. Cela fonctionnait de façon très satisfaisante.
PC SOFT à d’ailleurs rajouté beaucoup d’accès natifs et l’on a maintenant des solutions pour les SGBD suivants (MySQL, Oracle, SQLserver, Sybase, DB2,Informix, Progress)
La plupart de ces accès sont payants. Même si le prix est raisonnable, on peut hésiter à acquérir tous ces accès juste pour tester l’éligibilité de ses produits avec chaque SGBD.
C’est l’intérêt des accès alternatifs.
Telle a été mon approche.
Lassé de gérer deux types de codes (mySQL et Oracle), et tenté par la possibilité de rajouter une 3ème base de données complètement gratuite (SQLite) à mes applicatifs, je me suis décidé à revoir tout mon code avec des classes pour répondre aux problèmes suivants.
Comment gommer les différences de langage SQL et fonctionnalités entre ces SGBD ?
C’est l’objet de la classe c_GestionSQL
Question technique, il n’y a pas de soucis, mais la pérennité de ces accès est peut-être plus incertaine. Même si les sources sont disponibles, je n’aurais pas forcément les compétences pour suppléer leurs auteurs en cas de gros problèmes.
Je dois donc à tout moment pouvoir revenir sur l’utilisation des accès payants. Il manque aussi l'accès SQL Server parmi les accès alternatifs..
C’est l’objet de la classe c_NatifSQL qui va "émuler" les accès alternatifs en utilisant les ordres SQL du WLangage.
Le fichier .Ini
Les chaînes de connexions sont paramètrées dans le fichier EWSQL4WD.ini. Veuillez en premier lieu, renseigner ces valeurs en fonction de votre environnement.
Vous trouverez des scripts de création des tables pour Oracle, mySQL et SQLite dans le rep SQL.
Il y a deux tables QUID et PERMIS.
Les dll des accès alternatifs se trouvent dans le rep Exe.
Pour les accès PC SOFT, veuillez utiliser celles que vous avez acquises chez l’éditeur.
Il s’agit de deux fenêtres Type Table et Mode Fiche. (QUID_TAB et QUID_FIC)
Elles permettent de gérer une table QUID qui est une gestion d’invite que j’utilise lorsque j’ai besoin de demander un choix à l’utilisateur. On définit le texte de cette invite, et les options possibles.
Vous pouvez bien sûr ré-utiliser cet exemple dans vos propres développements.
Le code de ces fenêtres a été généré par mon module de RAD. C'est pourquoi tout le code est centralisé dans des procédures afin de limiter mes opérations de transfert par copier coller.
Par ailleurs, j’ai du supprimé un certain nombre d’options qui ne sont pas utiles pour l’exemple.
monsql est un c_GestionSQL
monsql:AddWhere(pWhere)
monsql:SetSGBD(gBase)
monsql:AddSelect("QUID","QUID_ID") //Id Invite
monsql:AddSelect("QUID","QUID_TITRE") //Titre de l'invite
monsql:AddSelect("QUID","QUID_TEXTE") //Texte de l'invite
monsql:AddSelect("QUID","QUID_OPTION") //Options autorisées
monsql:AddSelect("QUID","QUID_OBLIG") //Obligatoire Oui=1
// EquiJointure
//monsql:AddJoin("QUID.ID=TABLEJOINTE.ID","INNER")
monsql:AddWhere(pWhereFiltre)
monsql:AddOrder(pOrder)
monsql:AddWhere(pWhere)
Commande=monsql:Rtv_ReqSQL()
Le principe est simple. On va passer par la méthode des classe c_GestionSQL, :
-
les zones composant le select monsql:AddSelect.
Il est possible d’écrire aussi monsql:AddSelect("QUID.QUID_ID")
- les jointures monsql:AddJoin
-
les
clauses where monsql:AddWhere(pWhere)
-
la
clause Order monsql:AddOrder
et c’est la méthode monsql:Rtv_ReqSQL() qui nous retournera la commande SQL correspondante en fonction du SGBD (défini par monsql:SetSGBD(gBase))
SI PAS fSQL:mySQLExec(Commande,lCurreq) ALORS
fSQL:mySQLMsgBox("Erreur
sur requete "+RC+Commande)
fSQL:mySQLFerme(lCurreq)
RENVOYER
Faux
SINON
fSQL:mySQLPremier(lCurreq)
TANTQUE
PAS fSQL:mySQLEnDehors
NumCol=0
NumCol++;QUID_ID=fSQL:mySQLCol(lCurreq,NumCol) //Id Invite
NumCol++;QUID_TITRE=fSQL:mySQLCol(lCurreq,NumCol) //Titre de
NumCol++;QUID_TEXTE=fSQL:mySQLColLong(lCurreq,NumCol) //Texte de
NumCol++;QUID_OPTION=fSQL:mySQLCol(lCurreq,NumCol) //Options
NumCol++;QUID_OBLIG=fSQL:mySQLCol(lCurreq,NumCol)
fSQL:mySQLSuivant(lCurreq)
FIN //TANTQUE pas
fSQL:mySQLEnDehors
FIN
fSQL:mySQLFerme(lCurreq)
C’est la technique (SQLpremier, SQLSuivant) que j’utilise le plus souvent.
Notez qu’avec SQLPremier SQLSuivant, il faut utiliser mySQLCOL (et mySQLColLong).au lieu de mysSQLLitCol
Cela est sans conséquence pour les accès alternatifs, voire pour l’accès Oracle PCSoft, mais pour l’accès Natif mySQL PC SOFT, SQLLitCol de fonctionne pas dans une boucle SQLPremier.
Les méthodes SQLColLong et SQLLitColLong ont été créées pour améliorer les performances de lecture sur l'accès mySQL4WD. Elles sont présentes pour compatibilité sur les autres accès. Il faut les utiliser dès que la colonne à récupérer est supérieure à 255 Caractères.
Pour utiliser SQLLitCol, il faut utiliser le SQLFetch
TANTQUE fSQL:mySQLFetch(lCurReq)
table2.IMP_PosDeb=fSQL:mysqllitcol(lCurReq,1)
table2.IMP_Posfin=fSQL:mysqllitcol(lCurReq,2)
// etc
FIN //TANTQUE fSQL:mySQLFetch(lCurReq)
fSQL:mySQLFerme(lCurReq)
monsql:RAZ()
monsql:SetCurrentTable(MyTable)
monsql:SetSGBD(gBase)
SI
{PrimaryKey}<>0 ALORS monsql:AddInsert("QUID_ID",QUID_ID)
monsql:AddInsert("QUID_TITRE",Quote(QUID_TITRE))
monsql:AddInsert("QUID_TEXTE",Quote(QUID_TEXTE))
monsql:AddInsert("QUID_OPTION",Quote(QUID_OPTION))
monsql:AddInsert("QUID_OBLIG",QUID_OBLIG)
Commande=monsql:CreeOrdreSQL("INSERT")
On positionne sur la table à mettre à jour monsql:SetCurrentTable
On ajoute les colonnes et la valeur à insérer monsql:AddInsert. Les chaînes alpha doivent être formatées avec la fonction Quote.
On récupère l’ordre INSERT correspondant.
Rmq : j’utilise les identifiants auto incrément avec mySQL et SQLite. Cela n’existe pas pour Oracle où j’utilise les séquences Oracle. Dans le cas de mySQL et SQLite, cette colonne n’est pas passée à l’ordre INSERT (car à 0) d’où le test SI {PrimaryKey}<>0 ALORS monsql:AddInsert("QUID_ID",QUID_ID)
monsql:RAZ()
monsql:SetCurrentTable(MyTable)
monsql:SetSGBD(gBase)
monsql:AddUpdate("QUID_ID",QUID_ID)
//Id
monsql:AddUpdate("QUID_TITRE",Quote(QUID_TITRE))
monsql:AddUpdate("QUID_TEXTE",Quote(QUID_TEXTE))
monsql:AddUpdate("QUID_OPTION",Quote(QUID_OPTION))
monsql:AddUpdate("QUID_OBLIG",QUID_OBLIG)
monsql:AddWhere(PrimaryKey+"=
"+{PrimaryKey})
Commande=monsql:CreeOrdreSQL("UPDATE")
Pour bloquer les enregistrements sélectionnés, vous pouvez utiliser les méthodes mySQLBloque. Pour ma part, je n’aime pas bloquer toute la requête, car si j’ai des tables liées dans ma requête (ex récupérer le nom du client pour affichage), je n’ai pas forcément envie de bloquer l’enregistrement client alors que je veux bloquer sa commande. Je préfère effectuer le blocage grâce à une requête plus limitée de type Select MonId from MatablePrimaire.
C’est le travail de la méthode BloqueLigne de c_GestionSQL
monsql:RAZ()
monsql:SetCurrentTable(MyTable)
monsql:SetPrimaryKey(PrimaryKey)
monsql:SetSGBD(gBase)
monsql:AddSelect("QUID","QUID_ID") //Id Invite
monsql:AddSelect("QUID","QUID_TITRE") //Titre de l'invite
monsql:AddSelect("QUID","QUID_TEXTE") //Texte de l'invite
monsql:AddSelect("QUID","QUID_OPTION") //Options autorisées
monsql:AddSelect("QUID","QUID_OBLIG") //Obligatoire Oui=1
monsql:AddWhere(pWhere)
Commande=monsql:Rtv_ReqSQL()
// Blocage de la ligne et débute la transaction
SI ModeAppel="MODIFY" ALORS
SI PAS monsql:BloqueLigne(0,Quoi) ALORS
Erreur(monsql:m_MsgErreur)
gWhere="" // Ne pas réafficher
Ferme
FIN
FIN
La méthode Bloque_Ligne va créer une requete de type SELECT QUID_ID FROM QUID WHERE QUID_ID=2 et ce sont ces lignes qui seront bloquées. La requête a été générée grace au méthode SetCurrentTable, SetPrimaryKey et la valeur de la clé récupérée du membre m_ClauseWhere.
Si ces lignes sont déjà bloquées, un message personnalisé monsql:m_MsgErreur sera renvoyé.
Les fonctions et procédures peuvent parfois faire double emploi avec les méthodes de la classe c_GestionSQL. Ce sont d'ailleurs ces procédures qui ont été adaptées en classe. Je les ais conservées car elles sont quelque fois plus facile à utiliser que les classes, et surtout par compatibilité avec mes anciens projets.
Il y a par ailleurs quelques fonctions complémentaires utiles.