diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/Makefile | 6 | ||||
-rw-r--r-- | src/backend/executor/execAmi.c | 7 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 147 | ||||
-rw-r--r-- | src/backend/executor/execProcnode.c | 18 | ||||
-rw-r--r-- | src/backend/executor/execTuples.c | 10 | ||||
-rw-r--r-- | src/backend/executor/functions.c | 7 | ||||
-rw-r--r-- | src/backend/executor/nodeLimit.c | 324 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 39 |
8 files changed, 383 insertions, 175 deletions
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile index 7c79df5904d..7d57beb59f2 100644 --- a/src/backend/executor/Makefile +++ b/src/backend/executor/Makefile @@ -4,7 +4,7 @@ # Makefile for executor # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.15 2000/10/05 19:11:26 tgl Exp $ +# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.16 2000/10/26 21:35:15 tgl Exp $ # #------------------------------------------------------------------------- @@ -17,8 +17,8 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \ execUtils.o functions.o nodeAppend.o nodeAgg.o nodeHash.o \ nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \ nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSetOp.o nodeSort.o \ - nodeUnique.o nodeGroup.o spi.o nodeSubplan.o \ - nodeSubqueryscan.o nodeTidscan.o + nodeUnique.o nodeLimit.o nodeGroup.o nodeSubplan.o \ + nodeSubqueryscan.o nodeTidscan.o spi.o all: SUBSYS.o diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index 9d008494b30..cb47eda5c66 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: execAmi.c,v 1.53 2000/10/05 19:11:26 tgl Exp $ + * $Id: execAmi.c,v 1.54 2000/10/26 21:35:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,6 +37,7 @@ #include "executor/nodeHashjoin.h" #include "executor/nodeIndexscan.h" #include "executor/nodeTidscan.h" +#include "executor/nodeLimit.h" #include "executor/nodeMaterial.h" #include "executor/nodeMergejoin.h" #include "executor/nodeNestloop.h" @@ -350,6 +351,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent) ExecReScanSetOp((SetOp *) node, exprCtxt, parent); break; + case T_Limit: + ExecReScanLimit((Limit *) node, exprCtxt, parent); + break; + case T_Sort: ExecReScanSort((Sort *) node, exprCtxt, parent); break; diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 5523256bbe8..a26acc9a763 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -27,7 +27,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.130 2000/10/16 17:08:06 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.131 2000/10/26 21:35:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -52,11 +52,10 @@ static TupleDesc InitPlan(CmdType operation, EState *estate); static void EndPlan(Plan *plan, EState *estate); static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan, - CmdType operation, - int offsetTuples, - int numberTuples, - ScanDirection direction, - DestReceiver *destfunc); + CmdType operation, + long numberTuples, + ScanDirection direction, + DestReceiver *destfunc); static void ExecRetrieve(TupleTableSlot *slot, DestReceiver *destfunc, EState *estate); @@ -153,19 +152,18 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate) * EXEC_RETONE: return one tuple but don't 'retrieve' it * used in postquel function processing * + * Note: count = 0 is interpreted as "no limit". + * * ---------------------------------------------------------------- */ TupleTableSlot * -ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, - Node *limoffset, Node *limcount) +ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count) { CmdType operation; Plan *plan; TupleTableSlot *result; CommandDest dest; DestReceiver *destfunc; - int offset = 0; - int count = 0; /* * sanity checks @@ -191,111 +189,21 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, */ (*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) { - case EXEC_RUN: result = ExecutePlan(estate, plan, operation, - offset, count, ForwardScanDirection, destfunc); break; + case EXEC_FOR: result = ExecutePlan(estate, plan, operation, - offset, count, ForwardScanDirection, destfunc); @@ -308,7 +216,6 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, result = ExecutePlan(estate, plan, operation, - offset, count, BackwardScanDirection, destfunc); @@ -322,14 +229,14 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, result = ExecutePlan(estate, plan, operation, - 0, ONE_TUPLE, ForwardScanDirection, destfunc); break; + default: - result = NULL; elog(DEBUG, "ExecutorRun: Unknown feature %d", feature); + result = NULL; break; } @@ -917,25 +824,22 @@ EndPlan(Plan *plan, EState *estate) /* ---------------------------------------------------------------- * ExecutePlan * - * processes the query plan to retrieve 'tupleCount' tuples in the + * processes the query plan to retrieve 'numberTuples' tuples in the * direction specified. * Retrieves all tuples if tupleCount is 0 * - * result is either a slot containing a tuple in the case + * result is either a slot containing the last tuple in the case * of a RETRIEVE or NULL otherwise. * + * Note: the ctid attribute is a 'junk' attribute that is removed before the + * user can see it * ---------------------------------------------------------------- */ - -/* the ctid attribute is a 'junk' attribute that is removed before the - user can see it*/ - static TupleTableSlot * ExecutePlan(EState *estate, Plan *plan, CmdType operation, - int offsetTuples, - int numberTuples, + long numberTuples, ScanDirection direction, DestReceiver *destfunc) { @@ -943,7 +847,7 @@ ExecutePlan(EState *estate, TupleTableSlot *slot; ItemPointer tupleid = NULL; ItemPointerData tuple_ctid; - int current_tuple_count; + long current_tuple_count; TupleTableSlot *result; /* @@ -991,17 +895,6 @@ 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. * @@ -1152,10 +1045,10 @@ lnext: ; } /* - * check our tuple count.. if we've returned the proper number - * then return, else loop again and process more tuples.. + * check our tuple count.. if we've processed the proper number + * then quit, else loop again and process more tuples.. */ - current_tuple_count += 1; + current_tuple_count++; if (numberTuples == current_tuple_count) break; } diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 6269a7caa10..d7db099653d 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -12,7 +12,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.21 2000/10/05 19:11:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.22 2000/10/26 21:35:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -83,6 +83,7 @@ #include "executor/nodeHashjoin.h" #include "executor/nodeIndexscan.h" #include "executor/nodeTidscan.h" +#include "executor/nodeLimit.h" #include "executor/nodeMaterial.h" #include "executor/nodeMergejoin.h" #include "executor/nodeNestloop.h" @@ -204,6 +205,10 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent) result = ExecInitSetOp((SetOp *) node, estate, parent); break; + case T_Limit: + result = ExecInitLimit((Limit *) node, estate, parent); + break; + case T_Group: result = ExecInitGroup((Group *) node, estate, parent); break; @@ -331,6 +336,10 @@ ExecProcNode(Plan *node, Plan *parent) result = ExecSetOp((SetOp *) node); break; + case T_Limit: + result = ExecLimit((Limit *) node); + break; + case T_Group: result = ExecGroup((Group *) node); break; @@ -413,6 +422,9 @@ ExecCountSlotsNode(Plan *node) case T_SetOp: return ExecCountSlotsSetOp((SetOp *) node); + case T_Limit: + return ExecCountSlotsLimit((Limit *) node); + case T_Group: return ExecCountSlotsGroup((Group *) node); @@ -535,6 +547,10 @@ ExecEndNode(Plan *node, Plan *parent) ExecEndSetOp((SetOp *) node); break; + case T_Limit: + ExecEndLimit((Limit *) node); + break; + case T_Group: ExecEndGroup((Group *) node); break; diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index d1cdfabab3b..408716abf83 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.41 2000/10/05 19:11:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.42 2000/10/26 21:35:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -770,6 +770,14 @@ NodeGetResultTupleSlot(Plan *node) } break; + case T_Limit: + { + LimitState *limitstate = ((Limit *) node)->limitstate; + + slot = limitstate->cstate.cs_ResultTupleSlot; + } + break; + case T_MergeJoin: { MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate; diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 58fb68a6113..e5a5e55ef8d 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.38 2000/08/24 03:29:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.39 2000/10/26 21:35:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -135,9 +135,6 @@ init_execution_state(char *src, Oid *argOidVect, int nargs) 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; @@ -328,7 +325,7 @@ postquel_getnext(execution_state *es) feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN; - return ExecutorRun(es->qd, es->estate, feature, (Node *) NULL, (Node *) NULL); + return ExecutorRun(es->qd, es->estate, feature, 0L); } static void diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c new file mode 100644 index 00000000000..c7bc666c2f9 --- /dev/null +++ b/src/backend/executor/nodeLimit.c @@ -0,0 +1,324 @@ +/*------------------------------------------------------------------------- + * + * nodeLimit.c + * Routines to handle limiting of query results where appropriate + * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.1 2000/10/26 21:35:15 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +/* + * INTERFACE ROUTINES + * ExecLimit - extract a limited range of tuples + * ExecInitLimit - initialize node and subnodes.. + * ExecEndLimit - shutdown node and subnodes + */ + +#include "postgres.h" + +#include "executor/executor.h" +#include "executor/nodeLimit.h" + +static void recompute_limits(Limit *node); + + +/* ---------------------------------------------------------------- + * ExecLimit + * + * This is a very simple node which just performs LIMIT/OFFSET + * filtering on the stream of tuples returned by a subplan. + * ---------------------------------------------------------------- + */ +TupleTableSlot * /* return: a tuple or NULL */ +ExecLimit(Limit *node) +{ + LimitState *limitstate; + ScanDirection direction; + TupleTableSlot *resultTupleSlot; + TupleTableSlot *slot; + Plan *outerPlan; + long netlimit; + + /* ---------------- + * get information from the node + * ---------------- + */ + limitstate = node->limitstate; + direction = node->plan.state->es_direction; + outerPlan = outerPlan((Plan *) node); + resultTupleSlot = limitstate->cstate.cs_ResultTupleSlot; + + /* ---------------- + * If first call for this scan, compute limit/offset. + * (We can't do this any earlier, because parameters from upper nodes + * may not be set until now.) + * ---------------- + */ + if (! limitstate->parmsSet) + recompute_limits(node); + netlimit = limitstate->offset + limitstate->count; + + /* ---------------- + * now loop, returning only desired tuples. + * ---------------- + */ + for (;;) + { + /*---------------- + * If we have reached the subplan EOF or the limit, just quit. + * + * NOTE: when scanning forwards, we must fetch one tuple beyond the + * COUNT limit before we can return NULL, else the subplan won't be + * properly positioned to start going backwards. Hence test here + * is for position > netlimit not position >= netlimit. + * + * Similarly, when scanning backwards, we must re-fetch the last + * tuple in the offset region before we can return NULL. Otherwise + * we won't be correctly aligned to start going forward again. So, + * although you might think we can quit when position = offset + 1, + * we have to fetch a subplan tuple first, and then exit when + * position = offset. + *---------------- + */ + if (ScanDirectionIsForward(direction)) + { + if (limitstate->atEnd) + return NULL; + if (! limitstate->noCount && limitstate->position > netlimit) + return NULL; + } + else + { + if (limitstate->position <= limitstate->offset) + return NULL; + } + /* ---------------- + * fetch a tuple from the outer subplan + * ---------------- + */ + slot = ExecProcNode(outerPlan, (Plan *) node); + if (TupIsNull(slot)) + { + /* + * We are at start or end of the subplan. Update local state + * appropriately, but always return NULL. + */ + if (ScanDirectionIsForward(direction)) + { + Assert(! limitstate->atEnd); + /* must bump position to stay in sync for backwards fetch */ + limitstate->position++; + limitstate->atEnd = true; + } + else + { + limitstate->position = 0; + limitstate->atEnd = false; + } + return NULL; + } + /* + * We got the next subplan tuple successfully, so adjust state. + */ + if (ScanDirectionIsForward(direction)) + limitstate->position++; + else + { + limitstate->position--; + Assert(limitstate->position > 0); + } + limitstate->atEnd = false; + + /* ---------------- + * Now, is this a tuple we want? If not, loop around to fetch + * another tuple from the subplan. + * ---------------- + */ + if (limitstate->position > limitstate->offset && + (limitstate->noCount || limitstate->position <= netlimit)) + break; + } + + ExecStoreTuple(slot->val, + resultTupleSlot, + InvalidBuffer, + false); /* tuple does not belong to slot */ + + return resultTupleSlot; +} + +/* + * Evaluate the limit/offset expressions --- done at start of each scan. + * + * This is also a handy place to reset the current-position state info. + */ +static void +recompute_limits(Limit *node) +{ + LimitState *limitstate = node->limitstate; + ExprContext *econtext = limitstate->cstate.cs_ExprContext; + bool isNull; + + if (node->limitOffset) + { + limitstate->offset = DatumGetInt32(ExecEvalExpr(node->limitOffset, + econtext, + &isNull, + NULL)); + /* Interpret NULL offset as no offset */ + if (isNull) + limitstate->offset = 0; + else if (limitstate->offset < 0) + limitstate->offset = 0; + } + else + { + /* No OFFSET supplied */ + limitstate->offset = 0; + } + + if (node->limitCount) + { + limitstate->count = DatumGetInt32(ExecEvalExpr(node->limitCount, + econtext, + &isNull, + NULL)); + /* Interpret NULL count as no count */ + if (isNull) + limitstate->noCount = true; + else + { + /* Currently, LIMIT 0 is specified as meaning no limit. + * I think this is pretty bogus, but ... + */ + if (limitstate->count <= 0) + limitstate->noCount = true; + } + } + else + { + /* No COUNT supplied */ + limitstate->count = 0; + limitstate->noCount = true; + } + + /* Reset position data to start-of-scan */ + limitstate->position = 0; + limitstate->atEnd = false; + + /* Set flag that params are computed */ + limitstate->parmsSet = true; +} + +/* ---------------------------------------------------------------- + * ExecInitLimit + * + * This initializes the limit node state structures and + * the node's subplan. + * ---------------------------------------------------------------- + */ +bool /* return: initialization status */ +ExecInitLimit(Limit *node, EState *estate, Plan *parent) +{ + LimitState *limitstate; + Plan *outerPlan; + + /* ---------------- + * assign execution state to node + * ---------------- + */ + node->plan.state = estate; + + /* ---------------- + * create new LimitState for node + * ---------------- + */ + limitstate = makeNode(LimitState); + node->limitstate = limitstate; + limitstate->parmsSet = false; + + /* ---------------- + * Miscellaneous initialization + * + * Limit nodes never call ExecQual or ExecProject, but they need + * an exprcontext anyway to evaluate the limit/offset parameters in. + * ---------------- + */ + ExecAssignExprContext(estate, &limitstate->cstate); + +#define LIMIT_NSLOTS 1 + /* ------------ + * Tuple table initialization + * ------------ + */ + ExecInitResultTupleSlot(estate, &limitstate->cstate); + + /* ---------------- + * then initialize outer plan + * ---------------- + */ + outerPlan = outerPlan((Plan *) node); + ExecInitNode(outerPlan, estate, (Plan *) node); + + /* ---------------- + * limit nodes do no projections, so initialize + * projection info for this node appropriately + * ---------------- + */ + ExecAssignResultTypeFromOuterPlan((Plan *) node, &limitstate->cstate); + limitstate->cstate.cs_ProjInfo = NULL; + + return TRUE; +} + +int +ExecCountSlotsLimit(Limit *node) +{ + return ExecCountSlotsNode(outerPlan(node)) + + ExecCountSlotsNode(innerPlan(node)) + + LIMIT_NSLOTS; +} + +/* ---------------------------------------------------------------- + * ExecEndLimit + * + * This shuts down the subplan and frees resources allocated + * to this node. + * ---------------------------------------------------------------- + */ +void +ExecEndLimit(Limit *node) +{ + LimitState *limitstate = node->limitstate; + + ExecFreeExprContext(&limitstate->cstate); + + ExecEndNode(outerPlan((Plan *) node), (Plan *) node); + + /* clean up tuple table */ + ExecClearTuple(limitstate->cstate.cs_ResultTupleSlot); +} + + +void +ExecReScanLimit(Limit *node, ExprContext *exprCtxt, Plan *parent) +{ + LimitState *limitstate = node->limitstate; + + ExecClearTuple(limitstate->cstate.cs_ResultTupleSlot); + + /* force recalculation of limit expressions on first call */ + limitstate->parmsSet = false; + + /* + * if chgParam of subnode is not null then plan will be re-scanned by + * first ExecProcNode. + */ + if (((Plan *) node)->lefttree->chgParam == NULL) + ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node); +} diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 1ab6ae67d50..07a05561a64 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.47 2000/06/28 03:31:34 tgl Exp $ + * $Id: spi.c,v 1.48 2000/10/26 21:35:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -762,8 +762,6 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) bool isRetrieveIntoRelation = false; char *intoName = NULL; int res; - Const tcount_const; - Node *count = NULL; switch (operation) { @@ -798,39 +796,6 @@ _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 @@ -848,7 +813,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) elog(FATAL, "SPI_select: retrieve into portal not implemented"); } - ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count); + ExecutorRun(queryDesc, state, EXEC_FOR, (long) tcount); _SPI_current->processed = state->es_processed; if (operation == CMD_SELECT && queryDesc->dest == SPI) |