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.