diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/commands/portalcmds.c | 298 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 38 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 9 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 205 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 4 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 13 | ||||
-rw-r--r-- | src/backend/utils/mmgr/portalmem.c | 18 | ||||
-rw-r--r-- | src/include/commands/portalcmds.h | 10 | ||||
-rw-r--r-- | src/include/executor/executor.h | 3 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 13 | ||||
-rw-r--r-- | src/include/utils/portal.h | 19 |
11 files changed, 425 insertions, 205 deletions
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index 0621cdd5903..1ba72437ad7 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -8,7 +8,7 @@ * * * 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" +static long DoRelativeFetch(Portal portal, + bool forward, + long count, + CommandDest dest); +static void DoPortalRewind(Portal portal); static Portal PreparePortal(char *portalName); @@ -102,9 +107,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest) * PerformPortalFetch * Execute SQL FETCH or MOVE command. * - * name: name of portal - * forward: forward or backward fetch? - * count: # of tuples to fetch (INT_MAX means "all"; 0 means "refetch") + * stmt: parsetree node for command * dest: where to send results * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE * 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. */ void -PerformPortalFetch(char *name, - bool forward, - long count, +PerformPortalFetch(FetchStmt *stmt, CommandDest dest, char *completionTag) { @@ -123,48 +124,150 @@ PerformPortalFetch(char *name, /* initialize completion status in case of early exit */ if (completionTag) - strcpy(completionTag, (dest == None) ? "MOVE 0" : "FETCH 0"); - - /* sanity checks */ - if (name == NULL) - { - elog(WARNING, "PerformPortalFetch: missing portal name"); - return; - } + strcpy(completionTag, stmt->ismove ? "MOVE 0" : "FETCH 0"); /* get the portal from the portal name */ - portal = GetPortalByName(name); + portal = GetPortalByName(stmt->portalname); if (!PortalIsValid(portal)) { elog(WARNING, "PerformPortalFetch: portal \"%s\" not found", - name); + stmt->portalname); return; } /* Do it */ - nprocessed = DoPortalFetch(portal, forward, count, dest); + nprocessed = DoPortalFetch(portal, + stmt->direction, + stmt->howMany, + stmt->ismove ? None : dest); /* Return command status if wanted */ if (completionTag) snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld", - (dest == None) ? "MOVE" : "FETCH", + stmt->ismove ? "MOVE" : "FETCH", nprocessed); } /* * 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 -DoPortalFetch(Portal portal, bool forward, long count, CommandDest dest) +DoPortalFetch(Portal portal, + FetchDirection fdirection, + long count, + CommandDest dest) { - QueryDesc *queryDesc; - EState *estate; - MemoryContext oldcontext; - ScanDirection direction; - bool temp_desc = false; + bool forward; + + switch (fdirection) + { + 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) @@ -174,7 +277,7 @@ DoPortalFetch(Portal portal, bool forward, long count, CommandDest dest) bool on_row; /* Are we sitting on a row? */ - on_row = (portal->atStart == false && portal->atEnd == false); + on_row = (!portal->atStart && !portal->atEnd); 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 not sitting on a row, we still have to start up and * shut down the executor so that the destination is initialized - * and shut down correctly; so keep going. Further down in the - * routine, count == 0 means we will retrieve no row. + * and shut down correctly; so keep going. To DoRelativeFetch, + * count == 0 means we will retrieve no row. */ if (on_row) { - DoPortalFetch(portal, - false /* backward */, 1L, - None /* throw away output */); + DoRelativeFetch(portal, false, 1L, None); /* Set up to fetch one row forward */ count = 1; 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); estate = queryDesc->estate; @@ -224,12 +360,9 @@ DoPortalFetch(Portal portal, bool forward, long count, CommandDest dest) if (dest != queryDesc->dest && !(queryDesc->dest == RemoteInternal && dest == Remote)) { - QueryDesc *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc)); - - memcpy(qdesc, queryDesc, sizeof(QueryDesc)); - qdesc->dest = dest; - queryDesc = qdesc; - temp_desc = true; + memcpy(&temp_queryDesc, queryDesc, sizeof(QueryDesc)); + temp_queryDesc.dest = dest; + queryDesc = &temp_queryDesc; } /* @@ -240,65 +373,101 @@ DoPortalFetch(Portal portal, bool forward, long count, CommandDest dest) * robust about being called again if they've already returned NULL * 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 - * 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. */ if (forward) { - if (portal->atEnd || count == 0) + if (portal->atEnd || count <= 0) direction = NoMovementScanDirection; else direction = ForwardScanDirection; - /* In the executor, zero count processes all portal rows */ - if (count == INT_MAX) + /* In the executor, zero count processes all rows */ + if (count == FETCH_ALL) count = 0; ExecutorRun(queryDesc, direction, count); if (direction != NoMovementScanDirection) { + long oldPos; + if (estate->es_processed > 0) - portal->atStart = false; /* OK to back up now */ - if (count <= 0 || (long) estate->es_processed < count) + portal->atStart = false; /* OK to go backward now */ + if (count == 0 || + (unsigned long) estate->es_processed < (unsigned long) count) 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 { 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"); - if (portal->atStart || count == 0) + if (portal->atStart || count <= 0) direction = NoMovementScanDirection; else direction = BackwardScanDirection; - /* In the executor, zero count processes all portal rows */ - if (count == INT_MAX) + /* In the executor, zero count processes all rows */ + if (count == FETCH_ALL) count = 0; ExecutorRun(queryDesc, direction, count); if (direction != NoMovementScanDirection) { - if (estate->es_processed > 0) + if (estate->es_processed > 0 && portal->atEnd) + { portal->atEnd = false; /* OK to go forward now */ - if (count <= 0 || (long) estate->es_processed < count) + portal->portalPos++; /* adjust for endpoint case */ + } + 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; + } } } - /* - * Clean up and switch back to old context. - */ - if (temp_desc) - pfree(queryDesc); + return estate->es_processed; +} - MemoryContextSwitchTo(oldcontext); +/* + * DoPortalRewind - rewind a Portal to starting point + */ +static void +DoPortalRewind(Portal portal) +{ + QueryDesc *queryDesc; - return estate->es_processed; + queryDesc = PortalGetQueryDesc(portal); + + ExecutorRewind(queryDesc); + + portal->atStart = true; + portal->atEnd = false; + portal->portalPos = 0; + portal->posOverflow = false; } /* @@ -311,15 +480,6 @@ PerformPortalClose(char *name) 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 */ portal = GetPortalByName(name); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index f037e72fd91..638cc61bef4 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -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 diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index e1ccdf08f97..61eed9b4004 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -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"); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 045d3cc2ca2..7b28bdc9150 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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 ; diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index 727cff3eaf4..49432cb957a 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -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}, diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 0fae711a2c3..baf74aa3cc5 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -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; /* diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index 654247dd8c5..66ee72718cf 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -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); diff --git a/src/include/commands/portalcmds.h b/src/include/commands/portalcmds.h index 3f2a4221add..74855ddf605 100644 --- a/src/include/commands/portalcmds.h +++ b/src/include/commands/portalcmds.h @@ -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); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 785d21718b2..40a696e2976 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -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, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index c84348ded9e..216ed04c762 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -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; diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h index 21469dd52df..c9ca8547ce2 100644 --- a/src/include/utils/portal.h +++ b/src/include/utils/portal.h @@ -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; /* |