Code review for FETCH/MOVE 0 changes. Improve documentation, do the

right thing with the destination when FETCH 0 can't return a row,
don't try to stuff LONG_MAX into an int value.
This commit is contained in:
Tom Lane 2003-01-08 00:22:27 +00:00
parent 1bc9e98549
commit 061168d38f
5 changed files with 113 additions and 74 deletions

View File

@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/fetch.sgml,v 1.22 2002/12/30 15:31:47 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/fetch.sgml,v 1.23 2003/01/08 00:22:26 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -22,7 +22,7 @@ PostgreSQL documentation
</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> ] [ <replaceable class="PARAMETER">count</replaceable> ] { IN | FROM } <replaceable class="PARAMETER">cursor</replaceable>
FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</replaceable> | ALL | NEXT | PRIOR ] FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</replaceable> | ALL | LAST | NEXT | PRIOR ]
{ IN | FROM } <replaceable class="PARAMETER">cursor</replaceable> { IN | FROM } <replaceable class="PARAMETER">cursor</replaceable>
</synopsis> </synopsis>
@ -40,7 +40,7 @@ FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</repl
<term><replaceable class="PARAMETER">direction</replaceable></term> <term><replaceable class="PARAMETER">direction</replaceable></term>
<listitem> <listitem>
<para> <para>
<replaceable class="PARAMETER">selector</replaceable> <replaceable class="PARAMETER">direction</replaceable>
defines the fetch direction. It can be one of defines the fetch direction. It can be one of
the following: the following:
@ -50,7 +50,7 @@ FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</repl
<listitem> <listitem>
<para> <para>
fetch next row(s). This is the default fetch next row(s). This is the default
if <replaceable class="PARAMETER">selector</replaceable> is omitted. if <replaceable class="PARAMETER">direction</replaceable> is omitted.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -87,9 +87,9 @@ FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</repl
<term><replaceable class="PARAMETER">#</replaceable></term> <term><replaceable class="PARAMETER">#</replaceable></term>
<listitem> <listitem>
<para> <para>
A signed integer that specifies how many rows to fetch. A signed integer constant that specifies how many rows to fetch.
Note that a negative integer is equivalent to changing the sense of Note that a negative integer is equivalent to changing the sense of
FORWARD and BACKWARD. Zero re-fetches the current row. FORWARD and BACKWARD. Zero re-fetches the current row, if any.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -105,6 +105,17 @@ FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</repl
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
LAST
</term>
<listitem>
<para>
Same as <literal>ALL</>, but conforms to SQL92 syntax.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
NEXT NEXT
@ -151,7 +162,8 @@ FETCH [ FORWARD | BACKWARD | RELATIVE ] [ <replaceable class="PARAMETER">#</repl
Outputs Outputs
</title> </title>
<para> <para>
<command>FETCH</command> returns the results of the query defined by the specified cursor. <command>FETCH</command> returns rows from the result of the query defined
by the specified cursor.
The following messages will be returned if the query fails: The following messages will be returned if the query fails:
<variablelist> <variablelist>
@ -200,10 +212,33 @@ WARNING: FETCH/ABSOLUTE not supported, using RELATIVE
If the number of rows remaining in the cursor is less If the number of rows remaining in the cursor is less
than <replaceable class="PARAMETER">#</replaceable>, than <replaceable class="PARAMETER">#</replaceable>,
then only those available are fetched. then only those available are fetched.
Substituting the keyword ALL in place of a number will Substituting the keyword ALL or LAST in place of a number will
cause all remaining rows in the cursor to be retrieved. cause all remaining rows in the cursor to be retrieved.
Instances may be fetched in both FORWARD and BACKWARD Rows may be fetched in both FORWARD and BACKWARD
directions. The default direction is FORWARD. directions. The default direction is FORWARD.
</para>
<para>
The cursor position can be before the first row of the query result, or on
any particular row of the result, or after the last row of the result.
When created, a cursor is positioned before the first row. After fetching
some rows, the cursor is positioned on the last row retrieved. A new
<command>FETCH</command> always steps one row in the specified direction
(if possible) before beginning to return rows. If the
<command>FETCH</command> requests more rows than available, the cursor is
left positioned after the last row of the query result (or before the first
row, in the case of a backward fetch). This will always be the case after
<command>FETCH ALL</>.
</para>
<tip>
<para>
A zero row count requests fetching the current row without moving the
cursor --- that is, re-fetching the most recently fetched row.
This will succeed unless the cursor is positioned before the
first row or after the last row; in which case, no row is returned.
</para>
</tip>
<tip> <tip>
<para> <para>
@ -213,7 +248,6 @@ WARNING: FETCH/ABSOLUTE not supported, using RELATIVE
<command>FORWARD -1</command> is the same as <command>BACKWARD 1</command>. <command>FORWARD -1</command> is the same as <command>BACKWARD 1</command>.
</para> </para>
</tip> </tip>
</para>
<refsect2 id="R2-SQL-FETCH-3"> <refsect2 id="R2-SQL-FETCH-3">
<refsect2info> <refsect2info>
@ -224,11 +258,9 @@ WARNING: FETCH/ABSOLUTE not supported, using RELATIVE
</title> </title>
<para> <para>
Note that the FORWARD and BACKWARD keywords are Note that the FORWARD, BACKWARD, and ALL keywords are
<productname>PostgreSQL</productname> extensions. <productname>PostgreSQL</productname> extensions.
The <acronym>SQL92</acronym> syntax is also supported, specified See below for details on compatibility issues.
in the second form of the command. See below for details
on compatibility issues.
</para> </para>
<para> <para>
@ -246,11 +278,11 @@ WARNING: FETCH/ABSOLUTE not supported, using RELATIVE
</para> </para>
<para> <para>
<xref linkend="sql-declare" endterm="sql-declare-title">
is used to define a cursor.
Use Use
<xref linkend="sql-move" endterm="sql-move-title"> <xref linkend="sql-move" endterm="sql-move-title">
to change cursor position. to change cursor position without retrieving data.
<xref linkend="sql-declare" endterm="sql-declare-title">
will define a cursor.
Refer to Refer to
<xref linkend="sql-begin" endterm="sql-begin-title">, <xref linkend="sql-begin" endterm="sql-begin-title">,
<xref linkend="sql-commit" endterm="sql-commit-title">, <xref linkend="sql-commit" endterm="sql-commit-title">,

View File

@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/move.sgml,v 1.15 2002/12/30 15:31:47 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/move.sgml,v 1.16 2003/01/08 00:22:26 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -13,7 +13,7 @@ PostgreSQL documentation
MOVE MOVE
</refname> </refname>
<refpurpose> <refpurpose>
position a cursor on a specified row of a table reposition a cursor
</refpurpose> </refpurpose>
</refnamediv> </refnamediv>
<refsynopsisdiv> <refsynopsisdiv>
@ -21,9 +21,7 @@ PostgreSQL documentation
<date>1999-07-20</date> <date>1999-07-20</date>
</refsynopsisdivinfo> </refsynopsisdivinfo>
<synopsis> <synopsis>
MOVE [ <replaceable class="PARAMETER">direction</replaceable> ] MOVE [ <replaceable class="PARAMETER">direction</replaceable> ] [ <replaceable class="PARAMETER">count</replaceable> ] { IN | FROM } <replaceable class="PARAMETER">cursor</replaceable>
{<replaceable class="PARAMETER">count</replaceable> | LAST }
{ IN | FROM } <replaceable class="PARAMETER">cursor</replaceable>
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
@ -35,12 +33,10 @@ MOVE [ <replaceable class="PARAMETER">direction</replaceable> ]
Description Description
</title> </title>
<para> <para>
<command>MOVE</command> allows a user to move the cursor position a <command>MOVE</command> allows the user to move the cursor position a
specified number of rows. specified number of rows, or all the way to the end or start of the query.
<command>MOVE</command> works like the <command>FETCH</command> command, <command>MOVE</command> works exactly like the <command>FETCH</command>
but only positions the cursor and does not return rows. command, except it only repositions the cursor and does not return rows.
<replaceable class="PARAMETER">LAST</replaceable> moves to the end
of the cursor.
</para> </para>
<para> <para>
Refer to Refer to

View File

@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.175 2003/01/06 18:53:23 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.176 2003/01/08 00:22:26 tgl Exp $
--> -->
<appendix id="release"> <appendix id="release">
@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters. worries about funny characters.
--> -->
<literallayout><![CDATA[ <literallayout><![CDATA[
FETCH 0 now re-fetches cursor's current row, per SQL spec
Revised executor state representation; plan trees are read-only to executor now Revised executor state representation; plan trees are read-only to executor now
Information schema Information schema
Domains now support CHECK constraints Domains now support CHECK constraints

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.7 2002/12/30 15:31:47 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.8 2003/01/08 00:22:27 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -55,7 +55,7 @@ PortalCleanup(Portal portal)
* *
* name: name of portal * name: name of portal
* forward: forward or backward fetch? * forward: forward or backward fetch?
* count: # of tuples to 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.
@ -100,18 +100,15 @@ PerformPortalFetch(char *name,
return; return;
} }
/* If zero count, handle specially */ /*
* Zero count means to re-fetch the current row, if any (per SQL92)
*/
if (count == 0) if (count == 0)
{ {
bool on_row = false; bool on_row;
/* Are we sitting on a row? */ /* Are we sitting on a row? */
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); on_row = (portal->atStart == false && portal->atEnd == false);
queryDesc = PortalGetQueryDesc(portal);
estate = queryDesc->estate;
if (portal->atStart == false && portal->atEnd == false)
on_row = true;
MemoryContextSwitchTo(oldcontext);
if (dest == None) if (dest == None)
{ {
@ -122,26 +119,25 @@ PerformPortalFetch(char *name,
} }
else else
{ {
/* If we are not on a row, FETCH 0 returns nothing */ /*
if (!on_row) * If we are sitting on a row, back up one so we can re-fetch it.
return; * 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
/* Since we are sitting on a row, return the row */ * and shut down correctly; so keep going. Further down in the
/* Back up so we can reread the row */ * routine, count == 0 means we will retrieve no row.
PerformPortalFetch(name, false /* backward */, 1, */
None, /* throw away output */ if (on_row)
NULL /* do not modify the command tag */); {
PerformPortalFetch(name, false /* backward */, 1L,
/* Set up to fetch one row */ None, /* throw away output */
count = 1; NULL /* do not modify the command tag */);
forward = true; /* Set up to fetch one row forward */
count = 1;
forward = true;
}
} }
} }
/* Internally, zero count processes all portal rows */
if (count == LONG_MAX)
count = 0;
/* /*
* switch into the portal context * switch into the portal context
*/ */
@ -185,31 +181,45 @@ PerformPortalFetch(char *name,
*/ */
if (forward) if (forward)
{ {
if (portal->atEnd) if (portal->atEnd || count == 0)
direction = NoMovementScanDirection; direction = NoMovementScanDirection;
else else
direction = ForwardScanDirection; direction = ForwardScanDirection;
ExecutorRun(queryDesc, direction, (long) count); /* In the executor, zero count processes all portal rows */
if (count == INT_MAX)
count = 0;
if (estate->es_processed > 0) ExecutorRun(queryDesc, direction, count);
portal->atStart = false; /* OK to back up now */
if (count <= 0 || (int) estate->es_processed < count) if (direction != NoMovementScanDirection)
portal->atEnd = true; /* we retrieved 'em all */ {
if (estate->es_processed > 0)
portal->atStart = false; /* OK to back up now */
if (count <= 0 || (long) estate->es_processed < count)
portal->atEnd = true; /* we retrieved 'em all */
}
} }
else else
{ {
if (portal->atStart) if (portal->atStart || count == 0)
direction = NoMovementScanDirection; direction = NoMovementScanDirection;
else else
direction = BackwardScanDirection; direction = BackwardScanDirection;
ExecutorRun(queryDesc, direction, (long) count); /* In the executor, zero count processes all portal rows */
if (count == INT_MAX)
count = 0;
if (estate->es_processed > 0) ExecutorRun(queryDesc, direction, count);
portal->atEnd = false; /* OK to go forward now */
if (count <= 0 || (int) estate->es_processed < count) if (direction != NoMovementScanDirection)
portal->atStart = true; /* we retrieved 'em all */ {
if (estate->es_processed > 0)
portal->atEnd = false; /* OK to go forward now */
if (count <= 0 || (long) estate->es_processed < count)
portal->atStart = true; /* we retrieved 'em all */
}
} }
/* Return command status if wanted */ /* Return command status if wanted */

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.390 2003/01/06 00:31:44 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.391 2003/01/08 00:22:27 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -2594,7 +2594,7 @@ FetchStmt: FETCH direction fetch_how_many from_in name
if ($3 < 0) if ($3 < 0)
{ {
$3 = -$3; $3 = -$3;
$2 = (($2 == FORWARD)? BACKWARD: FORWARD); $2 = (($2 == FORWARD) ? BACKWARD : FORWARD);
} }
n->direction = $2; n->direction = $2;
n->howMany = $3; n->howMany = $3;
@ -2652,7 +2652,7 @@ FetchStmt: FETCH direction fetch_how_many from_in name
if ($3 < 0) if ($3 < 0)
{ {
$3 = -$3; $3 = -$3;
$2 = (($2 == FORWARD) ? BACKWARD: FORWARD); $2 = (($2 == FORWARD) ? BACKWARD : FORWARD);
} }
n->direction = $2; n->direction = $2;
n->howMany = $3; n->howMany = $3;
@ -2720,8 +2720,8 @@ direction: FORWARD { $$ = FORWARD; }
fetch_how_many: fetch_how_many:
Iconst { $$ = $1; } Iconst { $$ = $1; }
| '-' Iconst { $$ = - $2; } | '-' Iconst { $$ = - $2; }
| ALL { $$ = LONG_MAX; } | ALL { $$ = INT_MAX; }
| LAST { $$ = LONG_MAX; } | LAST { $$ = INT_MAX; }
| NEXT { $$ = 1; } | NEXT { $$ = 1; }
| PRIOR { $$ = -1; } | PRIOR { $$ = -1; }
; ;
@ -7115,8 +7115,8 @@ unreserved_keyword:
| INVOKER | INVOKER
| ISOLATION | ISOLATION
| KEY | KEY
| LANGUAGE
| LANCOMPILER | LANCOMPILER
| LANGUAGE
| LAST | LAST
| LEVEL | LEVEL
| LISTEN | LISTEN