vendredi 11 avril 2003

Thread


THREAD

Le parallélisme fait partie de notre quotidien. Il n'est pas rare d'exécuter plusieurs actions en même temps : manger, écouter, écrire... Une telle approche peut-être utilisé en programmation. De plus en plus de logiciels utilisent cette technique. Cette méthode est employée par certains lecteurs vidéo et audio sur le Web. On peut ainsi écouter le fichier sans devoir attendre qu'il soit totalement téléchargé. Un thread exécute le fichier, un autre le télécharge.

Le système alloue un certain temps d'exécution à chaque tâche. Le temps alloué à chaque programme est si court qu'on a l'impression que tout fonctionne simultanément. Un tel système est dit multitâche de prémption.

Un thread est un sous-programme d'une application, c'est une unité d'exécution de celui-ci. Plusieurs threads peuvent fonctionner en même temps dans une application. L'utilisation des threads permet d'augmenter les performances.

Priorité

La priorité permet d'allouer un certain temps d'exécution aux threads. Les valeurs suivantes peuvent être affectés à la propriété «Priority» du thread.
  • tpIdle Le thread s'exécute seulement quand le système est en attente.
  • tpLowest La priorité du thread est deux points en dessous de la normale.
  • tpLower La priorité du thread est un point en dessous de la normale.
  • tpNormal La priorité du thread est normale.
  • tpHigher La priorité du thread est un point au-dessus de la normale
  • tpHighest La priorité du thread est deux points au-dessus de la normale.
  • tpTimeCritical Le thread a la priorité la plus élevée.
Il faut bien identifier les besoins qu'on a pour ne pas allouer trop de temps à un thread qui attend des donnés de l'extérieur, on réduisait ainsi les performances au lieu de les augmenter.

Synchronisation de base

Il a sa propre pile et les variables locales sont locales à chaque thread. Des données globabes peuvent être partagées entre les différents threads, il peut donc avoir des problèmes de synchronisation. S'il y a qu'un thread qui utilise une variable globale, il n'y a aucun problème.

Aperçu des méthodes

Création

Il faut créer un descendant de la classe TThread

Execute

Cette méthode est abstraite, elle contiendra le code à exécuter lorsque le thread débutera.

Terminated

Cette propriété et la méthode Terminate permettent d'arrêter un thread.

Suspended

En affectant true à cette propriété ou en appelant la méthode Suspend, le thread sera suspendu.

Resume

Cette méthode reprend l'exécution d'un thread interrompu.

Synchronize

Cette méthode sert à exécuter une méthode dans le thread principal de la vcl. On évite de nombreux conflits lors du multi-thread en l'employant. La synchronisation peut s'avérer nécessaire lorsqu'on utilise des objets de la vcl/clx.
L'unité classes doit être incluse dans la partie uses.

Ce thread servira à afficher le nombre de fois qu'il est passé dans une boucle.

type
  TLoop = class(TThread)
  private
    cptIteration : integer;
  protected
    constructor create();
    procedure Execute; override;
    procedure ReAfficher;
end;
Nous sommes obligés de définir la méthode execute.
procedure TLoop.Execute;
begin
  while (not Terminated) do begin
    inc(cptIteration);
     Synchronize(ReAfficher);
  end;
end;

Destruction de thread

Afin d'évider les problèmes lors de la destruction de threads, il faut quitter le threads convenablement, récupérer la mémoire allouée et obtenir les résultats du threads.
Si le threads ne doit pas communiquer de l'information à nouveau au thread principal de la vcl, on n'a pas besoin de se préoccuper réllement de sa libération de mémoire. On utilise FreeOnTerminate et le thread effectue lui-même sa propre désalocation de la mémoire.

Arrêt prématuré de thread

Il peut arriver qu'un thread doit en informer un autre qu'il va se terminer. Ceci se produit généralement si un thread exécute une opération prolongé et que l'utilisateur décide de quitter l'application ou que l'exécution doit être interrompue. TThread inclut la méthode Terminate et la propriété Terminated pour supporter de telles situations. Lorsque thread est démaré, sa propriété terminated est mise à false.C'est la responsabilité des threads de vérifier périodiquement s'ils ont été terminés.En somme cette propriété signifié terminait le thread le plus rapidement possible.

L'événement OnTerminate

Cet évènement survient lorsqu'un thread a fini d'être exécuté et non lorsque la méthode Terminate est appelée. C'est très utile car on l'exécute comme le thread principal de la vcl. C'est une façon très intéressante de ne pas avoir un thread vcl et de transférer ses donnés à un thread de vcl. OnTerminate fonctionne étrangement à synchronise.

Grâce à du code trouvé sur le Web, j'ai créé une petite application qui peut exécuter jusqu'à 3 threads en même temps. Ce programme vous permettra de mieux comprendre les notions apprises sur les threads jusqu'à maintenant.
Code source disponible ici

Blocage

Méthode de WaitFor

Il peut arriver qu'on est besoin que tous les autres thread soient terminés à un certain moment lorsqu'on fait exécuter le thread de la vcl. voici un petit exemple pour mieux comprendre ce que fait cette méthode.

Un thread A appelle la méthode WaitFor d'un thread B, le tread A est mis en attente jusqu'à ce que le thread B est fini son exécution. Lorsque le thread A reprend, il est certain que le résultat du thread B peut-être lu et que l'objet du thread représentant B peut être détruit.

Il faut faire attention lorsqu'on utilise cette méthode, car elle ne peut pas recevoir de message. Le formulaire ne pourra pas se redessiner, se redimensionner et communiquer avec l'extérieur. En appelant PostMessage le problème sera moins visible, mais si le traitement est vraiment long, il faudrait penser à ajouter un messager à l'usager. Il existe de nombreuses techniques pour résoudre ce problème dont les messages d'attente de win32.

Danger

Si on utilise synchronize et waitfor il est possible qu'il se produise un blocage de notre application. Un blocage survient si les threads s'attendent les uns les autres de façon cyclique. Un cercle vicieux en quelques sortes. Ce problème peut-être résout en levant des exceptions. En utilisant pas synchronise et waitfor dans la même application, on s'assure ainsi de ne pas rencontrer ce problème.

Thread: avancé

Inconvénient de synchronize

Synchronise a plusieurs inconvénients qui peuvent le rendre inacceptable pour des applications multi-thread complexe.
  • Utile lorsqu'on veut faire communiquer nos threads avec ceux de la vcl
  • Si on utilise beaucoup de synchronize, la vcl bloque notre application
  • Synchronize peut bloquer notre application si la vcl attend nos threads
Le thread principal de l'application devrait s'exécuter rapidement pour avoir un temps réponse optimal.

Il arrive très souvent que des threads communiquent avec la vcl dans le même sens. C'est à dire lire un flux de donnés, exécuter une requête... Des données sont ainsi partagées. Il faut alors s'assurer que seul un thread pourra modifier des donnés. La classe TCriticalSection est une bonne solution.

Section critique

La classe TCriticalSection permet de bloquer l'accès à une partie du code à plusieurs threads. Seul un thread pourra exécuter le code. La méthode Acquire empêche les autres threads d'exécuter une section et Release enlève cette protection. L'api de Windows a bien évidemment des fonctionnalités plus complètes.

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.

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...