samedi 29 mars 2003

Base de registre


BASE DE REGISTRE

La base de registre constitue le système nerveux de Windows. Une panoplie d'information y est entreposée. Il est possible d'intervenir sur le matériel, logiciel et sur le système d'exploitation grâce à la base de registre. Cette base de données peut aisément devenir énorme (des centaines de meg). Elle peut souvent rendre service, mais trop souvent elle est utilisée à tort. Il n'est pas rare de voir un programme qui y laisse sa trace même si le programme en question n'existe pu.

La structure du registre

La base de registre est divisée en 5 sections
  • HKEY_CLASSES_ROOT
  • HKEY_CURRENT_USER
  • HKEY_LOCAL_MACHINE
  • HKEY_USERS
  • HKEY_CURRENT_CONFIG

HKEY_CLASSES_ROOT

Cette section permet de lier un type de fichier à un programme

HKEY_CURRENT_USER

Cette section contient tous les paramètres utilisateurs de celui qui est connecté

HKEY_LOCAL_MACHINE

Cette section contient tous les paramètres du système relatif à tous les utilisateurs

HKEY_USERS

Cette section contient toutes les préférences de tous les profils utilisateurs

HKEY_CURRENT_CONFIG

Cette section les informations sur le matériel du système
Nous avons vu les différentes sections de la base de registre. Il est bien attendu possible de lire et d'écrire dans ces sections.

Méthode

Il existe différentes méthodes disponibles dans Delphi permettant d'effectuer divers traitements dans la base de registre. L'unité «Registry» doit être ajoutée dans la section «uses» afin de pouvoir utiliser les méthodes liées à la base de registre.

Exemple

Nous allons créer un petit programme qui créer une clé dans la base de registre qui dira au programme la couleur que la forme doit prendre.

Lecture

Var
  Registre : TRegistry;
  tmpCouleur:integer;
