2014-11-14 80 views
11

下面是一些PL/SQL代码的摘录,我认为展示一个PL/SQL错误:这是PL/SQL错误吗?

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

当这些线条被执行,它打印

guid_ is null: 07D242FCC55000FCE0530A30D4928A21 

我在Oracle 11R2

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 

我可以用下面的类型和匿名块重现这一点。很抱歉的长度,但我相信我能不能缩短它了:

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; 

还要注意,当我改变b tq84_ob tq84_d,不会再出现错误。

有人可以验证这是否也发生在其他系统上?

+0

我不确定这是为什么,但是当'if'条件被评估时,将'b tq84_o'改为'b tq84_d'会导致'guid_'不为空。添加一个打印类似语句的'else'语句证实了这一点。 – Allan 2014-11-14 15:20:28

+1

我刚刚意识到错误是'如果guid_为null'则评估为true,而不是当'dbms_output'在变量应该为null时返回一个值。 – Allan 2014-11-14 15:24:21

+0

此外,添加'else'会导致带有'b tq84_o'的版本按预期行事。 – Allan 2014-11-14 15:28:31

回答

1

对我来说这是一个错误。在IF中,变量guid_的处理方式与put_line的字符串连接中的处理方式不同。我觉得奇怪的是,b.clear语句之前is null作品:

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; 
/

输出:

after clear: guid_ is null: 07D43ACB728A2173E054A0481C66CF28 

我解决方法从函数返回的GUID的问题时:

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; 
/

的上面的代码不会进入if guid_ is null。所以对我来说,这证明了它:

这是一个错误。

0

它看起来像一个Oracle错误。我在Oracle Enterprise 11.2.0.3.0(64位)的实例中看到了同样的情况。

稍微玩了一下之后,很明显该错误出现在if的条件下:guid_ is null即使它包含一个值也正在评估为true。


我之前对else的评论似乎不再是真实的。要么我以某种方式无意中更改了测试脚本,要么该错误有点不可预测。


我似乎可靠地使else场景工作是按照以下步骤:

  1. 更改if到:

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;

  • 运行脚本;输出返回空消息。
  • 将声明从tq84_o更改为tq84_d
  • 运行脚本;输出将返回非空消息。
  • 将声明更改回tq84_o
  • 运行脚本;输出将返回非空消息。
  • 我从这个过程的输出是:

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

    它看起来像校正行为无关与else。如果我只是采用原始脚本并在同一会话中运行两次,它将在第一次正确运行,第二次正确运行。


    正如@hol观察到的,如果代码在函数或存储过程中,这个bug也会消失。就我而言,我将整个匿名块更改为一个过程,然后运行该过程,并且没有发生错误。

    +0

    在我的安装中,使用'else',它仍然打印'guid_为null:...'。 – 2014-11-14 15:54:24