2014-11-14 14 views
11

Dưới đây là một đoạn trích từ một số mã PL/SQL mà tôi tin thể hiện một lỗi PL/SQL:Đây có phải là lỗi PL/SQL không?

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

Khi những dòng này được thực hiện, nó in

guid_ is null: 07D242FCC55000FCE0530A30D4928A21 

Tôi đang trên 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 

Tôi có thể tạo lại điều này với các loại sau và khối ẩn danh. Xin lỗi vì chiều dài, nhưng tôi tin rằng tôi không thể rút ngắn nó nữa:

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; 

Cũng lưu ý, đó là khi tôi thay đổi b tq84_o-b tq84_d, lỗi không xảy ra nữa.

Ai đó có thể xác minh xem điều này có xảy ra trên các hệ thống khác không?

+0

Tôi không chắc chắn lý do tại sao đây là nêu ra, nhưng thay đổi 'b tq84_o' để' b tq84_d' gây 'guid_' là không rỗng khi' điều kiện if' được đánh giá. thêm câu lệnh 'else' để in một câu lệnh tương tự xác nhận điều đó. – Allan

+1

Tôi chỉ nhận ra rằng lỗi là 'nếu guid_ được null' được đánh giá là true, không phải là 'cái dbms_output' được trả lại một giá trị khi biến nên được null. – Allan

+0

Hơn nữa, thêm một 'else' làm cho phiên bản với 'b tq84_o' để hoạt động như mong đợi. – Allan

Trả lời

1

Đối với tôi đây là một lỗi. Trong IF biến guid_ không được điều trị giống như trong nối các chuỗi cho put_line. Những gì tôi thấy lạ là trước khi tuyên bố b.clear các is null công trình:

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

Output:

after clear: guid_ is null: 07D43ACB728A2173E054A0481C66CF28 

tôi workaround vấn đề khi trở về GUID từ một hàm:

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

Các mã trên không đi vào trong số if guid_ is null. Vì vậy, đối với tôi điều này chứng tỏ nó:

Đây là một lỗi.

0

Dường như lỗi của Oracle. Tôi thấy điều tương tự trên phiên bản Oracle Enterprise 11.2.0.3.0 (64bit) của chúng tôi.

Sau khi chơi với nó một chút, nó là khá rõ ràng rằng lỗi là trong điều kiện if: guid_ is null được đánh giá là đúng ngay cả khi nó có chứa một giá trị.


Nhận xét trước đây của tôi về else dường như không còn đúng. Hoặc tôi vô tình thay đổi kịch bản thử nghiệm theo một cách nào đó hoặc lỗi này có phần không thể đoán trước được.


tôi dường như đáng tin cậy làm cho công việc else kịch bản được làm theo các bước sau:

  1. Thay đổi if tới:

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. Chạy tập lệnh; đầu ra trả về thông điệp rỗng.
  2. Thay đổi tuyên bố từ tq84_o thành tq84_d.
  3. Chạy tập lệnh; đầu ra trả về thông điệp không rỗng.
  4. Thay đổi tuyên bố về tq84_o.
  5. Chạy tập lệnh; đầu ra trả về thông điệp không rỗng.

đầu ra của tôi từ quá trình này là:

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

Dường như hành vi điều chỉnh không có gì để làm với các else. Nếu tôi chỉ đơn giản là lấy kịch bản gốc và chạy nó hai lần trong cùng một phiên, nó hoạt động không chính xác lần đầu tiên và chính xác lần thứ hai.


Khi @hol quan sát, lỗi này cũng biến mất nếu mã nằm trong một hàm hoặc thủ tục được lưu trữ. Trong trường hợp của tôi, tôi đã thay đổi toàn bộ khối ẩn danh thành một thủ tục rồi chạy thủ tục và lỗi đã không xảy ra.

+0

Khi cài đặt của tôi, với 'else', nó vẫn in' guid_ is null: ... '. –

Các vấn đề liên quan