Le guide Oracle Forms 9i/10g


précédentsommairesuivant

XXXII. Forms et PL/SQL

Le PL/SQL dans Forms


XXXII-A. Définition

Une application Forms se programme en utilisant le langage PL/SQL.

A l'exception des ordres du DDL (CREATE TABLE, ALTER TRIGGER, etc.), la plupart des instructions PL/SQL sont directement utilisables.

Le moteur PL/SQL de Forms étant différent de celui de la base de donnée, certaines nouvelles caractéristiques implémentées au niveau noyau ne sont pas encore reconnues au niveau Forms (TABLE INDEX BY VARCHAR2(x) ou INDEX BY PLS_INTEGER par exemple) ainsi que certaines fonctionnalités restreintes au noyau (BULK COLLECT, EXECUTE IMMEDIATE).

Dans une application Forms, le code PL/SQL peut être implémenté dans les composants suivants :

  • Menu
  • Librairie PL/SQL
  • Déclencheur
  • Unité de programme

De plus, le code PL/SQL stocké en base est également exécutable depuis l'application (packages, fonctions et procédures stockées).

XXXII-B. Concept

Les variables Forms

Les variables utilisables dans une application sont les suivantes :

  • Variables déclarées dans la section Declare d'un bloc PL/SQL
  • Variables globales
  • Items de la forme
  • Paramètres de la forme
  • Variables globales de package internes à la forme
  • Variables globales de package stockées en librairie PL/SQL

Variables de bloc PL/SQL

Les variables déclarées dans un bloc PL/SQL ne sont visibles qu'à l'intérieur du bloc et peuvent être de tout type PL/SQL.

 
Sélectionnez

PROCEDURE xx IS

  -- variable de type enregistrement --
  TYPE zz IS RECORD( a varchar2(10), b number(3));
  -- tableau d'enregistrements --
  TYPE t_zz IS TABLE OF zz INDEX BY BINARY_INTEGER ;
  tableau t_zz ;
  LC$Item  VARCHAR2(32767) ;
  LI$Nbr   PLS_INTEGER := 0 ;
  LD$Date  DATE ;

BEGIN

  LC$Item := Rpad( 'X', 32000, 'X' ) ;
  LD$Date := SYSDATE ;
  
  Select
     Count(*)
  Into
     LI$Nbr
  From
     EMP
  ;
  
  For i IN 1..10 Loop
    tableau(i).a := CHR(i+64) ;
    tableau(i).b := i ;
  End loop ;

END;

Variables globales

Les variable globales sont visibles par toutes les formes qui s'exécutent dans la même session.

Elles sont de type CHAR et sont limitées à 255 caractères.
Elles doivent être précédées du préfixe :GLOBAL.

Elles sont déclarées lors de leur première utilisation

 
Sélectionnez

Begin
   :GLOBAL.NOMBRE_MAXI := To_char( 18 * 140 ) ;
   :GLOBAL.DATE_JOUR   := To_char( SYSDATE, 'DD/MM/YYYY' ) ;
   :GLOBAL.MESSAGE     := 'Bonjour système solaire' ;

   If :GLOBAL.MESSAGE LIKE 'Bon%' Then
      ...
   End if ;
End ;

Il est possible d'utiliser la procedure Default_Value() pour initialiser une variable dont le contenu est NULL

 
Sélectionnez

Default_value( 'Bonjour', 'GLOBAL.MESSAGE' );

La valeur 'Bonjour' ne sera attribuée à la variable globale que si celle-ci est NULL.

Ces variables peuvent être supprimées de la mémoire avec l'instruction : ERASE()

 
Sélectionnez

Erase( 'GLOBAL.NOMBRE_MAXI' ) ;

Si vous tentez d'accéder à la valeur d'une variable globale non initialisée, Forms retourne une erreur.

Items de la forme

Les items de la forme sont visibles uniquement dans la forme qui les accueille.

Ils sont créés à l'intérieur des blocs de données et peuvent être de type :

  • VARCHAR2
  • NUMBER
  • DATE
  • DATETIME
  • LONG
  • REF OBJET

Ils peuvent être basé ou non basé.

Pour les référencer, vous devez les faire précéder du nom du bloc auquel ils appartiennent ( :NOM_BLOC.NOM_ITEM)

 
Sélectionnez