begin
   //Crée un objet TRegistry
  Registre:=TRegistry.Create;
  //Définit la clé principale
  Registre.RootKey:=HKEY_LOCAL_MACHINE;
  //Ouvre la clé et la crée si elle n'existe pas
  Registre.OpenKey('\Software\BorlandRulez\Test\',True);
  if Registre.ValueExists('Couleur') then
  begin
    tmpCouleur:=Registre.ReadInteger('Couleur');
    ColorBox1.ItemIndex := tmpCouleur;
    form1.Color := ColorBox1.Colors[ColorBox1.ItemIndex];
  end
  else
  begin
    showmessage('Veuillez écrire une valeur avant de pouvoir écrire');
    Button1.Enabled := False;
  end;
  //Ferme la clé
  Registre.CloseKey;
  //Détruit l'objet
  Registre.Free;
end;
 
Nous pouvons voir sur l'image ci-dessous l'effet qu'a la méthode «OpenKey» lorsque la clé n'existe pas. L'arborescence est crée. La clé Couleur fait partie de cette arborescence. Sa valeur est 23 (sa valeur en décimal est entre paranthèse)selon cette image.

Écriture

Var
  Registre : TRegistry;
begin
   //Crée un objet TRegistry
  Registre:=TRegistry.Create;
  //Définit la clé principale
  Registre.RootKey:=HKEY_LOCAL_MACHINE;
  //Ouvre la clé et la crée si elle n'existe pas
  Registre.OpenKey('\Software\BorlandRulez\Test\',True);

  if ColorBox1.ItemIndex = -1 then
    ColorBox1.ItemIndex := 0;
  //Écrit la valeur
  Registre.WriteInteger('Couleur',ColorBox1.ItemIndex);
  //Ferme la clé
  Registre.CloseKey;
  //Détruit l'objet
  Registre.Free;
end;

Suppression

Var
  Registre : TRegistry;
begin
   //Crée un objet TRegistry
  Registre:=TRegistry.Create;
  //Définit la clé principale
  Registre.RootKey:=HKEY_LOCAL_MACHINE;
  //Ouvre la clé et la crée si elle n'existe pas
  Registre.OpenKey('\Software\BorlandRulez\Test\',True);
  //Écrit la valeur
  Registre.WriteInteger('Couleur',2);
  //Efface la valeur
  Registre.DeleteValue('Couleur');
  Registre.CloseKey;
  //Détruit l'objet
  Registre.Free;
end;


En exécutant ce code, la valeur 'Couleur' est enlevée de la base de registre. Il serait possible d'enlever la clé test en utilisant la méthode DeleteKey.

 
if Registre.KeyExists('\Software\BorlandRulez\Test\') then
  Registre.DeleteKey('\Software\BorlandRulez\Test\');

La méthode KeyExists permet de savoir si la clé existe, une telle méthode existe aussi pour les valeurs: ValueExists

Nous avons pu voir que la base de registre permet d'obtenir beaucoup d'information sur le matériel, logiciel et sur Windows. Il est aussi possible de l'utiliser afin de créer une configuration par défaut de notre programme. Elle peut alors remplacer l'utilisation des fichiers ini.

Code source disponible ici

samedi 21 décembre 2002

Delphi 7 studio



Ce livre aborde la programmation sous Windows et Linux.

Ce livre ne touche pas uniquement à Delphi, on y aborde des sujets tels que l'ergonomie, uml... Delphi est mise en avant première à travers les nombreux concepts vus.

Même si ce livre est consacré à la version 7 de Delphi, il est fort utile pour les autres versions de Delphi. Comme la majorité des livres, il manque d'exemples approfondis et on survole parfois trop certains sujets.

Ce livre demeure tout de même la référence présentement des livres en français sur Delphi.

lundi 16 décembre 2002

Software Engineering: Theory and Practice




Ce livre introduit les concepts du génie logiciel. Le développement avec l'approche procédurale et orienté objet y sont discuté.

L'emphase du livre est mise sur la modélisation. Les concepts montrés sont appuyés par deux exemples: un système d'information et un système temps réel.

En plus de cet aspect, la planification et la gestion de projet y fait partie. L'analyse chez le client afin de pouvoir définir les spécifications, le design du système ainsi que les tests font partie des chapitres que couvre ce livre.

Un livre très complet qui permet de faire le pont entre la théorie et la pratique.

dimanche 8 décembre 2002

Html


HTML

Le HTML est lisible sur toute plateforme qui possède un navigateur internet. On peut ainsi dire la majorité. Il peut alors être intéressant d'utiliser cette compatibilité afin de toucher le plus de gens possible. Bien sûr il existe divers formats de type de fichier, mais il arrive trop souvent que le logiciel permettant de lire un type de ficher donnée ne se trouve sur la plateforme désiré, que le rendu n'est pas semblable d'un système à un autre ou que notre confidentialité est mise en doute.

Nous pouvons alors utilisé le HTML pour créer divers types de document qui sera lisible à peut prêt partout et qui à l'avantage d'être très léger.

TPageProducer

Ce composant permet de créer des pages web à partir d'un modèle. Il existe aussi possible d'utiliser le TDataSetPageProducer (bd). Il est alors possible de créer des lettres génériques. Les mots génériques créés par nous sous la forme " <#nom_du_tab> seront par la suite changé par une valeur désirée.

Modèle

<HTML>
  <HEAD>
    <TITLE> </TITLE> 
  </HEAD>
  
<BODY>

<p> <#date>  </p>
<p> Traitement Automatisé des Fiches de salaire.</p>


<p> <#nom_employe> </p>

<p>Nos archives indiquent que n'avez pas pris de journée de congé au cours des <#annee> dernière(s) 
année(s).

Vous n'êtes pas sans savoir que notre entreprise accorde 2 semaines de congés payés aux employés 
par an, ou bien leur offre la possibilité de prendre l'équivalent en salaire.

En outre, en accord avec les conventions signées avec les syndicats vous accorde une 
semaine supplémentaire de congés payés pour chaque période de cinq années de travail dans l'entreprise.
</p>

<p>Bien à vous,</p>

<p>La comptabilité</p>
</body>
</html>
 
Nous pouvons voir que la lettre ci-dessus est générique. Elle pourrait par exemple être envoyé au employé d'une entreprise. Elle présente quelques tags personnalisés.
  • <#date>
  • <#nom_employe>
  • <#annee>
Il serait possible par exemple de prendre des valeurs dans une base de donnée et de remplacer ces tag. Les possibilités sont alors immenses: envois de courriel, lettre...

Fonctionnement

Il faut spécifier le nom de notre fichier HTML générique par la propriété HTMLFile du TPageProducer. Il faut ensuite indiquer les tags devant être modifiés et spécifier leurs valeurs.

var      
  S:string;
begin
  S := PageProducer1.Content; //Renvoi le contenu après les modifications des tags.
  if Length(S) > 0 then
    with TFileStream.Create('tmp.htm', fmCreate) do
    try
      Write(S[1],Length(S));
    finally
      Free;
end;
 

Le remplacement des tags par les valeurs souhaitées se déroule dans l'évènement HTMLTag.
Note que dans notre code nous avons écris <#date> mais qu'il faut seulement écrire date dans cet
évènement.

procedure TForm1.PageProducer1HTMLTag(Sender: TObject; Tag: TTag;
  const TagString: String; TagParams: TStrings; var ReplaceText: String);
begin
 if TagString = 'date' then
    ReplaceText := '12 juillet'
 else if TagString = 'nom_employe' then
    ReplaceText := 'Mr. Gendron'
 else if TagString = 'annee' then
    ReplaceText := '10';
end;
 

Nous avons utilisé des valeurs statiques dans cet exemple, mais il aurait été possible
d'utiliser des valeurs d'une base de données.

mardi 3 décembre 2002

Algorithme de tri


ALGORITHME DE TRI

Il existe de nombreux algorithmes de tri, je tenterais seulement de vous montrer les plus populaires et les plus utilisés.

Il n'y a pas vraiment de tri qui soit meilleur que les autres, la vitesse d'exécution d'un algorithme dépend des donnés à trier. Certains algorithmes sont plus efficaces dans certaines circonstances c'est ce que nous tenterons de vous montrer

Complexité

Dans le but de mesurer la complexité d'un algorithme de tri,deux quantités sont à observer :
  • le nombre d'échanges effectués,
  • le nombre de comparaisons effectués entre éléments du tableau.

Grand O

Le grand O  est utilisé pour indiquer la croissance d'une fonction. Le symbole utilisé est O.

Grand oméga

Le grand oméga est utilisé pour avoir la limite inférieur d'une fonction, en d'autre mot le minimum. Le symbole utilisé est Ω

Les tries

Buble sort

Ce type de tri est le plus simple, mais souvent le moins efficace. Il peut s'avérer utile pour des petits tris étant donné sa simplicité, il y a peu de chance de faire des erreurs.
L'idée du buble sort est de comparer un élément à son voisin et de les permuter si l'élément est plus grand que celui-ci.

procedure BubbleSort(var tabNote: array of Integer);
var
  i,j: integer;
  temp: integer;
begin
  for i := high(tabNote) downto low(tabNote) do 
    for j := low(tabNote) to high(tabNote)-1 do 
      if tabNote[j] >tabNote[j + 1] then 
      begin
        temp := tabNote[j];
        tabNote[j] := tabNote[j + 1];
        tabNote[j + 1] := temp;
      end;
end;
 
Comme vous pouvez le voir un tel algorithme est lent, imaginez trier 1000 000 de donnés avec ça. Vous pouvez remarquer que lorsqu'on change de position l'élément, il arrive souvent que le tableau soit trié avant que l'algorithme soit fini. On peut aisément améliorer cela en ajoutant une petite vérification.

procedure BubbleSort(var tabNote: array of Integer); 
var 
  i,j: integer;
  temp: integer; 
  Test: Boolean; 
begin 
  for i := low(tabNote) to high(tabNote) do begin  
    Test := false;
    for j := low(tabNote) to high(tabNote) - 1 do begin 
      if tabNote[j] > tabNote[Succ(j)] then begin 
        temp := tabNote[j]; 
        tabNote[j] := tabNote[Succ(j)];
        tabNote[Succ(j)] := temp;
        Test := true; 
      end; 
    end; 
    if not Test then break; 
  end; 
end;

Complexité

La complexité est O(n^2) pour des données mélangées, mais l'approche est O(n) si la liste est presque trié au début.

Insertionsort

Cette méthode est semblable à celle que nous utilisons lorsqu'on trie des cartes. Nous prenons chaque nouvelle carte et nous l'insérons à la bonne position dans le paquet déjà trié. Ce tri est particulièrement rapide lorsqu'il y a peu de désordre.

procedure Insertionsort(var tabNote: array of Integer); 
var 
  i, j: Integer; 
   temp: Byte; 
begin 
  tabNote[0] := 0;          //garde l'algo hors de l'alignement 
  for i := 2 to high(tabNote) do begin 
                           //débute à 2 puisque le premier élément 
                           //n'est ni plus petit 
                           //ni plus grand que lui-même
    temp := tabNote[i] ;
    j := i; 
    while tabNote[Pred(j)] > temp do 
    begin
      tabNote[j] := tabNote[Pred(j)]; 
      dec(j);
    end; 
     tabNote[j] := temp;  //insère l'élément à la position trouvé  
  end; 
end;

Complexité

Le meilleur cas est n et le pire cas est O(n2)

Shellsort

Ce tri est similaire à l'insertionsort. Il est un peu plus performant. L'insertionsort n'est pas très rapide puisque les éléments sont bougés d'un espace à la fois. Nous pouvons le faire bouger de plusieurs espaces, jusqu'à ce que nous trouvions le bon emplacement. Pour arriver à une telle solution, nous pouvons réduire la grosseur de k, chaque fois que nous constatons que (j-k) ième élément est plus grand que l'élément actuel. Nous pouvons diviser k par 3 chaque fois.

procedure ShellSort(var A : ArrayType; N : integer);
var
  Done : boolean;
  Jump,I,J : integer;
begin
  Jump := N;
  while (Jump > 1) do
  begin
    Jump := Jump div 2;
    repeat
      Done := true;
      for J := 1 to (N - Jump) do
      begin
        I := J + Jump;
        if (A[J] > A[I]) then
        begin
          Swap(A[J], A[I]);
          Done := false
        end;
      end;
    until Done;
  end
end;

Quicksort

Quicksort est l'algorithme de tri le plus populaire. Sur une entré aléatoire, Quicksort est le plus rapide des algorithmes que je connais. Quicksort est implanté de façon récursif, il peut ainsi être plus complexe à comprendre.
1. On doit spécifier un élément x pour établir l'alignement.
2. Chaque élément plus petit que x sera mis à droite et ceux plus grand à gauche.
3. Quicksort s'appelle et passe les deux parties. Lorsqu'il est appelé avec un tableau de grosseur 1, un élément a été trié.
4. Lorsque quicksort revient de la récursion, les deux parties ont été triées et peuvent être mises ensemble.

procedure Quicksort(var tabNote: TArray,longueur, r: Integer); 
var 
  i, j: Integer; 
  temp, old: Byte; 
begin 
  old := tabNote[(longueur + r) div 2]; 
  i := longeur;
  j := r;  
  repeat   
    while tabNote[i] < old do inc(i);   
    while old < tabNote[j] do dec(j);   
    if i <= j then 
    begin   
      temp := tabNote[i];
      tabNote[i] := tabNote[j];   
      tabNote[j] := temp;    
      inc(i);     
      dec(j);   
    end; 
    until i > j;
    if longeur < j then Quicksort( longueur, j); 
    if i < r then Quicksort( i, r); 
end;

Complexité

Le pire cas est O(n2).
La moyenne des résultats : O(n log n)..

Selection Sort

Ce tri parcourt le tableau à trier, cherche l'élément à remplacer et le permute. Ce tri peut s'avérer intéressant, s'il y a peu d'affectation (fichier).

procedure SelectionSort(var tabNote: array of Integer);
var
  I, J, temp: Integer;
begin
  for I := Low(tabNote) to High(tabNote) - 1 do
    for J := High(tabNote) downto I + 1 do
      if tabNote[I] > tabNote[J] then
      begin
        temp := tabNote[I];
        tabNote[I] := tabNote[J];
        tabNote[J] := temp;
      end;
end;

Complexité

La moyenne des résultats :O( n^2).
Un programme utilisant de nombreux algorithmes de tri est disponible ici.

lundi 2 décembre 2002

Procédure stockée


PROCÉDURE STOCKÉE

Une procédure stockée ressemble à une fonction en delphi. Cette procédure est entreposée sur le serveur de base de données, le client peut l'appeler. Une procédure peut avoir 0 ou plusieurs paramètres et retourné 0 ou plusieurs valeurs. Une procédure stockée est compilée sur le serveur lorsqu'elle est créée. Une requête est compilée à chaque fois qu'elle est envoyée au serveur. Il y a quelques avantages à utiliser les procédures stockées:
  • Plus rapide, car elle est déjà compilée sur le serveur
  • Diminue le trafic réseau car seuls les paramètres et le nom de la requête transitent par le réseau
  • Partage des ressources, plusieurs programmes peuvent utilisé la procédure
  • facilitée de maintenance, la mise à jour de la procédure profite à tous les programmes

Syntaxe d'une procédure stockée


CREATE PROCEDURE name
[( param datatype [, param datatype ...])]
[RETURNS ( param datatype [, param datatype ...])]
AS
<procedure_body>;
<procedure_body> = [< déclaration_variables >]
< block>
< déclaration_variables> =
DECLARE VARIABLE var datatype;
[DECLARE VARIABLE var datatype; ...]
<block> =
BEGIN
< compound_statement>
[< compound_statement> ...]
END
< compound_statement> = {<block> | statement;}

Suppression d'une procédure stockée

La syntaxe de suppression de la procédure stockée est fort simple.
drop procedure nom_procedure;

Déclaration de variable

La déclaration d'une variable doit suivre la convention: <DECLARE VARIABLE nomVariable Type de donnée>. Les variables globales n'existent pas.

/*Déclaration de variable nécessaire à la procédure*/
DECLARE VARIABLE tmpChar CHAR(5);
DECLARE VARIABLE tmpInt integer;
DECLARE VARIABLE tmpNum NUMERIC(15,2);

Déclaration de variable

Condition

La syntaxe du if else... ressemble étrangement à celle présents sous delphi.
IF <Expression de la condition> THEN
  <code>
ELSE
  <code>
Dans l'expression de la condition, il est possible d'utiliser certain opérateur SQL
  • BETWEEN ... and ...
  • LIKE ...
  • IN (..., ..., ...
  • EXISTS (sous-requête)
  • ANY (sous-requête)
  • ALL (sous-requête)
  • IS NULL
  • IS NOT NULL

Boucle

Cet opérateur permet comme nous le savons d'exécuter du code une certaine quantité de fois
WHILE (<Expression de la condition>) DO
        <code>

Nous allons créer une table pour notre exemple.
 
CREATE TABLE personne
(
  nopersonne INTEGER NOT NULL,
  age    INTEGER NOT NULL,
  pays         CHAR(8)  NOT NULL,
CONSTRAINT PK_nopersonne PRIMARY KEY (nopersonne)
);


Imaginons maintenant que cette table renferme des milliers d'enregistrements et que nous désirons obtenir l'âge moyen des personnes vivant dans un pays donné. Il serait possible d'écrire la requête ci-dessous et de l'assigner à un ibquery, ibsql ou à un ibdataset.
 
select avg(age)from  personne where pays = :PPAYS


Maintenant regardons la solution avec une procédure stockée

create procedure GET_AGE (PPAYS CHAR(8))
returns (AVG_AGE DECIMAL(8,2))AS
DECLARE VARIABLE i integer;
begin
  WHILE (i <= 5) DO
  begin
    select avg(age)
    from personne
  where pays = :PPAYS
  into :AVG_AGE;
  IF (AVG_AGE = 0) THEN
       AVG_AGE = 1;
  i = i +1;
  end
end
 

Dans cette procédure stockée, le select ne retourne qu'une valeur, si plusieurs valeurs auraient été retournées, il
aurait fallu utilisé: FOR SELECT...DO

Notez que c'est la valeur de avg_age qui va être retournée. En utilisant le composant: IBStoredProc, vous n'avez qu'à renseignez la propriété database et transaction. Ensuite, vous allez voir toutes les procédures stockées dans la propriété StoredProcName, vous n'avez qu'à sélectionner celle que vous désirez. Dans notre exemple ça sera: GET_AGE. Il est possible de voir les paramètres d'entrée et de sortie de la procédure en cliquant dans la propriété Params du composant IBStoredProc. Lorsque nous voulons appeler la procédure stockée dans notre code delphi et obtenir la valeur de retour, il suffit de faire pour notre exemple:

var
  avgAge:float;
begin
  IBStoredProc1.ExecProc;  //IBStoredProc1 étant le nom du composant dans delphi
  avgAge := IBStoredProc.ParamByName('AVG_AGE').AsFloat; 
end;

Il est possible d'exécuter toute sorte de requêtes avec les procédures stockées. La procédure ci-dessous supprime
les personnes ayant l'âge passé en paramètre.

create procedure AGEINF18 (persage int) as
begin
  delete from personne
  where age = :persage;
end

On a vu rapidement l'utilisation et la création de procédure stockée. Une connaissance de programmation et 
de SQL facilite leur utilisation  et permet d'alléger le client.

samedi 30 novembre 2002

Trigger


TRIGGER

Un trigger est associé à une table ou vue et permet d'exécuter du code selon un évènement donné. Tout comme les procédures stockées, tout s'exécute sur le serveur. Le trigger n'est jamais appelé directement. C'est lorsque l'évènement auquel est associé le trigger survient, le code est alors exécuté. Le langage utilisé par la base de données peut être utilisé pour le trigger, point besoin d'être limité à du SQL. Il est donc possible d'effectuer des tâches très complexes très aisément en utilisant ce langage au lieu d'avoir à gérer de complexe et lourde requête SQL.

Il est donc possible de se passer des triggers, mais un plus grand effort sera nécessaire pour parvenir au même objectif. Un trigger est exécuté sur le serveur, il n'y a donc pas de trafic réseau qui est généré telle que lors de requête SQL. Cette centralisation permet que plusieurs applications puissent y avoir accès. Si un changement doit se faire, il n'est pas nécessaire de recompiler l'application. L'utilisation de cette technique peut alors s'avérer beaucoup plus rapide que son équivalent en SQL. Un trigger n'a aucun paramètre d'entré et de sortie.
Il est possible d'utiliser les triggers pour diverses raisons:
  • Gérer l'intégrité des données
  • Gérer les règles d'affaires
  • Sécurité
  • ...

Syntaxe d'un trigger

CREATE TRIGGER name FOR { table | view}
[ACTIVE | INACTIVE]
{BEFORE | AFTER} {DELETE | INSERT | UPDATE}
[POSITION number]
AS < trigger_body >
< trigger_body > = [< variable_declaration_list >] < block >
< variable_declaration_list > =DECLARE VARIABLE variable < datatype >;
[DECLARE VARIABLE variable < datatype > ;...]
< block > =
BEGIN
< compound_statement > [< compound_statement >...]
END
< compound_statement > = {< block > | statement;}

Il existe tel qu'on peut le voir certaines ressemblances avec la syntaxe des procédures stockées

Opérateur

Les conditions et les boucles sont identiques à celles qu'on a pu voir dans les procédures stockées
Un trigger peut être exécuté pour les évènements suivants
  • BeforeInsert
  • BeforeUpdate
  • BeforeDelete
  • AfterInsert
  • AfterUpdate
  • AfterDelete
Lors du tutoriel des Générateurs, nous avons rapidement vu le code d'un trigger
SET TERM ^;
CREATE TRIGGER TRIG_CLIENT_GenId FOR CLIENT
ACTIVE BEFORE INSERT AS
BEGIN
  IF ( NEW.NOCLIENT IS NULL ) THEN
    NEW.NOCLIENT = GEN_ID(TRIG_CLIENT_GenId,1);
END

Ce trigger permet automatiquement de renseigner la clé primaire de la table. Il n'est alors plus nécessaire
d'intervenir, Interbase le fait pour nous. Une telle approche permet d'éviter les erreurs en cas d'omission.
Création d'une table

create table tclient(
 noms char(12),
 prenom char(12),
 motpasse char(12)
 );

SET TERM ^;
CREATE TRIGGER TRIG_CLIENT_GenId FOR CLIENT
ACTIVE AFTER INSERT AS
BEGIN
  IF ( NEW.motpasse IS NULL ) THEN
    NEW.motpasse = 'tmp';
END

La création de cette table ainsi que la procédure stockée permet de mettre un mot de passe si aucun n'a été inclus.Il
est possible de faire appel à une procédure stockée ou un UDF dans un trigger

UDF

UDF signifie fonction définie par l'usager (user defined function). Ces UDF sont bien entendu exécutés sur le serveur, la majorité du temps, le langage utilisé est le c ou le c++. Il est possible d'utiliser d'autre langage. Dans les répertoires d'Interbase, il y a de nombreux exemples.

Les UDF sont utilisés pour ajouter des fonctionnalités non disponibles dans SQL.
Les UDF ont 2 défauts: lorsqu'une UDF est exécuté, aucun accès à la BD ne peut survenir (affecte interbase inférieur à 7). Le second est que si le besoin de changer de machine pour une quelques raisons, on doit installer tous les UDF avant de restaurer la sauvegarde de la bd.

Lorsqu'on créer une UDF, on doit garder à l'esprit qu'elle devrait être le plus simple possible. Il est tout à faire possible dans une UDF d'exécuter un programme ou de faire des insertions, suppression... mais une telle approche peut mettre diminuer significativement les performances du serveur de plus ça pourraient occasionner une congestion des transactions.
Interbase inclus plusieurs UDF dont:
  • lower: converti une chaîne de caractère en minuscule
  • strcat: concatène deux chaînes
  • substr: retourne une portion d'une chaîne
  • trim: enlève les espaces d'une chaîne
  • trunc: trunc une chaîne
  • sysdate: retourne la date du système
  • sqrt: retourne la racine carré d'un double
  • abs : retourne la valeur absolue d'un double

Création d'une UDF avec delphi

Nous allons créer une UDF qui retournera la taxe (7%) sur un chiffre passé en paramètre
  • Choisir l'expert dll
  • Ajouter une unité au projet
  • Sauvegarder l'unité sous le nom MathFct
  • Sauvegarder le projet sous le nom brudflib
L'unité MathFct à l'allure suivante
unit MathFct;

interface

function TaxeTps(var i:Double): Double; cdecl; export;

implementation

function TaxeTps(var i:Double): Double; cdecl; export;
begin
  result := i*0.07+i;
end;

end.

Voici maintenant le code du projet
library brudflib;

uses
  SysUtils,
  Classes,
  MathFct in 'MathFct.pas';

{$R *.res}

exports
  TaxeTps;

begin
end.

Notez la présence du exports. TaxeTps fait partie de cette section, elle pourra donc être utilisé par un autre programme.
Il aurait été possible dans l'unité MathFct d'avoir plusieurs fonctions, mais que seulement quelque unes soit accessible
de l'extérieur.Ne pas oublier que tous les paramètres dans une UDF sont passés par pointeur donc il ne faut pas oublier
de mettre var devant nos paramètres.

En exécutant le projet, une dll est créé brudflib.dll. Cette dll doit être placée dans le répertoire UDF d'Interbase, habituellement c'est: disqu:\Borland\InterBase\UDF\. Il faut par la suite déclarer cette fonction pour l'utiliser dans Interbase.

Syntaxe de la déclaration de l'UDF pour Interbase

Voici la syntaxe d'une UDF:
DEFINE EXTERNAL FUNCTION name [<datatype> | CSTRING (int)
[, <datatype> | CSTRING (int) ...]]
RETURNS {<datatype&gt; [BY VALUE] | CSTRING (int)}
ENTRY_POINT "<entryname>"
MODULE_NAME "<modulename>" ;

Déclarons maintenant la fonction à Interbase
Declare external function f_TaxeTps float
  returns float by value
  entry_point 'TaxeTps' module_name 'brudflib.dll';

Il est maintenant possible d'utiliser cette fonction dans Interbase. Nous pouvons donc effectuer ce genre de
requête:
select f_TaxeTps(12.5) from rdb$database

L'exécution de cette requête retournera bien attendu 13,375. Les fonctions ainsi créées peuvent être ensuite utilisées dans n'importe quelle requête. Imaginons que nous avons une table logicielle avec un champ prix. Nous pourrions connaitre le coût du logiciel après taxe en faisant: select f_TaxeTps(prix) from logiciel.

String

Jusqu'à maintenant, nous avons utilisé que des nombres, nous allons maintenant utilisé des chaînes de caractères. Les strings utilisés par Delphi, lui sont propres. Interbase ne les utilise pas. Nous allons donc être obligés d'utiliser la fonction PChar.

function MixStr(Incoming: PChar):PChar;cdecl; export;
var OutStr, IncomingStr: string;
    i, j: Integer;
begin
  IncomingStr := StrPas(Incoming);
  OutStr := '';
  while Length(IncomingStr) > 0
  do begin
       i := Random(Length(IncomingStr) - 1) + 1;
       OutStr := OutStr + IncomingStr[i];
       Delete(IncomingStr, i, 1);
     end;
  StrPCopy(Incoming, OutStr);
  result := Incoming;
end;

Tappez ce code sous votre outil de gestion de bd:
Declare external function f_MixStr cstring(64)
  returns cstring(64)
  entry_point 'MixStr' module_name 'brudflib2.dll';
select f_MixStr('linux') from rdb$database 
Vous devriez voir que les lettres du mot Linux ont changé de position.

Suppression

Il suffit de taper drop external function nom_de_la_fonction pour la supprimer de la bd. Pour notre fonction, ça serait:

drop external function f_MixStr;

Migration d’une application Spring Boot 2.2 vers Spring Boot 4.0 : retour d’expérience concret

 En 2019, nous avons développé une application métier basée sur : Java 8 Spring Boot 2.2.7 Gradle 6.6.1 Thymeleaf Boots...