Обсуждение: return next in recursive function

Поиск
Список
Период
Сортировка

return next in recursive function

От
Petr Bravenec
Дата:
I have found that when I use the RETURN NEXT command in recursive function,
not all records are returned. The only records I can obtain from function
are records from the highest level of recursion. Does exist some
work-around?

Thanks
Petr Bravenec

example:
create table foo (
    uid   int4,
    pid   int4
);

insert into foo values (1,0);
insert into foo values (2,0);
insert into foo values (3,0);
insert into foo values (4,1);
insert into foo values (5,1);
insert into foo values (6,5);
insert into foo values (7,5);
insert into foo values (8,2);

create or replace function foo (integer)
          returns setof foo as '
    declare pid     alias for $1;
    declare rec     RECORD;
    BEGIN
    FOR rec in select * from foo
               where foo.pid=pid LOOP
            return next rec;
            raise warning ''uid=% pid=%'',rec.uid,rec.pid;
            select into rec * from foo (rec.uid);
    END LOOP;
    return null;
    end;
' language 'plpgsql';

select * from foo(0);


The output:
WARNING:  uid=1 pid=0
WARNING:  uid=4 pid=1
WARNING:  uid=5 pid=1
WARNING:  uid=6 pid=5
WARNING:  uid=7 pid=5
WARNING:  uid=2 pid=0
WARNING:  uid=8 pid=2
WARNING:  uid=3 pid=0
 uid | pid
-----+-----
   1 |   0
   2 |   0
   3 |   0

The warnings show how the output should look.

PgSQL version 7.3.4


--

email: pbravenec@solartec.cz
telefon: 777 566 384
icq: 227051816





Re: return next in recursive function

От
Stephan Szabo
Дата:
On Thu, 2 Oct 2003, Petr Bravenec wrote:

>
> I have found that when I use the RETURN NEXT command in recursive function,
> not all records are returned. The only records I can obtain from function
> are records from the highest level of recursion. Does exist some
> work-around?

> create or replace function foo (integer)
>           returns setof foo as '
>     declare pid     alias for $1;
>     declare rec     RECORD;
>     BEGIN
>     FOR rec in select * from foo
>                where foo.pid=pid LOOP
>             return next rec;
>             raise warning ''uid=% pid=%'',rec.uid,rec.pid;
>             select into rec * from foo (rec.uid);

Shouldn't you be looping over these results in order to return them,
something like
 FOR rec2 in select * from foo(rec.uid) LOOP
  return next rec2;
 END LOOP;

Otherwise, why should the results from the other call become results from
your call (what if you want to process them and not return all of them, or
what if it's a function with a different type?)

>     END LOOP;
>     return null;
>     end;
> ' language 'plpgsql';

Re: return next in recursive function

От
Tom Lane
Дата:
Petr Bravenec <pbravenec@solartec.cz> writes:
>     FOR rec in select * from foo
>                where foo.pid=pid LOOP
>             return next rec;
>             raise warning ''uid=% pid=%'',rec.uid,rec.pid;
>             select into rec * from foo (rec.uid);
>     END LOOP;
>     return null;

This is simply throwing away the results of the recursive call.
If you are trying to append those results to the outer call's
results, maybe do this:

    FOR rec in select * from foo
               where foo.pid=pid LOOP
            return next rec;
            raise warning ''uid=% pid=%'',rec.uid,rec.pid;
        FOR rec2 in select * from foo (rec.uid) LOOP
        return next rec2;
        END LOOP;
    END LOOP;
    return null;

            regards, tom lane

Case Tool for PostgreSQL

От
"Roberto de Amorim"
Дата:
Hi all

where can I find a case tool for PostgreeSQL?

Actually I'm using the (CA) ER-Win, but it isn't integrated with PostgreSQL.

TIA

Roberto de Amorim


Re: return next in recursive function

От
Petr Bravenec
Дата:
Stephan Szabo napsal(a):

>>create or replace function foo (integer)
>>          returns setof foo as '
>>    declare pid     alias for $1;
>>    declare rec     RECORD;
>>    BEGIN
>>    FOR rec in select * from foo
>>               where foo.pid=pid LOOP
>>            return next rec;
>>            raise warning ''uid=% pid=%'',rec.uid,rec.pid;
>>            select into rec * from foo (rec.uid);
>>
>>
>
>Shouldn't you be looping over these results in order to return them,
>something like
> FOR rec2 in select * from foo(rec.uid) LOOP
>  return next rec2;
> END LOOP;
>
>Otherwise, why should the results from the other call become results from
>your call (what if you want to process them and not return all of them, or
>what if it's a function with a different type?)
>
>
>
Yes, I understand but I expect that the Postgres will try to do what I
wrote.
In the case of datatype michmach I would expect that the Postgres returns
error as it do in case of
select a:int4 from table1
union all
select b:text from table2;

How Postgres recognizes how was the function called?
How can Postgres recognize the the function is called recursivelly?
I can insert selected rows into temporary table and return them
in the highest level of recursion when I recognized it.


--

email: pbravenec@solartec.cz
telefon: 777 566 384
icq: 227051816





Re: return next in recursive function

От
Stephan Szabo
Дата:
On Fri, 3 Oct 2003, Petr Bravenec wrote:

> Stephan Szabo napsal(a):
>
> >>create or replace function foo (integer)
> >>          returns setof foo as '
> >>    declare pid     alias for $1;
> >>    declare rec     RECORD;
> >>    BEGIN
> >>    FOR rec in select * from foo
> >>               where foo.pid=pid LOOP
> >>            return next rec;
> >>            raise warning ''uid=% pid=%'',rec.uid,rec.pid;
> >>            select into rec * from foo (rec.uid);
> >>
> >>
> >
> >Shouldn't you be looping over these results in order to return them,
> >something like
> > FOR rec2 in select * from foo(rec.uid) LOOP
> >  return next rec2;
> > END LOOP;
> >
> >Otherwise, why should the results from the other call become results from
> >your call (what if you want to process them and not return all of them, or
> >what if it's a function with a different type?)
>
> Yes, I understand but I expect that the Postgres will try to do what I
> wrote.

AFAICS it is doing exactly what you wrote. It's giving you a row in rec
from the resultset of the recursive call which you do nothing with and
then overwrite back at the top of the loop.

It's not determining it's called recursively or anything of the sort, each
function call has its own result set, there's no implicit union or any
such going on.  That'd be doing something other than what you wrote.