Begin

  :EMP.ENAME := 'SCOTT' ;
  :BLOC1.DATEJOUR := SYSDATE ;

  If :EMP.DEPTNO = 10 Then
    ...
  End if ;

End ;

Les paramètres

Les paramètres sont attachés à une forme mais indépendamment de tout bloc de données. Ils ne sont visible que de la forme à laquelle ils sont attachés.

Ils sont de type :

  • CHAR
  • NUMBER
  • DATE

Pour les référencer, vous devez faire précéder leur nom du préfixe :PARAMETER.

 
Sélectionnez

Begin

  :EMP.EMPNO := :PARAMETER.NUM_EMP ;
  Go_Block( 'EMP' ) ;
  Execute_Query ;

  :PARAMETER.NOMBRE := 2000 ;

End ;

Les variables globales de packages

Elles sont visibles durant toute la session Forms.
Si le package est stocké en librairie PL/SQL et que les formes sont appelées avec l'argument SHARE_LIBRARY_DATA, alors elles sont partagées par toutes les formes dans la session.

 
Sélectionnez

PACKAGE BODY PKG_TEST 
IS
  -- Variable globales du package --
  GC$Texte   Varchar2(2000);
  GN$Nbre   Number ;

  -- Foncions et procédures --
  Function xx () Return ... IS ...
  Procedure yy() IS ...

Begin
  -- Initialisation des variables globales du package --  
  GC$Texte := 'Variable visible pendant toute la session' ;
  GN$Nbre := 10 ;
End PKG_TEST ;

XXXII-C. Mise en œuvre

Quel type de variable utiliser ?

A part les variables globales de package qui perdurent pendant toute la session, les variables de bloc PL/SQL n'ont d'utilité que pour le traitement particulier du bloc.

Les variables globales sont visibles dans toutes les formes de l'instance mais sont uniquement de type CHAR et limitées à 255 caractères.

Les paramètres sont généralement utilisés pour récupérer les arguments transmis par une forme appelante ou depuis la ligne de commande. De plus, ils doivent être créés au moment de la conception de la forme.

Les items de bloc, surtout lorsqu'ils ne sont pas basés sont d'excellentes variables visibles dans toute la forme.
L'inconvénient est qu'une instruction CLEAR_FORM() les réinitialise à leur valeur initiale.

Si vous manipulez des types complexes dans votre forme (RECORD, NESTED TABLE, etc.) utilisez des variables globales de package.

Si vous devez partager des variables entre plusieurs formes, utilisez les variable globales ou les variables globales de packages stockés en librairies PL/SQL.

