Skip to Main Content
  • Questions
  • Pipelined function does not handle collection function calls properly

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Jacek.

Asked: November 20, 2016 - 1:27 am UTC

Last updated: November 28, 2016 - 2:55 am UTC

Version: Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production

Viewed 1000+ times

You Asked

Hi,
When using a pipelined function that calls another function, returning a collection I get wrong results.

Here is an isolated test case
select * from v$version;

create or replace type an_array as table of varchar2(32767);
/

create or replace package tst_array_pipe_bug is
  function get_array return an_array;
  function get_array_pipe return an_array pipelined;
end;
/

create or replace package body tst_array_pipe_bug is
  function get_array return an_array is
  begin
    return an_array('a');
  end;
  function get_array_pipe return an_array pipelined is
    l_results an_array := an_array();
  begin

    for i in 1 .. 10 loop
      -- l_results.delete; -- this one causes exception when i > 1 second row
      l_results := get_array();
      dbms_output.put_line('l_results.count='||lpad(l_results.count,2)||' (should be l_results.count=1)' );
      for j in 1 .. l_results.count loop
        pipe row(l_results(j));
      end loop;
    end loop;
    return;
  end;
end;
/

declare
  l_result an_array;
begin
  select *
    bulk collect into l_Result
    from table(tst_array_pipe_bug.get_array_pipe());
    dbms_output.put_Line('returned l_result.count='||l_result.count);
end;
/


And the results that I see:

BANNER                                                                         
--------------------------------------------------------------------------------
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production       
PL/SQL Release 11.2.0.2.0 - Production                                          
CORE 11.2.0.2.0 Production                                                        
TNS for Linux: Version 11.2.0.2.0 - Production                                  
NLSRTL Version 11.2.0.2.0 - Production                                          


Type AN_ARRAY compiled


Package TST_ARRAY_PIPE_BUG compiled


Package body TST_ARRAY_PIPE_BUG compiled


PL/SQL procedure successfully completed.

l_results.count= 1 (should be l_results.count=1)
l_results.count= 2 (should be l_results.count=1)
l_results.count= 3 (should be l_results.count=1)
l_results.count= 4 (should be l_results.count=1)
l_results.count= 5 (should be l_results.count=1)
l_results.count= 6 (should be l_results.count=1)
l_results.count= 7 (should be l_results.count=1)
l_results.count= 8 (should be l_results.count=1)
l_results.count= 9 (should be l_results.count=1)
l_results.count=10 (should be l_results.count=1)
returned l_result.count=55


I've tried the same code on LiveSQL and got the valid results:


with LiveSQL Test Case:

and Connor said...

I'm seeing valid results on 11.2.0.4 and 12.1.0.2


SQL> set serverout on
SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
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 64-bit Windows: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

5 rows selected.

SQL>
SQL> create or replace type an_array as table of varchar2(32767);
  2  /

Type created.

SQL>
SQL> create or replace package tst_array_pipe_bug is
  2    function get_array return an_array;
  3    function get_array_pipe return an_array pipelined;
  4  end;
  5  /

Package created.

SQL>
SQL> create or replace package body tst_array_pipe_bug is
  2
  3    function get_array return an_array is
  4    begin
  5      return an_array('a');
  6    end;
  7
  8    function get_array_pipe return an_array pipelined is
  9      l_results an_array := an_array();
 10    begin
 11
 12      for i in 1 .. 10 loop
 13        -- l_results.delete; -- this one causes exception when i > 1 second row
 14        l_results := get_array();
 15        dbms_output.put_line('l_results.count='||lpad(l_results.count,2)||' (should be l_results.count=1)' );
 16        for j in 1 .. l_results.count loop
 17          pipe row(l_results(j));
 18        end loop;
 19      end loop;
 20      return;
 21    end;
 22  end;
 23  /

Package body created.

SQL>
SQL> declare
  2    l_result an_array;
  3  begin
  4    select *
  5      bulk collect into l_Result
  6      from table(tst_array_pipe_bug.get_array_pipe());
  7      dbms_output.put_Line('returned l_result.count='||l_result.count);
  8  end;
  9  /
l_results.count= 1 (should be l_results.count=1)
l_results.count= 1 (should be l_results.count=1)
l_results.count= 1 (should be l_results.count=1)
l_results.count= 1 (should be l_results.count=1)
l_results.count= 1 (should be l_results.count=1)
l_results.count= 1 (should be l_results.count=1)
l_results.count= 1 (should be l_results.count=1)
l_results.count= 1 (should be l_results.count=1)
l_results.count= 1 (should be l_results.count=1)
l_results.count= 1 (should be l_results.count=1)
returned l_result.count=10

PL/SQL procedure successfully completed.

SQL>


What is your plsql_optimize_level set to ? Try tinkering with that - perhaps the compiler is (incorrectly) re-shuffling your code. Otherwise, it might be time to look at being on the latest patch version (11.2.0.4)


Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Oracle 11g Release 2 XE is only availiable as 11.2.0.2

Jacek Gebal, November 27, 2016 - 10:58 pm UTC

Hi Connor,
Thanks for your answer.

I've validated the test case with different values of PLSQL_OPTIMIZE_LEVEL. It seems that I only see the misbehavior on level 3.
Interestingly, I didn't set the level explicitly on my session when compiling and somehow it must have been set to 3 by default.
Are you aware of parameter(s) that would affect the default PLSQL_OPTIMIZE_LEVEL?

About moving to 11.2.0.4. This is not feasible if you're using Oracle XE.

This is what I'm using for my Open Source and educational development at home.

Unfortunately Oracle stopped providing newer versions of XE database.

Until I'll move my Virtual Machine to 11r2 SE, I'm stuck with this official version.


Connor McDonald
November 28, 2016 - 2:55 am UTC

I've never seen the level at 3 *by default*, so my content would be that "something" set it (maybe a tool or otherwise).

I should note that pretty much *all* Oracle software is free for "personal use", where that is defined by the standard terms as per:

http://www.oracle.com/technetwork/licenses/standard-license-152015.html

so you are not limited to XE (in that sense)

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library