Le guide Oracle Forms 9i/10g
Date de publication : Juin 2005
Forms et PL/SQL
Définition
Concept
Mise en oeuvre
Techniques avancées
Forms et PL/SQL
Le PL/SQL dans Forms
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).
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.
PROCEDURE xx IS
TYPE zz IS RECORD( a varchar2(10), b number(3));
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
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
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()
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)
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 :
Pour les référencer, vous devez faire précéder leur nom du préfixe :PARAMETER.
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.
PACKAGE BODY PKG_TEST
IS
GC$Texte Varchar2(2000);
GN$Nbre Number ;
Function xx () Return ... IS ...
Procedure yy() IS ...
Begin
GC$Texte := 'Variable visible pendant toute la session' ;
GN$Nbre := 10 ;
End PKG_TEST ;
Mise en oeuvre
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
LC$Nom := Name_In( 'PARAMETER.NOM_UTIL' ) ;
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().
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
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 :
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 :
CREATE SYNONYM LYON_PKG_RECHERCHE FOR SCOTT.PKG_RECHERCHE@LYON;
Vous pouvez même masquer la notion de package avec le synonyme suivant:
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 Nud : Objets de la base de données du navigateur.
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.
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
PROCEDURE When_Validate_Item
Is
LC$Item Varchar2(61) := :SYSTEM.TRIGGER_ITEM ;
Begin
If LC$Item = 'EMP.EMPNO' Then
Elsif LC$Item = 'EMP.EMPNAME' Then
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 :
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
Forms_ddl( 'ROLLBACK' ) ;
Forms_ddl( 'ALTER SESSION SET NLS_DATE = ''DD/MM/YYYY HH24:MI:SS'' ' ) ;
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 ;
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:
Forms_ddl ( 'BEGIN Control_Insertion_Employé( :EMP.EMPNO ) ; END ;' ) ;
Génère une erreur est doit être remplacé par:
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 noeud : Packages intégrés.
|