예제 #1
0
파일: nodeLimit.c 프로젝트: colinet/sqlix
/*
 * Evaluate the limit/offset expressions --- done at startup or rescan.
 *
 * This is also a handy place to reset the current-position state info.
 */
static void
recompute_limits(limit_ps *node)
{
	expr_ctx_n *econtext;
	datum_t	 val;
	bool isNull;

	econtext = node->ps.ps_ExprContext;
	if (node->limitOffset) {
		val = exec_eval_expr_switch_ctx(node->limitOffset, econtext, &isNull, NULL);

		/* Interpret NULL offset as no offset */
		if (isNull)
			node->offset = 0;
		else {
			node->offset = D_TO_INT64(val);
			if (node->offset < 0)
				ereport(ERROR, (
				errcode(E_INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE),
				errmsg("OFFSET must not be negative")));
		}
	} else {
		/* No OFFSET supplied */
		node->offset = 0;
	}

	if (node->limitCount) {
		val = exec_eval_expr_switch_ctx(node->limitCount, econtext, &isNull, NULL);

		/* Interpret NULL count as no count (LIMIT ALL) */
		if (isNull) {
			node->count = 0;
			node->noCount = true;
		} else {
			node->count = D_TO_INT64(val);
			if (node->count < 0)
				ereport(ERROR, (
				errcode(E_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE),
				errmsg("LIMIT must not be negative")));

			node->noCount = false;
		}
	} else {
		/* No COUNT supplied */
		node->count = 0;
		node->noCount = true;
	}

	/* Reset position to start-of-scan */
	node->position = 0;
	node->subSlot = NULL;

	/* Set state-machine state */
	node->lstate = LIMIT_RESCAN;

	/* Notify child node about limit, if useful */
	pass_down_bound(node, OUTER_PLAN_STATE(node));
}
예제 #2
0
파일: nodeLimit.c 프로젝트: colinet/sqlix
/*
 * If we have a COUNT, and our input is a sort_pl node, notify it that it can
 * use bounded sort.  Also, if our input is a merge_append_pl, we can apply the
 * same bound to any Sorts that are direct children of the merge_append_pl,
 * since the merge_append_pl surely need read no more than that many tuples from
 * any one input.  We also have to be prepared to look through a result_pl,
 * since the planner might stick one atop merge_append_pl for projection purposes.
 *
 * This is a bit of a kluge, but we don't have any more-abstract way of
 * communicating between the two nodes; and it doesn't seem worth trying
 * to invent one without some more examples of special communication needs.
 *
 * Note: it is the responsibility of nodeSort.c to react properly to
 * changes of these parameters.  If we ever do redesign this, it'd be a
 * good idea to integrate this signaling with the parameter-change mechanism.
 */
static void
pass_down_bound(limit_ps *node, plan_state_n *child_node)
{
	if (IS_A(child_node, SortState)) {
		sort_ss  *sortState;
		int64 tuples_needed;

		sortState = (sort_ss *) child_node;
		tuples_needed = node->count + node->offset;

		/* negative test checks for overflow in sum */
		if (node->noCount || tuples_needed < 0) {
			/* make sure flag gets reset if needed upon rescan */
			sortState->bounded = false;
		} else {
			sortState->bounded = true;
			sortState->bound = tuples_needed;
		}
	} else if (IS_A(child_node, MergeAppendState)) {
		merge_append_ps *maState;
		int i;

		maState = (merge_append_ps *) child_node;
		for (i = 0; i < maState->ms_nplans; i++)
			pass_down_bound(node, maState->mergeplans[i]);
	} else if (IS_A(child_node, ResultState)) {
		/*
		 * An extra consideration here is that if the result_pl is projecting a
		 * targetlist that contains any SRFs, we can't assume that every input
		 * tuple generates an output tuple, so a sort_pl underneath might need to
		 * return more than N tuples to satisfy LIMIT N. So we cannot use
		 * bounded sort.
		 *
		 * If result_pl supported qual checking, we'd have to punt on seeing a
		 * qual, too.  Note that having a resconstantqual is not a
		 * showstopper: if that fails we're not getting any rows at all.
		 */
		if (OUTER_PLAN_STATE(child_node) &&
			!expr_returns_set((node_n *) child_node->plan->targetlist))
			pass_down_bound(node, OUTER_PLAN_STATE(child_node));
	}
}
예제 #3
0
/*
 * If we have a COUNT, and our input is a Sort node, notify it that it can
 * use bounded sort.  Also, if our input is a MergeAppend, we can apply the
 * same bound to any Sorts that are direct children of the MergeAppend,
 * since the MergeAppend surely need read no more than that many tuples from
 * any one input.  We also have to be prepared to look through a Result,
 * since the planner might stick one atop MergeAppend for projection purposes.
 *
 * This is a bit of a kluge, but we don't have any more-abstract way of
 * communicating between the two nodes; and it doesn't seem worth trying
 * to invent one without some more examples of special communication needs.
 *
 * Note: it is the responsibility of nodeSort.c to react properly to
 * changes of these parameters.  If we ever do redesign this, it'd be a
 * good idea to integrate this signaling with the parameter-change mechanism.
 */
static void
pass_down_bound(LimitState *node, PlanState *child_node)
{
	if (IsA(child_node, SortState))
	{
		SortState  *sortState = (SortState *) child_node;
		int64		tuples_needed = node->count + node->offset;

		/* negative test checks for overflow in sum */
		if (node->noCount || tuples_needed < 0)
		{
			/* make sure flag gets reset if needed upon rescan */
			sortState->bounded = false;
		}
		else
		{
			sortState->bounded = true;
			sortState->bound = tuples_needed;
		}
	}
	else if (IsA(child_node, MergeAppendState))
	{
		MergeAppendState *maState = (MergeAppendState *) child_node;
		int			i;

		for (i = 0; i < maState->ms_nplans; i++)
			pass_down_bound(node, maState->mergeplans[i]);
	}
	else if (IsA(child_node, ResultState))
	{
		/*
		 * If Result supported qual checking, we'd have to punt on seeing a
		 * qual.  Note that having a resconstantqual is not a showstopper: if
		 * that fails we're not getting any rows at all.
		 */
		if (outerPlanState(child_node))
			pass_down_bound(node, outerPlanState(child_node));
	}
}
예제 #4
0
/*
 * Evaluate the limit/offset expressions --- done at startup or rescan.
 *
 * This is also a handy place to reset the current-position state info.
 */
static void
recompute_limits(LimitState *node)
{
	ExprContext *econtext = node->ps.ps_ExprContext;
	Datum		val;
	bool		isNull;

	if (node->limitOffset)
	{
		val = ExecEvalExprSwitchContext(node->limitOffset,
										econtext,
										&isNull);
		/* Interpret NULL offset as no offset */
		if (isNull)
			node->offset = 0;
		else
		{
			node->offset = DatumGetInt64(val);
			if (node->offset < 0)
				ereport(ERROR,
				 (errcode(ERRCODE_INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE),
				  errmsg("OFFSET must not be negative")));
		}
	}
	else
	{
		/* No OFFSET supplied */
		node->offset = 0;
	}

	if (node->limitCount)
	{
		val = ExecEvalExprSwitchContext(node->limitCount,
										econtext,
										&isNull);
		/* Interpret NULL count as no count (LIMIT ALL) */
		if (isNull)
		{
			node->count = 0;
			node->noCount = true;
		}
		else
		{
			node->count = DatumGetInt64(val);
			if (node->count < 0)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE),
						 errmsg("LIMIT must not be negative")));
			node->noCount = false;
		}
	}
	else
	{
		/* No COUNT supplied */
		node->count = 0;
		node->noCount = true;
	}

	/* Reset position to start-of-scan */
	node->position = 0;
	node->subSlot = NULL;

	/* Set state-machine state */
	node->lstate = LIMIT_RESCAN;

	/* Notify child node about limit, if useful */
	pass_down_bound(node, outerPlanState(node));
}