2017-12-07 2 views
4

Ich bin in einem Verhalten, wo ich versuche, Fall-spezifische Ausnahmehandler für mehrere Oracle PL/SQL-Blöcke in einem Flyway-Skript und Oracle zu verwenden, scheinbar im Widerspruch zu seinen dokumentiert Scoping für Exception-Handler, sendet alle Ausnahmen an den Exception-Handler für den ersten Block. Zum Beispiel in diesem Code:Oracle verwendet Ausnahmehandler aus dem ersten Block in späteren Blöcken

begin 

    begin 
    execute immediate ' 
create table "test" (
    "id" number not null, 
    "name" varchar2(100) not null, 
    constraint "test_pk" primary key ("id") 
) 
'; 
    exception 
    when others then 
    if sqlcode != -955 then raise; end if; 
    end; 

    begin 
    execute immediate 'fail to create index "test_name_idx" on "test" ("name")'; 
    exception 
    when others then 
    if sqlcode != -6512 then raise; end if; 
    end; 

end; 

der ORA-06512 Ausnahme nicht abgefangen wird, und die Ausnahme ausgelöst wird, wie von der Linie markiert 13.

Wrapping die Blöcke in mehreren Blöcken hilft nicht.

Was geht hier vor? Wie verhindere ich das?

+0

Das ist sehr ... interessant. Wenn Sie vor dem ersten Raise (innerhalb des if) einen einfachen 'dbms_output'-Aufruf hinzufügen, wird die korrekte Zeilennummer von einem schnellen Test auf livesql.oracle.com gemeldet.Aber auch mit mehr Debugs trifft es den ersten Exception-Handler nicht (wie man es natürlich erwartet), auch wenn er die falsche Zeilennummer meldet. Sieht aus wie ein (Parsing?) Fehler, vielleicht in 'dbms_sql'? Könnte interessant sein zu sehen, ob es sich gleichgültig verhält. –

+2

Sieht ein bisschen wie Bug 8856896 von 10g, aber das ist 12cR2, zumindest an dieser Stelle. Könnte es Zeit sein, eine Serviceanfrage mit Oracle Support zu stellen? –

+1

FWIW, reproduziert Problem auf Oracle 12.1.0.2.0. Nur eine beiseite, sich wundernd, warum Sie versuchen, ORA-06512 ("Fehler ist in Zeile n") zu fangen, da die tatsächlichen Ausnahmen, die Sie interessieren würden, wäre ORA-00955 ("Name wird bereits verwendet von ein bestehendes Objekt ") und ORA-01408 (" solche Spaltenliste ist bereits indiziert "). –

Antwort

3

Dies scheint ein Fehler zu sein, der (bisher) in 11.2.0.4, 12.1.0.2 und 12.2.0.1 reproduziert wurde. Es scheint DDL oder irgendeine echte Handlung im ersten Unterblock nicht zu erfordern (obwohl gerade null; als ein Platzhalter es nicht löst, möglicherweise weil der Compiler es entfernt), aber es scheint, das if innen zu benötigen beide Exception-Handler:

begin 
    begin 
    dbms_output.put_line('Dummy message'); 
    exception 
    when others then 
     dbms_output.put_line('In first exception handler'); 
     if 1=1 then 
     raise; 
     end if; 
    end; 

    begin 
    execute immediate 'invalid'; 
    exception 
    when others then 
     dbms_output.put_line('In second exception handler'); 
     if 1=1 then 
     raise; 
     end if; 
    end; 
end; 
/

Dummy message 
In second exception handler 

ORA-00900: invalid SQL statement 
ORA-06512: at line 8 
ORA-06512: at line 13 

wie bei Ihrem Beispiel die Ausnahme 13 durch die Linie geworfen wird, um gemeldet werden sollte (Wieder-) in Zeile angehoben 18; aber es wird stattdessen berichtet, wie es aus Zeile 8 hervorgeht, was keinen Sinn ergibt. (Die Meldung at line 13 wird nur in 12.2 angezeigt; in 11.2 und 12.1 meldet sie nur die erste ORA-06512, die eher verwirrend ist. Zumindest in 12 2 haben Sie eine Ahnung, wo das Problem wirklich liegt.)

Die Debugs, die Sie sehen können, verwenden nicht den ersten Ausnahmebehandler, und es geht in den zweiten über. Es "scheint" nur gegen die falsche Zeilennummer zu berichten, anstatt den falschen Code auszuführen.

Es scheint, dass im Innern der if eigentliche Arbeit tun, unmittelbar vor den raise irgendwie behebt Dinge - in entweder Ausnahmebehandlung Abschnitt; Dies fügt eine Nachricht in der ersten, die nicht erreicht werden kann:

begin 
    begin 
    dbms_output.put_line('Dummy message'); 
    exception 
    when others then 
     dbms_output.put_line('In first exception handler'); 
     if 1=1 then 
     dbms_output.put_line('This avoids the bug somehow'); 
     raise; 
     end if; 
    end; 

    begin 
    execute immediate 'invalid'; 
    exception 
    when others then 
     dbms_output.put_line('In second exception handler'); 
     if 1=1 then 
     raise; 
     end if; 
    end; 
end; 
/

Dummy message 
In second exception handler 

ORA-00900: invalid SQL statement 
ORA-06512: at line 19 
ORA-06512: at line 14 

und dies in der zweiten:

begin 
    begin 
    dbms_output.put_line('Dummy message'); 
    exception 
    when others then 
     dbms_output.put_line('In first exception handler'); 
     if 1=1 then 
     raise; 
     end if; 
    end; 

    begin 
    execute immediate 'invalid'; 
    exception 
    when others then 
     dbms_output.put_line('In second exception handler'); 
     if 1=1 then 
     dbms_output.put_line('This avoids the bug somehow'); 
     raise; 
     end if; 
    end; 
end; 
/

Dummy message 
In second exception handler 

ORA-00900: invalid SQL statement 
ORA-06512: at line 19 
ORA-06512: at line 13 

In beiden Fällen ist die gemeldete Zeilennummer jetzt korrekt ist. Irgendwie.

Es muss kein dbms_output Aufruf sein, irgendetwas scheint zu funktionieren, wie ein Dummy-Prozeduraufruf oder -abfrage, sogar ein zusätzlicher Unterblock (zB begin execute immediate 'select * from dual'; end;, obwohl die Abfrage nicht ausgeführt wird, weil es keine gibt into ...). Wieder funktioniert nur null; funktioniert nicht.

Dies ist ein bisschen hässlich, aber gibt Ihnen einen Weg, um es zumindest zu stoppen, irgendwie.

Es ist eindeutig seltsam und unerwartet und inkonsistent Verhalten, und es ist schon seit einer Weile, so sollte es wahrscheinlich als Service-Anfrage über My Oracle Support ausgelöst werden. Ich kann keine vorhandenen Berichte sehen, aber ich habe nicht sehr angestrengt, also könnte irgendwo jemand lauern.

Verwandte Themen