IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Utilisation de Kylix pour écrire une UDF Firebird sous Linux

Utilisation de Kylix pour écrire une UDF (user defined function) pour Firebird sous Linux

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

La norme SQL ne prévoit pas beaucoup de possibilités de calculs à l'intérieur des requêtes. Interbase et Firebird, qui respectent la norme SQL d'assez près, ne fournissent pas plus de support pour les calculs. Par contre, ils disposent d'une possibilité d'extension avec l'importation de fonctions de calcul depuis des librairies externes à chargement dynamique. Il s'agit des UDF, User Defined Functions. Le terrain de prédilection de ces fonctions va être les calculs mathématiques ou les traitements de chaînes. Les fonctions seront exécutées sur le serveur, tout comme les procédures stockées. Pour ceci, ces librairies dynamiques doivent être installées sur le même ordinateur que le serveur Interbase/Firebird, en tenant compte de son système d'exploitation. Si Interbase/Firebird tourne sous Linux, la librairie devra être compilée pour Linux.

Dans la suite de cet article, je vais vous montrer comment créer et mettre en œuvre une telle librairie pour un serveur Firebird sous Linux/i386 à l'aide Kylix.

D'un point de vue pratique, j'ai utilisé un serveur SME 6.0 qui dérive de RedHat 7.3. J'ai installé dessus Firebird 1.5.2 SuperServer (FirebirdSS-1.5.2.4731-0.rpm). Kylix 2 était installé sur une station de travail avec RedHat 9.

II. Écriture de la librairie

Il faut écrire une librairie dynamique (.so shared object sous Linux, DLL sous Windows). Dans mon cas, je voulais calculer la distance entre deux points vers la surface de la terre en fonction de leurs latitudes/longitudes respectives. Il y a une petite formule à base de sinus et cosinus dont je vous dispense. J'ai démarré Kylix. J'ai fait Fichier|Nouveau|Autre ... Comme je n'ai pas trouvé de quoi faire une librairie, j'ai pris l'option Application console. J'ai mis le code suivant :

 
Sélectionnez
library geocentric;

uses
  Math;

{$APPTYPE CONSOLE}

function GEO_DISTANCE(var Lat1, Long1, Lat2, Long2 : double) : double; cdecl; export;
// calcul la distance entre deux points à la surface de la sphère
// le résultat est en radian
// à multiplier par le rayon de la sphère pour avoir une distance réelle
begin
  result:=arccos(sin(Lat1)*sin(Lat2)+cos(Lat1)*cos(Lat2)*cos(Long2-Long1));
end;

exports
  GEO_DISTANCE;

end.

Notez que pour la première ligne, j'ai remplacé Program par Library. J'ai aussi donné un nom (geocentric) à ma librairie et j'ai sauvé le projet avec le même nom. La fonction est exportée avec la convention cdecl. Une compilation et ma librairie sont prêtes. Le fichier résultant s'appelle libgeocentric.so avec lib accoler au début du nom.

III. Installation de la librairie sur le serveur

Il faut maintenant prendre le fichier libgeocentric.so et le copier sur le serveur dans le dossier /opt/Firebird/UDF/. Nous allons changer ses droits pour que l'utilisateur Firebird puisse s'en servir et personne d'autre. On se connecte à la ligne de commande Linux en root et on exécute les instructions suivantes :

 
Sélectionnez
chmod 500 /opt/Firebird/UDF/libgeocentric.so 
chown Firebird /opt/Firebird/UDF/libgeocentric.so 
chgrp Firebird /opt/Firebird/UDF/libgeocentric.so

Le mode 500 correspond à la lecture et l'exécution du fichier, mais sans modification possible, et le tout uniquement pour le propriétaire (Firebird).

IV. Utilisation sous Firebird

Pour utiliser la fonction sous Firebird, il faut commencer par la déclarer. Toujours en étant connecté sur le serveur en root, démarrez ISQL et connectez-vous à la base où vous voulez utiliser votre fonction.

 
Sélectionnez
/opt/Firebird/bin/ISQL
connect waypoints.fdb user SYSDBA password 'passSysdba';

La déclaration elle-même, toujours dans ISQL :

 
Sélectionnez
DECLARE EXTERNAL FUNCTION GEO_DISTANCE
DOUBLE PRECISION, DOUBLE PRECISION, DOUBLE PRECISION, DOUBLE PRECISION
RETURNS DOUBLE PRECISION BY VALUE 
ENTRY_POINT 'GEO_DISTANCE' MODULE_NAME 'libgeocentric.so';

Il n'y a plus qu'à tester votre fonction.

 
Sélectionnez
SQL> select geo_distance(0.8,0.1,0.9,0.2) from rdb$database;

           GEO_DISTANCE
=======================

     0.1197329466389183

Et ça marche... Vous pouvez alors utiliser votre fonction où vous voulez comme dans un SELECT.

 
Sélectionnez
SELECT ID_WAYPOINT, 
  GEO_DISTANCE(0.79,0.1,WP_LATITUDE,WP_LONGITUDE) AS DISTANCE
FROM WAYPOINTS
WHERE (GEO_DISTANCE(0.79,0.1,WP_LATITUDE,WP_LONGITUDE)<=0.01)
ORDER BY 2;

Cette charmante requête va me sélectionner l'ID et la distance de tous les points GPS autour d'un point au sud de la Chartreuse (45°15'49''N/5°72'96''E), dans un rayon de 63,71 km (rayon_terre x 0,01) et va me classer l'ensemble suivant la distance.

V. Conclusion

L'exemple présenté dans cet article a permis de voir comment programmer et mettre en œuvre une fonction définie par l'utilisateur pour l'utiliser dans Firebird sous Linux. C'est très simple et il ne faut pas hésiter à s'en servir si on en a besoin. Bien que je n'aie pas testé, la méthode doit s'appliquer à l'identique avec Interbase.

A priori, le même mécanisme doit être possible sous Windows avec Delphi en générant une DLL. Je n'ai pas fait d'essai. Il doit falloir remplacer cdecl par stdcall dans l'entête des fonctions. N'hésitez pas à aller voir le tutoriel sur la Image non disponiblecréation de DLL avec Delphi. À terme, je pense plutôt passer à FreePascal d'une part parce que Kylix est une branche morte et d'autre part pour supporter une plus grande variété de serveurs et d'OS, comme Firebird lui-même et avec en ligne de mire la plateforme x86_64 qui pourrait se généraliser en serveur sous Linux et Windows. Certains ont déjà essayé avec succès d'utiliser FreePascal.

Je n'ai pas abordé le problème des chaînes de caractères renvoyées en résultat d'une fonction. L'article qui m'a servi de support pour écrire ce didacticiel en parle longuement. Il y a quelques difficultés, analogues à celles qu'on rencontre quand une fonction d'une DLL classique écrite avec Delphi doit renvoyer une chaîne de caractères. Le tutoriel sur Strings et PChars en Delphi aborde aussi cette difficulté et explique les fonctionnements sous-jacents.

Liste de mes articles

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 Eric SIBERT . Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.