diff options
author | Jan Wieck <JanWieck@Yahoo.com> | 1999-02-08 14:14:32 +0000 |
---|---|---|
committer | Jan Wieck <JanWieck@Yahoo.com> | 1999-02-08 14:14:32 +0000 |
commit | be948af2e81d44290a15a0b8614fdd209924f698 (patch) | |
tree | 7ea39a552a8cb96e2740a814de3bab7e2b0e04ee /src/backend | |
parent | 54e5d256664ece2cb180f4d5a278397906fe5988 (diff) | |
download | postgresql-be948af2e81d44290a15a0b8614fdd209924f698.tar.gz postgresql-be948af2e81d44290a15a0b8614fdd209924f698.zip |
Added LIMIT/OFFSET functionality including new regression test for it.
Removed CURRENT keyword for rule queries and changed rules regression
accordingly. CURRENT has beed announced to disappear in v6.5.
Jan
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/command.c | 22 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 144 | ||||
-rw-r--r-- | src/backend/executor/functions.c | 7 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 39 | ||||
-rw-r--r-- | src/backend/parser/analyze.c | 6 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 95 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 7 | ||||
-rw-r--r-- | src/backend/rewrite/rewriteDefine.c | 8 | ||||
-rw-r--r-- | src/backend/tcop/pquery.c | 12 |
9 files changed, 305 insertions, 35 deletions
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 1a65f4d4d0d..310325d2f81 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.36 1999/02/03 21:16:02 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.37 1999/02/08 14:14:08 wieck Exp $ * * NOTES * The PortalExecutorHeapMemory crap needs to be eliminated @@ -40,6 +40,7 @@ #include "utils/portal.h" #include "utils/syscache.h" #include "miscadmin.h" +#include "string.h" /* ---------------- * PortalExecutorHeapMemory stuff @@ -102,6 +103,7 @@ PerformPortalFetch(char *name, int feature; QueryDesc *queryDesc; MemoryContext context; + Const limcount; /* ---------------- * sanity checks @@ -114,6 +116,21 @@ PerformPortalFetch(char *name, } /* ---------------- + * Create a const node from the given count value + * ---------------- + */ + memset(&limcount, 0, sizeof(limcount)); + limcount.type = T_Const; + limcount.consttype = INT4OID; + limcount.constlen = sizeof(int4); + limcount.constvalue = (Datum)count; + limcount.constisnull = FALSE; + limcount.constbyval = TRUE; + limcount.constisset = FALSE; + limcount.constiscast = FALSE; + + + /* ---------------- * get the portal from the portal name * ---------------- */ @@ -176,7 +193,8 @@ PerformPortalFetch(char *name, PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal); - ExecutorRun(queryDesc, PortalGetState(portal), feature, count); + ExecutorRun(queryDesc, PortalGetState(portal), feature, + (Node *)NULL, (Node *)&limcount); if (dest == None) /* MOVE */ pfree(queryDesc); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 5ce90902b4c..e11869ce783 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.75 1999/02/07 16:17:11 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.76 1999/02/08 14:14:09 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -60,21 +60,27 @@ void ExecCheckPerms(CmdType operation, int resultRelation, List *rangeTable, /* decls for local routines only used within this module */ -static TupleDesc InitPlan(CmdType operation, Query *parseTree, - Plan *plan, EState *estate); -static void EndPlan(Plan *plan, EState *estate); +static TupleDesc InitPlan(CmdType operation, + Query *parseTree, + Plan *plan, + EState *estate); +static void EndPlan(Plan *plan, + EState *estate); static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan, - CmdType operation, int numberTuples, ScanDirection direction, - DestReceiver *destfunc); + CmdType operation, + int offsetTuples, + int numberTuples, + ScanDirection direction, + DestReceiver *destfunc); static void ExecRetrieve(TupleTableSlot *slot, - DestReceiver *destfunc, - EState *estate); + DestReceiver *destfunc, + EState *estate); static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid, - EState *estate); + EState *estate); static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid, - EState *estate); + EState *estate); static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid, - EState *estate); + EState *estate); TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid); static TupleTableSlot *EvalPlanQualNext(EState *estate); @@ -187,13 +193,16 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate) * ---------------------------------------------------------------- */ TupleTableSlot * -ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) +ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, + Node *limoffset, Node *limcount) { CmdType operation; Plan *plan; TupleTableSlot *result; CommandDest dest; DestReceiver *destfunc; + int offset = 0; + int count = 0; /****************** * sanity checks @@ -222,6 +231,96 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) */ (*destfunc->setup) (destfunc, (TupleDesc) NULL); + /****************** + * if given get the offset of the LIMIT clause + ****************** + */ + if (limoffset != NULL) + { + Const *coffset; + Param *poffset; + ParamListInfo paramLI; + int i; + + switch (nodeTag(limoffset)) + { + case T_Const: + coffset = (Const *)limoffset; + offset = (int)(coffset->constvalue); + break; + + case T_Param: + poffset = (Param *)limoffset; + paramLI = estate->es_param_list_info; + + if (paramLI == NULL) + elog(ERROR, "parameter for limit offset not in executor state"); + for (i = 0; paramLI[i].kind != PARAM_INVALID; i++) + { + if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == poffset->paramid) + break; + } + if (paramLI[i].kind == PARAM_INVALID) + elog(ERROR, "parameter for limit offset not in executor state"); + if (paramLI[i].isnull) + elog(ERROR, "limit offset cannot be NULL value"); + offset = (int)(paramLI[i].value); + + break; + + default: + elog(ERROR, "unexpected node type %d as limit offset", nodeTag(limoffset)); + } + + if (offset < 0) + elog(ERROR, "limit offset cannot be negative"); + } + + /****************** + * if given get the count of the LIMIT clause + ****************** + */ + if (limcount != NULL) + { + Const *ccount; + Param *pcount; + ParamListInfo paramLI; + int i; + + switch (nodeTag(limcount)) + { + case T_Const: + ccount = (Const *)limcount; + count = (int)(ccount->constvalue); + break; + + case T_Param: + pcount = (Param *)limcount; + paramLI = estate->es_param_list_info; + + if (paramLI == NULL) + elog(ERROR, "parameter for limit count not in executor state"); + for (i = 0; paramLI[i].kind != PARAM_INVALID; i++) + { + if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == pcount->paramid) + break; + } + if (paramLI[i].kind == PARAM_INVALID) + elog(ERROR, "parameter for limit count not in executor state"); + if (paramLI[i].isnull) + elog(ERROR, "limit count cannot be NULL value"); + count = (int)(paramLI[i].value); + + break; + + default: + elog(ERROR, "unexpected node type %d as limit count", nodeTag(limcount)); + } + + if (count < 0) + elog(ERROR, "limit count cannot be negative"); + } + switch (feature) { @@ -229,7 +328,8 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) result = ExecutePlan(estate, plan, operation, - ALL_TUPLES, + offset, + count, ForwardScanDirection, destfunc); break; @@ -237,6 +337,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) result = ExecutePlan(estate, plan, operation, + offset, count, ForwardScanDirection, destfunc); @@ -250,6 +351,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) result = ExecutePlan(estate, plan, operation, + offset, count, BackwardScanDirection, destfunc); @@ -264,6 +366,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count) result = ExecutePlan(estate, plan, operation, + 0, ONE_TUPLE, ForwardScanDirection, destfunc); @@ -784,6 +887,7 @@ static TupleTableSlot * ExecutePlan(EState *estate, Plan *plan, CmdType operation, + int offsetTuples, int numberTuples, ScanDirection direction, DestReceiver* destfunc) @@ -846,6 +950,20 @@ lnext:; } /****************** + * For now we completely execute the plan and skip + * result tuples if requested by LIMIT offset. + * Finally we should try to do it in deeper levels + * if possible (during index scan) + * - Jan + ****************** + */ + if (offsetTuples > 0) + { + --offsetTuples; + continue; + } + + /****************** * if we have a junk filter, then project a new * tuple with the junk removed. * diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 51ea6655e9d..7108a1cab52 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.22 1999/02/03 21:16:12 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.23 1999/02/08 14:14:09 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -130,6 +130,9 @@ init_execution_state(FunctionCachePtr fcache, None); estate = CreateExecutorState(); + if (queryTree->limitOffset != NULL || queryTree->limitCount != NULL) + elog(ERROR, "LIMIT clause from SQL functions not yet implemented"); + if (nargs > 0) { int i; @@ -199,7 +202,7 @@ postquel_getnext(execution_state *es) feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN; - return ExecutorRun(es->qd, es->estate, feature, 0); + return ExecutorRun(es->qd, es->estate, feature, (Node *)NULL, (Node *)NULL); } static void diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 7ca2a6c21e5..397f68a4055 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -3,7 +3,7 @@ * spi.c-- * Server Programming Interface * - * $Id: spi.c,v 1.32 1999/01/27 16:15:20 wieck Exp $ + * $Id: spi.c,v 1.33 1999/02/08 14:14:10 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -779,6 +779,8 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) bool isRetrieveIntoRelation = false; char *intoName = NULL; int res; + Const tcount_const; + Node *count = NULL; switch (operation) { @@ -813,6 +815,39 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) return SPI_ERROR_OPUNKNOWN; } + /* ---------------- + * Get the query LIMIT tuple count + * ---------------- + */ + if (parseTree->limitCount != NULL) + { + /* ---------------- + * A limit clause in the parsetree overrides the + * tcount parameter + * ---------------- + */ + count = parseTree->limitCount; + } + else + { + /* ---------------- + * No LIMIT clause in parsetree. Use a local Const node + * to put tcount into it + * ---------------- + */ + memset(&tcount_const, 0, sizeof(tcount_const)); + tcount_const.type = T_Const; + tcount_const.consttype = INT4OID; + tcount_const.constlen = sizeof(int4); + tcount_const.constvalue = (Datum)tcount; + tcount_const.constisnull = FALSE; + tcount_const.constbyval = TRUE; + tcount_const.constisset = FALSE; + tcount_const.constiscast = FALSE; + + count = (Node *)&tcount_const; + } + if (state == NULL) /* plan preparation */ return res; #ifdef SPI_EXECUTOR_STATS @@ -833,7 +868,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) return SPI_OK_CURSOR; } - ExecutorRun(queryDesc, state, EXEC_FOR, tcount); + ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count); _SPI_current->processed = state->es_processed; if (operation == CMD_SELECT && queryDesc->dest == SPI) diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 6232a2d067d..ada18bb71d3 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -5,7 +5,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: analyze.c,v 1.97 1999/02/02 03:44:32 momjian Exp $ + * $Id: analyze.c,v 1.98 1999/02/08 14:14:11 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -205,7 +205,11 @@ transformStmt(ParseState *pstate, Node *parseTree) case T_SelectStmt: if (!((SelectStmt *) parseTree)->portalname) + { result = transformSelectStmt(pstate, (SelectStmt *) parseTree); + result->limitOffset = ((SelectStmt *)parseTree)->limitOffset; + result->limitCount = ((SelectStmt *)parseTree)->limitCount; + } else result = transformCursorStmt(pstate, (SelectStmt *) parseTree); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e88b9073084..b649ceba36c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.53 1999/02/07 19:02:19 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.54 1999/02/08 14:14:12 wieck Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -48,6 +48,7 @@ #include "storage/lmgr.h" #include "utils/numeric.h" #include "parser/analyze.h" +#include "catalog/pg_type.h" #ifdef MULTIBYTE #include "mb/pg_wchar.h" @@ -168,7 +169,8 @@ Oid param_type(int t); /* used in parse_expr.c */ sort_clause, sortby_list, index_params, index_list, name_list, from_clause, from_list, opt_array_bounds, nest_array_bounds, expr_list, attrs, res_target_list, res_target_list2, - def_list, opt_indirection, group_clause, TriggerFuncArgs + def_list, opt_indirection, group_clause, TriggerFuncArgs, + opt_select_limit %type <node> func_return %type <boolean> set_opt @@ -197,6 +199,8 @@ Oid param_type(int t); /* used in parse_expr.c */ %type <ival> fetch_how_many +%type <node> select_limit_value, select_offset_value + %type <list> OptSeqList %type <defelt> OptSeqElem @@ -306,9 +310,10 @@ Oid param_type(int t); /* used in parse_expr.c */ DATABASE, DELIMITERS, DO, EACH, ENCODING, EXPLAIN, EXTEND, FORWARD, FUNCTION, HANDLER, INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL, - LANCOMPILER, LISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE, + LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P, + MAXVALUE, MINVALUE, MOVE, NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL, - OIDS, OPERATOR, PASSWORD, PROCEDURAL, + OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL, RECIPE, RENAME, RESET, RETURNS, ROW, RULE, SEQUENCE, SERIAL, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED, UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION @@ -2731,7 +2736,7 @@ opt_of: OF columnList * * The rule returns a SelectStmt Node having the set operations attached to * unionClause and intersectClause (NIL if no set operations were present) */ -SelectStmt: select_w_o_sort sort_clause for_update_clause +SelectStmt: select_w_o_sort sort_clause for_update_clause opt_select_limit { /* There were no set operations, so just attach the sortClause */ if IsA($1, SelectStmt) @@ -2739,6 +2744,8 @@ SelectStmt: select_w_o_sort sort_clause for_update_clause SelectStmt *n = (SelectStmt *)$1; n->sortClause = $2; n->forUpdate = $3; + n->limitOffset = nth(0, $4); + n->limitCount = nth(1, $4); $$ = (Node *)n; } /* There were set operations: The root of the operator tree @@ -2920,6 +2927,84 @@ OptUseOp: USING Op { $$ = $2; } | /*EMPTY*/ { $$ = "<"; /*default*/ } ; + +opt_select_limit: LIMIT select_limit_value ',' select_offset_value + { $$ = lappend(lappend(NIL, $4), $2); } + | LIMIT select_limit_value OFFSET select_offset_value + { $$ = lappend(lappend(NIL, $4), $2); } + | LIMIT select_limit_value + { $$ = lappend(lappend(NIL, NULL), $2); } + | OFFSET select_offset_value LIMIT select_limit_value + { $$ = lappend(lappend(NIL, $2), $4); } + | OFFSET select_offset_value + { $$ = lappend(lappend(NIL, $2), NULL); } + | /* EMPTY */ + { $$ = lappend(lappend(NIL, NULL), NULL); } + ; + +select_limit_value: Iconst + { + Const *n = makeNode(Const); + + if ($1 < 1) + elog(ERROR, "selection limit must be ALL or a positive integer value > 0"); + + n->consttype = INT4OID; + n->constlen = sizeof(int4); + n->constvalue = (Datum)$1; + n->constisnull = FALSE; + n->constbyval = TRUE; + n->constisset = FALSE; + n->constiscast = FALSE; + $$ = (Node *)n; + } + | ALL + { + Const *n = makeNode(Const); + + n->consttype = INT4OID; + n->constlen = sizeof(int4); + n->constvalue = (Datum)0; + n->constisnull = FALSE; + n->constbyval = TRUE; + n->constisset = FALSE; + n->constiscast = FALSE; + $$ = (Node *)n; + } + | PARAM + { + Param *n = makeNode(Param); + + n->paramkind = PARAM_NUM; + n->paramid = $1; + n->paramtype = INT4OID; + $$ = (Node *)n; + } + ; + +select_offset_value: Iconst + { + Const *n = makeNode(Const); + + n->consttype = INT4OID; + n->constlen = sizeof(int4); + n->constvalue = (Datum)$1; + n->constisnull = FALSE; + n->constbyval = TRUE; + n->constisset = FALSE; + n->constiscast = FALSE; + $$ = (Node *)n; + } + | PARAM + { + Param *n = makeNode(Param); + + n->paramkind = PARAM_NUM; + n->paramid = $1; + n->paramtype = INT4OID; + $$ = (Node *)n; + } + ; /* * jimmy bell-style recursive queries aren't supported in the * current system. diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index f1e59781ff3..b9af71dc46b 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.52 1999/02/02 03:44:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.53 1999/02/08 14:14:13 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -68,9 +68,6 @@ static ScanKeyword ScanKeywords[] = { {"createdb", CREATEDB}, {"createuser", CREATEUSER}, {"cross", CROSS}, - {"current", CURRENT}, /* 6.4 to 6.5 is migration time! CURRENT - * will be removed in 6.5! Use OLD keyword - * in rules. Jan */ {"current_date", CURRENT_DATE}, {"current_time", CURRENT_TIME}, {"current_timestamp", CURRENT_TIMESTAMP}, @@ -139,6 +136,7 @@ static ScanKeyword ScanKeywords[] = { {"left", LEFT}, {"level", LEVEL}, {"like", LIKE}, + {"limit", LIMIT}, {"listen", LISTEN}, {"load", LOAD}, {"local", LOCAL}, @@ -168,6 +166,7 @@ static ScanKeyword ScanKeywords[] = { {"nullif", NULLIF}, {"numeric", NUMERIC}, {"of", OF}, + {"offset", OFFSET}, {"oids", OIDS}, {"old", CURRENT}, {"on", ON}, diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index b20b6f69d32..a1145402d86 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.23 1998/10/06 22:14:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.24 1999/02/08 14:14:13 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -312,6 +312,12 @@ DefineQueryRewrite(RuleStmt *stmt) heap_close(event_relation); /* + * LIMIT in view is not supported + */ + if (query->limitOffset != NULL || query->limitCount != NULL) + elog(ERROR, "LIMIT clause not supported in views"); + + /* * ... and finally the rule must be named _RETviewname. */ sprintf(expected_name, "_RET%s", event_obj->relname); diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 577a8590779..abe3c31a9cc 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.19 1998/09/02 23:05:34 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.20 1999/02/08 14:14:14 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -40,7 +40,8 @@ #include "commands/command.h" static char *CreateOperationTag(int operationType); -static void ProcessQueryDesc(QueryDesc *queryDesc); +static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, + Node *limcount); /* ---------------------------------------------------------------- @@ -205,7 +206,7 @@ ProcessPortal(char *portalName, * ---------------------------------------------------------------- */ static void -ProcessQueryDesc(QueryDesc *queryDesc) +ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount) { Query *parseTree; Plan *plan; @@ -330,7 +331,7 @@ ProcessQueryDesc(QueryDesc *queryDesc) * actually run the plan.. * ---------------- */ - ExecutorRun(queryDesc, state, EXEC_RUN, 0); + ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount); /* save infos for EndCommand */ UpdateCommandInfo(operation, state->es_lastoid, state->es_processed); @@ -373,5 +374,6 @@ ProcessQuery(Query *parsetree, print_plan(plan, parsetree); } else - ProcessQueryDesc(queryDesc); + ProcessQueryDesc(queryDesc, parsetree->limitOffset, + parsetree->limitCount); } |