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

📄 nodemergejoin.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 3 页
字号:
				break;				/*-----------------------------------------------------------				 * EXEC_MJ_SKIPINNER means skip over tuples in the inner plan				 * until we find an inner tuple >= current outer tuple.				 *				 * For example:				 *				 *				outer inner				 *				  5		5				 *				  5		5				 * outer tuple - 12		8  - inner tuple				 *				 14    10				 *				 17    12				 *				 * we have to advance the inner scan				 * until we find the inner 12.				 *				 * To avoid redundant tests, we divide this into three				 * sub-states: BEGIN, TEST, ADVANCE.				 *-------------------------------------------------------				 */			case EXEC_MJ_SKIPINNER_BEGIN:				MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_BEGIN\n");				/*				 * before we advance, make sure the current tuples do not				 * satisfy the mergeclauses.  If they do, then we update				 * the marked tuple and go join them.				 */				ResetExprContext(econtext);				outerTupleSlot = node->mj_OuterTupleSlot;				econtext->ecxt_outertuple = outerTupleSlot;				innerTupleSlot = node->mj_InnerTupleSlot;				econtext->ecxt_innertuple = innerTupleSlot;				qualResult = ExecQual(mergeclauses, econtext, false);				MJ_DEBUG_QUAL(mergeclauses, qualResult);				if (qualResult)				{					ExecMarkPos(innerPlan);					MarkInnerTuple(innerTupleSlot, node);					node->mj_JoinState = EXEC_MJ_JOINTUPLES;					break;				}				node->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;				break;			case EXEC_MJ_SKIPINNER_TEST:				MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_TEST\n");				/*				 * ok, now test the skip qualification				 */				outerTupleSlot = node->mj_OuterTupleSlot;				econtext->ecxt_outertuple = outerTupleSlot;				innerTupleSlot = node->mj_InnerTupleSlot;				econtext->ecxt_innertuple = innerTupleSlot;				compareResult = MergeCompare(mergeclauses,											 innerSkipQual,											 econtext);				MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);				/*				 * compareResult is true as long as we should continue				 * skipping inner tuples.				 */				if (compareResult)				{					node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;					break;				}				/*				 * now check the outer skip qual to see if we should now				 * skip outer tuples... if we fail the outer skip qual,				 * then we know we have a new pair of matching tuples.				 */				compareResult = MergeCompare(mergeclauses,											 outerSkipQual,											 econtext);				MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);				if (compareResult)					node->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;				else					node->mj_JoinState = EXEC_MJ_JOINMARK;				break;				/*				 * Before advancing, we check to see if we must emit an				 * outer-join fill tuple for this inner tuple.				 */			case EXEC_MJ_SKIPINNER_ADVANCE:				MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_ADVANCE\n");				if (doFillInner && !node->mj_MatchedInner)				{					/*					 * Generate a fake join tuple with nulls for the outer					 * tuple, and return it if it passes the non-join					 * quals.					 */					node->mj_MatchedInner = true;		/* do it only once */					ResetExprContext(econtext);					outerTupleSlot = node->mj_NullOuterTupleSlot;					econtext->ecxt_outertuple = outerTupleSlot;					innerTupleSlot = node->mj_InnerTupleSlot;					econtext->ecxt_innertuple = innerTupleSlot;					if (ExecQual(otherqual, econtext, false))					{						/*						 * qualification succeeded.  now form the desired						 * projection tuple and return the slot containing						 * it.						 */						TupleTableSlot *result;						ExprDoneCond isDone;						MJ_printf("ExecMergeJoin: returning fill tuple\n");						result = ExecProject(node->js.ps.ps_ProjInfo,											 &isDone);						if (isDone != ExprEndResult)						{							node->js.ps.ps_TupFromTlist =								(isDone == ExprMultipleResult);							return result;						}					}				}				/*				 * now we get the next inner tuple, if any				 */				innerTupleSlot = ExecProcNode(innerPlan);				node->mj_InnerTupleSlot = innerTupleSlot;				MJ_DEBUG_PROC_NODE(innerTupleSlot);				node->mj_MatchedInner = false;				/*				 * if the inner tuple is null then we are done with the				 * join, unless we have outer tuples we need to null-fill.				 */				if (TupIsNull(innerTupleSlot))				{					MJ_printf("ExecMergeJoin: end of inner subplan\n");					outerTupleSlot = node->mj_OuterTupleSlot;					if (doFillOuter && !TupIsNull(outerTupleSlot))					{						/*						 * Need to emit left-join tuples for remaining						 * outer tuples.						 */						node->mj_JoinState = EXEC_MJ_ENDINNER;						break;					}					/* Otherwise we're done. */					return NULL;				}				/*				 * otherwise test the new tuple against the skip qual.				 */				node->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;				break;				/*				 * EXEC_MJ_ENDOUTER means we have run out of outer tuples,				 * but are doing a right/full join and therefore must				 * null- fill any remaing unmatched inner tuples.				 */			case EXEC_MJ_ENDOUTER:				MJ_printf("ExecMergeJoin: EXEC_MJ_ENDOUTER\n");				Assert(doFillInner);				if (!node->mj_MatchedInner)				{					/*					 * Generate a fake join tuple with nulls for the outer					 * tuple, and return it if it passes the non-join					 * quals.					 */					node->mj_MatchedInner = true;		/* do it only once */					ResetExprContext(econtext);					outerTupleSlot = node->mj_NullOuterTupleSlot;					econtext->ecxt_outertuple = outerTupleSlot;					innerTupleSlot = node->mj_InnerTupleSlot;					econtext->ecxt_innertuple = innerTupleSlot;					if (ExecQual(otherqual, econtext, false))					{						/*						 * qualification succeeded.  now form the desired						 * projection tuple and return the slot containing						 * it.						 */						TupleTableSlot *result;						ExprDoneCond isDone;						MJ_printf("ExecMergeJoin: returning fill tuple\n");						result = ExecProject(node->js.ps.ps_ProjInfo,											 &isDone);						if (isDone != ExprEndResult)						{							node->js.ps.ps_TupFromTlist =								(isDone == ExprMultipleResult);							return result;						}					}				}				/*				 * now we get the next inner tuple, if any				 */				innerTupleSlot = ExecProcNode(innerPlan);				node->mj_InnerTupleSlot = innerTupleSlot;				MJ_DEBUG_PROC_NODE(innerTupleSlot);				node->mj_MatchedInner = false;				if (TupIsNull(innerTupleSlot))				{					MJ_printf("ExecMergeJoin: end of inner subplan\n");					return NULL;				}				/* Else remain in ENDOUTER state and process next tuple. */				break;				/*				 * EXEC_MJ_ENDINNER means we have run out of inner tuples,				 * but are doing a left/full join and therefore must null-				 * fill any remaing unmatched outer tuples.				 */			case EXEC_MJ_ENDINNER:				MJ_printf("ExecMergeJoin: EXEC_MJ_ENDINNER\n");				Assert(doFillOuter);				if (!node->mj_MatchedOuter)				{					/*					 * Generate a fake join tuple with nulls for the inner					 * tuple, and return it if it passes the non-join					 * quals.					 */					node->mj_MatchedOuter = true;		/* do it only once */					ResetExprContext(econtext);					outerTupleSlot = node->mj_OuterTupleSlot;					econtext->ecxt_outertuple = outerTupleSlot;					innerTupleSlot = node->mj_NullInnerTupleSlot;					econtext->ecxt_innertuple = innerTupleSlot;					if (ExecQual(otherqual, econtext, false))					{						/*						 * qualification succeeded.  now form the desired						 * projection tuple and return the slot containing						 * it.						 */						TupleTableSlot *result;						ExprDoneCond isDone;						MJ_printf("ExecMergeJoin: returning fill tuple\n");						result = ExecProject(node->js.ps.ps_ProjInfo,											 &isDone);						if (isDone != ExprEndResult)						{							node->js.ps.ps_TupFromTlist =								(isDone == ExprMultipleResult);							return result;						}					}				}				/*				 * now we get the next outer tuple, if any				 */				outerTupleSlot = ExecProcNode(outerPlan);				node->mj_OuterTupleSlot = outerTupleSlot;				MJ_DEBUG_PROC_NODE(outerTupleSlot);				node->mj_MatchedOuter = false;				if (TupIsNull(outerTupleSlot))				{					MJ_printf("ExecMergeJoin: end of outer subplan\n");					return NULL;				}				/* Else remain in ENDINNER state and process next tuple. */				break;				/*				 * broken state value?				 */			default:				elog(ERROR, "unrecognized mergejoin state: %d",					 (int) node->mj_JoinState);		}	}}/* ---------------------------------------------------------------- *		ExecInitMergeJoin * ---------------------------------------------------------------- */MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate){	MergeJoinState *mergestate;	MJ1_printf("ExecInitMergeJoin: %s\n",			   "initializing node");	/*	 * create state structure	 */	mergestate = makeNode(MergeJoinState);	mergestate->js.ps.plan = (Plan *) node;	mergestate->js.ps.state = estate;	/*	 * Miscellaneous initialization	 *	 * create expression context for node	 */	ExecAssignExprContext(estate, &mergestate->js.ps);	/*	 * initialize child expressions	 */	mergestate->js.ps.targetlist = (List *)		ExecInitExpr((Expr *) node->join.plan.targetlist,					 (PlanState *) mergestate);	mergestate->js.ps.qual = (List *)		ExecInitExpr((Expr *) node->join.plan.qual,					 (PlanState *) mergestate);	mergestate->js.jointype = node->join.jointype;	mergestate->js.joinqual = (List *)		ExecInitExpr((Expr *) node->join.joinqual,					 (PlanState *) mergestate);	mergestate->mergeclauses = (List *)		ExecInitExpr((Expr *) node->mergeclauses,					 (PlanState *) mergestate);	/*	 * initialize child nodes	 */	outerPlanState(mergestate) = ExecInitNode(outerPlan(node), estate);	innerPlanState(mergestate) = ExecInitNode(innerPlan(node), estate);#define MERGEJOIN_NSLOTS 4	/*	 * tuple table initialization	 */	ExecInitResultTupleSlot(estate, &mergestate->js.ps);	mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate);	ExecSetSlotDescriptor(mergestate->mj_MarkedTupleSlot,						  ExecGetResultType(innerPlanState(mergestate)),						  false);	switch (node->join.jointype)	{		case JOIN_INNER:		case JOIN_IN:			break;		case JOIN_LEFT:			mergestate->mj_NullInnerTupleSlot =				ExecInitNullTupleSlot(estate,						  ExecGetResultType(innerPlanState(mergestate)));			break;		case JOIN_RIGHT:			mergestate->mj_NullOuterTupleSlot =				ExecInitNullTupleSlot(estate,						  ExecGetResultType(outerPlanState(mergestate)));			/*			 * Can't handle right or full join with non-nil extra			 * joinclauses.  This should have been caught by planner.			 */			if (node->join.joinqual != NIL)				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("RIGHT JOIN is only supported with merge-joinable join conditions")));			break;		case JOIN_FULL:			mergestate->mj_NullOuterTupleSlot =				ExecInitNullTupleSlot(estate,						  ExecGetResultType(outerPlanState(mergestate)));			mergestate->mj_NullInnerTupleSlot =				ExecInitNullTupleSlot(estate,						  ExecGetResultType(innerPlanState(mergestate)));			/*			 * Can't handle right or full join with non-nil extra			 * joinclauses.			 */			if (node->join.joinqual != NIL)				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("FULL JOIN is only supported with merge-joinable join conditions")));			break;		default:			elog(ERROR, "unrecognized join type: %d",				 (int) node->join.jointype);	}	/*	 * initialize tuple type and projection info	 */	ExecAssignResultTypeFromTL(&mergestate->js.ps);	ExecAssignProjectionInfo(&mergestate->js.ps);	/*	 * form merge skip qualifications	 */	MJFormSkipQuals(node->mergeclauses,					&mergestate->mj_OuterSkipQual,					&mergestate->mj_InnerSkipQual,					(PlanState *) mergestate);	MJ_printf("\nExecInitMergeJoin: OuterSkipQual is ");	MJ_nodeDisplay(mergestate->mj_OuterSkipQual);	MJ_printf("\nExecInitMergeJoin: InnerSkipQual is ");	MJ_nodeDisplay(mergestate->mj_InnerSkipQual);	MJ_printf("\n");	/*	 * initialize join state	 */	mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;	mergestate->js.ps.ps_TupFromTlist = false;	mergestate->mj_MatchedOuter = false;	mergestate->mj_MatchedInner = false;	mergestate->mj_OuterTupleSlot = NULL;	mergestate->mj_InnerTupleSlot = NULL;	/*	 * initialization successful	 */	MJ1_printf("ExecInitMergeJoin: %s\n",			   "node initialized");	return mergestate;}intExecCountSlotsMergeJoin(MergeJoin *node){	return ExecCountSlotsNode(outerPlan((Plan *) node)) +		ExecCountSlotsNode(innerPlan((Plan *) node)) +		MERGEJOIN_NSLOTS;}/* ---------------------------------------------------------------- *		ExecEndMergeJoin * * old comments *		frees storage allocated through C routines. * ---------------------------------------------------------------- */voidExecEndMergeJoin(MergeJoinState *node){	MJ1_printf("ExecEndMergeJoin: %s\n",			   "ending node processing");	/*	 * Free the exprcontext	 */	ExecFreeExprContext(&node->js.ps);	/*	 * clean out the tuple table	 */	ExecClearTuple(node->js.ps.ps_ResultTupleSlot);	ExecClearTuple(node->mj_MarkedTupleSlot);	/*	 * shut down the subplans	 */	ExecEndNode(innerPlanState(node));	ExecEndNode(outerPlanState(node));	MJ1_printf("ExecEndMergeJoin: %s\n",			   "node processing ended");}voidExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt){	ExecClearTuple(node->mj_MarkedTupleSlot);	node->mj_JoinState = EXEC_MJ_INITIALIZE;	node->js.ps.ps_TupFromTlist = false;	node->mj_MatchedOuter = false;	node->mj_MatchedInner = false;	node->mj_OuterTupleSlot = NULL;	node->mj_InnerTupleSlot = NULL;	/*	 * if chgParam of subnodes is not null then plans will be re-scanned	 * by first ExecProcNode.	 */	if (((PlanState *) node)->lefttree->chgParam == NULL)		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);	if (((PlanState *) node)->righttree->chgParam == NULL)		ExecReScan(((PlanState *) node)->righttree, exprCtxt);}

⌨️ 快捷键说明

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