2010-01-27 24 views
3

Je repérer des erreurs d'une opération d'insertion en bloc comme ceci:erreurs Oracle DML manquent de détails

begin 
    --bulk insert 
    forall i in v_data.first .. v_data.last save exceptions 
     insert into my_filter_table values v_data (i); 

    commit; 

exception 
    -- catch and print the saved-up DML errors. 
    when X_DML_ERRORS then 
     declare 
      v_iteration number; 
     begin 
      dbms_output.put_line(''); 
      dbms_output.put_line('DML Errors:'); 
      for i in 1 .. SQL%BULK_EXCEPTIONS.count loop 
       v_iteration := SQL%BULK_EXCEPTIONS(i).error_index; 

       dbms_output.put_line('Iteration: '||v_iteration||' Message: '|| 
           SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE)); 


      end loop; 
     end; 
end; 

La sortie ressemble à ceci:

 
    Iteration: 3 Message: ORA-01400: cannot insert NULL into() 
    Iteration: 4 Message: ORA-02290: check constraint (.) violated 
    Iteration: 8 Message: ORA-00001: unique constraint (.) violated 

Le fait que je reçois des erreurs ne ne me dérange pas, car je teste le code de gestion des erreurs. Le problème est que le message d'erreur Oracle n'affiche pas les noms des contraintes, c'est-à-dire qu'il affiche check constraint (.) violated mais cela ne me dit pas QUELLE contrainte de vérification j'ai violée.

Est-ce que quelqu'un sait quoi de neuf?

(version Oracle 10.2)

Répondre

6

BULK_EXCEPTIONS SQL% (i) .error_code enregistre uniquement le numéro d'erreur Oracle. Vous utilisez ensuite la fonction sqlerrm pour rechercher le texte du message d'erreur. Cette fonction n'aurait aucun moyen de savoir quelle contrainte est brisée.

Vous pouvez appeler la fonction sqlerrm sans qu'une exception soit levée pour dupliquer vos résultats.

begin 
    dbms_output.put_Line(sqlerrm(-1400)); 
    dbms_output.put_Line(sqlerrm(-2290)); 
    dbms_output.put_Line(sqlerrm(-1)); 
end; 

qui délivre en sortie

ORA-01400: cannot insert NULL into() 
ORA-02290: check constraint (.) violated 
ORA-00001: unique constraint (.) violated 

Une solution possible serait de réexécuter l'instruction a échoué dans le gestionnaire d'exception.

Tableau Def:

create table t (x number(1) primary key); 

code:

declare 
    dml_errors EXCEPTION; 
    PRAGMA EXCEPTION_INIT(dml_errors, -24381); 
    TYPE t_nums is table of NUMBER; 
    l_nums t_nums := t_nums(1,1,10); 
begin 
    forall i in 1..l_nums.count save exceptions 
     execute immediate 'insert into t values (:x)' using l_nums(i); 
exception 
    when dml_errors then 
     for j in 1..sql%bulk_exceptions.count 
     loop 
     if sql%bulk_exceptions(j).error_code = 1 
     then 
      begin 
       execute immediate 'insert into t values (:x)' 
        using l_nums(sql%bulk_exceptions(j).error_index); 
      exception 
       when dup_val_on_index then 
        dbms_output.put_line(sqlerrm); 
      end; 
     else 
      dbms_output.put_line(sqlerrm(-sql%bulk_exceptions(j).error_code)); 
     end if; 
     end loop; 
end; 

qui sort:

ORA-01438: value larger than specified precision allowed for this column 
ORA-00001: unique constraint (XXXXXXXX.SYS_C00264470) violated 
ORA-24381: error(s) in array DML 
+0

Emge @ Daniel: Hmmm ouais ce sens. Tirer! Je suppose que% BULK_EXCEPTIONS ne stocke pas les détails de l'erreur spécifique, ce que j'essaie de faire n'est probablement pas possible. – FrustratedWithFormsDesigner

+1

J'ai pensé à une solution de contournement. Vous pouvez réexécuter l'instruction dans le gestionnaire d'exceptions pour chaque ligne ayant échoué. Vous pouvez alors attraper cette exception qui aura le nom de la contrainte. –

+0

Hey c'est assez intelligent! Merci! :) – FrustratedWithFormsDesigner