#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); }