void ExecReScanLimit(LimitState *node, ExprContext *exprCtxt) { /* * 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 (((PlanState *) node)->lefttree->chgParam == NULL) ExecReScan(((PlanState *) node)->lefttree, exprCtxt); }
void exec_rescan_limit(limit_ps *node) { /* * 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_pl 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 exec_proc_node. */ if (node->ps.lefttree->chgParam == NULL) ExecReScan(node->ps.lefttree); }
/* ---------------------------------------------------------------- * ExecLimit * * This is a very simple node which just performs LIMIT/OFFSET * filtering on the stream of tuples returned by a subplan. * ---------------------------------------------------------------- */ struct tupslot* /* return: a tuple or NULL */ ExecLimit(limit_ps *node) { enum scandir direction; struct tupslot* slot; plan_state_n* outerPlan; /* * get information from the node */ direction = node->ps.state->es_direction; outerPlan = OUTER_PLAN_STATE(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 (!SCANDIR_FORWARD(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 = exec_proc_node(outerPlan); if (TUPSLOT_NULL(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 (SCANDIR_FORWARD(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 = exec_proc_node(outerPlan); if (TUPSLOT_NULL(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 = exec_proc_node(outerPlan); if (TUPSLOT_NULL(slot)) elog(ERROR, "LIMIT subplan failed to run backwards"); node->subSlot = slot; node->position--; } break; case LIMIT_SUBPLANEOF: if (SCANDIR_FORWARD(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 = exec_proc_node(outerPlan); if (TUPSLOT_NULL(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 (SCANDIR_FORWARD(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 (!SCANDIR_FORWARD(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(!TUPSLOT_NULL(slot)); return slot; }
/* ---------------------------------------------------------------- * 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(LimitState *node) { 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; /* * CDB: We'll read no more from outer subtree. To keep our * sibling QEs from being starved, tell source QEs not to clog * up the pipeline with our never-to-be-consumed data. */ ExecSquelchNode(outerPlan); 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. */ ExecSquelchNode(outerPlan); /* CDB */ 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; ExecSquelchNode(outerPlan); /* CDB */ 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; ExecSquelchNode(outerPlan); /* CDB */ 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)); if (!TupIsNull(slot)) { Gpmon_M_Incr_Rows_Out(GpmonPktFromLimitState(node)); CheckSendPlanStateGpmonPkt(&node->ps); } return slot; }
/* ---------------------------------------------------------------- * 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(LimitState *node) { ScanDirection direction; TupleTableSlot *resultTupleSlot; TupleTableSlot *slot; PlanState *outerPlan; /* * get information from the node */ direction = node->ps.state->es_direction; outerPlan = outerPlanState(node); resultTupleSlot = node->ps.ps_ResultTupleSlot; /* * The main logic is a simple state machine. */ switch (node->lstate) { case LIMIT_INITIAL: /* * If backwards scan, just return NULL without changing state. */ if (!ScanDirectionIsForward(direction)) return NULL; /* * First call for this scan, so compute limit/offset. (We * can't do this any earlier, because parameters from upper * nodes may not be set until now.) This also sets position = * 0. */ recompute_limits(node); /* * 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)); ExecStoreTuple(slot->val, resultTupleSlot, InvalidBuffer, false); /* tuple does not belong to slot */ return resultTupleSlot; }