示例#1
0
文件: nodeLimit.c 项目: 50wu/gpdb
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);
}
示例#2
0
文件: nodeLimit.c 项目: colinet/sqlix
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);
}
示例#3
0
文件: nodeLimit.c 项目: colinet/sqlix
/* ----------------------------------------------------------------
 *		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;
}
示例#4
0
文件: nodeLimit.c 项目: 50wu/gpdb
/* ----------------------------------------------------------------
 *		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;
}
示例#5
0
/* ----------------------------------------------------------------
 *		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;
}