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

DB2 Discussion :

Gestion des exceptions dans une procédure stockée


Sujet :

DB2

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut Gestion des exceptions dans une procédure stockée
    Bonjour !

    Mes connaissances en PL/SQL étant limitées, je viens vers vous pour solliciter votre aide sur un sujet. Soit la procédure suivante :

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    /*
    Incident : ETU573695 - Fusion des caisses
     
    Objectifs : 
    - Table decompte_poste, mise à jour des champs DEC_MT_POSTE, DEC_MT_RESTANT
    - Table decompte_poste, suppression des enregistrements des codes créance '0312xxx' ayant
      le même nombre d'enregistrements sur la créance '0715xxx' correspondante
      
    Date de création : 13/09/2012
     
    Auteur : Vincent PARIS
     
    Date de modification : 
     
    Nature de la modification : 
    */
     
    CREATE OR REPLACE PROCEDURE MAJ_DecomptePoste_03120715_01()
    BEGIN
     
        --Déclaration des variables
        DECLARE DecCodeContrat312_C2 char(20);
        DECLARE DecCodeContrat715 char(20);
        DECLARE DecCodePoste char(2);
        DECLARE DecTypeDecompte integer;
        DECLARE DecCodeClient char(20);
        DECLARE DecMtPoste double;
        DECLARE DecMtRestant double;
        DECLARE DecTypeTiers char(1);
        DECLARE DecCodeTiers char(20);
        DECLARE DecCodeContrat312 char(20); 
        DECLARE exitcode integer;
     
        --Curseur 1 : liste des créances '0312xxx' ayant une créance '0715xxx' correspondante avec l'ensemble 
        --des codes poste, soit le même nombre d'enregistrements
        DECLARE Cursor1 CURSOR FOR
            select A.dec_code_contrat
            from (
                select dec_code_contrat, count(*) as nb_enr_312	
                from decompte_poste
                where dec_code_contrat like '0312%'
                group by dec_code_contrat
            ) as A,
            (
                select dec_code_contrat, count(*) as nb_enr_715	
                from decompte_poste
                where dec_code_contrat like '0715%'
                group by dec_code_contrat
            ) as B
            where substr(A.dec_code_contrat,5,16) = substr(B.dec_code_contrat,5,16)
            and nb_enr_312 = nb_enr_715;
     
        --Curseur 2 : liste des données de decompte_poste pour la créance 0312 en cours lue par le curseur Cursor1
        DECLARE C2 CURSOR FOR
                select dec_code_contrat, dec_code_poste, dec_type_decompte, dec_code_client, dec_mt_poste, dec_mt_restant, 
                dec_type_tiers, dec_code_tiers
                from decompte_poste
                where dec_code_contrat = DecCodeContrat312;
     
        --Handler détectant la fin de la lecture de la requête
        DECLARE CONTINUE HANDLER FOR NOT FOUND
            SET exitcode = 1;
     
        --ouverture du curseur Cursor1
        OPEN Cursor1;
     
        --parcours du curseur Cursor1
        loop_over_cursor1:
        LOOP
            FETCH FROM Cursor1 INTO DecCodeContrat312;
     
            --on teste si le curseur est arrivé ou non à la fin des résultats de la requête ci-dessus
            IF exitcode = 1 THEN
                LEAVE loop_over_cursor1; --sortie de la boucle LOOP
            END IF;
     
            --Ouverture du curseur C2
            open C2;
     
            --Parcours du curseur C2
            loop_over_cursor2:
            LOOP
                FETCH FROM C2 INTO DecCodeContrat312_C2, DecCodePoste, DecTypeDecompte, DecCodeClient, DecMtPoste, DecMtRestant, 
                DecTypeTiers, DecCodeTiers;
     
                --on teste si le curseur est arrivé ou non à la fin des résultats de la requête ci-dessus
                IF exitcode = 1 THEN
                    LEAVE loop_over_cursor2; --sortie de la boucle LOOP
                END IF;
     
                --pour initialiser le code contrat 0715, on concatène à 0715 les derniers chiffres du code créance 0312 correspondant
                SET DecCodeContrat715 = '0715'||substr(DecCodeContrat312_C2,5,16);
     
                UPDATE decompte_poste
                SET dec_mt_poste = dec_mt_poste + dec(DecMtPoste,8,2),
                    dec_mt_restant = dec_mt_restant + dec(DecMtRestant,8,2)
                WHERE dec_code_contrat = DecCodeContrat715
                AND dec_code_poste = DecCodePoste
                AND dec_type_decompte = DecTypeDecompte
                and dec_code_client = DecCodeClient
                and dec_type_tiers = DecTypeTiers
                and dec_code_tiers = DecCodeTiers;
     
                delete from decompte_poste
                where dec_code_contrat = DecCodeContrat312_C2
                and dec_code_poste = DecCodePoste
                and dec_type_decompte = DecTypeDecompte
                and dec_code_client = DecCodeClient
                and dec_type_tiers = DecTypeTiers
                and dec_code_tiers = DecCodeTiers;
     
            END LOOP loop_over_cursor2;
            SET exitcode = 0;
     
            --Fermeture curseur C2    
            close C2;
        END LOOP loop_over_cursor1;
     
        --Fermeture du curseur Cursor1
        CLOSE Cursor1;
     
    END
    Cette procédure est appelée dans un autre script sql (call_procedures.sql), via une instruction 'call'. Dans cet autre script figurent d'autres appels de procédures. Pour celle-ci et toutes les autres, j'aimerais gérer les exceptions qui permettraient de stopper l'exécution de ce script en cas d'erreur dans une procédure.

    Peu importe la nature de l'exception levée, la procédure doit s'arrêter et l'exécution du script call_procedures.sql doit s'interrompre.

    Je n'ai absolument aucune idée de la syntaxe à utiliser dans mon cas, malgré plusieurs recherches sur internet. Pourriez-vous m'aider svp ?

    P.S. : j'utilise l'outil Sql Developer

  2. #2
    Expert éminent sénior Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Points : 11 252
    Points
    11 252
    Par défaut
    Quelle base des données ? Parce que la syntaxe ce n’est pas tout à fait du PL/SQL d’Oracle.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut
    Ah pardon, c'est du DB2 ... Merci de déplacer le sujet.

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut
    Au passage, j'ai également des soucis (non visibles dans le code ci-dessus) si je veux éditer des messages en sortie avec la méthode DBMS_OUTPUT.PUT_LINE('mon message'). Je ne vois jamais mon message ... Mais le plus important reste tout de même la façon dont je dois gérer les exceptions. Je n'ai absolument aucune connaissance en la matière.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut
    Bonjour

    Je poste ici la partie du fichier permettant l'appel des procédures (fichier call_procedures.sql)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /*------------------------------------------------------------------------------
                                 TABLE DECOMPTE_POSTE
    ------------------------------------------------------------------------------*/
    call MAJ_DecomptePoste_03120715_01();
     
    call MAJ_DecomptePoste_03120715_02();
     
    update decompte_poste 
    SET dec_code_contrat = '0715'||substr(dec_code_contrat,5,16) 
    where substr(dec_code_contrat,1,4) = '0312';
    En gros, si la première procédure ne se passe pas bien, il ne doit pas pouvoir exécuter la suite du script.

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut
    Y a-t-il un moyen de savoir si la procédure a généré un code erreur SQLCODE ?

    Faut-il que je change ma procédure en fonction renvoyant un SQLCODE ?

    Merci d'avance de votre aide, et n'hésitez pas à me demander plus de précisions si besoin

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2002
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2002
    Messages : 6
    Points : 8
    Points
    8
    Par défaut
    Tu devrais lire le chapitre 8 de ce redbook pour savoir comment gérer les erreurs :
    http://www.redbooks.ibm.com/redbooks/pdfs/sg246503.pdf

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut
    Bonjour et merci pour le lien.

    J'ai changé quelque peu ma façon de faire en optant pour des fonctions. Pour l'instant, je n'ai pas vraiment avancé. Avant de me mettre à coder les fonctions dont j'ai besoin, j'ai préféré me lancer tout doucement en créant des fonctions toutes simples.. Malheureusement, j'ai encore des difficultés.

    Sur le lien du message précédent, issu donc d'une documentation IBM - qui a développé le DB2 - j'ai copié la fonction suivante dans mon outil Squirrel v3.4.0

    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
    CREATE FUNCTION DEC2DATE (
    DATEDEC DECIMAL(8, 0) )
    RETURNS DATE
    LANGUAGE SQL
    DETERMINISTIC
    CONTAINS SQL
    RETURNS NULL ON NULL INPUT
    NO EXTERNAL ACTION
    BEGIN
    DECLARE RESULT DATE ;
    DECLARE InvalidDate CONDITION FOR '22007';
    DECLARE EXIT HANDLER FOR InvalidDate
    BEGIN
    RETURN CAST(NULL AS DATE);
    SIGNAL SQLSTATE '01HDI' SET MESSAGE_TEXT='Invalid date';
    END;
    SET RESULT = DATE(
    SUBSTRING(DIGITS(DATEDEC),1,4) || '-' ||
    SUBSTRING(DIGITS(DATEDEC),5,2) || '-' ||
    SUBSTRING(DIGITS(DATEDEC),7,2));
    RETURN RESULT;
    END ;
    Le plus fort, c'est qu'il plante ! Le message d'erreur sorti par Squirrel est le suivant :

    An unexpected token "END-OF-STATEMENT" was found following "
    DECLARE RESULT DATE". Expected tokens may include: "<psm_semicolon>". SQL Code: -104, SQL State: 42601
    Error occured in:
    CREATE FUNCTION DEC2DATE (
    ...
    BEGIN
    DECLARE RESULT DATE

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2002
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2002
    Messages : 6
    Points : 8
    Points
    8
    Par défaut
    Tu n'as pas besoin de déclarer la zone RESULT. Aussi, remplace
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    RETURN DATE(                                   
      SUBSTRING(DIGITS(DATEDEC), 1, 4)   || '-' || 
      SUBSTRING(DIGITS(DATEDEC), 5, 2)   || '-' || 
      SUBSTRING(DIGITS(DATEDEC), 7, 2));
    et supprime
    ça doit marcher mais ne me demande pas pourquoi.

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut
    Effectivement, c'est bon merci. Je faisais juste ce test pour pouvoir appeler ma fonction (éditée sous SQL Developer) sous Squirrel.

    Je fais maintenant face à un autre problème concernant les fonctions. Voici la fonction en question :

    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
    CREATE FUNCTION TOTO()
         RETURNS INTEGER
         /*LANGUAGE SQL
         DETERMINISTIC
         NO EXTERNAL ACTION
         --MODIFIES SQL DATA
         STATIC DISPATCH
         CALLED ON NULL INPUT
         INHERIT SPECIAL REGISTERS*/
    BEGIN --not ATOMIC
         DECLARE TEST1 INTEGER;
         SET TEST1 = 1;
         UPDATE toto_vincent
         SET champ1 = 2
         where champ2 = 'toto';
         RETURN TEST1;
    END
    Voici le rapport d'erreur obtenu lors de la compilation sous SQL Developer :
    Rapport d'erreur :
    DB2 SQL error: SQLCODE: -577, SQLSTATE: 42985, SQLERRMC: TOTO;
    Le code SQLSTATE 42985 signifie que l'instruction n'est pas autorisée dans une routine. Dès que je mets la requête UPDATE en commentaires, la compilation passe. N'aurait-on pas le droit d'exécuter des requêtes UPDATE dans des fonctions ??? Cela me paraîtrait surprenant, mais bon je suis débutant en DB2 ...

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut
    Après avoir corrigé ma fonction, elle compile

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    CREATE FUNCTION TOTO()
         RETURNS INTEGER
         LANGUAGE SQL
         MODIFIES SQL DATA
    BEGIN --not ATOMIC
         DECLARE TEST1 INTEGER;
         SET TEST1 = 1;
         UPDATE toto_vincent
         SET champ1 = 1
         where champ2 = 'toto';
         RETURN TEST1;
    END
    Seulement, je rencontre un problème lors de l'exécution. Sous Squirrel, j'exécute la requête suivante :

    SELECT TOTO() FROM SYSIBM.SYSDUMMY1

    Et j'obtiens le message d'erreur suivant :

    Routine "LIGIS.TOTO" (specific name "SQL120927110055300") is defined with the MODIFIES SQL DATA option, which is not valid in the context where the routine is invoked. SQL Code: -740, SQL State: 51034
    J'ai cru comprendre que la clause 'MODIFIES SQL DATA' ne devait être appliquée que dans le cas de fonctions retournant une table et non des valeurs scalaires. Cependant, ma fonction a bel et bien été compilée ... Je n'y comprends plus grand chose !

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut
    Bonjour

    J'ai avancé sur mon sujet, mais je galère depuis le début d'après-midi sur un point. J'ai un script sql qui lance une procédure. Cette procédure doit me retourner en sortie les codes erreur des exceptions générées. Ensuite, dans mon script sql, si les codes sql retournés indique des erreurs, j'insère ces erreurs dans une table de ma base et je stoppe ensuite l'exécution du script sql.

    Pour être plus clair dans ma demande, je vous fournis les différents scripts :

    script sql lançant les procédures

    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
    CREATE OR REPLACE PROCEDURE appel_procedures() LANGUAGE SQL
    BEGIN
        --Déclaration des variables
        --declare retsqlcode_decompte_poste_01 integer default 0;
        --declare retsqlstate_decompte_poste_01 char(5) default '00000';
        DECLARE sqlcode_toto integer default 0;
        declare sqlstate_toto char(5) default '00000';
     
    /*------------------------------------------------------------------------------
                                    TABLE TOTO
    ------------------------------------------------------------------------------*/
        call insert_toto(sqlcode_toto,sqlstate_toto);
        if sqlcode_toto <> 0 and sqlstate_toto <> '00000' then
            call insert_erreur_fusion_caisses(sqlcode_toto, sqlstate_toto, 'insert_toto');
            exit;
        end if;
     END
    Procédure appelée (insert_toto)

    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
    create or replace procedure insert_toto (out retsqlcode integer, out retsqlstate char(5))
    begin
        DECLARE SQLCODE INTEGER DEFAULT 0;
        DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
        declare var INTEGER;
     
        DECLARE continue HANDLER FOR SQLEXCEPTION
        begin
            set var=3;
            INSERT INTO toto values (var);
            commit;
            SET retsqlcode = SQLCODE;
            SET retsqlstate = SQLSTATE;
        end;
     
     
     
        insert into toto values ('taratata');
     
    end
    Procédure d'insertion en base

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    CREATE OR REPLACE PROCEDURE insert_erreurs_fusion_caisses(
    IN code_erreur integer, IN etat_erreur char(5), IN nom_procedure char(100)) LANGUAGE SQL
     
    BEGIN
        INSERT INTO GESTION_ERREURS_SQL
        VALUES('FUSION CAISSES 0312 0715',nom_procedure,code_erreur,etat_erreur,current timestamp);
    END
    Je précise que la table toto est constituée d'un champ de type integer. Ainsi, dans ma procédure insert_toto, lorsque il exécute l'instruction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    insert into toto values ('taratata');
    , il devrait lever une exception et me l'insérer dans la table GESTION_ERREURS_SQL, mais rien ne se passe. Pouvez-vous m'aider svp ? Merci

  13. #13
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut
    J'ai pas mal avancé depuis ma dernière intervention. Parmi les procédures ci-dessus, seule insert_toto a été modifiée :

    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
    create or replace procedure insert_toto (inout retsqlcode integer, inout retsqlstate char(5))
    begin
        DECLARE SQLCODE INTEGER default 0;
        DECLARE SQLSTATE CHAR(5);
        declare var INTEGER;
     
        DECLARE continue HANDLER FOR SQLEXCEPTION
        begin
            SET retsqlcode = SQLCODE;
            SET retsqlstate = SQLSTATE;
            insert into toto2 values (retsqlcode, retsqlstate);
            commit;
        end;
        insert into toto values ('ffdsfsd');
     
    end
    La dernière requête de cette procédure génère bien une exception. Le code SQLCODE est bien enregistré dans la table toto2, mais le code SQLSTATE n'est pas actualisé et reste à '00000'. Une idée du pourquoi du comment ?

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 157
    Points : 69
    Points
    69
    Par défaut
    J'abandonne pour le SQLSTATE. Merci à ceux qui auront pris le temps de réfléchir à mes problèmes !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Gestion d'exception dans une procédure stockée
    Par ramone dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 30/09/2010, 18h58
  2. Réponses: 0
    Dernier message: 07/11/2009, 11h46
  3. Réponses: 2
    Dernier message: 30/10/2008, 16h29
  4. Réponses: 3
    Dernier message: 21/12/2007, 09h57
  5. Réponses: 1
    Dernier message: 12/12/2007, 13h46

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