2014-11-14 14 views
11

Hier ist ein Auszug aus einigen PL/SQL-Code, ich glaube, ein PL/SQL-Fehler zeigt:Ist das ein PL/SQL-Fehler?

if guid_ is null then 
    dbms_output.put_line('guid_ is null: ' || guid_); 
end if; 

Wenn diese Zeilen ausgeführt werden, es

guid_ is null: 07D242FCC55000FCE0530A30D4928A21 

druckt ich auf Oracle 11R2 am

select * from v$version; 

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production 
PL/SQL Release 11.2.0.4.0 - Production 
CORE 11.2.0.4.0  Production 
TNS for IBM/AIX RISC System/6000: Version 11.2.0.4.0 - Production 
NLSRTL Version 11.2.0.4.0 - Production 

Ich kann dies mit den folgenden Typen und anonymen Block reproduzieren. Sorry für die Länge, aber ich glaube ich es nicht mehr verkürzen kann:

auch
create type tq84_t as table of varchar2(32); 
/

create type tq84_o as object (
    dummy number(1), 

    not final member procedure clear 

) not final; 
/

show errors 

create type tq84_d under tq84_o (

    g varchar2(32), 
    constructor function tq84_d return self as result, 

    overriding member procedure clear 


); 
/
show errors 


create package tq84_h as 

    t tq84_t; 

end tq84_h; 
/
show errors 



create package body tq84_h as 
begin 

    t := tq84_t(); 
end; 
/
show errors 

create type body tq84_o as 

    member procedure clear is begin 
     null; 
    end clear; 

end; 
/

create type body tq84_d as 

    constructor function tq84_d return self as result is 
    begin 

     g := sys_guid; 
     return; 

    end tq84_d; 

    overriding member procedure clear is begin 

     tq84_h.t.extend; 
     tq84_h.t(tq84_h.t.count) := g; 

     g := null; 

    end clear; 

end; 
/
show errors 


declare 

    b tq84_o; -- Change to tq84_d ... 

    guid_ varchar2(32); 

begin 

    b := new tq84_d; 

    guid_ := treat(b as tq84_d).g; 

    b.clear; 

    if guid_ is null then 
    dbms_output.put_line('guid_ is null: ' || guid_); 
    end if; 


end; 
/

drop type tq84_t; 
drop type tq84_d; 
drop type tq84_o; 
drop package tq84_h; 

Beachten Sie, dass, wenn ich b tq84_o-b tq84_d ändern, tritt der Fehler nicht mehr auftreten.

Kann jemand überprüfen, ob dies auch auf anderen Systemen geschieht?

+0

Ich bin mir nicht sicher, warum dies noch nicht der Fall ist, aber wenn 'b tq84_o' in' b tq84_d' geändert wird, wird 'guid_' nicht-null, wenn die 'if'-Bedingung ausgewertet wird. Das Hinzufügen einer "else" -Anweisung, die eine ähnliche Aussage ausgibt, bestätigt dies. – Allan

+1

Ich habe gerade festgestellt, dass der Fehler ist, dass "wenn guid_ null ist" evaluiert, um wahr, nicht dass der 'dbms_output' einen Wert zurückgibt, wenn die Variable null sein sollte. – Allan

+0

Darüber hinaus bewirkt das Hinzufügen eines "else", dass die Version mit "b tq84_o" wie erwartet funktioniert. – Allan

Antwort

1

Für mich ist das ein Fehler. In der IF wird die Variable guid_ nicht gleich behandelt wie in der String-Verkettung für die put_line. Was ich seltsam finde ist, dass vor der b.clear Aussage der is null Werke:

declare 
    b tq84_o; -- Change to tq84_d ... 
    guid_ varchar2(32); 
begin 
    b := new tq84_d; 
    guid_ := treat(b as tq84_d).g; 

    if guid_ is null then 
    dbms_output.put_line('before clear: guid_ is null: ' || guid_); 
    end if; 

    b.clear; 

    if guid_ is null then 
    dbms_output.put_line('after clear: guid_ is null: ' || guid_); 
    end if; 
end; 
/

Ausgang:

after clear: guid_ is null: 07D43ACB728A2173E054A0481C66CF28 

ich das Problem zu umgehen, wenn die GUID aus einer Funktion zurückkehrt:

declare 
    b tq84_o; -- Change to tq84_d ... 
    guid_ varchar2(32); 
    function get_guid 
    return varchar2 is 
    begin 
    return treat(b as tq84_d).g; 
    end; 
begin 
    b := new tq84_d; 
    guid_ := get_guid; -- treat(b as tq84_d).g; 

    if guid_ is null then 
    dbms_output.put_line('before clear: guid_ is null: ' || guid_); 
    end if; 

    b.clear; 

    if guid_ is null then 
    dbms_output.put_line('after clear: guid_ is null: ' || guid_); 
    end if; 
end; 
/

Die Der obige Code geht nicht in die if guid_ is null. Also für mich das beweist es:

Dies ist ein Fehler.

0

Es sieht aus wie ein Oracle Bug. Ich sehe dasselbe auf unserer Instanz von Oracle Enterprise 11.2.0.3.0 (64bit).

Nach dem Spielen ein wenig, ist es ziemlich klar, dass der Fehler in der if Bedingung ist: guid_ is null bewertet zu True, obwohl es einen Wert enthält.


Meine früheren Kommentar zu else scheint nicht mehr wahr zu sein. Entweder habe ich versehentlich das Testskript in irgendeiner Weise geändert oder der Fehler ist etwas unvorhersehbar.


Ich scheine zuverlässig die else Szenario Arbeit im Anschluss an diese Schritte zu machen:

  1. Ändern der if zu:

if guid_ is null then dbms_output.put_line('guid_ is null: ' || guid_); else dbms_output.put_line('guid_ is not null: ' || guid_); end if;

  1. Führen Sie das Skript aus. Die Ausgabe gibt die Nullnachricht zurück.
  2. Änderungserklärung von tq84_o zu tq84_d.
  3. Führen Sie das Skript aus; Die Ausgabe gibt die Nicht-Null-Nachricht zurück.
  4. Änderungserklärung zurück zu tq84_o.
  5. Führen Sie das Skript aus; Die Ausgabe gibt die Nicht-Null-Nachricht zurück.

aus diesem Prozess Meine Ausgabe ist:

guid_ is null: 07D41C8BCE696EA3E0539014190A7DA0 
guid_ is not null: 07D41C8BCE7D6EA3E0539014190A7DA0 
guid_ is not null: 07D41C8BCE916EA3E0539014190A7DA0 

Es sieht aus wie das korrigierte Verhalten nichts mit dem else zu tun hat. Wenn ich einfach das ursprüngliche Skript nehme und es zweimal in der gleichen Sitzung ausfühle, funktioniert es beim ersten Mal falsch und beim zweiten Mal richtig.

Wie @hol beobachtet, verschwindet dieser Fehler auch, wenn der Code in einer Funktion oder gespeicherten Prozedur ist. In meinem Fall habe ich den gesamten anonymen Block in eine Prozedur geändert und dann die Prozedur ausgeführt und der Fehler ist nicht aufgetreten.

+0

Bei meiner Installation, mit einem 'else', druckt es immer noch' guid_ ist null: ... '. –