⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nodenestloop.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
字号:
/*------------------------------------------------------------------------- * * nodeNestloop.c *	  routines to support nest-loop joins * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.39.2.1 2005/11/22 18:23:09 momjian Exp $ * *------------------------------------------------------------------------- *//* *	 INTERFACE ROUTINES *		ExecNestLoop	 - process a nestloop join of two plans *		ExecInitNestLoop - initialize the join *		ExecEndNestLoop  - shut down the join */#include "postgres.h"#include "executor/execdebug.h"#include "executor/nodeNestloop.h"#include "utils/memutils.h"/* ---------------------------------------------------------------- *		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");	}}/* ---------------------------------------------------------------- *		ExecInitNestLoop * ---------------------------------------------------------------- */NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate){	NestLoopState *nlstate;	NL1_printf("ExecInitNestLoop: %s\n",			   "initializing node");	/*	 * create state structure	 */	nlstate = makeNode(NestLoopState);	nlstate->js.ps.plan = (Plan *) node;	nlstate->js.ps.state = estate;	/*	 * Miscellaneous initialization	 *	 * create expression context for node	 */	ExecAssignExprContext(estate, &nlstate->js.ps);	/*	 * initialize child expressions	 */	nlstate->js.ps.targetlist = (List *)		ExecInitExpr((Expr *) node->join.plan.targetlist,					 (PlanState *) nlstate);	nlstate->js.ps.qual = (List *)		ExecInitExpr((Expr *) node->join.plan.qual,					 (PlanState *) nlstate);	nlstate->js.jointype = node->join.jointype;	nlstate->js.joinqual = (List *)		ExecInitExpr((Expr *) node->join.joinqual,					 (PlanState *) nlstate);	/*	 * initialize child nodes	 */	outerPlanState(nlstate) = ExecInitNode(outerPlan(node), estate);	innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate);#define NESTLOOP_NSLOTS 2	/*	 * tuple table initialization	 */	ExecInitResultTupleSlot(estate, &nlstate->js.ps);	switch (node->join.jointype)	{		case JOIN_INNER:		case JOIN_IN:			break;		case JOIN_LEFT:			nlstate->nl_NullInnerTupleSlot =				ExecInitNullTupleSlot(estate,								 ExecGetResultType(innerPlanState(nlstate)));			break;		default:			elog(ERROR, "unrecognized join type: %d",				 (int) node->join.jointype);	}	/*	 * initialize tuple type and projection info	 */	ExecAssignResultTypeFromTL(&nlstate->js.ps);	ExecAssignProjectionInfo(&nlstate->js.ps);	/*	 * finally, wipe the current outer tuple clean.	 */	nlstate->js.ps.ps_OuterTupleSlot = NULL;	nlstate->js.ps.ps_TupFromTlist = false;	nlstate->nl_NeedNewOuter = true;	nlstate->nl_MatchedOuter = false;	NL1_printf("ExecInitNestLoop: %s\n",			   "node initialized");	return nlstate;}intExecCountSlotsNestLoop(NestLoop *node){	return ExecCountSlotsNode(outerPlan(node)) +		ExecCountSlotsNode(innerPlan(node)) +		NESTLOOP_NSLOTS;}/* ---------------------------------------------------------------- *		ExecEndNestLoop * *		closes down scans and frees allocated storage * ---------------------------------------------------------------- */voidExecEndNestLoop(NestLoopState *node){	NL1_printf("ExecEndNestLoop: %s\n",			   "ending node processing");	/*	 * Free the exprcontext	 */	ExecFreeExprContext(&node->js.ps);	/*	 * clean out the tuple table	 */	ExecClearTuple(node->js.ps.ps_ResultTupleSlot);	/*	 * close down subplans	 */	ExecEndNode(outerPlanState(node));	ExecEndNode(innerPlanState(node));	NL1_printf("ExecEndNestLoop: %s\n",			   "node processing ended");}/* ---------------------------------------------------------------- *		ExecReScanNestLoop * ---------------------------------------------------------------- */voidExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt){	PlanState  *outerPlan = outerPlanState(node);	/*	 * If outerPlan->chgParam is not null then plan will be automatically	 * re-scanned by first ExecProcNode. innerPlan is re-scanned for each new	 * outer tuple and MUST NOT be re-scanned from here or you'll get troubles	 * from inner index scans when outer Vars are used as run-time keys...	 */	if (outerPlan->chgParam == NULL)		ExecReScan(outerPlan, exprCtxt);	/* let outerPlan to free its result tuple ... */	node->js.ps.ps_OuterTupleSlot = NULL;	node->js.ps.ps_TupFromTlist = false;	node->nl_NeedNewOuter = true;	node->nl_MatchedOuter = false;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -