#include "nodes/execnodes.h"

Go to the source code of this file.
Functions | |
| LimitState * | ExecInitLimit (Limit *node, EState *estate, int eflags) |
| TupleTableSlot * | ExecLimit (LimitState *node) |
| void | ExecEndLimit (LimitState *node) |
| void | ExecReScanLimit (LimitState *node) |
| void ExecEndLimit | ( | LimitState * | node | ) |
Definition at line 435 of file nodeLimit.c.
References ExecEndNode(), ExecFreeExprContext(), outerPlanState, and LimitState::ps.
Referenced by ExecEndNode().
{
ExecFreeExprContext(&node->ps);
ExecEndNode(outerPlanState(node));
}
| LimitState* ExecInitLimit | ( | Limit * | node, | |
| EState * | estate, | |||
| int | eflags | |||
| ) |
Definition at line 373 of file nodeLimit.c.
References Assert, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignResultTypeFromTL(), ExecInitExpr(), ExecInitNode(), ExecInitResultTupleSlot(), Limit::limitCount, Limit::limitOffset, LimitState::limitOffset, LimitState::lstate, makeNode, outerPlan, outerPlanState, PlanState::plan, LimitState::ps, PlanState::ps_ProjInfo, and PlanState::state.
Referenced by ExecInitNode().
{
LimitState *limitstate;
Plan *outerPlan;
/* check for unsupported flags */
Assert(!(eflags & EXEC_FLAG_MARK));
/*
* create state structure
*/
limitstate = makeNode(LimitState);
limitstate->ps.plan = (Plan *) node;
limitstate->ps.state = estate;
limitstate->lstate = LIMIT_INITIAL;
/*
* 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->ps);
/*
* initialize child expressions
*/
limitstate->limitOffset = ExecInitExpr((Expr *) node->limitOffset,
(PlanState *) limitstate);
limitstate->limitCount = ExecInitExpr((Expr *) node->limitCount,
(PlanState *) limitstate);
/*
* Tuple table initialization (XXX not actually used...)
*/
ExecInitResultTupleSlot(estate, &limitstate->ps);
/*
* then initialize outer plan
*/
outerPlan = outerPlan(node);
outerPlanState(limitstate) = ExecInitNode(outerPlan, estate, eflags);
/*
* limit nodes do no projections, so initialize projection info for this
* node appropriately
*/
ExecAssignResultTypeFromTL(&limitstate->ps);
limitstate->ps.ps_ProjInfo = NULL;
return limitstate;
}
| TupleTableSlot* ExecLimit | ( | LimitState * | node | ) |
Definition at line 40 of file nodeLimit.c.
References Assert, LimitState::count, elog, ERROR, EState::es_direction, ExecProcNode(), LIMIT_EMPTY, LIMIT_INITIAL, LIMIT_INWINDOW, LIMIT_RESCAN, LIMIT_SUBPLANEOF, LIMIT_WINDOWEND, LIMIT_WINDOWSTART, LimitState::lstate, LimitState::noCount, LimitState::offset, outerPlanState, LimitState::position, LimitState::ps, recompute_limits(), ScanDirectionIsForward, PlanState::state, LimitState::subSlot, and TupIsNull.
Referenced by ExecProcNode().
{
ScanDirection direction;
TupleTableSlot *slot;
PlanState *outerPlan;
/*
* get information from the node
*/
direction = node->ps.state->es_direction;
outerPlan = outerPlanState(node);
/*
* The main logic is a simple state machine.
*/
switch (node->lstate)
{
case LIMIT_INITIAL:
/*
* First call for this node, so compute limit/offset. (We can't do
* this any earlier, because parameters from upper nodes will not
* be set during ExecInitLimit.) This also sets position = 0 and
* changes the state to LIMIT_RESCAN.
*/
recompute_limits(node);
/* FALL THRU */
case LIMIT_RESCAN:
/*
* If backwards scan, just return NULL without changing state.
*/
if (!ScanDirectionIsForward(direction))
return NULL;
/*
* Check for empty window; if so, treat like empty subplan.
*/
if (node->count <= 0 && !node->noCount)
{
node->lstate = LIMIT_EMPTY;
return NULL;
}
/*
* Fetch rows from subplan until we reach position > offset.
*/
for (;;)
{
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
{
/*
* The subplan returns too few tuples for us to produce
* any output at all.
*/
node->lstate = LIMIT_EMPTY;
return NULL;
}
node->subSlot = slot;
if (++node->position > node->offset)
break;
}
/*
* Okay, we have the first tuple of the window.
*/
node->lstate = LIMIT_INWINDOW;
break;
case LIMIT_EMPTY:
/*
* The subplan is known to return no tuples (or not more than
* OFFSET tuples, in general). So we return no tuples.
*/
return NULL;
case LIMIT_INWINDOW:
if (ScanDirectionIsForward(direction))
{
/*
* Forwards scan, so check for stepping off end of window. If
* we are at the end of the window, return NULL without
* advancing the subplan or the position variable; but change
* the state machine state to record having done so.
*/
if (!node->noCount &&
node->position - node->offset >= node->count)
{
node->lstate = LIMIT_WINDOWEND;
return NULL;
}
/*
* Get next tuple from subplan, if any.
*/
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
{
node->lstate = LIMIT_SUBPLANEOF;
return NULL;
}
node->subSlot = slot;
node->position++;
}
else
{
/*
* Backwards scan, so check for stepping off start of window.
* As above, change only state-machine status if so.
*/
if (node->position <= node->offset + 1)
{
node->lstate = LIMIT_WINDOWSTART;
return NULL;
}
/*
* Get previous tuple from subplan; there should be one!
*/
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
elog(ERROR, "LIMIT subplan failed to run backwards");
node->subSlot = slot;
node->position--;
}
break;
case LIMIT_SUBPLANEOF:
if (ScanDirectionIsForward(direction))
return NULL;
/*
* Backing up from subplan EOF, so re-fetch previous tuple; there
* should be one! Note previous tuple must be in window.
*/
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
elog(ERROR, "LIMIT subplan failed to run backwards");
node->subSlot = slot;
node->lstate = LIMIT_INWINDOW;
/* position does not change 'cause we didn't advance it before */
break;
case LIMIT_WINDOWEND:
if (ScanDirectionIsForward(direction))
return NULL;
/*
* Backing up from window end: simply re-return the last tuple
* fetched from the subplan.
*/
slot = node->subSlot;
node->lstate = LIMIT_INWINDOW;
/* position does not change 'cause we didn't advance it before */
break;
case LIMIT_WINDOWSTART:
if (!ScanDirectionIsForward(direction))
return NULL;
/*
* Advancing after having backed off window start: simply
* re-return the last tuple fetched from the subplan.
*/
slot = node->subSlot;
node->lstate = LIMIT_INWINDOW;
/* position does not change 'cause we didn't change it before */
break;
default:
elog(ERROR, "impossible LIMIT state: %d",
(int) node->lstate);
slot = NULL; /* keep compiler quiet */
break;
}
/* Return the current tuple */
Assert(!TupIsNull(slot));
return slot;
}
| void ExecReScanLimit | ( | LimitState * | node | ) |
Definition at line 443 of file nodeLimit.c.
References PlanState::chgParam, ExecReScan(), PlanState::lefttree, NULL, LimitState::ps, and recompute_limits().
Referenced by ExecReScan().
{
/*
* Recompute limit/offset in case parameters changed, and reset the state
* machine. We must do this before rescanning our child node, in case
* it's a Sort that we are passing the parameters down to.
*/
recompute_limits(node);
/*
* if chgParam of subnode is not null then plan will be re-scanned by
* first ExecProcNode.
*/
if (node->ps.lefttree->chgParam == NULL)
ExecReScan(node->ps.lefttree);
}
1.7.1