Thread: FETCH in subqueries or CTEs

FETCH in subqueries or CTEs

From
Craig Ringer
Date:
Hi all

I've noticed that FETCH doesn't seem to be supported in subqueries or in
CTEs.

Is there a specific reason for that, beyond "nobody's needed it and
implemented it"? I'm not complaining at all, merely curious.

A toy example:

     DECLARE somecursor CURSOR FOR SELECT generate_series(1,1000)
     SELECT * FROM ( FETCH ALL FROM somecursor ) x;

produces:

     ERROR:  syntax error at or near "FETCH"
     LINE 1: SELECT * FROM ( FETCH ALL FROM somecursor ) x;
                         ^
Same with a CTE:

      WITH x AS ( FETCH ALL FROM somecursor ) SELECT * FROM x;

ERROR:  syntax error at or near "FETCH"
LINE 1: WITH x AS ( FETCH ALL FROM somecursor ) SELECT * FROM x;

--
Craig Ringer


Re: FETCH in subqueries or CTEs

From
Jeff Davis
Date:
On Fri, 2012-08-24 at 09:35 +0800, Craig Ringer wrote:
> Hi all
>
> I've noticed that FETCH doesn't seem to be supported in subqueries or in
> CTEs.
>
> Is there a specific reason for that, beyond "nobody's needed it and
> implemented it"? I'm not complaining at all, merely curious.

1. Cursors have their own snapshot, so it would be kind of like looking
at two snapshots of data at the same time. That would be a little
strange.

2. For regular subqueries, it would also be potentially
non-deterministic, because the FETCH operation has the side effect of
advancing the cursor. So, if you had something like "SELECT * FROM
(FETCH 1 FROM mycursor) x WHERE FALSE", it's not clear whether the FETCH
would execute or not. After the query, it may have advanced the cursor
or may not have, depending on whether the optimizer decided it didn't
need to compute the subquery.

3. Cursors are really meant for a more effective interaction with the
client, it's not really meant as an operator (and it doesn't change the
results, anyway). You can already do LIMIT/OFFSET in a subquery if you
need that kind of thing.

All that being said, there may be some use case for something like what
you are describing, if you get creative.

Regards,
    Jeff Davis



Re: FETCH in subqueries or CTEs

From
Pavel Stehule
Date:
Hello

2012/8/24 Craig Ringer <ringerc@ringerc.id.au>:
> Hi all
>
> I've noticed that FETCH doesn't seem to be supported in subqueries or in
> CTEs.
>
> Is there a specific reason for that, beyond "nobody's needed it and
> implemented it"? I'm not complaining at all, merely curious.
>
> A toy example:
>
>     DECLARE somecursor CURSOR FOR SELECT generate_series(1,1000)
>     SELECT * FROM ( FETCH ALL FROM somecursor ) x;
>
> produces:
>
>     ERROR:  syntax error at or near "FETCH"
>     LINE 1: SELECT * FROM ( FETCH ALL FROM somecursor ) x;
>                         ^
> Same with a CTE:
>
>      WITH x AS ( FETCH ALL FROM somecursor ) SELECT * FROM x;
>
> ERROR:  syntax error at or near "FETCH"
> LINE 1: WITH x AS ( FETCH ALL FROM somecursor ) SELECT * FROM x;
>

you can't mix planned and unplanned statements together - think about
stored plans every time

Regards

Pavel

> --
> Craig Ringer
>
>
> --
> Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-general


Re: FETCH in subqueries or CTEs

From
Craig Ringer
Date:
On 08/24/2012 12:34 PM, Pavel Stehule wrote:

> you can't mix planned and unplanned statements together - think about
> stored plans every time

Thanks Pavel and Jeff.

I can't say I fully understand the arguments, but I'll take it that
accepting cursors in CTEs or subqueries wouldn't make sense. I guess the
main issue really is that you'd have to materialize them anyway to avoid
issues with multiple scans, so there's little point having a cursor.

I didn't find a reasonable way to simply fetch a cursor into a (possibly
temporary) table, like:

INSERT INTO sometable FETCH ALL FROM somecursor;

... which could be handy with PL/PgSQL functions that return multiple
refcursors. It only seems to be possible via a PL/PgSQL wrapper that
loops over the cursor and returns a rowset.

--
Craig Ringer


Re: FETCH in subqueries or CTEs

From
Pavel Stehule
Date:
2012/8/24 Craig Ringer <ringerc@ringerc.id.au>:
> On 08/24/2012 12:34 PM, Pavel Stehule wrote:
>
>> you can't mix planned and unplanned statements together - think about
>> stored plans every time
>
>
> Thanks Pavel and Jeff.
>
> I can't say I fully understand the arguments, but I'll take it that
> accepting cursors in CTEs or subqueries wouldn't make sense. I guess the
> main issue really is that you'd have to materialize them anyway to avoid
> issues with multiple scans, so there's little point having a cursor.
>
> I didn't find a reasonable way to simply fetch a cursor into a (possibly
> temporary) table, like:
>
> INSERT INTO sometable FETCH ALL FROM somecursor;

it should be implemented as function - like materialize_cursor(cursor, table)

I would to see full support of stored procedures (with multirecordsets) rather.

Regards

Pavel

>
> ... which could be handy with PL/PgSQL functions that return multiple
> refcursors. It only seems to be possible via a PL/PgSQL wrapper that loops
> over the cursor and returns a rowset.
>
> --
> Craig Ringer


Re: FETCH in subqueries or CTEs

From
Tom Lane
Date:
Craig Ringer <ringerc@ringerc.id.au> writes:
> I didn't find a reasonable way to simply fetch a cursor into a (possibly
> temporary) table, like:
> INSERT INTO sometable FETCH ALL FROM somecursor;

Why would you bother with a cursor, and not just INSERT ... SELECT
using the original query?

Putting a cursor in between will just make matters more complicated and
slower.  (For one thing, the plan created for a cursor is optimized for
incremental fetching not read-it-all-at-once.)

            regards, tom lane


Re: FETCH in subqueries or CTEs

From
Craig Ringer
Date:
On 08/24/2012 10:31 PM, Tom Lane wrote:
> Craig Ringer <ringerc@ringerc.id.au> writes:
>> I didn't find a reasonable way to simply fetch a cursor into a (possibly
>> temporary) table, like:
>> INSERT INTO sometable FETCH ALL FROM somecursor;
> Why would you bother with a cursor, and not just INSERT ... SELECT
> using the original query?
I wouldn't. The context - and the reason it's mostly a matter of
curiosity, not something I care about - is that it arose out of
discussion elsewhere on how to work with pre-defined PL/PgSQL functions
that return multiple refcursors.

--
Craig Ringer