mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Implement SQL92-compatible FIRST, LAST, ABSOLUTE n, RELATIVE n options
for FETCH and MOVE.
This commit is contained in:
parent
e4704001ea
commit
6261c75014
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/fetch.sgml,v 1.26 2003/03/10 03:53:49 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/fetch.sgml,v 1.27 2003/03/11 19:40:22 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -18,17 +18,32 @@ PostgreSQL documentation
|
|||||||
</refnamediv>
|
</refnamediv>
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<refsynopsisdivinfo>
|
<refsynopsisdivinfo>
|
||||||
<date>1999-07-20</date>
|
<date>2003-03-11</date>
|
||||||
</refsynopsisdivinfo>
|
</refsynopsisdivinfo>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
FETCH [ <replaceable class="PARAMETER">direction</replaceable> ] [ <replaceable class="PARAMETER">count</replaceable> ] { IN | FROM } <replaceable class="PARAMETER">cursor</replaceable>
|
FETCH [ <replaceable class="PARAMETER">direction</replaceable> { FROM | IN } ] <replaceable class="PARAMETER">cursor</replaceable>
|
||||||
FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</replaceable> | ALL | NEXT | PRIOR ]
|
|
||||||
{ IN | FROM } <replaceable class="PARAMETER">cursor</replaceable>
|
where <replaceable class="PARAMETER">direction</replaceable> can be empty or one of:
|
||||||
|
|
||||||
|
NEXT
|
||||||
|
PRIOR
|
||||||
|
FIRST
|
||||||
|
LAST
|
||||||
|
ABSOLUTE <replaceable class="PARAMETER">count</replaceable>
|
||||||
|
RELATIVE <replaceable class="PARAMETER">count</replaceable>
|
||||||
|
<replaceable class="PARAMETER">count</replaceable>
|
||||||
|
ALL
|
||||||
|
FORWARD
|
||||||
|
FORWARD <replaceable class="PARAMETER">count</replaceable>
|
||||||
|
FORWARD ALL
|
||||||
|
BACKWARD
|
||||||
|
BACKWARD <replaceable class="PARAMETER">count</replaceable>
|
||||||
|
BACKWARD ALL
|
||||||
</synopsis>
|
</synopsis>
|
||||||
|
|
||||||
<refsect2 id="R2-SQL-FETCH-1">
|
<refsect2 id="R2-SQL-FETCH-1">
|
||||||
<refsect2info>
|
<refsect2info>
|
||||||
<date>1998-09-01</date>
|
<date>2003-03-11</date>
|
||||||
</refsect2info>
|
</refsect2info>
|
||||||
<title>
|
<title>
|
||||||
Inputs
|
Inputs
|
||||||
@ -41,35 +56,151 @@ FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</repl
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<replaceable class="PARAMETER">direction</replaceable>
|
<replaceable class="PARAMETER">direction</replaceable>
|
||||||
defines the fetch direction. It can be one of
|
defines the fetch direction and number of rows to fetch.
|
||||||
the following:
|
It can be one of the following:
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>FORWARD</term>
|
<term>NEXT</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
fetch next row(s). This is the default
|
fetch next row. This is the default
|
||||||
if <replaceable class="PARAMETER">direction</replaceable> is omitted.
|
if <replaceable class="PARAMETER">direction</replaceable> is omitted.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>PRIOR</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch prior row.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>FIRST</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch first row of query (same as ABSOLUTE 1).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>LAST</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch last row of query (same as ABSOLUTE -1).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>ABSOLUTE <replaceable class="PARAMETER">count</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch the <replaceable class="PARAMETER">count</replaceable>'th
|
||||||
|
row of query, or the
|
||||||
|
abs(<replaceable class="PARAMETER">count</replaceable>)'th row
|
||||||
|
from the end if
|
||||||
|
<replaceable class="PARAMETER">count</replaceable> < 0.
|
||||||
|
Position before first row or after last row
|
||||||
|
if <replaceable class="PARAMETER">count</replaceable> is out of
|
||||||
|
range; in particular, ABSOLUTE 0 positions before first row.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>RELATIVE <replaceable class="PARAMETER">count</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch the <replaceable class="PARAMETER">count</replaceable>'th
|
||||||
|
succeeding row, or the
|
||||||
|
abs(<replaceable class="PARAMETER">count</replaceable>)'th prior
|
||||||
|
row if <replaceable class="PARAMETER">count</replaceable> < 0.
|
||||||
|
RELATIVE 0 re-fetches current row, if any.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="PARAMETER">count</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch the next <replaceable class="PARAMETER">count</replaceable>
|
||||||
|
rows (same as FORWARD <replaceable class="PARAMETER">count</replaceable>).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>ALL</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch all remaining rows (same as FORWARD ALL).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>FORWARD</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch next row (same as NEXT).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>FORWARD <replaceable class="PARAMETER">count</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch next <replaceable class="PARAMETER">count</replaceable>
|
||||||
|
rows. FORWARD 0 re-fetches current row.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>FORWARD ALL</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch all remaining rows.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>BACKWARD</term>
|
<term>BACKWARD</term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
fetch previous row(s).
|
fetch prior row (same as PRIOR).
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>RELATIVE</term>
|
<term>BACKWARD <replaceable class="PARAMETER">count</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Same as FORWARD; provided for SQL92 compatibility.
|
fetch prior <replaceable class="PARAMETER">count</replaceable>
|
||||||
|
rows (scanning backwards). BACKWARD 0 re-fetches current row.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>BACKWARD ALL</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
fetch all prior rows (scanning backwards).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
@ -80,53 +211,11 @@ FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</repl
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<replaceable class="PARAMETER">count</replaceable>
|
<replaceable class="PARAMETER">count</replaceable>
|
||||||
determines how many rows to fetch. It can be one of the following:
|
is a possibly-signed integer constant, determining the location
|
||||||
|
or number of rows to fetch. For FORWARD and BACKWARD cases,
|
||||||
<variablelist>
|
specifying a negative <replaceable
|
||||||
<varlistentry>
|
class="PARAMETER">count</replaceable>
|
||||||
<term><replaceable class="PARAMETER">#</replaceable></term>
|
is equivalent to changing the sense of FORWARD and BACKWARD.
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
A signed integer constant that specifies how many rows to fetch.
|
|
||||||
Note that a negative integer is equivalent to changing the sense of
|
|
||||||
FORWARD and BACKWARD. Zero re-fetches the current row, if any.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term>
|
|
||||||
ALL
|
|
||||||
</term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Retrieve all remaining rows.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term>
|
|
||||||
NEXT
|
|
||||||
</term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Equivalent to specifying a count of <command>1</command>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term>
|
|
||||||
PRIOR
|
|
||||||
</term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Equivalent to specifying a count of <command>-1</command>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</variablelist>
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -145,7 +234,7 @@ FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</repl
|
|||||||
|
|
||||||
<refsect2 id="R2-SQL-FETCH-2">
|
<refsect2 id="R2-SQL-FETCH-2">
|
||||||
<refsect2info>
|
<refsect2info>
|
||||||
<date>1998-04-15</date>
|
<date>2003-03-11</date>
|
||||||
</refsect2info>
|
</refsect2info>
|
||||||
<title>
|
<title>
|
||||||
Outputs
|
Outputs
|
||||||
@ -162,25 +251,11 @@ WARNING: PerformPortalFetch: portal "<replaceable class="PARAMETER">cursor</rep
|
|||||||
</computeroutput></term>
|
</computeroutput></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
If <replaceable class="PARAMETER">cursor</replaceable>
|
If <replaceable class="PARAMETER">cursor</replaceable> is not known.
|
||||||
is not previously declared.
|
The cursor must have been declared within the current transaction block.
|
||||||
The cursor must be declared within a transaction block.
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><computeroutput>
|
|
||||||
WARNING: FETCH/ABSOLUTE not supported, using RELATIVE
|
|
||||||
</computeroutput></term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<productname>PostgreSQL</productname> does not support absolute
|
|
||||||
positioning of cursors.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
@ -188,75 +263,79 @@ WARNING: FETCH/ABSOLUTE not supported, using RELATIVE
|
|||||||
|
|
||||||
<refsect1 id="R1-SQL-FETCH-1">
|
<refsect1 id="R1-SQL-FETCH-1">
|
||||||
<refsect1info>
|
<refsect1info>
|
||||||
<date>1998-04-15</date>
|
<date>2003-03-11</date>
|
||||||
</refsect1info>
|
</refsect1info>
|
||||||
<title>
|
<title>
|
||||||
Description
|
Description
|
||||||
</title>
|
</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<command>FETCH</command> allows a user to retrieve rows using a cursor.
|
<command>FETCH</command> retrieves rows using a cursor.
|
||||||
The number of rows retrieved is specified by
|
|
||||||
<replaceable class="PARAMETER">#</replaceable>.
|
|
||||||
If the number of rows remaining in the cursor is less
|
|
||||||
than <replaceable class="PARAMETER">#</replaceable>,
|
|
||||||
then only those available are fetched.
|
|
||||||
Substituting the keyword ALL in place of a number will
|
|
||||||
cause all remaining rows in the cursor to be retrieved.
|
|
||||||
Rows may be fetched in both FORWARD and BACKWARD
|
|
||||||
directions. The default direction is FORWARD.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The cursor position can be before the first row of the query result, or on
|
A cursor has an associated <firstterm>position</> that is used by
|
||||||
any particular row of the result, or after the last row of the result.
|
<command>FETCH</>. The cursor position can be before the first row of the
|
||||||
When created, a cursor is positioned before the first row. After fetching
|
query result, or on any particular row of the result, or after the last row
|
||||||
some rows, the cursor is positioned on the last row retrieved. A new
|
of the result. When created, a cursor is positioned before the first row.
|
||||||
<command>FETCH</command> always steps one row in the specified direction
|
After fetching some rows, the cursor is positioned on the row most recently
|
||||||
(if possible) before beginning to return rows. If the
|
retrieved. If <command>FETCH</> runs off the end of the available rows
|
||||||
<command>FETCH</command> requests more rows than available, the cursor is
|
then the cursor is left positioned after the last row, or before the first
|
||||||
left positioned after the last row of the query result (or before the first
|
row if fetching backward. <command>FETCH ALL</> or <command>FETCH BACKWARD
|
||||||
row, in the case of a backward fetch). This will always be the case after
|
ALL</> will always leave the cursor positioned after the last row or before
|
||||||
<command>FETCH ALL</>.
|
the first row.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The SQL-compatible forms (NEXT, PRIOR, FIRST, LAST, ABSOLUTE, RELATIVE)
|
||||||
|
fetch a single row after moving the cursor appropriately. If there is
|
||||||
|
no such row, an empty result is returned, and the cursor is left positioned
|
||||||
|
before the first row or after the last row as appropriate.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The forms using FORWARD and BACKWARD are not in the SQL standard, but
|
||||||
|
are <productname>PostgreSQL</productname> extensions. These forms
|
||||||
|
retrieve the indicated number of rows moving in the forward or backward
|
||||||
|
direction, leaving the cursor positioned on the last-returned row
|
||||||
|
(or after/before all rows, if the <replaceable
|
||||||
|
class="PARAMETER">count</replaceable> exceeds the number of rows
|
||||||
|
available).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<tip>
|
<tip>
|
||||||
<para>
|
<para>
|
||||||
A zero row count requests fetching the current row without moving the
|
RELATIVE 0, FORWARD 0, and BACKWARD 0 all request
|
||||||
|
fetching the current row without moving the
|
||||||
cursor --- that is, re-fetching the most recently fetched row.
|
cursor --- that is, re-fetching the most recently fetched row.
|
||||||
This will succeed unless the cursor is positioned before the
|
This will succeed unless the cursor is positioned before the
|
||||||
first row or after the last row; in which case, no row is returned.
|
first row or after the last row; in which case, no row is returned.
|
||||||
</para>
|
</para>
|
||||||
</tip>
|
</tip>
|
||||||
|
|
||||||
<tip>
|
|
||||||
<para>
|
|
||||||
Negative numbers are allowed to be specified for the
|
|
||||||
row count. A negative number is equivalent to reversing
|
|
||||||
the sense of the FORWARD and BACKWARD keywords. For example,
|
|
||||||
<command>FORWARD -1</command> is the same as <command>BACKWARD 1</command>.
|
|
||||||
</para>
|
|
||||||
</tip>
|
|
||||||
|
|
||||||
<refsect2 id="R2-SQL-FETCH-3">
|
<refsect2 id="R2-SQL-FETCH-3">
|
||||||
<refsect2info>
|
<refsect2info>
|
||||||
<date>1998-04-15</date>
|
<date>2003-03-11</date>
|
||||||
</refsect2info>
|
</refsect2info>
|
||||||
<title>
|
<title>
|
||||||
Notes
|
Notes
|
||||||
</title>
|
</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
A cursor to be used in backwards fetching should be declared with the
|
The cursor should be declared with the SCROLL option if one intends to
|
||||||
SCROLL option. In simple cases, <productname>PostgreSQL</productname>
|
use any variants of <command>FETCH</> other than <command>FETCH NEXT</>
|
||||||
will allow backwards fetch from cursors not declared with SCROLL, but
|
or <command>FETCH FORWARD</> with a positive count. For simple queries
|
||||||
this behavior is best not relied on.
|
<productname>PostgreSQL</productname> will allow backwards fetch from
|
||||||
|
cursors not declared with SCROLL, but this behavior is best not relied on.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The FORWARD, BACKWARD, and ALL keywords are
|
ABSOLUTE fetches are not any faster than navigating to the desired row
|
||||||
<productname>PostgreSQL</productname> extensions.
|
with a relative move: the underlying implementation must traverse all
|
||||||
See below for details on compatibility issues.
|
the intermediate rows anyway. Negative absolute fetches are even worse:
|
||||||
|
the query must be read to the end to find the last row, and then
|
||||||
|
traversed backward from there. However, rewinding to the start of the
|
||||||
|
query (as with FETCH ABSOLUTE 0) is fast.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -316,7 +395,7 @@ FETCH FORWARD 5 IN liahona;
|
|||||||
</computeroutput>
|
</computeroutput>
|
||||||
|
|
||||||
-- Fetch previous row:
|
-- Fetch previous row:
|
||||||
FETCH BACKWARD 1 IN liahona;
|
FETCH PRIOR FROM liahona;
|
||||||
|
|
||||||
<computeroutput>
|
<computeroutput>
|
||||||
code | title | did | date_prod | kind | len
|
code | title | did | date_prod | kind | len
|
||||||
@ -339,52 +418,39 @@ COMMIT WORK;
|
|||||||
|
|
||||||
<refsect2 id="R2-SQL-FETCH-4">
|
<refsect2 id="R2-SQL-FETCH-4">
|
||||||
<refsect2info>
|
<refsect2info>
|
||||||
<date>1998-09-01</date>
|
<date>2003-03-11</date>
|
||||||
</refsect2info>
|
</refsect2info>
|
||||||
<title>
|
<title>
|
||||||
SQL92
|
SQL92
|
||||||
</title>
|
</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<note>
|
<acronym>SQL92</acronym> defines FETCH for use in embedded contexts only.
|
||||||
<para>
|
Therefore, it describes placing the results into explicit variables using
|
||||||
The non-embedded use of cursors is a <productname>PostgreSQL</productname>
|
an <literal>INTO</> clause, for example:
|
||||||
extension. The syntax and usage of cursors is being compared
|
|
||||||
against the embedded form of cursors defined in <acronym>SQL92</acronym>.
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
<acronym>SQL92</acronym> allows absolute positioning of the cursor for
|
|
||||||
FETCH, and allows placing the results into explicit variables:
|
|
||||||
|
|
||||||
<synopsis>
|
<synopsis>
|
||||||
FETCH ABSOLUTE <replaceable class="PARAMETER">#</replaceable>
|
FETCH ABSOLUTE <replaceable class="PARAMETER">n</replaceable>
|
||||||
FROM <replaceable class="PARAMETER">cursor</replaceable>
|
FROM <replaceable class="PARAMETER">cursor</replaceable>
|
||||||
INTO :<replaceable class="PARAMETER">variable</replaceable> [, ...]
|
INTO :<replaceable class="PARAMETER">variable</replaceable> [, ...]
|
||||||
</synopsis>
|
</synopsis>
|
||||||
|
|
||||||
<variablelist>
|
<productname>PostgreSQL</productname>'s use of non-embedded cursors
|
||||||
<varlistentry>
|
is non-standard, and so is its practice of returning the result data
|
||||||
<term>ABSOLUTE</term>
|
as if it were a SELECT result. Other than this point, FETCH is fully
|
||||||
<listitem>
|
upward-compatible with <acronym>SQL92</acronym>.
|
||||||
<para>
|
|
||||||
The cursor should be positioned to the specified absolute
|
|
||||||
row number. All row numbers in <productname>PostgreSQL</productname>
|
|
||||||
are relative numbers so this capability is not supported.
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
<varlistentry>
|
|
||||||
<term>:<replaceable class="PARAMETER">variable</replaceable></term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
<para>
|
||||||
Target host variable(s).
|
The FETCH forms involving FORWARD and BACKWARD (including the forms
|
||||||
|
FETCH <replaceable class="PARAMETER">count</replaceable> and FETCH ALL,
|
||||||
|
in which FORWARD is implicit) are <productname>PostgreSQL</productname>
|
||||||
|
extensions.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
<para>
|
||||||
</variablelist>
|
<acronym>SQL92</acronym> allows only <literal>FROM</> preceding the
|
||||||
|
cursor name; the option to use <literal>IN</> is an extension.
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/move.sgml,v 1.19 2003/03/10 03:53:49 tgl Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/move.sgml,v 1.20 2003/03/11 19:40:22 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ PostgreSQL documentation
|
|||||||
<date>1999-07-20</date>
|
<date>1999-07-20</date>
|
||||||
</refsynopsisdivinfo>
|
</refsynopsisdivinfo>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
MOVE [ <replaceable class="PARAMETER">direction</replaceable> ] [ <replaceable class="PARAMETER">count</replaceable> ] { IN | FROM } <replaceable class="PARAMETER">cursor</replaceable>
|
MOVE [ <replaceable class="PARAMETER">direction</replaceable> { FROM | IN } ] <replaceable class="PARAMETER">cursor</replaceable>
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
@ -33,9 +33,7 @@ MOVE [ <replaceable class="PARAMETER">direction</replaceable> ] [ <replaceable c
|
|||||||
Description
|
Description
|
||||||
</title>
|
</title>
|
||||||
<para>
|
<para>
|
||||||
<command>MOVE</command> allows the user to move the cursor position a
|
<command>MOVE</command> repositions a cursor without retrieving any data.
|
||||||
specified number of rows, or to the beginning or end of the cursor.
|
|
||||||
<command>MOVE ALL</command> moves to the end of the cursor.
|
|
||||||
<command>MOVE</command> works exactly like the <command>FETCH</command>
|
<command>MOVE</command> works exactly like the <command>FETCH</command>
|
||||||
command, except it only repositions the cursor and does not return rows.
|
command, except it only repositions the cursor and does not return rows.
|
||||||
</para>
|
</para>
|
||||||
@ -54,8 +52,9 @@ MOVE [ <replaceable class="PARAMETER">direction</replaceable> ] [ <replaceable c
|
|||||||
</title>
|
</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<command>MOVE</command> is a <productname>PostgreSQL</productname>
|
The count returned in <command>MOVE</command>'s status string is the
|
||||||
language extension.
|
count of the number of rows that would have been returned by the
|
||||||
|
equivalent <command>FETCH</command> command.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -119,9 +118,6 @@ COMMIT WORK;
|
|||||||
</title>
|
</title>
|
||||||
<para>
|
<para>
|
||||||
There is no <acronym>SQL92</acronym> <command>MOVE</command> statement.
|
There is no <acronym>SQL92</acronym> <command>MOVE</command> statement.
|
||||||
Instead, <acronym>SQL92</acronym> allows
|
|
||||||
one to <command>FETCH</command> rows from an absolute cursor position,
|
|
||||||
implicitly moving the cursor to the correct position.
|
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.9 2003/03/10 03:53:49 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.10 2003/03/11 19:40:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -23,6 +23,11 @@
|
|||||||
#include "rewrite/rewriteHandler.h"
|
#include "rewrite/rewriteHandler.h"
|
||||||
|
|
||||||
|
|
||||||
|
static long DoRelativeFetch(Portal portal,
|
||||||
|
bool forward,
|
||||||
|
long count,
|
||||||
|
CommandDest dest);
|
||||||
|
static void DoPortalRewind(Portal portal);
|
||||||
static Portal PreparePortal(char *portalName);
|
static Portal PreparePortal(char *portalName);
|
||||||
|
|
||||||
|
|
||||||
@ -102,9 +107,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest)
|
|||||||
* PerformPortalFetch
|
* PerformPortalFetch
|
||||||
* Execute SQL FETCH or MOVE command.
|
* Execute SQL FETCH or MOVE command.
|
||||||
*
|
*
|
||||||
* name: name of portal
|
* stmt: parsetree node for command
|
||||||
* forward: forward or backward fetch?
|
|
||||||
* count: # of tuples to fetch (INT_MAX means "all"; 0 means "refetch")
|
|
||||||
* dest: where to send results
|
* dest: where to send results
|
||||||
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
|
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
|
||||||
* in which to store a command completion status string.
|
* in which to store a command completion status string.
|
||||||
@ -112,9 +115,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest)
|
|||||||
* completionTag may be NULL if caller doesn't want a status string.
|
* completionTag may be NULL if caller doesn't want a status string.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
PerformPortalFetch(char *name,
|
PerformPortalFetch(FetchStmt *stmt,
|
||||||
bool forward,
|
|
||||||
long count,
|
|
||||||
CommandDest dest,
|
CommandDest dest,
|
||||||
char *completionTag)
|
char *completionTag)
|
||||||
{
|
{
|
||||||
@ -123,48 +124,150 @@ PerformPortalFetch(char *name,
|
|||||||
|
|
||||||
/* initialize completion status in case of early exit */
|
/* initialize completion status in case of early exit */
|
||||||
if (completionTag)
|
if (completionTag)
|
||||||
strcpy(completionTag, (dest == None) ? "MOVE 0" : "FETCH 0");
|
strcpy(completionTag, stmt->ismove ? "MOVE 0" : "FETCH 0");
|
||||||
|
|
||||||
/* sanity checks */
|
|
||||||
if (name == NULL)
|
|
||||||
{
|
|
||||||
elog(WARNING, "PerformPortalFetch: missing portal name");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get the portal from the portal name */
|
/* get the portal from the portal name */
|
||||||
portal = GetPortalByName(name);
|
portal = GetPortalByName(stmt->portalname);
|
||||||
if (!PortalIsValid(portal))
|
if (!PortalIsValid(portal))
|
||||||
{
|
{
|
||||||
elog(WARNING, "PerformPortalFetch: portal \"%s\" not found",
|
elog(WARNING, "PerformPortalFetch: portal \"%s\" not found",
|
||||||
name);
|
stmt->portalname);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do it */
|
/* Do it */
|
||||||
nprocessed = DoPortalFetch(portal, forward, count, dest);
|
nprocessed = DoPortalFetch(portal,
|
||||||
|
stmt->direction,
|
||||||
|
stmt->howMany,
|
||||||
|
stmt->ismove ? None : dest);
|
||||||
|
|
||||||
/* Return command status if wanted */
|
/* Return command status if wanted */
|
||||||
if (completionTag)
|
if (completionTag)
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld",
|
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld",
|
||||||
(dest == None) ? "MOVE" : "FETCH",
|
stmt->ismove ? "MOVE" : "FETCH",
|
||||||
nprocessed);
|
nprocessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DoPortalFetch
|
* DoPortalFetch
|
||||||
* Guts of PerformPortalFetch --- shared with SPI cursor operations
|
* Guts of PerformPortalFetch --- shared with SPI cursor operations.
|
||||||
|
* Caller must already have validated the Portal.
|
||||||
*
|
*
|
||||||
* Returns number of rows processed.
|
* Returns number of rows processed (suitable for use in result tag)
|
||||||
*/
|
*/
|
||||||
long
|
long
|
||||||
DoPortalFetch(Portal portal, bool forward, long count, CommandDest dest)
|
DoPortalFetch(Portal portal,
|
||||||
|
FetchDirection fdirection,
|
||||||
|
long count,
|
||||||
|
CommandDest dest)
|
||||||
{
|
{
|
||||||
QueryDesc *queryDesc;
|
bool forward;
|
||||||
EState *estate;
|
|
||||||
MemoryContext oldcontext;
|
switch (fdirection)
|
||||||
ScanDirection direction;
|
{
|
||||||
bool temp_desc = false;
|
case FETCH_FORWARD:
|
||||||
|
if (count < 0)
|
||||||
|
{
|
||||||
|
fdirection = FETCH_BACKWARD;
|
||||||
|
count = -count;
|
||||||
|
}
|
||||||
|
/* fall out of switch to share code with FETCH_BACKWARD */
|
||||||
|
break;
|
||||||
|
case FETCH_BACKWARD:
|
||||||
|
if (count < 0)
|
||||||
|
{
|
||||||
|
fdirection = FETCH_FORWARD;
|
||||||
|
count = -count;
|
||||||
|
}
|
||||||
|
/* fall out of switch to share code with FETCH_FORWARD */
|
||||||
|
break;
|
||||||
|
case FETCH_ABSOLUTE:
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Definition: Rewind to start, advance count-1 rows, return
|
||||||
|
* next row (if any). In practice, if the goal is less than
|
||||||
|
* halfway back to the start, it's better to scan from where
|
||||||
|
* we are. In any case, we arrange to fetch the target row
|
||||||
|
* going forwards.
|
||||||
|
*/
|
||||||
|
if (portal->posOverflow || portal->portalPos == LONG_MAX ||
|
||||||
|
count-1 <= portal->portalPos / 2)
|
||||||
|
{
|
||||||
|
DoPortalRewind(portal);
|
||||||
|
if (count > 1)
|
||||||
|
DoRelativeFetch(portal, true, count-1, None);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long pos = portal->portalPos;
|
||||||
|
|
||||||
|
if (portal->atEnd)
|
||||||
|
pos++; /* need one extra fetch if off end */
|
||||||
|
if (count <= pos)
|
||||||
|
DoRelativeFetch(portal, false, pos-count+1, None);
|
||||||
|
else if (count > pos+1)
|
||||||
|
DoRelativeFetch(portal, true, count-pos-1, None);
|
||||||
|
}
|
||||||
|
return DoRelativeFetch(portal, true, 1L, dest);
|
||||||
|
}
|
||||||
|
else if (count < 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Definition: Advance to end, back up abs(count)-1 rows,
|
||||||
|
* return prior row (if any). We could optimize this if we
|
||||||
|
* knew in advance where the end was, but typically we won't.
|
||||||
|
* (Is it worth considering case where count > half of size
|
||||||
|
* of query? We could rewind once we know the size ...)
|
||||||
|
*/
|
||||||
|
DoRelativeFetch(portal, true, FETCH_ALL, None);
|
||||||
|
if (count < -1)
|
||||||
|
DoRelativeFetch(portal, false, -count-1, None);
|
||||||
|
return DoRelativeFetch(portal, false, 1L, dest);
|
||||||
|
}
|
||||||
|
else /* count == 0 */
|
||||||
|
{
|
||||||
|
/* Rewind to start, return zero rows */
|
||||||
|
DoPortalRewind(portal);
|
||||||
|
return DoRelativeFetch(portal, true, 0L, dest);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FETCH_RELATIVE:
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Definition: advance count-1 rows, return next row (if any).
|
||||||
|
*/
|
||||||
|
if (count > 1)
|
||||||
|
DoRelativeFetch(portal, true, count-1, None);
|
||||||
|
return DoRelativeFetch(portal, true, 1L, dest);
|
||||||
|
}
|
||||||
|
else if (count < 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Definition: back up abs(count)-1 rows, return prior row
|
||||||
|
* (if any).
|
||||||
|
*/
|
||||||
|
if (count < -1)
|
||||||
|
DoRelativeFetch(portal, false, -count-1, None);
|
||||||
|
return DoRelativeFetch(portal, false, 1L, dest);
|
||||||
|
}
|
||||||
|
else /* count == 0 */
|
||||||
|
{
|
||||||
|
/* Same as FETCH FORWARD 0, so fall out of switch */
|
||||||
|
fdirection = FETCH_FORWARD;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "DoPortalFetch: bogus direction");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get here with fdirection == FETCH_FORWARD or FETCH_BACKWARD,
|
||||||
|
* and count >= 0.
|
||||||
|
*/
|
||||||
|
forward = (fdirection == FETCH_FORWARD);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Zero count means to re-fetch the current row, if any (per SQL92)
|
* Zero count means to re-fetch the current row, if any (per SQL92)
|
||||||
@ -174,7 +277,7 @@ DoPortalFetch(Portal portal, bool forward, long count, CommandDest dest)
|
|||||||
bool on_row;
|
bool on_row;
|
||||||
|
|
||||||
/* Are we sitting on a row? */
|
/* Are we sitting on a row? */
|
||||||
on_row = (portal->atStart == false && portal->atEnd == false);
|
on_row = (!portal->atStart && !portal->atEnd);
|
||||||
|
|
||||||
if (dest == None)
|
if (dest == None)
|
||||||
{
|
{
|
||||||
@ -187,14 +290,12 @@ DoPortalFetch(Portal portal, bool forward, long count, CommandDest dest)
|
|||||||
* If we are sitting on a row, back up one so we can re-fetch it.
|
* If we are sitting on a row, back up one so we can re-fetch it.
|
||||||
* If we are not sitting on a row, we still have to start up and
|
* If we are not sitting on a row, we still have to start up and
|
||||||
* shut down the executor so that the destination is initialized
|
* shut down the executor so that the destination is initialized
|
||||||
* and shut down correctly; so keep going. Further down in the
|
* and shut down correctly; so keep going. To DoRelativeFetch,
|
||||||
* routine, count == 0 means we will retrieve no row.
|
* count == 0 means we will retrieve no row.
|
||||||
*/
|
*/
|
||||||
if (on_row)
|
if (on_row)
|
||||||
{
|
{
|
||||||
DoPortalFetch(portal,
|
DoRelativeFetch(portal, false, 1L, None);
|
||||||
false /* backward */, 1L,
|
|
||||||
None /* throw away output */);
|
|
||||||
/* Set up to fetch one row forward */
|
/* Set up to fetch one row forward */
|
||||||
count = 1;
|
count = 1;
|
||||||
forward = true;
|
forward = true;
|
||||||
@ -203,9 +304,44 @@ DoPortalFetch(Portal portal, bool forward, long count, CommandDest dest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* switch into the portal context
|
* Optimize MOVE BACKWARD ALL into a Rewind.
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
if (!forward && count == FETCH_ALL && dest == None)
|
||||||
|
{
|
||||||
|
long result = portal->portalPos;
|
||||||
|
|
||||||
|
if (result > 0 && !portal->atEnd)
|
||||||
|
result--;
|
||||||
|
DoPortalRewind(portal);
|
||||||
|
/* result is bogus if pos had overflowed, but it's best we can do */
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DoRelativeFetch(portal, forward, count, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DoRelativeFetch
|
||||||
|
* Do fetch for a simple N-rows-forward-or-backward case.
|
||||||
|
*
|
||||||
|
* count <= 0 is interpreted as a no-op: the destination gets started up
|
||||||
|
* and shut down, but nothing else happens. Also, count == FETCH_ALL is
|
||||||
|
* interpreted as "all rows".
|
||||||
|
*
|
||||||
|
* Caller must already have validated the Portal.
|
||||||
|
*
|
||||||
|
* Returns number of rows processed (suitable for use in result tag)
|
||||||
|
*/
|
||||||
|
static long
|
||||||
|
DoRelativeFetch(Portal portal,
|
||||||
|
bool forward,
|
||||||
|
long count,
|
||||||
|
CommandDest dest)
|
||||||
|
{
|
||||||
|
QueryDesc *queryDesc;
|
||||||
|
EState *estate;
|
||||||
|
ScanDirection direction;
|
||||||
|
QueryDesc temp_queryDesc;
|
||||||
|
|
||||||
queryDesc = PortalGetQueryDesc(portal);
|
queryDesc = PortalGetQueryDesc(portal);
|
||||||
estate = queryDesc->estate;
|
estate = queryDesc->estate;
|
||||||
@ -224,12 +360,9 @@ DoPortalFetch(Portal portal, bool forward, long count, CommandDest dest)
|
|||||||
if (dest != queryDesc->dest &&
|
if (dest != queryDesc->dest &&
|
||||||
!(queryDesc->dest == RemoteInternal && dest == Remote))
|
!(queryDesc->dest == RemoteInternal && dest == Remote))
|
||||||
{
|
{
|
||||||
QueryDesc *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
|
memcpy(&temp_queryDesc, queryDesc, sizeof(QueryDesc));
|
||||||
|
temp_queryDesc.dest = dest;
|
||||||
memcpy(qdesc, queryDesc, sizeof(QueryDesc));
|
queryDesc = &temp_queryDesc;
|
||||||
qdesc->dest = dest;
|
|
||||||
queryDesc = qdesc;
|
|
||||||
temp_desc = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -240,65 +373,101 @@ DoPortalFetch(Portal portal, bool forward, long count, CommandDest dest)
|
|||||||
* robust about being called again if they've already returned NULL
|
* robust about being called again if they've already returned NULL
|
||||||
* once.) Then call the executor (we must not skip this, because the
|
* once.) Then call the executor (we must not skip this, because the
|
||||||
* destination needs to see a setup and shutdown even if no tuples are
|
* destination needs to see a setup and shutdown even if no tuples are
|
||||||
* available). Finally, update the atStart/atEnd state depending on
|
* available). Finally, update the portal position state depending on
|
||||||
* the number of tuples that were retrieved.
|
* the number of tuples that were retrieved.
|
||||||
*/
|
*/
|
||||||
if (forward)
|
if (forward)
|
||||||
{
|
{
|
||||||
if (portal->atEnd || count == 0)
|
if (portal->atEnd || count <= 0)
|
||||||
direction = NoMovementScanDirection;
|
direction = NoMovementScanDirection;
|
||||||
else
|
else
|
||||||
direction = ForwardScanDirection;
|
direction = ForwardScanDirection;
|
||||||
|
|
||||||
/* In the executor, zero count processes all portal rows */
|
/* In the executor, zero count processes all rows */
|
||||||
if (count == INT_MAX)
|
if (count == FETCH_ALL)
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
ExecutorRun(queryDesc, direction, count);
|
ExecutorRun(queryDesc, direction, count);
|
||||||
|
|
||||||
if (direction != NoMovementScanDirection)
|
if (direction != NoMovementScanDirection)
|
||||||
{
|
{
|
||||||
|
long oldPos;
|
||||||
|
|
||||||
if (estate->es_processed > 0)
|
if (estate->es_processed > 0)
|
||||||
portal->atStart = false; /* OK to back up now */
|
portal->atStart = false; /* OK to go backward now */
|
||||||
if (count <= 0 || (long) estate->es_processed < count)
|
if (count == 0 ||
|
||||||
|
(unsigned long) estate->es_processed < (unsigned long) count)
|
||||||
portal->atEnd = true; /* we retrieved 'em all */
|
portal->atEnd = true; /* we retrieved 'em all */
|
||||||
|
oldPos = portal->portalPos;
|
||||||
|
portal->portalPos += estate->es_processed;
|
||||||
|
/* portalPos doesn't advance when we fall off the end */
|
||||||
|
if (portal->portalPos < oldPos)
|
||||||
|
portal->posOverflow = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!portal->backwardOK)
|
if (!portal->backwardOK)
|
||||||
elog(ERROR, "Cursor cannot scan backwards"
|
elog(ERROR, "Cursor can only scan forward"
|
||||||
"\n\tDeclare it with SCROLL option to enable backward scan");
|
"\n\tDeclare it with SCROLL option to enable backward scan");
|
||||||
|
|
||||||
if (portal->atStart || count == 0)
|
if (portal->atStart || count <= 0)
|
||||||
direction = NoMovementScanDirection;
|
direction = NoMovementScanDirection;
|
||||||
else
|
else
|
||||||
direction = BackwardScanDirection;
|
direction = BackwardScanDirection;
|
||||||
|
|
||||||
/* In the executor, zero count processes all portal rows */
|
/* In the executor, zero count processes all rows */
|
||||||
if (count == INT_MAX)
|
if (count == FETCH_ALL)
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
ExecutorRun(queryDesc, direction, count);
|
ExecutorRun(queryDesc, direction, count);
|
||||||
|
|
||||||
if (direction != NoMovementScanDirection)
|
if (direction != NoMovementScanDirection)
|
||||||
{
|
{
|
||||||
if (estate->es_processed > 0)
|
if (estate->es_processed > 0 && portal->atEnd)
|
||||||
|
{
|
||||||
portal->atEnd = false; /* OK to go forward now */
|
portal->atEnd = false; /* OK to go forward now */
|
||||||
if (count <= 0 || (long) estate->es_processed < count)
|
portal->portalPos++; /* adjust for endpoint case */
|
||||||
portal->atStart = true; /* we retrieved 'em all */
|
|
||||||
}
|
}
|
||||||
|
if (count == 0 ||
|
||||||
|
(unsigned long) estate->es_processed < (unsigned long) count)
|
||||||
|
{
|
||||||
|
portal->atStart = true; /* we retrieved 'em all */
|
||||||
|
portal->portalPos = 0;
|
||||||
|
portal->posOverflow = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long oldPos;
|
||||||
|
|
||||||
|
oldPos = portal->portalPos;
|
||||||
|
portal->portalPos -= estate->es_processed;
|
||||||
|
if (portal->portalPos > oldPos ||
|
||||||
|
portal->portalPos <= 0)
|
||||||
|
portal->posOverflow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return estate->es_processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up and switch back to old context.
|
* DoPortalRewind - rewind a Portal to starting point
|
||||||
*/
|
*/
|
||||||
if (temp_desc)
|
static void
|
||||||
pfree(queryDesc);
|
DoPortalRewind(Portal portal)
|
||||||
|
{
|
||||||
|
QueryDesc *queryDesc;
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcontext);
|
queryDesc = PortalGetQueryDesc(portal);
|
||||||
|
|
||||||
return estate->es_processed;
|
ExecutorRewind(queryDesc);
|
||||||
|
|
||||||
|
portal->atStart = true;
|
||||||
|
portal->atEnd = false;
|
||||||
|
portal->portalPos = 0;
|
||||||
|
portal->posOverflow = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -310,15 +479,6 @@ PerformPortalClose(char *name)
|
|||||||
{
|
{
|
||||||
Portal portal;
|
Portal portal;
|
||||||
|
|
||||||
/*
|
|
||||||
* sanity checks ... why is this case allowed by the grammar, anyway?
|
|
||||||
*/
|
|
||||||
if (name == NULL)
|
|
||||||
{
|
|
||||||
elog(WARNING, "PerformPortalClose: missing portal name");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the portal from the portal name
|
* get the portal from the portal name
|
||||||
*/
|
*/
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.201 2003/03/10 03:53:49 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.202 2003/03/11 19:40:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -287,6 +287,42 @@ ExecutorEnd(QueryDesc *queryDesc)
|
|||||||
queryDesc->planstate = NULL;
|
queryDesc->planstate = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* ExecutorRewind
|
||||||
|
*
|
||||||
|
* This routine may be called on an open queryDesc to rewind it
|
||||||
|
* to the start.
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ExecutorRewind(QueryDesc *queryDesc)
|
||||||
|
{
|
||||||
|
EState *estate;
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
|
/* sanity checks */
|
||||||
|
Assert(queryDesc != NULL);
|
||||||
|
|
||||||
|
estate = queryDesc->estate;
|
||||||
|
|
||||||
|
Assert(estate != NULL);
|
||||||
|
|
||||||
|
/* It's probably not sensible to rescan updating queries */
|
||||||
|
Assert(queryDesc->operation == CMD_SELECT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switch into per-query memory context
|
||||||
|
*/
|
||||||
|
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rescan plan
|
||||||
|
*/
|
||||||
|
ExecReScan(queryDesc->planstate, NULL);
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExecCheckRTPerms
|
* ExecCheckRTPerms
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.87 2003/03/10 03:53:49 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.88 2003/03/11 19:40:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1349,7 +1349,10 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||||||
_SPI_current->tuptable = NULL;
|
_SPI_current->tuptable = NULL;
|
||||||
|
|
||||||
/* Run the cursor */
|
/* Run the cursor */
|
||||||
_SPI_current->processed = DoPortalFetch(portal, forward, (long) count,
|
_SPI_current->processed =
|
||||||
|
DoPortalFetch(portal,
|
||||||
|
forward ? FETCH_FORWARD : FETCH_BACKWARD,
|
||||||
|
(long) count,
|
||||||
dest);
|
dest);
|
||||||
|
|
||||||
if (dest == SPI && _SPI_checktuples())
|
if (dest == SPI && _SPI_checktuples())
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.405 2003/03/10 03:53:50 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.406 2003/03/11 19:40:23 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -191,7 +191,7 @@ static void doNegateFloat(Value *v);
|
|||||||
|
|
||||||
%type <range> qualified_name OptConstrFromTable
|
%type <range> qualified_name OptConstrFromTable
|
||||||
|
|
||||||
%type <str> opt_id all_Op MathOp opt_name SpecialRuleRelation
|
%type <str> all_Op MathOp opt_name SpecialRuleRelation
|
||||||
|
|
||||||
%type <str> iso_level opt_encoding
|
%type <str> iso_level opt_encoding
|
||||||
%type <node> grantee
|
%type <node> grantee
|
||||||
@ -248,12 +248,10 @@ static void doNegateFloat(Value *v);
|
|||||||
|
|
||||||
%type <boolean> copy_from
|
%type <boolean> copy_from
|
||||||
|
|
||||||
%type <ival> direction reindex_type drop_type
|
%type <ival> reindex_type drop_type fetch_count
|
||||||
opt_column event comment_type cursor_options
|
opt_column event comment_type cursor_options
|
||||||
|
|
||||||
%type <ival> fetch_how_many
|
%type <node> fetch_direction select_limit_value select_offset_value
|
||||||
|
|
||||||
%type <node> select_limit_value select_offset_value
|
|
||||||
|
|
||||||
%type <list> OptSeqList
|
%type <list> OptSeqList
|
||||||
%type <defelt> OptSeqElem
|
%type <defelt> OptSeqElem
|
||||||
@ -345,7 +343,7 @@ static void doNegateFloat(Value *v);
|
|||||||
EACH ELSE ENCODING ENCRYPTED END_P ESCAPE EXCEPT
|
EACH ELSE ENCODING ENCRYPTED END_P ESCAPE EXCEPT
|
||||||
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
|
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
|
||||||
|
|
||||||
FALSE_P FETCH FLOAT_P FOR FORCE FOREIGN FORWARD
|
FALSE_P FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
|
||||||
FREEZE FROM FULL FUNCTION
|
FREEZE FROM FULL FUNCTION
|
||||||
|
|
||||||
GLOBAL GRANT GROUP_P
|
GLOBAL GRANT GROUP_P
|
||||||
@ -361,7 +359,7 @@ static void doNegateFloat(Value *v);
|
|||||||
|
|
||||||
KEY
|
KEY
|
||||||
|
|
||||||
LANCOMPILER LANGUAGE LEADING LEFT LEVEL LIKE LIMIT
|
LANCOMPILER LANGUAGE LAST_P LEADING LEFT LEVEL LIKE LIMIT
|
||||||
LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
|
LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
|
||||||
LOCK_P
|
LOCK_P
|
||||||
|
|
||||||
@ -1239,16 +1237,15 @@ opt_drop_behavior:
|
|||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* QUERY :
|
* QUERY :
|
||||||
* close <optname>
|
* close <portalname>
|
||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
ClosePortalStmt:
|
ClosePortalStmt:
|
||||||
CLOSE opt_id
|
CLOSE name
|
||||||
{
|
{
|
||||||
ClosePortalStmt *n = makeNode(ClosePortalStmt);
|
ClosePortalStmt *n = makeNode(ClosePortalStmt);
|
||||||
n->portalname = $2;
|
n->portalname = $2;
|
||||||
@ -1256,10 +1253,6 @@ ClosePortalStmt:
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
opt_id: ColId { $$ = $1; }
|
|
||||||
| /*EMPTY*/ { $$ = NULL; }
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
@ -2583,61 +2576,17 @@ comment_text:
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* QUERY:
|
* QUERY:
|
||||||
* fetch/move [forward | backward] [ # | all ] [ in <portalname> ]
|
* fetch/move
|
||||||
* fetch [ forward | backward | absolute | relative ]
|
|
||||||
* [ # | all | next | prior ] [ [ in | from ] <portalname> ]
|
|
||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
FetchStmt: FETCH direction fetch_how_many from_in name
|
FetchStmt: FETCH fetch_direction from_in name
|
||||||
{
|
{
|
||||||
FetchStmt *n = makeNode(FetchStmt);
|
FetchStmt *n = (FetchStmt *) $2;
|
||||||
if ($3 < 0)
|
|
||||||
{
|
|
||||||
$3 = -$3;
|
|
||||||
$2 = (($2 == FETCH_FORWARD) ? FETCH_BACKWARD : FETCH_FORWARD);
|
|
||||||
}
|
|
||||||
n->direction = $2;
|
|
||||||
n->howMany = $3;
|
|
||||||
n->portalname = $5;
|
|
||||||
n->ismove = FALSE;
|
|
||||||
$$ = (Node *)n;
|
|
||||||
}
|
|
||||||
| FETCH fetch_how_many from_in name
|
|
||||||
{
|
|
||||||
FetchStmt *n = makeNode(FetchStmt);
|
|
||||||
if ($2 < 0)
|
|
||||||
{
|
|
||||||
n->howMany = -$2;
|
|
||||||
n->direction = FETCH_BACKWARD;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n->direction = FETCH_FORWARD;
|
|
||||||
n->howMany = $2;
|
|
||||||
}
|
|
||||||
n->portalname = $4;
|
n->portalname = $4;
|
||||||
n->ismove = FALSE;
|
n->ismove = FALSE;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| FETCH direction from_in name
|
|
||||||
{
|
|
||||||
FetchStmt *n = makeNode(FetchStmt);
|
|
||||||
n->direction = $2;
|
|
||||||
n->howMany = 1;
|
|
||||||
n->portalname = $4;
|
|
||||||
n->ismove = FALSE;
|
|
||||||
$$ = (Node *)n;
|
|
||||||
}
|
|
||||||
| FETCH from_in name
|
|
||||||
{
|
|
||||||
FetchStmt *n = makeNode(FetchStmt);
|
|
||||||
n->direction = FETCH_FORWARD;
|
|
||||||
n->howMany = 1;
|
|
||||||
n->portalname = $3;
|
|
||||||
n->ismove = FALSE;
|
|
||||||
$$ = (Node *)n;
|
|
||||||
}
|
|
||||||
| FETCH name
|
| FETCH name
|
||||||
{
|
{
|
||||||
FetchStmt *n = makeNode(FetchStmt);
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
@ -2647,55 +2596,13 @@ FetchStmt: FETCH direction fetch_how_many from_in name
|
|||||||
n->ismove = FALSE;
|
n->ismove = FALSE;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| MOVE direction fetch_how_many from_in name
|
| MOVE fetch_direction from_in name
|
||||||
{
|
{
|
||||||
FetchStmt *n = makeNode(FetchStmt);
|
FetchStmt *n = (FetchStmt *) $2;
|
||||||
if ($3 < 0)
|
|
||||||
{
|
|
||||||
$3 = -$3;
|
|
||||||
$2 = (($2 == FETCH_FORWARD) ? FETCH_BACKWARD : FETCH_FORWARD);
|
|
||||||
}
|
|
||||||
n->direction = $2;
|
|
||||||
n->howMany = $3;
|
|
||||||
n->portalname = $5;
|
|
||||||
n->ismove = TRUE;
|
|
||||||
$$ = (Node *)n;
|
|
||||||
}
|
|
||||||
| MOVE fetch_how_many from_in name
|
|
||||||
{
|
|
||||||
FetchStmt *n = makeNode(FetchStmt);
|
|
||||||
if ($2 < 0)
|
|
||||||
{
|
|
||||||
n->howMany = -$2;
|
|
||||||
n->direction = FETCH_BACKWARD;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n->direction = FETCH_FORWARD;
|
|
||||||
n->howMany = $2;
|
|
||||||
}
|
|
||||||
n->portalname = $4;
|
n->portalname = $4;
|
||||||
n->ismove = TRUE;
|
n->ismove = TRUE;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| MOVE direction from_in name
|
|
||||||
{
|
|
||||||
FetchStmt *n = makeNode(FetchStmt);
|
|
||||||
n->direction = $2;
|
|
||||||
n->howMany = 1;
|
|
||||||
n->portalname = $4;
|
|
||||||
n->ismove = TRUE;
|
|
||||||
$$ = (Node *)n;
|
|
||||||
}
|
|
||||||
| MOVE from_in name
|
|
||||||
{
|
|
||||||
FetchStmt *n = makeNode(FetchStmt);
|
|
||||||
n->direction = FETCH_FORWARD;
|
|
||||||
n->howMany = 1;
|
|
||||||
n->portalname = $3;
|
|
||||||
n->ismove = TRUE;
|
|
||||||
$$ = (Node *)n;
|
|
||||||
}
|
|
||||||
| MOVE name
|
| MOVE name
|
||||||
{
|
{
|
||||||
FetchStmt *n = makeNode(FetchStmt);
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
@ -2707,27 +2614,121 @@ FetchStmt: FETCH direction fetch_how_many from_in name
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
direction: FORWARD { $$ = FETCH_FORWARD; }
|
fetch_direction:
|
||||||
| BACKWARD { $$ = FETCH_BACKWARD; }
|
/*EMPTY*/
|
||||||
| RELATIVE { $$ = FETCH_FORWARD; }
|
|
||||||
| ABSOLUTE
|
|
||||||
{
|
{
|
||||||
elog(NOTICE,
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
"FETCH / ABSOLUTE not supported, using RELATIVE");
|
n->direction = FETCH_FORWARD;
|
||||||
$$ = FETCH_FORWARD;
|
n->howMany = 1;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| NEXT
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_FORWARD;
|
||||||
|
n->howMany = 1;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| PRIOR
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_BACKWARD;
|
||||||
|
n->howMany = 1;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| FIRST_P
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_ABSOLUTE;
|
||||||
|
n->howMany = 1;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| LAST_P
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_ABSOLUTE;
|
||||||
|
n->howMany = -1;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| ABSOLUTE fetch_count
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_ABSOLUTE;
|
||||||
|
n->howMany = $2;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| RELATIVE fetch_count
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_RELATIVE;
|
||||||
|
n->howMany = $2;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| fetch_count
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_FORWARD;
|
||||||
|
n->howMany = $1;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| ALL
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_FORWARD;
|
||||||
|
n->howMany = FETCH_ALL;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| FORWARD
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_FORWARD;
|
||||||
|
n->howMany = 1;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| FORWARD fetch_count
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_FORWARD;
|
||||||
|
n->howMany = $2;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| FORWARD ALL
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_FORWARD;
|
||||||
|
n->howMany = FETCH_ALL;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| BACKWARD
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_BACKWARD;
|
||||||
|
n->howMany = 1;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| BACKWARD fetch_count
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_BACKWARD;
|
||||||
|
n->howMany = $2;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| BACKWARD ALL
|
||||||
|
{
|
||||||
|
FetchStmt *n = makeNode(FetchStmt);
|
||||||
|
n->direction = FETCH_BACKWARD;
|
||||||
|
n->howMany = FETCH_ALL;
|
||||||
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
fetch_how_many:
|
fetch_count:
|
||||||
Iconst { $$ = $1; }
|
Iconst { $$ = $1; }
|
||||||
| '-' Iconst { $$ = - $2; }
|
| '-' Iconst { $$ = - $2; }
|
||||||
| ALL { $$ = INT_MAX; }
|
|
||||||
| NEXT { $$ = 1; }
|
|
||||||
| PRIOR { $$ = -1; }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
from_in: IN_P {}
|
from_in: FROM {}
|
||||||
| FROM {}
|
| IN_P {}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
@ -7093,6 +7094,7 @@ unreserved_keyword:
|
|||||||
| EXPLAIN
|
| EXPLAIN
|
||||||
| EXTERNAL
|
| EXTERNAL
|
||||||
| FETCH
|
| FETCH
|
||||||
|
| FIRST_P
|
||||||
| FORCE
|
| FORCE
|
||||||
| FORWARD
|
| FORWARD
|
||||||
| FUNCTION
|
| FUNCTION
|
||||||
@ -7115,6 +7117,7 @@ unreserved_keyword:
|
|||||||
| KEY
|
| KEY
|
||||||
| LANCOMPILER
|
| LANCOMPILER
|
||||||
| LANGUAGE
|
| LANGUAGE
|
||||||
|
| LAST_P
|
||||||
| LEVEL
|
| LEVEL
|
||||||
| LISTEN
|
| LISTEN
|
||||||
| LOAD
|
| LOAD
|
||||||
@ -7170,9 +7173,9 @@ unreserved_keyword:
|
|||||||
| SCROLL
|
| SCROLL
|
||||||
| SECOND_P
|
| SECOND_P
|
||||||
| SECURITY
|
| SECURITY
|
||||||
| SESSION
|
|
||||||
| SEQUENCE
|
| SEQUENCE
|
||||||
| SERIALIZABLE
|
| SERIALIZABLE
|
||||||
|
| SESSION
|
||||||
| SET
|
| SET
|
||||||
| SHARE
|
| SHARE
|
||||||
| SHOW
|
| SHOW
|
||||||
@ -7211,8 +7214,8 @@ unreserved_keyword:
|
|||||||
| VOLATILE
|
| VOLATILE
|
||||||
| WITH
|
| WITH
|
||||||
| WITHOUT
|
| WITHOUT
|
||||||
| WRITE
|
|
||||||
| WORK
|
| WORK
|
||||||
|
| WRITE
|
||||||
| YEAR_P
|
| YEAR_P
|
||||||
| ZONE
|
| ZONE
|
||||||
;
|
;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.134 2003/02/10 04:44:46 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.135 2003/03/11 19:40:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -128,6 +128,7 @@ static const ScanKeyword ScanKeywords[] = {
|
|||||||
{"extract", EXTRACT},
|
{"extract", EXTRACT},
|
||||||
{"false", FALSE_P},
|
{"false", FALSE_P},
|
||||||
{"fetch", FETCH},
|
{"fetch", FETCH},
|
||||||
|
{"first", FIRST_P},
|
||||||
{"float", FLOAT_P},
|
{"float", FLOAT_P},
|
||||||
{"for", FOR},
|
{"for", FOR},
|
||||||
{"force", FORCE},
|
{"force", FORCE},
|
||||||
@ -171,6 +172,7 @@ static const ScanKeyword ScanKeywords[] = {
|
|||||||
{"key", KEY},
|
{"key", KEY},
|
||||||
{"lancompiler", LANCOMPILER},
|
{"lancompiler", LANCOMPILER},
|
||||||
{"language", LANGUAGE},
|
{"language", LANGUAGE},
|
||||||
|
{"last", LAST_P},
|
||||||
{"leading", LEADING},
|
{"leading", LEADING},
|
||||||
{"left", LEFT},
|
{"left", LEFT},
|
||||||
{"level", LEVEL},
|
{"level", LEVEL},
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.194 2003/03/10 03:53:51 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.195 2003/03/11 19:40:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -321,15 +321,8 @@ ProcessUtility(Node *parsetree,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_FetchStmt:
|
case T_FetchStmt:
|
||||||
{
|
PerformPortalFetch((FetchStmt *) parsetree, dest,
|
||||||
FetchStmt *stmt = (FetchStmt *) parsetree;
|
|
||||||
|
|
||||||
PerformPortalFetch(stmt->portalname,
|
|
||||||
stmt->direction == FETCH_FORWARD,
|
|
||||||
stmt->howMany,
|
|
||||||
(stmt->ismove) ? None : dest,
|
|
||||||
completionTag);
|
completionTag);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.52 2003/03/10 03:53:51 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.53 2003/03/11 19:40:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -167,10 +167,12 @@ PortalSetQuery(Portal portal,
|
|||||||
AssertArg(PortalIsValid(portal));
|
AssertArg(PortalIsValid(portal));
|
||||||
|
|
||||||
portal->queryDesc = queryDesc;
|
portal->queryDesc = queryDesc;
|
||||||
portal->backwardOK = ExecSupportsBackwardScan(queryDesc->plantree);
|
|
||||||
portal->atStart = true; /* Allow fetch forward only, to start */
|
|
||||||
portal->atEnd = false;
|
|
||||||
portal->cleanup = cleanup;
|
portal->cleanup = cleanup;
|
||||||
|
portal->backwardOK = ExecSupportsBackwardScan(queryDesc->plantree);
|
||||||
|
portal->atStart = true;
|
||||||
|
portal->atEnd = false; /* allow fetches */
|
||||||
|
portal->portalPos = 0;
|
||||||
|
portal->posOverflow = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -211,10 +213,12 @@ CreatePortal(const char *name)
|
|||||||
|
|
||||||
/* initialize portal query */
|
/* initialize portal query */
|
||||||
portal->queryDesc = NULL;
|
portal->queryDesc = NULL;
|
||||||
portal->backwardOK = false;
|
|
||||||
portal->atStart = true; /* disallow fetches until query is set */
|
|
||||||
portal->atEnd = true;
|
|
||||||
portal->cleanup = NULL;
|
portal->cleanup = NULL;
|
||||||
|
portal->backwardOK = false;
|
||||||
|
portal->atStart = true;
|
||||||
|
portal->atEnd = true; /* disallow fetches until query is set */
|
||||||
|
portal->portalPos = 0;
|
||||||
|
portal->posOverflow = false;
|
||||||
|
|
||||||
/* put portal in table */
|
/* put portal in table */
|
||||||
PortalHashTableInsert(portal);
|
PortalHashTableInsert(portal);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: portalcmds.h,v 1.5 2003/03/10 03:53:51 tgl Exp $
|
* $Id: portalcmds.h,v 1.6 2003/03/11 19:40:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -19,10 +19,12 @@
|
|||||||
|
|
||||||
extern void PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest);
|
extern void PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest);
|
||||||
|
|
||||||
extern void PerformPortalFetch(char *name, bool forward, long count,
|
extern void PerformPortalFetch(FetchStmt *stmt, CommandDest dest,
|
||||||
CommandDest dest, char *completionTag);
|
char *completionTag);
|
||||||
|
|
||||||
extern long DoPortalFetch(Portal portal, bool forward, long count,
|
extern long DoPortalFetch(Portal portal,
|
||||||
|
FetchDirection fdirection,
|
||||||
|
long count,
|
||||||
CommandDest dest);
|
CommandDest dest);
|
||||||
|
|
||||||
extern void PerformPortalClose(char *name);
|
extern void PerformPortalClose(char *name);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: executor.h,v 1.90 2003/03/10 03:53:51 tgl Exp $
|
* $Id: executor.h,v 1.91 2003/03/11 19:40:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -86,6 +86,7 @@ extern void ExecutorStart(QueryDesc *queryDesc);
|
|||||||
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
|
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
|
||||||
ScanDirection direction, long count);
|
ScanDirection direction, long count);
|
||||||
extern void ExecutorEnd(QueryDesc *queryDesc);
|
extern void ExecutorEnd(QueryDesc *queryDesc);
|
||||||
|
extern void ExecutorRewind(QueryDesc *queryDesc);
|
||||||
extern void ExecCheckRTPerms(List *rangeTable, CmdType operation);
|
extern void ExecCheckRTPerms(List *rangeTable, CmdType operation);
|
||||||
extern void ExecEndPlan(PlanState *planstate, EState *estate);
|
extern void ExecEndPlan(PlanState *planstate, EState *estate);
|
||||||
extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo,
|
extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parsenodes.h,v 1.232 2003/03/10 03:53:51 tgl Exp $
|
* $Id: parsenodes.h,v 1.233 2003/03/11 19:40:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1228,16 +1228,21 @@ typedef struct ClosePortalStmt
|
|||||||
*/
|
*/
|
||||||
typedef enum FetchDirection
|
typedef enum FetchDirection
|
||||||
{
|
{
|
||||||
|
/* for these, howMany is how many rows to fetch; FETCH_ALL means ALL */
|
||||||
FETCH_FORWARD,
|
FETCH_FORWARD,
|
||||||
FETCH_BACKWARD
|
FETCH_BACKWARD,
|
||||||
/* ABSOLUTE someday? */
|
/* for these, howMany indicates a position; only one row is fetched */
|
||||||
|
FETCH_ABSOLUTE,
|
||||||
|
FETCH_RELATIVE
|
||||||
} FetchDirection;
|
} FetchDirection;
|
||||||
|
|
||||||
|
#define FETCH_ALL LONG_MAX
|
||||||
|
|
||||||
typedef struct FetchStmt
|
typedef struct FetchStmt
|
||||||
{
|
{
|
||||||
NodeTag type;
|
NodeTag type;
|
||||||
FetchDirection direction; /* see above */
|
FetchDirection direction; /* see above */
|
||||||
long howMany; /* number of rows */
|
long howMany; /* number of rows, or position argument */
|
||||||
char *portalname; /* name of portal (cursor) */
|
char *portalname; /* name of portal (cursor) */
|
||||||
bool ismove; /* TRUE if MOVE */
|
bool ismove; /* TRUE if MOVE */
|
||||||
} FetchStmt;
|
} FetchStmt;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: portal.h,v 1.38 2003/03/10 03:53:52 tgl Exp $
|
* $Id: portal.h,v 1.39 2003/03/11 19:40:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -27,10 +27,21 @@ typedef struct PortalData
|
|||||||
char *name; /* Portal's name */
|
char *name; /* Portal's name */
|
||||||
MemoryContext heap; /* subsidiary memory */
|
MemoryContext heap; /* subsidiary memory */
|
||||||
QueryDesc *queryDesc; /* Info about query associated with portal */
|
QueryDesc *queryDesc; /* Info about query associated with portal */
|
||||||
bool backwardOK; /* is fetch backwards allowed at all? */
|
|
||||||
bool atStart; /* T => fetch backwards is not allowed now */
|
|
||||||
bool atEnd; /* T => fetch forwards is not allowed now */
|
|
||||||
void (*cleanup) (Portal); /* Cleanup routine (optional) */
|
void (*cleanup) (Portal); /* Cleanup routine (optional) */
|
||||||
|
bool backwardOK; /* is fetch backwards allowed? */
|
||||||
|
/*
|
||||||
|
* atStart, atEnd and portalPos indicate the current cursor position.
|
||||||
|
* portalPos is zero before the first row, N after fetching N'th row of
|
||||||
|
* query. After we run off the end, portalPos = # of rows in query, and
|
||||||
|
* atEnd is true. If portalPos overflows, set posOverflow (this causes
|
||||||
|
* us to stop relying on its value for navigation). Note that atStart
|
||||||
|
* implies portalPos == 0, but not the reverse (portalPos could have
|
||||||
|
* overflowed).
|
||||||
|
*/
|
||||||
|
bool atStart;
|
||||||
|
bool atEnd;
|
||||||
|
bool posOverflow;
|
||||||
|
long portalPos;
|
||||||
} PortalData;
|
} PortalData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user