Si vous devez stocker des variables persistantes à l'intérieur de la forme, utilisez des items non basés placés sur un canevas NULL. Ils ne seront jamais affichés.
Créez un bloc non basé (control block) dans lequel vous réunissez tous les items (et donc variables) nécessaires.
Si l'utilisateur exécute une commande Clear_Form(), capturez la dans un trigger KEY-CLRFRM de niveau forme et appelez à la place l'instruction Clear_Block() sur chaque bloc de la forme (à l'exception de votre bloc non basé, évidemment).

Référencement direct des variables Forms

Toutes les variables Forms sont accessibles avec le préfixe : (deux points)

  • :Bloc.item := 10 ;
  • :GLOBAL.truc := 'Chose' ;
  • LC$Nom := :PARAMETER.NOM_UIL ;

Référencement indirect des variables Forms

Une variable Forms peut être référencée indirectement avec la fonction native : Name_IN().

Cette fonction accepte en paramètre de type CHAR le nom de la variable et en retourne sa valeur actuelle

 
Sélectionnez

LC$Nom := Name_In( 'PARAMETER.NOM_UTIL' ) ;

-- récupérer la valeur d'un item dont le nom est passé en paramètre --
LC$Item := :SYSTEM.TRIGGER_ITEM ;
LC$Val  := Name_In( LC$Item ) ;

Notez qu'avec cette syntaxe le préfixe : n'est pas transmis.

Le référencement indirect est pratique lorsque vous souhaite consulter ou valoriser des variables à l'extérieur de Forms.
En effet, dans les menus ou les librairies PL/SQL, le nom interne des variables Forms n'est pas connu.

Pour valoriser indirectement une variable Forms, utilisez la fonction native : Copy().

 
Sélectionnez

Copy( source, destination ) ;

Copy( 'Scott', 'EMP.ENAME' ) ;
Copy( 'Chose', 'GLOBAL.truc' ) ;
Copy( Name_In( 'EMP.ENAME' ), 'GLOBAL.truc' ) ;

Le référencement indirect est particulièrement utile lorsque vous écrivez des fonctions génériques qui valorisent vos variables ou items de façon dynamique

 
Sélectionnez

Declare
  LC$Item  Varchar2(61) ;
Begin
  For i IN 1 .. 10 Loop
    LC$Item := 'BLOC.IT_' || Ltrim( To_char( i ) ) ;
    Copy( LN$I, LC$Item ) ;
  End loop ;
End;

Accès au code PL/SQL stocké en base


Pour exécuter une fonction, procédure ou package stocké en base, utilisez la syntaxe PL/SQL standard.
Si la procédure est dans un autre schéma ou sur une base distante, vous devez masquer le nom du schéma ou de la base distante avec un synonyme.

Si la fonction PKG_RECHERCHE.Fonction() se trouve dans le schéma SCOTT, créez le synonyme suivant :

 
Sélectionnez

CREATE SYNONYM PKG_RECHERCHE FOR SCOTT.PKG_RECHERCHE;

Si cette même fonction se trouve sur la base distante de Lyon, créez le synonyme suivant :

 
Sélectionnez

CREATE SYNONYM LYON_PKG_RECHERCHE FOR SCOTT.PKG_RECHERCHE@LYON;

Vous pouvez même masquer la notion de package avec le synonyme suivant:

 
Sélectionnez

CREATE SYNONYM LYON_RECHERCHE FOR SCOTT.PKG_RECHERCHE.Fonction@LYON;

Maintenance des objets stockés en base depuis Forms Builder


Vous pouvez gérer les objets de la base de donnée depuis le Nœud : Objets de la base de données du navigateur.

Maintenance des objets stockée en base

L'arborescence affiche tous les objets de chaque schéma qui supporte du code PL/SQL.

  • Fonctions, procédures, packages
  • Déclencheurs pour les tables et le vues
  • Code PL/SQL des méthodes affectées aux types objets

L'éditeur PL/SQL permet de charge ce code, de le créer ou de le modifier et de le compiler.

Bien sûr, vous devez avoir les droits nécessaires au niveau de la base pour effectuer les actions correspondantes.

XXXII-D. Techniques avancées

Les points de codage dans un module Forms sont nombreux:

  • Déclencheurs de niveau forme
  • Déclencheurs de niveau bloc
  • Déclencheurs de niveau item
  • Unités de programmes

Dans une application complexe munie de nombreux blocs et de nombreux items, le codage des règles de gestion à tous les niveaux devient vite un monstrueux bazard.

Chaque item de chaque bloc peut contenir plusieurs déclencheurs (When-New-Item-Instance, When-Validate-Item, etc.)

Dans ce cas, la phase de maintenance devient lourde car elle oblige le programmeur à développer dans le navigateur l'ensemble des objets pour parcourir le code.

Lorsque le corps d'un déclencheur contient plusieurs lignes de code, je suggère de déplacer ce code dans une unité de programme et de ne laisser dans le déclencheur initial que l'appel de cette procédure.

Par exemple, si sur chaque item de votre bloc vous codez un déclencheur de type When-Validate-Item, supprimez ces déclencheurs, créez un déclencheur de même type mais au niveau bloc ou même forme, et insérez l'appel d'une simple procédure stockée dans une unité de programme.

Les variables système :SYSTEM.TRIGGER_ITEM et :SYSTEM.CURSOR_ITEM sont là pour vous indiquer de quel élément il s'agit.

Soit l'unité de programme suivante : When_Validate_Item

 
Sélectionnez

PROCEDURE When_Validate_Item
Is
  -- nom de l'item qui a généré le déclencheur --
  LC$Item  Varchar2(61) := :SYSTEM.TRIGGER_ITEM ;
Begin
  If LC$Item = 'EMP.EMPNO' Then
     -- Traitement de validation de EMP.EMPNO
  Elsif LC$Item = 'EMP.EMPNAME' Then
     -- Traitement de validation de EMP.ENAME
  Elsif LC$Item = 'EMP.JOB' Then
     ...
     ...
  End if ;
End ;

Et dans votre déclencheur de niveau forme codez un simple appel à cette procédure:

Code du déclencheur : When-Validate-Item :

 
Sélectionnez

Begin
   When_Validate_Item ;
End

Vous avez centralisé la gestion de la validation de tous les items de votre forme dans une seule procédure, fait le ménage dans tous vos déclencheurs de niveau item et grandement facilité la tâche de celui ou celle (qui peut être vous, d'ailleurs) qui devra maintenir l'écran.
Un simple coup d'œil dans les unités de programme suffit a englober l'ensemble du code relatif à l'application.

Les instructions du DDL (Data Description Language)


Si vous avez besoin d'utiliser ces instructions, utiliser la fonction Forms_ddl().

Forms_ddl( 'instruction' ) ;

instruction est une chaîne de caractères (32K maxi) qui représente une instruction simple ou un bloc PL/SQL.
elle peut être:

  • Un littéral
  • Une expression ou une variable de type VARCHAR2
  • Une instruction du DML
  • Une instruction du DDL

Dans le cas d'une instruction unique, celle-ci ne doit pas être terminée par ; ou par /
Dans le cas d'un bloc PL/SQL, celui-ci doit être encadré des instructions BEGIN et END;

FORMS_DDL
Sélectionnez

-- Annulation de la transaction en base --
Forms_ddl( 'ROLLBACK' ) ;

-- Changement de paramètre --
Forms_ddl( 'ALTER SESSION SET NLS_DATE = ''DD/MM/YYYY HH24:MI:SS'' ' ) ;

-- Manipulation dynamiques --
Declare
  LC$Sql  Varchar2(1000);
Begin
  LC$Sql := 'BEGIN CREATE TABLE X ( COL1 VARCHAR2(10), COL2 NUMBER(5) ) ;'
  LC$Sql := LC$Sql || ' INSERT INTO X VALUES(''Code1'', 10 ) ;' ;  
  LC$Sql := LC$Sql || ' INSERT INTO X VALUES(''Code2'', 15 ) ;' ;  
  LC$Sql := LC$Sql || ' INSERT INTO X VALUES(''Code3'', 20 ) ; END;' ;      
  Forms_ddl( LC$Sql ) ;
  ...
  ...
  Forms_ddl( 'DROP TABLE X' ) ;
End ;  

-- Appel d'une procédure stockée --
Forms_ddl ( 'BEGIN Control_Insertion_Employé ; END ;' ) ;

Attention:
Toute instruction du DDL génère un COMMIT implicite en base

Si vous utilisez une instruction de ce type (CREATE TABLE…), assurez-vous que l'enregistrement de la transaction implicite est bien ce que vous souhaitez

Pour vérifier que la commande a été correctement exécutée, consultez les variables système FORM_SUCCES ou FORM_FAILURE

En cas d'erreur, consultez les variables système DBMS_ERROR_CODE, DBMS_ERROR_TEXT.

Limitations:
instruction ne peut pas contenir de variables de substitution.
Par exemple, l'appel suivant:

 
Sélectionnez

Forms_ddl ( 'BEGIN Control_Insertion_Employé( :EMP.EMPNO ) ; END ;' ) ;

Génère une erreur est doit être remplacé par:

 
Sélectionnez

Forms_ddl ( 'BEGIN Control_Insertion_Employé(' || To_char(:EMP.EMPNO) || ') ; END ;' ) ;


Le SQL dynamique dans Forms

Il est possible d'exécuter du SQL dynamique via les fonctions du package Forms intégré : EXEC_SQL

Ce package est une copie version Client de la version Serveur : DBMS_SQL.

L'étude détaillée de ce package mériterait un chapitre entier, ce qui n'est pas le but de cet article.
Sachez toutefois que ce package autorise les connexions multiples via la fonction EXEC_SQL.Open_Connection().
Cela permet de se connecter sur un schéma différent de celui de la session Forms en cours.

Pour le détail des fonctions de ce package, consultez l'aide en ligne (Ctrl+H) de Forms Builder, ou affichez la syntaxe des fonctions dans le navigateur d'objets au niveau du nœud : Packages intégrés.


précédentsommairesuivant

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

  

Copyright © 2005 SheikYerbouti. Aucune reproduction, même partielle, ne peut être faite de ce site et 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.