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

📄 nodemergejoin.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 3 页
字号:
				 * If they do satisfy, then we join them and move on to the				 * next inner tuple (EXEC_MJ_JOINTUPLES).				 *				 * If they do not satisfy then advance to next outer tuple.				 */			case EXEC_MJ_JOINTEST:				MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTEST\n");				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)					node->mj_JoinState = EXEC_MJ_JOINTUPLES;				else					node->mj_JoinState = EXEC_MJ_NEXTOUTER;				break;				/*				 * EXEC_MJ_JOINTUPLES means we have two tuples which				 * satisfied the merge clause so we join them and then				 * proceed to get the next inner tuple (EXEC_NEXT_INNER).				 */			case EXEC_MJ_JOINTUPLES:				MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");				node->mj_JoinState = EXEC_MJ_NEXTINNER;				/*				 * Check the extra qual conditions to see if we actually				 * want to return this join tuple.	If not, can proceed				 * with merge.	We must distinguish the additional				 * joinquals (which must pass to consider the tuples				 * "matched" for outer-join logic) from the otherquals				 * (which must pass before we actually return the tuple).				 *				 * We don't bother with a ResetExprContext here, on the				 * assumption that we just did one before checking the				 * merge qual.	One per tuple should be sufficient.  Also,				 * the econtext's tuple pointers were set up before				 * checking the merge qual, so we needn't do it again.				 */				if (node->js.jointype == JOIN_IN &&					node->mj_MatchedOuter)					qualResult = false;				else				{					qualResult = (joinqual == NIL ||								  ExecQual(joinqual, econtext, false));					MJ_DEBUG_QUAL(joinqual, qualResult);				}				if (qualResult)				{					node->mj_MatchedOuter = true;					node->mj_MatchedInner = true;					qualResult = (otherqual == NIL ||								  ExecQual(otherqual, econtext, false));					MJ_DEBUG_QUAL(otherqual, qualResult);					if (qualResult)					{						/*						 * qualification succeeded.  now form the desired						 * projection tuple and return the slot containing						 * it.						 */						TupleTableSlot *result;						ExprDoneCond isDone;						MJ_printf("ExecMergeJoin: returning tuple\n");						result = ExecProject(node->js.ps.ps_ProjInfo,											 &isDone);						if (isDone != ExprEndResult)						{							node->js.ps.ps_TupFromTlist =								(isDone == ExprMultipleResult);							return result;						}					}				}				break;				/*				 * EXEC_MJ_NEXTINNER means advance the inner scan to the				 * next tuple. If the tuple is not nil, we then proceed to				 * test it against the join qualification.				 *				 * Before advancing, we check to see if we must emit an				 * outer-join fill tuple for this inner tuple.				 */			case EXEC_MJ_NEXTINNER:				MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\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 (TupIsNull(innerTupleSlot))					node->mj_JoinState = EXEC_MJ_NEXTOUTER;				else					node->mj_JoinState = EXEC_MJ_JOINTEST;				break;				/*-------------------------------------------				 * EXEC_MJ_NEXTOUTER means				 *				 *				outer inner				 * outer tuple -  5		5  - marked tuple				 *				  5		5				 *				  6		6  - inner tuple				 *				  7		7				 *				 * we know we just bumped into the				 * first inner tuple > current outer tuple				 * so get a new outer tuple and then				 * proceed to test it against the marked tuple				 * (EXEC_MJ_TESTOUTER)				 *				 * Before advancing, we check to see if we must emit an				 * outer-join fill tuple for this outer tuple.				 *------------------------------------------------				 */			case EXEC_MJ_NEXTOUTER:				MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n");				if (doFillOuter && !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 the outer tuple is null then we are done with the				 * join, unless we have inner tuples we need to null-fill.				 */				if (TupIsNull(outerTupleSlot))				{					MJ_printf("ExecMergeJoin: end of outer subplan\n");					innerTupleSlot = node->mj_InnerTupleSlot;					if (doFillInner && !TupIsNull(innerTupleSlot))					{						/*						 * Need to emit right-join tuples for remaining						 * inner tuples.						 */						node->mj_JoinState = EXEC_MJ_ENDOUTER;						break;					}					/* Otherwise we're done. */					return NULL;				}				node->mj_JoinState = EXEC_MJ_TESTOUTER;				break;				/*--------------------------------------------------------				 * EXEC_MJ_TESTOUTER If the new outer tuple and the marked				 * tuple satisfy the merge clause then we know we have				 * duplicates in the outer scan so we have to restore the				 * inner scan to the marked tuple and proceed to join the				 * new outer tuples with the inner tuples (EXEC_MJ_JOINTEST)				 *				 * This is the case when				 *						  outer inner				 *							4	  5  - marked tuple				 *			 outer tuple -	5	  5				 *		 new outer tuple -	5	  5				 *							6	  8  - inner tuple				 *							7	 12				 *				 *				new outer tuple = marked tuple				 *				 *		If the outer tuple fails the test, then we know we have				 *		to proceed to skip outer tuples until outer >= inner				 *		(EXEC_MJ_SKIPOUTER).				 *				 *		This is the case when				 *				 *						  outer inner				 *							5	  5  - marked tuple				 *			 outer tuple -	5	  5				 *		 new outer tuple -	6	  8  - inner tuple				 *							7	 12				 *				 *				 *		 new outer tuple > marked tuple				 *				 *---------------------------------------------------------				 */			case EXEC_MJ_TESTOUTER:				MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");				/*				 * here we compare the outer tuple with the marked inner				 * tuple				 */				ResetExprContext(econtext);				outerTupleSlot = node->mj_OuterTupleSlot;				econtext->ecxt_outertuple = outerTupleSlot;				innerTupleSlot = node->mj_MarkedTupleSlot;				econtext->ecxt_innertuple = innerTupleSlot;				qualResult = ExecQual(mergeclauses, econtext, false);				MJ_DEBUG_QUAL(mergeclauses, qualResult);				if (qualResult)				{					/*					 * the merge clause matched so now we restore the					 * inner scan position to the first mark, and loop					 * back to JOINTEST.  Actually, since we know the					 * mergeclause matches, we can skip JOINTEST and go					 * straight to JOINTUPLES.					 *					 * NOTE: we do not need to worry about the MatchedInner					 * state for the rescanned inner tuples.  We know all					 * of them will match this new outer tuple and					 * therefore won't be emitted as fill tuples.  This					 * works *only* because we require the extra joinquals					 * to be nil when doing a right or full join ---					 * otherwise some of the rescanned tuples might fail					 * the extra joinquals.					 */					ExecRestrPos(innerPlan);					node->mj_JoinState = EXEC_MJ_JOINTUPLES;				}				else				{					/* ----------------					 *	if the inner tuple was nil and the new outer					 *	tuple didn't match the marked outer tuple then					 *	we have the case:					 *					 *			 outer inner					 *			   4	 4	- marked tuple					 * new outer - 5	 4					 *			   6	nil - inner tuple					 *			   7					 *					 *	which means that all subsequent outer tuples will be					 *	larger than our marked inner tuples.  So we're done.					 * ----------------					 */					innerTupleSlot = node->mj_InnerTupleSlot;					if (TupIsNull(innerTupleSlot))					{						if (doFillOuter)						{							/*							 * Need to emit left-join tuples for remaining							 * outer tuples.							 */							node->mj_JoinState = EXEC_MJ_ENDINNER;							break;						}						/* Otherwise we're done. */						return NULL;					}					/* continue on to skip outer tuples */					node->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;				}				break;				/*----------------------------------------------------------				 * EXEC_MJ_SKIPOUTER means skip over tuples in the outer plan				 * until we find an outer tuple >= current inner tuple.				 *				 * For example:				 *				 *				outer inner				 *				  5		5				 *				  5		5				 * outer tuple -  6		8  - inner tuple				 *				  7    12				 *				  8    14				 *				 * we have to advance the outer scan				 * until we find the outer 8.				 *				 * To avoid redundant tests, we divide this into three				 * sub-states: BEGIN, TEST, ADVANCE.				 *----------------------------------------------------------				 */			case EXEC_MJ_SKIPOUTER_BEGIN:				MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_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_SKIPOUTER_TEST;				break;			case EXEC_MJ_SKIPOUTER_TEST:				MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_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,											 outerSkipQual,											 econtext);				MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);				/*				 * compareResult is true as long as we should continue				 * skipping outer tuples.				 */				if (compareResult)				{					node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;					break;				}				/*				 * now check the inner skip qual to see if we should now				 * skip inner tuples... if we fail the inner skip qual,				 * then we know we have a new pair of matching tuples.				 */				compareResult = MergeCompare(mergeclauses,											 innerSkipQual,											 econtext);				MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);				if (compareResult)					node->mj_JoinState = EXEC_MJ_SKIPINNER_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 outer tuple.				 */			case EXEC_MJ_SKIPOUTER_ADVANCE:				MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_ADVANCE\n");				if (doFillOuter && !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 the outer tuple is null then we are done with the				 * join, unless we have inner tuples we need to null-fill.				 */				if (TupIsNull(outerTupleSlot))				{					MJ_printf("ExecMergeJoin: end of outer subplan\n");					innerTupleSlot = node->mj_InnerTupleSlot;					if (doFillInner && !TupIsNull(innerTupleSlot))					{						/*						 * Need to emit right-join tuples for remaining						 * inner tuples.						 */						node->mj_JoinState = EXEC_MJ_ENDOUTER;						break;					}					/* Otherwise we're done. */					return NULL;				}				/*				 * otherwise test the new tuple against the skip qual.				 */				node->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;

⌨️ 快捷键说明

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