Gestion des erreurs Packages ©Alain Villeneuve, 1999 GIS882 Gestion des erreurs Packages ©Alain Villeneuve, 1999
Erreurs dans Forms FORMS Une erreur (exception) peut survenir dans: instruction SQL instruction PL/SQL un module PL/SQL appelé par un autre Lorsqu'une erreur n'est pas gérée au niveau où elle survient, elle sera propagée au niveau supérieur Le développeur peut manipuler lui-même l'exception et la rendre plus conviviale Par défaut, à moins de gestion d'erreur, le reste du code est exécuté
Triggers dans Forms Triggers d'application dans FORMS Oracle va essayer de récupérer le traitement suivant une erreur dans un trigger d'application Le comportement par défaut est défini dans l'environnement FORMS (voir manuel de référence) Exemples de triggers: Pre-item On-insert When-validate-item When-button-pressed When-mouse-click triggers au niveau du formulaire, du block, ou de l'item
Triggers Forms: stratégies Triggers d'application dans FORMS: 3 stratégies écrire un gestionnaire complet d'exception laisser le traitement par défaut à Oracle ne gérer que les exceptions les plus critiques pour vous Fonctions disponibles ERROR_TYPE(retourne CHAR) ERROR_CODE(retourne NUMBER) ERROR_TEXT(retourne CHAR) DBMS_ERROR_CODE(retourne NUMBER) DBMS_ERROR_TEXT(retourne CHAR)
Erreurs internes dans Forms Erreurs dans les routines internes (built-ins) au delà d'une centaine de routines internes exemples: GO_BLOCK ('nom_du_bloc'); GO_ITEM ('nom_item'); FORM_SUCCESS (retourne un booléen) FORM_FAILURE (retourne un booléen) FORM_FATAL (retourne un booléen) on signale l'erreur par RAISE FORM_TRIGGER_FAILURE dans le code; cette exception n'a pas à être définie dans votre code
Built-ins dans Forms Erreurs dans les routines internes (built-ins) Exemple: /* when_button_pressed trigger */ GO_BLOCK('bloc_quelconque'); IF NOT FORM_SUCCESS THEN RAISE Form_Trigger_Failure; END IF; END; Si le bloc désigné n'existe pas par exemple, alors le GO_BLOCK sera fautif et le FORM_SUCCESS sera à FALSE
Chapitre Handling errors de Forms
PACKAGES Sert à regrouper un ensemble d'objets, de types de données et de sous-programmes (fonctions et procédures) qui sont logiquement apparentés consiste en deux grandes sections la spécification du package le corps du package la spécification est l'interface visible du package sert à déclarer les types, variables, constantes, exceptions, curseurs, et sous-programmes disponibles le corps contient le code programmé en soi
Packages (2) Un package est différent d'un programme normal contenant des sous-programmes en essence, les deux types de construction se ressemblent mais le package a la particularité de permettre l'adressage à partir de l'externe des procédures qui le composent une procédure qui contient des sous-programmes (d'autres procédures) ne permet pas d'atteindre directement ces sous-programmes de l'extérieur le package au contraire permettra sous certaines conditions de rendre ses sous-programmes visibles
Exemple de package Les sous-programmes viennent ici! PACKAGE nom_package IS /* déclaration des variables, cursors, etc tous ces éléments sont publics et disponibles aux sous-programmes inclus dans le corps du package de plus ces déclarations sont visibles à l'environnement appelant */ END [nom_package]; PACKAGE BODY nom_package IS /* déclaration des variables, cursors, et autres objets privés codes programmés des sous-programmes */ BEGIN … -- instructions d'initialisation et autres Les sous-programmes viennent ici!
Avantages Avantages programmation modulaire facilité de développement protection de l'implantation (information hiding) fonctionnalités additionnelles à l'application performance améliorée
Mise en place CREATE PACKAGE emp_actions AS /* Définition des types, cursors et exceptions visibles */ TYPE EmpRecTyp IS RECORD (emp_id INTEGER, salary REAL); TYPE DeptRecTyp IS RECORD (dept_id INTEGER, location VARCHAR2); CURSOR desc_salary RETURN EmpRecTyp; salary_missing EXCEPTION; Spécifications du package: déclaration des variables et objets. Suite de cette section sur la prochaine page.
Spécifications du package /* Sous-programmes visibles de l'extérieur. */ /* chacun peut être appelé par un autre programme */ FUNCTION hire_employee ( ename VARCHAR2, job VARCHAR2, mgr NUMBER, sal NUMBER, comm NUMBER, deptno NUMBER) RETURN INTEGER; PROCEDURE fire_employee (emp_id INTEGER); PROCEDURE raise_salary (emp_id INTEGER, increase NUMBER); FUNCTION nth_highest_salary (n INTEGER) RETURN EmpRecTyp; END emp_actions; Suite et fin de la partie spécifications du package. Tous ces éléments seront visibles. Fin des specs.
Corps du package Début du corps PACKAGE BODY emp_actions IS number_hired INTEGER; -- variable visible au package seulement /* Définition du cursor déclaré dans la spécification du package. */ CURSOR desc_salary RETURN EmpRecTyp IS SELECT empno, sal FROM emp ORDER BY sal DESC; /* Chacun des sous-programmes sera défini en entier ici */ FUNCTION hire_employee (ename VARCHAR2, job VARCHAR2, mgr NUMBER, sal NUMBER, comm NUMBER, deptno NUMBER) RETURN INTEGER IS new_empno INTEGER; BEGIN
Corps (2) SELECT empno_seq.NEXTVAL INTO new_empno FROM dual; INSERT INTO emp VALUES (new_empno, ename, job, mgr, SYSDATE, sal, comm, deptno); number_hired := number_hired + 1; RETURN new_empno; END hire_employee; Ceci marque la fin de la fonction hire_employee et non la fin du package: d'autres sous-programmes ont été déclarés qui doivent être définis avant le END final
Corps (3) Cette procédure sert à retirer un employé de la table emp. PROCEDURE fire_employee (emp_id INTEGER) IS BEGIN DELETE FROM emp WHERE empno = emp_id; END fire_employee; Cette procédure sert à retirer un employé de la table emp.
Corps (4) Augmenter le salaire d'un employé par un certain montant PROCEDURE raise_salary (emp_id INTEGER, increase NUMBER) IS current_salary NUMBER; BEGIN SELECT sal INTO current_salary FROM emp WHERE empno = emp_id; IF current_salary IS NULL THEN RAISE salary_missing; ELSE UPDATE emp SET sal = sal + increase END IF; END raise_salary; Augmenter le salaire d'un employé par un certain montant
Corps (5) Sont définis dans le package specs. FUNCTION nth_highest_salary (n INTEGER) RETURN EmpRecTyp IS emp_rec EmpRecTyp; BEGIN OPEN desc_salary; FOR i IN 1..n LOOP FETCH desc_salary INTO emp_rec; END LOOP; CLOSE desc_salary; RETURN emp_rec; END nth_highest_salary; Sont définis dans le package specs. Retourne le record de l'employé qui a le nième salaire le plus élevé: le n (rang) désiré est fourni comme paramètre de la fonction.
Corps (6) Cette fonction est privée au package (donc pas visible à l'extérieur) parce qu'elle n'est pas annoncée dans le package specs /* Define local function, available only in package. */ FUNCTION rank (emp_id INTEGER, job_title VARCHAR2) RETURN INTEGER IS /* Return rank (highest = 1) of employee in a given job classification based on performance rating. */ head_count INTEGER; score NUMBER; BEGIN SELECT COUNT(*) INTO head_count FROM emp WHERE job = job_title; SELECT rating INTO score FROM reviews WHERE empno = emp_id; score := score / 100; -- maximum score is 100 RETURN (head_count + 1) - ROUND(head_count * score); END rank;
Corps (7) BEGIN -- initialization part starts here INSERT INTO emp_audit VALUES (SYSDATE, USER, 'EMP_ACTIONS'); number_hired := 0; END emp_actions; Entre le BEGIN et le END du corps du package, on placera les instructions d'initialisation requises par le package. Ici, on insère un tuplet dans un table de piste des événements pour fins de contrôle: c'est une idée farfelue puisque le BEGIN du package ne sera exécuté qu'une seule fois soit au premier appel.
Utilisation du package Appel ou référence à un composant d'un package: nom_package.nom_objet [paramètres optionnels] Exécution à partir de SQL*plus: EXECUTE nom_package.nom_fonction[paramètres] Exécution à partir de Reports, Forms via PL/SQL nom_package.nom_fonction[paramètres]
TABLEAUX PL/SQL Structures de données en mémoire vive ne comportent qu'une seule colonne ne correspondent pas à une table SQL les lignes de la table sont adressées par une valeur entière du type BINARY_INTEGER taille dynamique: les tables s'agrandissent automatiquement au besoin en fait, un tableau n'est ni plus ni moins qu'un vecteur on pourra créer autant de tableaux PL/SQL qu'il y a de colonnes correspondantes dans la table désirée
Définition de tableau Première étape: définir un type de référence DECLARE … TYPE type_tableau_nom IS TABLE OF CHAR(20) INDEX BY BINARY_INTEGER; Deuxième étape: définir le tableau NOMS_EMPLOYES TYPE_TABLEAU_NOM; PRENOMS_EMPLOYES TYPE_TABLEAU_NOM; Un tableau ne peut pas être initialisé dans sa déclaration toujours mettre INDEX BY BINARY_INTEGER
Définition Le %TYPE est aussi supporté dans la déclaration d'un tableau: DECLARE … TYPE type_tableau_nom IS TABLE OF employes.nom%TYPE INDEX BY BINARY_INTEGER; Une variable BINARY_INTEGER est requise dans votre DECLARE pour adresser le tableau dans le programme i BINARY_INTEGER := 0; -- peut être initialisé cette variable servira comme index dans le tableau
Utilisation Limite de taille: (-231 -1 à 231 - 1) nombre de cellule contraint à l'espace RAM réel Utilisation des variables tableaux comme toute autre variable simple il faut toujours spécifier le numéro de cellule désiré, ceci se fait avec votre variable de type binary_integer exemples nom_tableau(index) := valeur; IF nom_tableau(index) = … THEN
Exemple Exemple: Supposons un système de gestion des ressources humaines dans lequel plusieurs codes sont présents dans les dossiers d'employés (statut marital, sexe, statut d'emploi, etc.). Supposons aussi une table liste_codes qui contient les codes ainsi que leurs descriptions. Nous voulons imprimer les dossiers étoffés des employés. Plusieurs centaines d'employés existent dans la table.
Exemple (2) Alors typiquement, à chaque tuplet en provenance de la table employé, on devra aller chercher la description qui correspond à un code (statut marital), et ce pour chacun des codes. Cette recherche sera normalement par un SELECT. Supposons l'existence de 10 colonnes de code par employé et supposons 1000 employés dans la table, alors 10.000 SELECT seront exécutés.
Exemple (3) Solution: créer un package le package aura une fonction de chargement de tous les codes dans un tableau PL/SQL le package contiendra une fonction de recherche de la description d'un code et retournera celle-ci le chargement initial serait dans la section BEGIN du package: nombre de SELECT totaux = 100 n'oubliez pas que le package est initialisé lors du premier appel à n'importe laquelle de ses procédures
Exemple (4) Describe de la table codes codes not null varchar2(8); description not null varchar2(30); Pour fins de cet exemple, on pose que tous les codes sont dans cette table de codes et que par exemple les deux premiers caractères de la clé identifie la catégorie de code: SX pour sexe, alors 'SXF', 'SXM' existent SM pour statut marital, alors 'SMC', 'SMM','SMV', … DD pour dernier diplôme, alors 'DDSEC5', 'DDDEC','DDBAA',...
Exemple (5) PACKAGE descriptifs IS TYPE description_codes IS TABLE OF codes.description%TYPE INDEX BY BINARY_INTEGER; TYPE code_code IS TABLE OF codes.code%TYPE liste_code code_code; --- tableau en soi liste_description description_codes; -- tableau en soi nombre NUMBER; -- compteur du nombre de codes FUNCTION retourne_descriptif(CODE codes.code%TYPE) RETURN CHAR; END descriptifs;
Exemple (6) Lorsque l'on trouve la valeur recherchée, on retourne le descriptif qui lui correspond. PACKAGE BODY descriptifs IS CURSOR c_description IS SELECT * FROM codes; FUNCTION retourne_descriptif(CODE codes.code%TYPE) RETURN CHAR IS i BINARY_INTEGER := 0; BEGIN FOR i IN 1..nombre LOOP IF descriptifs.liste_code(i) = CODE THEN RETURN descriptifs.liste_description(i) END IF; END LOOP; RETURN ('Code invalide'); END retourne_descriptif; Si fin de la boucle, c'est qu'on n'a rien trouvé!
Exemple (7) BEGIN -- ceci est le BEGIN du package et ne sera exécuté qu'une fois nombre := 1; OPEN c_description; LOOP FETCH c_description INTO liste_code(nombre), liste_description(nombre); EXIT WHEN c_description%NOTFOUND; nombre := nombre + 1; END LOOP; CLOSE c_description; END descriptifs; Les tableaux de codes et de descriptions sont chargés. Nombre contient le nombre réel d'entrées dans les tableaux.