Gestion d'exceptions en Oracle
Si un programme affiche un flux inhabituel et inattendu pendant l'exécution, ce qui peut entraîner l'arrêt anormal du programme, la situation est considérée comme une exception. Ces erreurs doivent être interceptées et traitées dans la section EXCEPTION du bloc PL/SQL. Les gestionnaires d'exceptions peuvent supprimer l'arrêt anormal avec une action alternative et sécurisée.
La gestion des exceptions est l'une des étapes importantes de la programmation d'une base de données. Les exceptions non gérées peuvent entraîner des pannes d'applications imprévues, avoir un impact sur la continuité des activités et frustrer les utilisateurs finaux.
Il existe deux types d'exceptions: définies par le système et définies par l'utilisateur. Alors que la base de données Oracle déclenche implicitement une exception définie par le système, une exception définie par l'utilisateur est explicitement déclarée et déclenchée dans l'unité de programme.
En outre, Oracle fournit deux fonctions utilitaires, SQLCODE et SQLERRM, pour récupérer le code d'erreur et le message de l'exception la plus récente.
Exceptions définies par le système
Comme son nom l'indique, les exceptions définies par le système sont définies et gérées implicitement par la base de données Oracle. Elles sont définis dans le package Oracle STANDARD. Chaque fois qu'une exception se produit dans un programme, la base de données récupère l'exception appropriée dans la liste disponible. Toutes les exceptions définies par le système sont associées à un code d'erreur négatif (sauf 1 à 100) et à un nom abrégé, qui est utilisé lors de la spécification des gestionnaires d'exceptions.
Par exemple, le programme PL/SQL suivant inclut une instruction SELECT pour sélectionner les détails de l'employé 8376. Il déclenche une exception NO_DATA_FOUND car l'ID d'employé 8376 n'existe pas.
DECLARE Nom VARCHAR2 (100); Salaire NUMBER; EMPID NUMBER := 8376; BEGIN SELECT ENAME, SAL INTO Nom, Salaire FROM EMP WHERE EMPNO = EMPID; END; /
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 8
Réécrivons le bloc PL/SQL précédent pour inclure une section EXCEPTION et gérer l'exception NO_DATA_FOUND:
DECLARE Nom VARCHAR2 (100); Salaire NUMBER; EMPID NUMBER := 8376; BEGIN SELECT ENAME, SAL INTO Nom, Salaire FROM EMP WHERE EMPNO = EMPID; EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE ('Aucun employé n existe avec l identifiant '||EMPID); END; /
Aucun employé n existe avec l identifiant 8376
PL/SQL procedure successfully completed.
Le tableau suivant présente certaines exceptions définies par le système, ainsi que leur nom abrégé et leur code d'erreur ORA:
Erreur | Nom d'exception | Soulevéss quand |
---|---|---|
ORA-00001 | DUP_VAL_ON_INDEX | Une valeur en double existe |
ORA-01001 | INVALID_CURSOR | Le curseur n'est pas valide |
ORA-010121 | NOT_LOGGED_ON | L'utilisateur n'est pas connecté |
ORA-01017 | LOGIN_DENIED | Une erreur système s'est produite |
ORA-01017 | LOGIN_DENIED | Une erreur système s'est produite |
ORA-01017 | LOGIN_DENIED | Une erreur système s'est produite |
ORA-01403 | NO_DATA_FOUND | La requête ne renvoie aucune donnée |
ORA-01422 | TOO_MANY_ROWS | Une requête sur une seule ligne renvoie plusieurs lignes |
ORA-01476 | ZERO_DIVIDE | Une tentative a été faite pour diviser un nombre par zéro |
ORA-01722 | INVALID_NUMBER | Le numéro est invalide |
ORA-06504 | ROWTYPE_MISMATCH | Une incompatibilité s'est produite dans le type de ligne |
ORA-06511 | CURSOR_ALREADY_OPEN | Le curseur est déjà ouvert |
ORA-06532 | COLLECTION_IS_NULL | Travailler avec la collection NULL |
ORA-06531 | SUBSCRIPT_OUTSIDE_LIMIT | Index de collection hors de portée |
>ORA-06533 | SUBSCRIPT_BEYOND_COUNT | Index de collection hors de compte |
Exceptions définies par l'utilisateur
Oracle permet aux utilisateurs de créer des exceptions personnalisées, de spécifier des noms, d'associer des codes d'erreur et de déclencher des instructions conformément à la logique de mise en œuvre. Si les applications PL/SQL doivent normaliser la gestion des exceptions, non seulement pour contrôler le flux de programme anormal, mais également pour modifier la logique d'exécution du programme, vous devez utiliser des exceptions définies par l'utilisateur. Les exceptions définies par l'utilisateur sont déclenchées dans la section BEGIN..END du bloc à l'aide de l'instruction RAISE.
Il existe trois façons de déclarer des exceptions :
- Déclarez la variable de type EXCEPTION dans la section déclaration. Soulevez cette exception explicitement dans le corps du programme à l'aide de l'instruction RAISE. Gérez cette exception dans la section EXCEPTION. Notez qu'aucun code d'erreur n'est impliqué ici.
- Déclarez la variable EXCEPTION et associez-la à un numéro d'erreur standard à l'aide de PRAGMA EXCEPTION_INIT.Un Pragma est une directive adressée au compilateur pour manipuler le comportement de l'unité de programme pendant la compilation, et non au moment de l'exécution.
PRAGMA EXCEPTION_INIT peut également être utilisé pour mapper une exception à une exception non prédéfinie. Ce sont des erreurs standard d'Oracle mais non définies comme des exceptions PL/SQL. - Utilisez RAISE_APPLICATION_ERROR pour déclarer un numéro d'erreur et un message d'erreur dédiés.
Le bloc PL/SQL suivant déclare une exception définie par l'utilisateur et la déclenche dans le corps du programme:
DECLARE a NUMBER :=5; b NUMBER :=0; res NUMBER; /* Déclarer une exception ERREUR */ ERREUR EXCEPTION; BEGIN IF b=0 THEN RAISE ERREUR; END IF res:= a/b DBMS_OUTPUT.PUT_LINE('Le résultat est : '||res); EXCEPTION WHEN ERREUR THEN DBMS_OUTPUT.PUT_LINE ('La valeur de b doit être différente de zéro '); END; /
La valeur de b doit être différente de zéro
PL/SQL procedure successfully completed.
La procédure RAISE_APPLICATION_ERROR
RAISE_APPLICATION_ERROR est une procédure fournie par Oracle qui déclenche une exception définie par l'utilisateur avec un message d'exception personnalisé. L'exception peut être éventuellement prédéfinie dans la section déclaration du PL/SQL.
La syntaxe de la procédure RAISE_APPLICATION_ERROR est la suivante:
RAISE_APPLICATION_ERROR (numero_erreur, message_erreur[, {TRUE |FALSE}])
Dans cette syntaxe, le paramètre numero_erreur est un paramètre obligatoire dont la valeur d'erreur est comprise entre 20000 et 20999. message_erreur est le message défini par l'utilisateur qui apparaît avec l'exception. Le dernier paramètre est un argument facultatif utilisé pour ajouter le code d'erreur d'exception à la pile d'erreurs actuelle.
Le programme PL/SQL suivant liste les employés qui ont rejoint l'organisation après la date donnée. Le programme doit lever une exception si la date d'embauche est antérieure à la date donnée. Le bloc utilise RAISE_APPLICATION_ERROR pour lever l'exception avec un code d'erreur 20005, et un message d'erreur approprié apparaît à l'écran :
DECLARE DATE_DONNEE DATE := '01-DEC-1981'; CURSOR C IS SELECT empno, ename, hiredate FROM emp; BEGIN FOR I IN C LOOP IF i.hiredate < DATE_DONNEE THEN RAISE_APPLICATION_ERROR (-20005,'Date d embauche antérieure à la date donnée !'); ELSE DBMS_OUTPUT.PUT_LINE(i.ename||'a été embauché le'||i.hiredate); END IF; END LOOP; END; /
Error report -
ORA-20005: Date d embauche antérieure à la date donnée !
ORA-06512: at line 8
Dans l'exemple précédent, notez que le nom de l'exception n'est pas utilisé pour créer le gestionnaire d'exception. Juste après que l'exception ait été levée par RAISE_APPLICATION_ERROR, le programme est terminé.
Si vous souhaitez avoir un gestionnaire d'exception spécifique pour les exceptions soulevées par RAISE_APPLICATION_ERROR, vous devez déclarer l'exception dans la section déclaration et associer le numéro d'erreur en utilisant PRAGMA EXCEPTION_INIT.
DECLARE DATE_DONNEE DATE := '01-DEC-1981'; /*Déclarer la variable d'exception*/ INVALID_EMP_DATES EXCEPTION; PRAGMA EXCEPTION_INIT(INVALID_EMP_DATES,-20005); CURSOR C IS SELECT empno, ename, hiredate FROM emp; BEGIN FOR I IN C LOOP IF i.hiredate < DATE_DONNEE THEN RAISE INVALID_EMP_DATES; ELSE DBMS_OUTPUT.PUT_LINE(i.ename||'a été embauché le'||i.hiredate); END IF; END LOOP; EXCEPTION WHEN INVALID_EMP_DATES THEN DBMS_OUTPUT.PUT_LINE(SQLERRM||'Date d embauche antérieure à la date donnée !'); END; /
ORA-20005: Date d embauche antérieure à la date donnée
PL/SQL procedure successfully completed.
Propagation des exceptions
Jusqu'à présent, nous avons vu que, dès que l'exception est levée dans la section BEGIN d'un bloc PL/SQL, le contrôle saute à la section EXCEPTION et choisit le gestionnaire d'exception approprié. L'inexistence du gestionnaire d'exception peut conduire à la fin anormale du programme.
Dans le cas de blocs PL/SQL imbriqués, si l'exception est déclenchée dans un bloc interne, le contrôle du programme descend vers la section d'exception du bloc interne. Si le bloc interne gère l'exception, il est exécuté et le contrôle du programme retourne à l'instruction exécutable suivante dans le bloc externe.
Si le bloc interne ne gère pas l'exception, le contrôle de programme continue de rechercher le gestionnaire approprié et se propage à la section d'exception du bloc externe. L'exécution du bloc externe est ignorée et le contrôle du programme arrive directement dans la section d'exception. Le contrôle de programme continuera à propager l'exception non gérée dans les blocs externes jusqu'à ce que celle appropriée soit trouvée et gérée.
Par exemple, le programme PL/SQL suivant contient un bloc interne dans le bloc externe:
/*bloc externe*/ DECLARE ... BEGIN /*Instructions exécutables de bloc externe*/ ... /*bloc interne*/ DECLARE ... BEGIN ... /*Instructions exécutables de bloc interne*/ ... EXCEPTION /*Gestionnaires d'exceptions de bloc interne*/ END; ... /*Instructions exécutables de bloc externe*/ EXCEPTION /*Gestionnaires d'exceptions de bloc exetrne*/ END;
Si l'exception est déclenchée dans l'une des instructions /* Instructions exécutables de bloc interne */, le contrôle passe vers /* Gestionnaires d'exceptions de bloc interne */. Si le gestionnaire d'exceptions approprié n'est pas trouvé, il se propage directement aux /* gestionnaires d'exceptions de bloc externe */ et l'exécution de /* instructions exécutables de bloc externe */ est ignorée.
Lorsqu'ils travaillent avec des blocs PL/SQL imbriqués, les développeurs doivent être prudents lorsqu'ils codent la logique de traitement des exceptions. La propagation des exceptions doit être testée de manière approfondie afin de créer des applications à l'épreuve des défaillances.