Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a PL/SQL bug?

Here's an excerpt from some PL/SQL code that I believe demonstrates a PL/SQL bug:

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

When these lines are executed, it prints

guid_ is null: 07D242FCC55000FCE0530A30D4928A21

I am on 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

I can reproduce this with the following types and anonymous block. Sorry for the length, but I believe I cannot shorten it any more:

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;

Note also, that when I change b tq84_o to b tq84_d, the error does not occur anymore.

Can someone verify if this is happening on other systems as well?

like image 434
René Nyffenegger Avatar asked Nov 14 '14 14:11

René Nyffenegger


People also ask

What is the error code prefix for PL SQL errors?

PL/SQL warning messages all use the prefix PLW .

Is PL SQL outdated?

The answer is that PL/SQL is not growing, but not going away either. Because it is used in the Oracle database, and the Oracle database is a fixture of enterprise systems world-wide, it will outlive you. High-performance batch processing has to happen close to the data, so PL/SQL will continue to rule in this area.

What is exception in PL SQL?

An exception is a PL/SQL error that is raised during program execution, either implicitly by TimesTen or explicitly by your program. Handle an exception by trapping it with a handler or propagating it to the calling environment.

Is PL SQL better than SQL?

Q: Which is better: SQL or PL/SQL? PL/SQL is an extension of SQL and further includes many procedural features like function, data variables, exception handling, and triggers. Moreover, PL/SQL allows us to transfer an entire block of statements to the database at once whereas SQL executes a single query at a time.


1 Answers

To me this is a bug. In the IF the variable guid_ is not treated the same as in the the string concatenation for the put_line. What I find strange is that before the b.clear statement the is null works:

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

I workaround the problem when returning the GUID from a function:

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

The above code does not go into neither of the if guid_ is null. So to me this proves it:

This is a bug.

like image 156
hol Avatar answered Oct 08 '22 05:10

hol