2013-04-24 12 views
6

Come posso trovare la posizione di un errore in un'istruzione SQL dinamica in PL/SQL o SQL?Oracle: trova la posizione di un errore in SQL dinamico utilizzando SQL o PL/SQL

da SQL * Plus vedo la posizione di un errore, per esempio, un invalido un'istruzione SQL DML:

[email protected]> SELECT 
     2 X 
     3 FROM 
     4 TABLEX 
     5/
    TABLEX 
    * 
ERROR at line 4: 
ORA-00942: table or view does not exist 

SQL * Plus mostra l'errore con il numero di riga, e le stampe e segni di quella linea con un asterisco in cui è stato trovato l'errore.

Conversione in SQL dinamico, posso ottenere il codice di errore (SQLCODE) e il messaggio di errore (SQLERRM):

[email protected]> SET SERVEROUTPUT ON 
[email protected]> BEGIN 
     2 EXECUTE IMMEDIATE 'SELECT X FROM TABLEX'; 
     3 EXCEPTION 
     4 WHEN OTHERS THEN 
     5  DBMS_OUTPUT.PUT_LINE('SQLCODE:' || SQLCODE); 
     6  DBMS_OUTPUT.PUT_LINE('SQLERRM:' || SQLERRM); 
     7 END; 
     8/
SQLCODE:-942 
SQLERRM:ORA-00942: table or view does not exist 

Ma come faccio a ottenere la posizione dell'errore nella stringa SQL dinamico?

Vedo che Oracle fornisce un'area di comunicazioni SQL (SQLCA) che contiene informazioni interessanti su un errore. In particolare:

  • i campi SQLCODE e SQLERRM (che potrebbe essere la fonte dei dati recuperati con le rispettive funzioni PL/SQL),
  • campo SQLERRD dove la (5) dell'elemento SQLERRD che dà la ' errore di errore di parsing '.

È possibile accedere a SQLERRD da PL/SQL o SQL? Se é cosi, come? In caso contrario, quale altra tecnica può dare la posizione dell'errore da PL/SQL o SQL?

(Qui http://docs.oracle.com/cd/B28359_01/appdev.111/b31231/chapter8.htm#BABIGBFF SQLCA è documentata e vi si accede con Pro * C.)

(La risposta qui how to declare SQLCA.SQLERRD? sembra indicare che SQLERRD non è definito in PL/SQL e quindi non accessibili.)

(La discussione qui Why doesn't Oracle tell you WHICH table or view does not exist? fornisce alcuni suggerimenti per mostrare l'errore di SQL utilizzando i file di traccia e per mostrare la posizione degli errori in alcuni strumenti di sviluppo.)

risposta

1

L'esecuzione dell'istruzione tramite PL/SQL dinamico memorizzerà il numero di riga pertinente nello stack di errori .

Ad esempio, questa affermazione ha un errore sulla linea 4:

declare 
    v_count number; 
    v_bad_sql varchar2(32767) := 
     'SELECT 
      X 
      FROM 
      TABLEX'; 
begin 
    execute immediate v_bad_sql into v_count; 
exception when others then 
    begin 
     execute immediate 
      'begin for i in ('||v_bad_sql||') loop null; end loop; end;'; 
    exception when others then 
     dbms_output.put_line(sqlerrm); 
    end; 
end; 
/

ORA-06550: line 4, column 4: 
PL/SQL: ORA-00942: table or view does not exist 
ORA-00942: table or view does not exist 
ORA-06550: line 1, column 18: 
PL/SQL: SQL Statement ignored 
ORA-00942: table or view does not exist 

Ci sono alcuni svantaggi di questo metodo:

  1. richiede un po ', brutto codice aggiuntivo per intercettare l'eccezione e ri -ripetere l'SQL.
  2. L'esempio funziona solo per selezionare. Dovrai modificarlo per inserire, aggiornare, eliminare, unire, PL/SQL dinamico, ecc. Normalmente dovresti sapere che tipo di istruzione SQL è. Se sei sfortunato, dovrai analizzare la dichiarazione, che può essere molto difficile.
  3. Il numero di colonna è errato se l'intera istruzione PL/SQL si trova su una riga.
+0

Sto cercando di imitare il comportamento di SQL * Plus stampando la linea incriminata e un'altra linea che segnano l'inizio del problema con un asterisco Posso ottenere ciò di cui ho bisogno analizzando lo stack degli errori per ottenere il numero di righe e colonne, ma esiste un modo più semplice? –

+0

Per quanto ne so non c'è modo più semplice. –

3

hai un pacchetto per estrarre i messaggi di errore in dbms_utility

begin 
    .. generate error 
exception when others then 
    dbms_output.put_line(
     dbms_utility.format_call_stack()  || chr(10) || 
     dbms_utility.format_error_backtrace() || chr(10) || 
     dbms_utility.format_error_stack()) 
end; 
+2

Fiddle SQL con esempio: http://www.sqlfiddle.com/#!4/471dd/1 – ThinkJet

+1

DBMS_UTILITY di per sé non è sufficiente per trovare il numero di riga * all'interno * di un'istruzione SQL dinamica. @ Il secondo blocco di ThinkJet funzionerà, sebbene ci sia ancora la difficoltà di avvolgere l'SQL in un blocco SQL dinamico. (Il primo blocco non funzionerà sempre - non otterrà i numeri di riga corretti per gli errori di analisi, ad esempio se il nome della tabella è sbagliato.) –