简体   繁体   中英

PL/SQL: Can you pass the returned data from a pipelined function on?

I have a function in a database package which returns a pipelined object collection. I wish to generalise that function so that the same functionality can be called based on a different data. however, I wish to retain the existing function for compatibility. Is there any way to pass the pipeline on without looping the rows?

An example to make it clearer. I have a function foo:

FUNCTION foo(some_id in varchar2) return mypackage.mytype pipelined is
   arFoo  mypackage.mytype;
BEGIN
  -- do stuff to fill data in arFoo based on some_id
  for i in nvl(arFoo.first,0) .. nvl(arFoo.last, -1) loop
     pipe row(arFoo(i));
  end loop;
  return;
END;

I will create a function bar instead

FUNCTION bar(arData in myParamType) return return mypackage.mytype pipelined is
   arFoo  mypackage.mytype;
BEGIN
  -- do stuff to fill data in arFoo based on data in arData
  for i in nvl(arFoo.first,0) .. nvl(arFoo.last, -1) loop
     pipe row(arFoo(i));
  end loop;
  return;
END;

I would like to retain foo in the following fashion:

FUNCTION foo(some_id in varchar2) return mypackage.mytype pipelined is
   arData  myParamType;
BEGIN
  -- do stuff to fill data in arData  based on some_id
  return arBar(arData);
END;

However, the return arBar(arData); is not allowed - pipelined functions must have return as a staement by itself. The question is how to connect the pipe returned by bar to the pipe returned by foo The only way I can see is to loop the results and pipe them again:

for r in (select * from table(bar(arData))) loop
   pipe row(r);
end loop;

That, however, strikes me as particularly inefficient. Is there any more efficient way to connect the pipeline from bar to the pipeline in foo without looping?

I am submitting this as an aswer since it is how I solved it. It is in some ways only a partial answer in that I could not find a good way to do this with pipelined functions. What I did instead was create the return objects as global user-defined objects (instead of as record types in the package spec) and then return the object directly.

In other words I defined the functions like this:

FUNCTION bar(arData in myParamType) return mytype is
   arFoo  mytype;
BEGIN
  -- do stuff to fill data in arFoo based on data in arData
  return arFoo;
END;

FUNCTION foo(some_id in varchar2) return mytype is
   arData  myParamType;
BEGIN
  -- do stuff to fill data in arData  based on some_id
  return arBar(arData);
END;

and remove the following (which had been in the mypackage spec)

type mytype is record(
   foo_id    foo.id%type
)

and instead ran a script to create a global type

create or replace type mytype as object(
   foo_id    number(5,0)
)

This means that the use of the function (which is variants on select * from table(foo('x')) ) remains unchanged while my new internal function exists and can be called directly in other situations.

It would be neater to have the type defined in the package spec, but we already have some global objects so we can handle it. (I think that oracle internally defines global objects to handle pipelined functions anyway). Unfortunately we cannot use %type in the global object definitions but we can live with that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM