示例#1
0
/* ----------------------------------------------------------------
 *   	ExecNestLoop(node)
 *
 * old comments
 *   	Returns the tuple joined from inner and outer tuples which 
 *   	satisfies the qualification clause.
 *
 *	It scans the inner relation to join with current outer tuple.
 *
 *	If none is found, next tuple form the outer relation is retrieved
 *	and the inner relation is scanned from the beginning again to join
 *	with the outer tuple.
 *
 *   	Nil is returned if all the remaining outer tuples are tried and
 *   	all fail to join with the inner tuples.
 *
 *   	Nil is also returned if there is no tuple from inner realtion.
 *   
 *   	Conditions:
 *   	  -- outerTuple contains current tuple from outer relation and
 *   	     the right son(inner realtion) maintains "cursor" at the tuple
 *   	     returned previously.
 *              This is achieved by maintaining a scan position on the outer
 *              relation.
 *   
 *   	Initial States:
 *   	  -- the outer child and the inner child 
 *             are prepared to return the first tuple.
 * ----------------------------------------------------------------
 */
TupleTableSlot *
ExecNestLoop(NestLoop *node, Plan* parent)
{
    NestLoopState 	*nlstate;
    Plan	  	*innerPlan;
    Plan	  	*outerPlan;
    bool 	  	needNewOuterTuple;

    TupleTableSlot  	*outerTupleSlot;
    TupleTableSlot  	*innerTupleSlot;

    List	  	*qual;
    bool	  	qualResult;
    ExprContext	  	*econtext;

    /* ----------------
     *	get information from the node
     * ----------------
     */
    ENL1_printf("getting info from node");

    nlstate =    node->nlstate;
    qual =       node->join.qual;
    outerPlan =  outerPlan(&node->join);
    innerPlan =  innerPlan(&node->join);

    /* ----------------
     *	initialize expression context
     * ----------------
     */
    econtext = nlstate->jstate.cs_ExprContext;

    /* ----------------     *	get the current outer tuple
     * ----------------
     */
    outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
    econtext->ecxt_outertuple = outerTupleSlot;

    /* ----------------
     *  Ok, everything is setup for the join so now loop until
     *  we return a qualifying join tuple..
     * ----------------
     */

    if (nlstate->jstate.cs_TupFromTlist) {
	TupleTableSlot  *result;
	bool		isDone;

	result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
	if (!isDone)
	    return result;
    }

    ENL1_printf("entering main loop");
    for(;;) {
	/* ----------------
	 *  The essential idea now is to get the next inner tuple
	 *  and join it with the current outer tuple.
	 * ----------------
	 */
	needNewOuterTuple = false;
	
	/* ----------------
	 *  If outer tuple is not null then that means
	 *  we are in the middle of a scan and we should
	 *  restore our previously saved scan position.
	 * ----------------
	 */
	if (! TupIsNull(outerTupleSlot)) {	    
	    ENL1_printf("have outer tuple, restoring outer plan");
	    ExecRestrPos(outerPlan);
	} else {
	    ENL1_printf("outer tuple is nil, need new outer tuple");
	    needNewOuterTuple = true;
	}
	
	/* ----------------
	 *  if we have an outerTuple, try to get the next inner tuple.
	 * ----------------
	 */
	if (!needNewOuterTuple) {
	    ENL1_printf("getting new inner tuple");
	
	    innerTupleSlot = ExecProcNode(innerPlan, (Plan*)node);
	    econtext->ecxt_innertuple = innerTupleSlot;
	    
	    if (TupIsNull(innerTupleSlot)) {
		ENL1_printf("no inner tuple, need new outer tuple");
		needNewOuterTuple = true;
	    }
	}
	
	/* ----------------
	 *  loop until we have a new outer tuple and a new
	 *  inner tuple.
	 * ----------------
	 */
	while (needNewOuterTuple) {
	    /* ----------------
	     *	now try to get the next outer tuple
	     * ----------------
	     */
	    ENL1_printf("getting new outer tuple");
	    outerTupleSlot = ExecProcNode(outerPlan, (Plan*)node);
	    econtext->ecxt_outertuple = outerTupleSlot;
	    
	    /* ----------------
	     *  if there are no more outer tuples, then the join
	     *  is complete..
	     * ----------------
	     */
	    if (TupIsNull(outerTupleSlot)) {
		ENL1_printf("no outer tuple, ending join");
		return NULL;
	    }
	    
	    /* ----------------
	     *  we have a new outer tuple so we mark our position
	     *  in the outer scan and save the outer tuple in the
	     *  NestLoop state
	     * ----------------
	     */
	    ENL1_printf("saving new outer tuple information");
	    ExecMarkPos(outerPlan);
	    nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
	    
	    /* ----------------
	     *	now rescan the inner plan and get a new inner tuple
	     * ----------------
	     */
	    
	    ENL1_printf("rescanning inner plan");
	    /* 
	     * The scan key of the inner plan might depend on the current
	     * outer tuple (e.g. in index scans), that's why we pass our
	     * expr context.
	     */
	    ExecReScan(innerPlan, econtext, parent);

	    ENL1_printf("getting new inner tuple");
	    
	    innerTupleSlot = ExecProcNode(innerPlan, (Plan*)node);
	    econtext->ecxt_innertuple = innerTupleSlot;
	    
	    if (TupIsNull(innerTupleSlot)) {
		ENL1_printf("couldn't get inner tuple - need new outer tuple");
	    } else {
		ENL1_printf("got inner and outer tuples");
		needNewOuterTuple = false;
	    }
	} /* while (needNewOuterTuple) */
	
	/* ----------------
	 *   at this point we have a new pair of inner and outer
	 *   tuples so we test the inner and outer tuples to see
	 *   if they satisify the node's qualification.
	 * ----------------
	 */
	ENL1_printf("testing qualification");
	qualResult = ExecQual((List*)qual, econtext);
	
	if (qualResult) {
	    /* ----------------
	     *  qualification was satisified so we project and
	     *  return the slot containing the result tuple
	     *  using ExecProject().
	     * ----------------
	     */
	    ProjectionInfo *projInfo;
	    TupleTableSlot *result;
	    bool           isDone;
	    
	    ENL1_printf("qualification succeeded, projecting tuple");
	    
	    projInfo = nlstate->jstate.cs_ProjInfo;
	    result = ExecProject(projInfo, &isDone);
	    nlstate->jstate.cs_TupFromTlist = !isDone;
	    return result;
	} 
	
	/* ----------------
	 *  qualification failed so we have to try again..
	 * ----------------
	 */
	ENL1_printf("qualification failed, looping");
    }
}
示例#2
0
/* ----------------------------------------------------------------
 *		ExecNestLoop(node)
 *
 * old comments
 *		Returns the tuple joined from inner and outer tuples which
 *		satisfies the qualification clause.
 *
 *		It scans the inner relation to join with current outer tuple.
 *
 *		If none is found, next tuple from the outer relation is retrieved
 *		and the inner relation is scanned from the beginning again to join
 *		with the outer tuple.
 *
 *		NULL is returned if all the remaining outer tuples are tried and
 *		all fail to join with the inner tuples.
 *
 *		NULL is also returned if there is no tuple from inner relation.
 *
 *		Conditions:
 *		  -- outerTuple contains current tuple from outer relation and
 *			 the right son(inner relation) maintains "cursor" at the tuple
 *			 returned previously.
 *				This is achieved by maintaining a scan position on the outer
 *				relation.
 *
 *		Initial States:
 *		  -- the outer child and the inner child
 *			   are prepared to return the first tuple.
 * ----------------------------------------------------------------
 */
TupleTableSlot *
ExecNestLoop(NestLoopState *node)
{
	PlanState  *innerPlan;
	PlanState  *outerPlan;
	TupleTableSlot *outerTupleSlot;
	TupleTableSlot *innerTupleSlot;
	List	   *joinqual;
	List	   *otherqual;
	ExprContext *econtext;

	/*
	 * get information from the node
	 */
	ENL1_printf("getting info from node");

	joinqual = node->js.joinqual;
	otherqual = node->js.ps.qual;
	outerPlan = outerPlanState(node);
	innerPlan = innerPlanState(node);
	econtext = node->js.ps.ps_ExprContext;

	/*
	 * get the current outer tuple
	 */
	outerTupleSlot = node->js.ps.ps_OuterTupleSlot;
	econtext->ecxt_outertuple = outerTupleSlot;

	/*
	 * Check to see if we're still projecting out tuples from a previous join
	 * tuple (because there is a function-returning-set in the projection
	 * expressions).  If so, try to project another one.
	 */
	if (node->js.ps.ps_TupFromTlist)
	{
		TupleTableSlot *result;
		ExprDoneCond isDone;

		result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
		if (isDone == ExprMultipleResult)
			return result;
		/* Done with that source tuple... */
		node->js.ps.ps_TupFromTlist = false;
	}

	/*
	 * If we're doing an IN join, we want to return at most one row per outer
	 * tuple; so we can stop scanning the inner scan if we matched on the
	 * previous try.
	 */
	if (node->js.jointype == JOIN_IN &&
		node->nl_MatchedOuter)
		node->nl_NeedNewOuter = true;

	/*
	 * Reset per-tuple memory context to free any expression evaluation
	 * storage allocated in the previous tuple cycle.  Note this can't happen
	 * until we're done projecting out tuples from a join tuple.
	 */
	ResetExprContext(econtext);

	/*
	 * Ok, everything is setup for the join so now loop until we return a
	 * qualifying join tuple.
	 */
	ENL1_printf("entering main loop");

	for (;;)
	{
		/*
		 * If we don't have an outer tuple, get the next one and reset the
		 * inner scan.
		 */
		if (node->nl_NeedNewOuter)
		{
			ENL1_printf("getting new outer tuple");
			outerTupleSlot = ExecProcNode(outerPlan);

			/*
			 * if there are no more outer tuples, then the join is complete..
			 */
			if (TupIsNull(outerTupleSlot))
			{
				ENL1_printf("no outer tuple, ending join");
				return NULL;
			}

			ENL1_printf("saving new outer tuple information");
			node->js.ps.ps_OuterTupleSlot = outerTupleSlot;
			econtext->ecxt_outertuple = outerTupleSlot;
			node->nl_NeedNewOuter = false;
			node->nl_MatchedOuter = false;

			/*
			 * now rescan the inner plan
			 */
			ENL1_printf("rescanning inner plan");

			/*
			 * The scan key of the inner plan might depend on the current
			 * outer tuple (e.g. in index scans), that's why we pass our expr
			 * context.
			 */
			ExecReScan(innerPlan, econtext);
		}

		/*
		 * we have an outerTuple, try to get the next inner tuple.
		 */
		ENL1_printf("getting new inner tuple");

		innerTupleSlot = ExecProcNode(innerPlan);
		econtext->ecxt_innertuple = innerTupleSlot;

		if (TupIsNull(innerTupleSlot))
		{
			ENL1_printf("no inner tuple, need new outer tuple");

			node->nl_NeedNewOuter = true;

			if (!node->nl_MatchedOuter &&
				node->js.jointype == JOIN_LEFT)
			{
				/*
				 * We are doing an outer join and there were no join matches
				 * for this outer tuple.  Generate a fake join tuple with
				 * nulls for the inner tuple, and return it if it passes the
				 * non-join quals.
				 */
				econtext->ecxt_innertuple = node->nl_NullInnerTupleSlot;

				ENL1_printf("testing qualification for outer-join tuple");

				if (ExecQual(otherqual, econtext, false))
				{
					/*
					 * qualification was satisfied so we project and return
					 * the slot containing the result tuple using
					 * ExecProject().
					 */
					TupleTableSlot *result;
					ExprDoneCond isDone;

					ENL1_printf("qualification succeeded, projecting tuple");

					result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);

					if (isDone != ExprEndResult)
					{
						node->js.ps.ps_TupFromTlist =
							(isDone == ExprMultipleResult);
						return result;
					}
				}
			}

			/*
			 * Otherwise just return to top of loop for a new outer tuple.
			 */
			continue;
		}

		/*
		 * at this point we have a new pair of inner and outer tuples so we
		 * test the inner and outer tuples to see if they satisfy the node's
		 * qualification.
		 *
		 * Only the joinquals determine MatchedOuter status, but all quals
		 * must pass to actually return the tuple.
		 */
		ENL1_printf("testing qualification");

		if (ExecQual(joinqual, econtext, false))
		{
			node->nl_MatchedOuter = true;

			if (otherqual == NIL || ExecQual(otherqual, econtext, false))
			{
				/*
				 * qualification was satisfied so we project and return the
				 * slot containing the result tuple using ExecProject().
				 */
				TupleTableSlot *result;
				ExprDoneCond isDone;

				ENL1_printf("qualification succeeded, projecting tuple");

				result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);

				if (isDone != ExprEndResult)
				{
					node->js.ps.ps_TupFromTlist =
						(isDone == ExprMultipleResult);
					return result;
				}
			}

			/* If we didn't return a tuple, may need to set NeedNewOuter */
			if (node->js.jointype == JOIN_IN)
				node->nl_NeedNewOuter = true;
		}

		/*
		 * Tuple fails qual, so free per-tuple memory and try again.
		 */
		ResetExprContext(econtext);

		ENL1_printf("qualification failed, looping");
	}
}