Structures de contrôles

Structures de contrôles #

Les boucles et les différentes structures de contrôles ne nécessitent pas de portage particulier, en dehors des instructions GOTO et FORALL.

Boucle FOR REVERSE #

La boucle FOR ... REVERSE présente également la particularité de devoir inverser les bornes min et max dans les boucles FOR ... IN ... REVERSE min..max.

Le code Oracle est le suivant :

FOR i IN REVERSE 1..10 BY 2 LOOP
  ...
END LOOP;

Il devra être modifié de la façon suivante :

FOR i IN REVERSE 10..1 BY 2 LOOP
  ...
END LOOP;

Une autre différence importante concerne les boucles FOR sur des requêtes (autres que des curseurs). Dans le code PL/SQL, sous Oracle, les variables cibles sont déclarées implicitement. Pour adapter une telle fonction à PostgreSQL, il est nécessaire de déclarer les variables cibles dans le bloc DECLARE de la fonction portée. Cela a également pour avantage de laisser cette variable accessible à la sortie de la boucle.

Ainsi, l’extrait de code PL/SQL suivant :

DECLARE
  v_date1 DATE, v_date2 DATE;
BEGIN
  FOR r IN (
    SELECT numberprgn FROM t2 
     WHERE status = 'ordered' AND assigned_dept = 'departt'
  )
LOOP
  SELECT min(datestamp) INTO v_date1
    FROM T1 WHERE NUMBER = r.numberprgn  AND description = 'etat1';

  SELECT min(datestamp) INTO v_date2
    FROM T1 WHERE NUMBER = r.numberprgn  AND description = 'etat2';
END LOOP;

sera porté de la façon suivante, en supposant que les variables v_date1 et v_date2 doivent être portées en type TIMESTAMP :

DECLARE
  v_date1 DATE, v_date2 TIMESTAMP;
  r record;
BEGIN
  FOR r IN (
    SELECT numberprgn FROM t2
    WHERE status = 'ordered' AND assigned_dept = 'departt'
  )
LOOP
  SELECT min(datestamp) INTO STRICT v_date1
    FROM T1 WHERE number = r.numberprgn  AND description = 'etat1';

  SELECT min(datestamp) INTO STRICT v_date2
    FROM T1 WHERE number = r.numberprgn  AND description = 'etat2';
END LOOP;

Références :

Instruction GOTO #

L’instruction GOTO n’a pas d’équivalent sous PostgreSQL et nécessite une réécriture de code. L’usage de cette instruction est souvent déconseillée, mais il n’est pas rare de la retrouver pour contrôler d’exécution d’une boucle, par exemple pour aller à l’itération suivante ou simplement sortir de la boucle.

Ainsi, le code PL/SQL suivant :

LOOP
  FETCH curs_courant INTO courant;
  EXIT WHEN curs_courant%NOTFOUND;
  IF v_cat = 'YYY' THEN
    v_cat := courant;
    GOTO DEBUT;
  END IF;
  IF courant = 'N1' THEN
    v_cat := courant;
    GOTO FIN;
  END IF;
  ...
<<DEBUT>>
NULL;
END LOOP;
<<FIN>>
CLOSE curs_courant;

nécessitera d’être réécrit de la façon suivante :

LOOP
  FETCH curs_courant INTO courant;
  IF NOT FOUND THEN
    EXIT;
  END IF;
  IF v_cat = 'YYY' THEN
    v_cat := courant;
    CONTINUE;
  END IF;
  IF courant = 'N1' THEN
    v_cat := courant;
    EXIT;
  END IF;
  ...
END LOOP;
CLOSE curs_courant;

Boucles FORALL #

L’instruction FORALL n’a pas d’équivalent dans PostgreSQL. La boucle FORALL, utilisée pour parcourir les lignes d’une collection sous Oracle, n’existe pas non plus sous PostgreSQL. Cependant, son implémentation sous PostgreSQL est simple car il s’agit uniquement de parcourir le tableau de la collection.

Ainsi, la procédure PL/SQL suivante :

CREATE OR REPLACE PROCEDURE allEmployees
IS
  TYPE v_array IS varray(50) OF CHAR(14);
  arr_emp v_array;
BEGIN
  SELECT ename BULK COLLECT INTO arr_emp
  FROM emp
  ORDER BY ename;
  FORALL i IN 1..arr_emp.COUNT
    dbms_output.put_line('|name'||arr_emp..(i)||'i'|| i);
END allEmployees;

sera réécrite de la façon suivante :

CREATE OR REPLACE FUNCTION allEmployees()
RETURNS VOID AS $body$
DECLARE
  arr_emp CHAR(14)[];
BEGIN
  arr_emp := array ( SELECT ename FROM emp ORDER BY ename);
  FOR i IN array_lower(arr_emp,1)..array_upper(arr_emp,1) LOOP
    RAISE NOTICE '|name % i %', arr_emp[i], i;
  END LOOP;
END;
$body$ LANGUAGE plpgsql;

Précédent
Portage des triggers
Suivant
Reprise du code PL/SQL