Commit 6261c750 authored by Tom Lane's avatar Tom Lane

Implement SQL92-compatible FIRST, LAST, ABSOLUTE n, RELATIVE n options

for FETCH and MOVE.
parent e4704001
This diff is collapsed.
<!--
$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
-->
......@@ -21,7 +21,7 @@ PostgreSQL documentation
<date>1999-07-20</date>
</refsynopsisdivinfo>
<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>
</refsynopsisdiv>
......@@ -33,9 +33,7 @@ MOVE [ <replaceable class="PARAMETER">direction</replaceable> ] [ <replaceable c
Description
</title>
<para>
<command>MOVE</command> allows the user to move the cursor position a
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> repositions a cursor without retrieving any data.
<command>MOVE</command> works exactly like the <command>FETCH</command>
command, except it only repositions the cursor and does not return rows.
</para>
......@@ -54,8 +52,9 @@ MOVE [ <replaceable class="PARAMETER">direction</replaceable> ] [ <replaceable c
</title>
<para>
<command>MOVE</command> is a <productname>PostgreSQL</productname>
language extension.
The count returned in <command>MOVE</command>'s status string is the
count of the number of rows that would have been returned by the
equivalent <command>FETCH</command> command.
</para>
<para>
......@@ -119,9 +118,6 @@ COMMIT WORK;
</title>
<para>
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>
</refsect2>
</refsect1>
......
This diff is collapsed.
......@@ -26,7 +26,7 @@
*
*
* 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;
}
/* ----------------------------------------------------------------
* 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
......
......@@ -8,7 +8,7 @@
*
*
* 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,8 +1349,11 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
_SPI_current->tuptable = NULL;
/* Run the cursor */
_SPI_current->processed = DoPortalFetch(portal, forward, (long) count,
dest);
_SPI_current->processed =
DoPortalFetch(portal,
forward ? FETCH_FORWARD : FETCH_BACKWARD,
(long) count,
dest);
if (dest == SPI && _SPI_checktuples())
elog(FATAL, "SPI_fetch: # of processed tuples check failed");
......
......@@ -11,7 +11,7 @@
*
*
* 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
* AUTHOR DATE MAJOR EVENT
......@@ -191,7 +191,7 @@ static void doNegateFloat(Value *v);
%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 <node> grantee
......@@ -248,12 +248,10 @@ static void doNegateFloat(Value *v);
%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
%type <ival> fetch_how_many
%type <node> select_limit_value select_offset_value
%type <node> fetch_direction select_limit_value select_offset_value
%type <list> OptSeqList
%type <defelt> OptSeqElem
......@@ -345,7 +343,7 @@ static void doNegateFloat(Value *v);
EACH ELSE ENCODING ENCRYPTED END_P ESCAPE EXCEPT
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
GLOBAL GRANT GROUP_P
......@@ -361,7 +359,7 @@ static void doNegateFloat(Value *v);
KEY
LANCOMPILER LANGUAGE LEADING LEFT LEVEL LIKE LIMIT
LANCOMPILER LANGUAGE LAST_P LEADING LEFT LEVEL LIKE LIMIT
LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
LOCK_P
......@@ -1239,16 +1237,15 @@ opt_drop_behavior:
;
/*****************************************************************************
*
* QUERY :
* close <optname>
* close <portalname>
*
*****************************************************************************/
ClosePortalStmt:
CLOSE opt_id
CLOSE name
{
ClosePortalStmt *n = makeNode(ClosePortalStmt);
n->portalname = $2;
......@@ -1256,10 +1253,6 @@ ClosePortalStmt:
}
;
opt_id: ColId { $$ = $1; }
| /*EMPTY*/ { $$ = NULL; }
;
/*****************************************************************************
*
......@@ -2583,151 +2576,159 @@ comment_text:
/*****************************************************************************
*
* QUERY:
* fetch/move [forward | backward] [ # | all ] [ in <portalname> ]
* fetch [ forward | backward | absolute | relative ]
* [ # | all | next | prior ] [ [ in | from ] <portalname> ]
* fetch/move
*
*****************************************************************************/
FetchStmt: FETCH direction fetch_how_many from_in name
FetchStmt: FETCH fetch_direction from_in name
{
FetchStmt *n = makeNode(FetchStmt);
if ($3 < 0)
{
$3 = -$3;
$2 = (($2 == FETCH_FORWARD) ? FETCH_BACKWARD : FETCH_FORWARD);
}
n->direction = $2;
n->howMany = $3;
n->portalname = $5;
FetchStmt *n = (FetchStmt *) $2;
n->portalname = $4;
n->ismove = FALSE;
$$ = (Node *)n;
}
| FETCH fetch_how_many from_in name
| FETCH 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->direction = FETCH_FORWARD;
n->howMany = 1;
n->portalname = $2;
n->ismove = FALSE;
$$ = (Node *)n;
}
| FETCH direction from_in name
| MOVE fetch_direction from_in name
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = $2;
n->howMany = 1;
FetchStmt *n = (FetchStmt *) $2;
n->portalname = $4;
n->ismove = FALSE;
n->ismove = TRUE;
$$ = (Node *)n;
}
| FETCH from_in name
| MOVE name
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_FORWARD;
n->howMany = 1;
n->portalname = $3;
n->ismove = FALSE;
n->portalname = $2;
n->ismove = TRUE;
$$ = (Node *)n;
}
| FETCH name
;
fetch_direction:
/*EMPTY*/
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_FORWARD;
n->howMany = 1;
n->portalname = $2;
n->ismove = FALSE;
$$ = (Node *)n;
}
| MOVE direction fetch_how_many from_in name
| NEXT
{
FetchStmt *n = makeNode(FetchStmt);
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;
n->direction = FETCH_FORWARD;
n->howMany = 1;
$$ = (Node *)n;
}
| MOVE fetch_how_many from_in name
| PRIOR
{
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->ismove = TRUE;
n->direction = FETCH_BACKWARD;
n->howMany = 1;
$$ = (Node *)n;
}
| MOVE direction from_in name
| FIRST_P
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = $2;
n->direction = FETCH_ABSOLUTE;
n->howMany = 1;
n->portalname = $4;
n->ismove = TRUE;
$$ = (Node *)n;
}
| MOVE from_in name
| 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;
n->portalname = $3;
n->ismove = TRUE;
$$ = (Node *)n;
}
| MOVE name
| 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;
n->portalname = $2;
n->ismove = TRUE;
$$ = (Node *)n;
}
;
direction: FORWARD { $$ = FETCH_FORWARD; }
| BACKWARD { $$ = FETCH_BACKWARD; }
| RELATIVE { $$ = FETCH_FORWARD; }
| ABSOLUTE
| BACKWARD fetch_count
{
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_BACKWARD;
n->howMany = $2;
$$ = (Node *)n;
}
| BACKWARD ALL
{
elog(NOTICE,
"FETCH / ABSOLUTE not supported, using RELATIVE");
$$ = FETCH_FORWARD;
FetchStmt *n = makeNode(FetchStmt);
n->direction = FETCH_BACKWARD;
n->howMany = FETCH_ALL;
$$ = (Node *)n;
}
;
fetch_how_many:
fetch_count:
Iconst { $$ = $1; }
| '-' Iconst { $$ = - $2; }
| ALL { $$ = INT_MAX; }
| NEXT { $$ = 1; }
| PRIOR { $$ = -1; }
;
from_in: IN_P {}
| FROM {}
from_in: FROM {}
| IN_P {}
;
......@@ -7093,6 +7094,7 @@ unreserved_keyword:
| EXPLAIN
| EXTERNAL
| FETCH
| FIRST_P
| FORCE
| FORWARD
| FUNCTION
......@@ -7115,6 +7117,7 @@ unreserved_keyword:
| KEY
| LANCOMPILER
| LANGUAGE
| LAST_P
| LEVEL
| LISTEN
| LOAD
......@@ -7170,9 +7173,9 @@ unreserved_keyword:
| SCROLL
| SECOND_P
| SECURITY
| SESSION
| SEQUENCE
| SERIALIZABLE
| SESSION
| SET
| SHARE
| SHOW
......@@ -7211,8 +7214,8 @@ unreserved_keyword:
| VOLATILE
| WITH
| WITHOUT
| WRITE
| WORK
| WRITE
| YEAR_P
| ZONE
;
......
......@@ -8,7 +8,7 @@
*
*
* 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},
{"false", FALSE_P},
{"fetch", FETCH},
{"first", FIRST_P},
{"float", FLOAT_P},
{"for", FOR},
{"force", FORCE},
......@@ -171,6 +172,7 @@ static const ScanKeyword ScanKeywords[] = {
{"key", KEY},
{"lancompiler", LANCOMPILER},
{"language", LANGUAGE},
{"last", LAST_P},
{"leading", LEADING},
{"left", LEFT},
{"level", LEVEL},
......
......@@ -10,7 +10,7 @@
*
*
* 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;
case T_FetchStmt:
{
FetchStmt *stmt = (FetchStmt *) parsetree;
PerformPortalFetch(stmt->portalname,
stmt->direction == FETCH_FORWARD,
stmt->howMany,
(stmt->ismove) ? None : dest,
completionTag);
}
PerformPortalFetch((FetchStmt *) parsetree, dest,
completionTag);
break;
/*
......
......@@ -8,7 +8,7 @@
*
*
* 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));
portal->queryDesc = queryDesc;
portal->backwardOK = ExecSupportsBackwardScan(queryDesc->plantree);
portal->atStart = true; /* Allow fetch forward only, to start */
portal->atEnd = false;
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 */
portal->queryDesc = NULL;
portal->backwardOK = false;
portal->atStart = true; /* disallow fetches until query is set */
portal->atEnd = true;
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 */
PortalHashTableInsert(portal);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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 PerformPortalFetch(char *name, bool forward, long count,
CommandDest dest, char *completionTag);
extern void PerformPortalFetch(FetchStmt *stmt, CommandDest dest,
char *completionTag);
extern long DoPortalFetch(Portal portal, bool forward, long count,
extern long DoPortalFetch(Portal portal,
FetchDirection fdirection,
long count,
CommandDest dest);
extern void PerformPortalClose(char *name);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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,
ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc);
extern void ExecutorRewind(QueryDesc *queryDesc);
extern void ExecCheckRTPerms(List *rangeTable, CmdType operation);
extern void ExecEndPlan(PlanState *planstate, EState *estate);
extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo,
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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
{
/* for these, howMany is how many rows to fetch; FETCH_ALL means ALL */
FETCH_FORWARD,
FETCH_BACKWARD
/* ABSOLUTE someday? */
FETCH_BACKWARD,
/* for these, howMany indicates a position; only one row is fetched */
FETCH_ABSOLUTE,
FETCH_RELATIVE
} FetchDirection;
#define FETCH_ALL LONG_MAX
typedef struct FetchStmt
{
NodeTag type;
FetchDirection direction; /* see above */
long howMany; /* number of rows */
long howMany; /* number of rows, or position argument */
char *portalname; /* name of portal (cursor) */
bool ismove; /* TRUE if MOVE */
} FetchStmt;
......
......@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* 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 */
MemoryContext heap; /* subsidiary memory */
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) */
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;
/*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment