IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PL/SQL Oracle Discussion :

Capture des erreurs levées dans le curseur


Sujet :

PL/SQL Oracle

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 9
    Points : 7
    Points
    7
    Par défaut Capture des erreurs levées dans le curseur
    Bonjour,

    Je souhaite capturer les erreurs levées lors du "fetch" d'un curseur puis continuer à l'itération suivante.

    Dans l'exemple ci-dessous, je crée une table où j'insère les valeurs suivantes : 1, 2, 3, -1 et 4. Ensuite, je fais en sorte que le programme plante sur le nombre négatif au moment de convertir 000-1 en nombre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    SET SERVEROUTPUT ON;
     
    -- Creation du jeu de donnees
    DROP TABLE table01;
     
    CREATE TABLE table01 (
      champ_nombre NUMBER
    );
     
    INSERT INTO table01 VALUES(1);
    INSERT INTO table01 VALUES(2);
    INSERT INTO table01 VALUES(3);
    INSERT INTO table01 VALUES(-1);
    INSERT INTO table01 VALUES(4);
     
    -- Procedure
    DECLARE
      TYPE rec_curseur01 IS RECORD (nb NUMBER);
      CURSOR curseur01 RETURN rec_curseur01 IS SELECT LPAD(champ_nombre,5,0) FROM table01;
    BEGIN
     
      FOR ligne IN curseur01 LOOP
        BEGIN
          DBMS_OUTPUT.PUT_LINE(ligne.nb);
     
          EXCEPTION
            WHEN OTHERS THEN
              DBMS_OUTPUT.PUT_LINE('e01 : ' || SQLERRM);
        END;
      END LOOP;
     
      EXCEPTION
            WHEN OTHERS THEN
              DBMS_OUTPUT.PUT_LINE('e02 : ' || SQLERRM);
    END;
    /
    Résultat actuel :
    1
    2
    3
    e02 : ORA-01722: Nombre non valide
    Résultat attendu (affichage de l'erreur puis itération suivante) :
    1
    2
    3
    e01 : ORA-01722: Nombre non valide
    4
    Avez-vous une idée ?

    Cordialement,

  2. #2
    Membre chevronné
    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Décembre 2019
    Messages
    1 138
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Décembre 2019
    Messages : 1 138
    Points : 1 918
    Points
    1 918
    Par défaut
    Bonjour,

    Le problème survient dans le parcours du curseur, à l'itération 4 quand Oracle essaie de placer le résultat dans la variable de type number. L'erreur est donc "à l'extérieur" de la boucle, et c'est pour cela que tu tombes dans le bloc d'exception global.
    Si tu veux pouvoir gérer l'exception à l'intérieur de la boucle, alors fais la conversion à l'intérieur de la boucle, pas dans la requête du curseur. Par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    -- Procedure
    DECLARE
      TYPE rec_curseur01 IS RECORD (nb NUMBER);
      v_num number;
      CURSOR curseur01 RETURN rec_curseur01 IS SELECT champ_nombre FROM table01;
    BEGIN
     
      FOR ligne IN curseur01 LOOP
        BEGIN
          DBMS_OUTPUT.PUT_LINE(ligne.nb);
     
          v_num := LPAD(ligne.nb,5,0);
     
          EXCEPTION
            WHEN value_error THEN
              DBMS_OUTPUT.PUT_LINE('e01 : ' || SQLERRM);
        END;
      END LOOP;
     
      EXCEPTION
            WHEN OTHERS THEN
              DBMS_OUTPUT.PUT_LINE('e02 : ' || SQLERRM);
              raise;
    END;
    /
    Tu verras que j'ai mis 'exception "value_error" car OTHERS n'est à utiliser que pour les exceptions auxquelles tu ne t'attends pas. Je rappelle qu'en PL/SQL on ne gère que les exceptions auxquelles on s'attend. Donc WHEN OTHERS est exclusivement réservé à des fins de logging, puis ensuite on raise.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 9
    Points : 7
    Points
    7
    Par défaut
    Oui vanagreg, j'ai créé un exemple simplifié car le programme réel contient beaucoup plus d'opérations. L'idéal serait de capturer n'importe quelle erreur levée dans le curseur sans interrompre la boucle afin de pouvoir réutiliser ce bout de code à tous les curseurs ou encore de prévoir d'éventuelles anomalies introduites lors d'évolutions.

    Cordialement,

  4. #4
    Membre chevronné
    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Décembre 2019
    Messages
    1 138
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Décembre 2019
    Messages : 1 138
    Points : 1 918
    Points
    1 918
    Par défaut
    Oui mais si la requête du curseur est susceptible de retourner des erreurs (ce qui ne devrait pas se produire), alors tu ne rentreras pas dans la boucle.
    Tu ne pas pas gérer "n'importe quelle erreur" puis continuer la boucle. Le WHEN OTHERS n'est pas fait pour cela, mais malheureusement il est très souvent mal utilisé. Tu veux continuer la boucle alors qu'une erreur inconnue s'est produite? Ca n'a pas de sens. Quelques exemples:

    - Tablespace plein, donc même si tu continues tu n'arriveras plus à insérer de lignes, mais tu ne le sauras pas tout de suite
    - Une conversion en TO_DATE se passe mal, donc on ignore l'erreur alors que la ligne aurait pu être traitée si la conversion avait bien été faite
    - Erreur indirecte ailleurs dans le code qu'on ne verra pas car avalée par le WHEN OTHERS, et après on se pose mille questions de savoir pourquoi cette ligne du curseur n'a pas été traitée alors qu'elle semble valide
    - etc.

    J'ai eu tellement de mauvaises surprises à cause d'abus de WHEN OTHERS.

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 9
    Points : 7
    Points
    7
    Par défaut
    Merci de ton retour d'expérience. L'objectif est de traiter les lignes correctes et de recenser dans un fichier spécifique les lignes tombées en erreur pour une analyse a posteriori. Cependant, si ce n'est pas possible (ou mauvaise pratique de développement), je peux envisager de refactoriser le code pour déplacer les opérations dans la boucle au lieu de les effectuer dans le curseur. Malheureusement, si ça plante dans le curseur, toutes les lignes suivantes ne seront pas lues mais je diminue tout de même le risque.

    Cordialement,

  6. #6
    Rédacteur

    Homme Profil pro
    Consultant / formateur Oracle et SQL Server
    Inscrit en
    Décembre 2002
    Messages
    3 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant / formateur Oracle et SQL Server

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 460
    Points : 8 074
    Points
    8 074
    Par défaut
    Si le contexte s'y prête, ça peut être l'occasion d'utiliser la journalisation des erreurs DML.
    UPDATE... LOG ERRORS

    On fait par exemple un UPDATE qui touche 100 lignes, mais génère une erreur sur 3 d'entre elles.
    Au lieu que la mise à jour échoue dès la première ligne en erreur, elle se poursuit sans interruption en se contentant d'enregistrer les erreurs dans la table de journalisation.
    Donc à la fin on a 97 lignes modifiées, et 3 en erreurs enregistrées dans la table journal.
    On doit ensuite balayer cette table journal et décider ce qu'on fait des erreurs.

    Ce mécanisme est même compatible avec BULK COLLECT ... FORALL.
    Mais il faut alors que l'UPDATE (pour prendre cet exemple), soit la seule opération DML à exécuter à partir de la collection.

    Si vous lisez l'anglais :
    https://oracle-base.com/articles/10g...-logging-10gr2
    https://blogs.oracle.com/oraclemagaz...ng-termination
    Consultant / formateur Oracle indépendant
    Certifié OCP 12c, 11g, 10g ; sécurité 11g

    Ma dernière formation Oracle 19c publiée sur Linkedin : https://fr.linkedin.com/learning/oracle-19c-l-administration

  7. #7
    Membre émérite
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Avril 2013
    Messages
    1 993
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2013
    Messages : 1 993
    Points : 2 499
    Points
    2 499
    Par défaut
    loxort, la gestion des erreurs est devenue complexe sous Oracle, un premier lien ici pour appréhender tout cela : http://dbaoraclesql.canalblog.com/ar.../37552845.html
    DBA Oracle
    Rédacteur du blog : dbaoraclesql.canalblog.com

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    9
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 9
    Points : 7
    Points
    7
    Par défaut
    Bonjour,

    Merci pour vos réponses.

    Je vais donc adapter le code pour minimiser le risque d'erreurs (non DML) dans le curseur. Si une erreur arrive malgré tout, alors le parcours du curseur s'interrompt (relancer le curseur en excluant les fetchs non valides serait un peu usine à gaz à mon goût). Pour les erreurs DML, je vais les intercepter avec un bloc imbriqué ou avec le bulk collect/for all si besoin de performances.

    Cordialement,

Discussions similaires

  1. Réponses: 4
    Dernier message: 14/02/2020, 09h42
  2. Gestion des erreurs WCF dans Silverlight 4
    Par EmacLi dans le forum Silverlight
    Réponses: 8
    Dernier message: 27/09/2012, 21h03
  3. Affichage des erreurs Tomcat dans la console
    Par Bobsinglar dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 13/01/2009, 19h19
  4. catching des exceptions levées dans l'EDT
    Par nouknouk dans le forum API standards et tierces
    Réponses: 2
    Dernier message: 29/07/2007, 11h23
  5. Gestion des erreurs ssh dans ant
    Par mystar dans le forum ANT
    Réponses: 3
    Dernier message: 19/01/2007, 19h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo