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

📄 nodemergejoin.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
				 * Set the next state machine state.  The right things will				 * happen whether we return this join tuple or just fall				 * through to continue the state machine execution.				 */				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 while checking the merge				 * qual.  One per tuple should be sufficient.  We do have to				 * set up the econtext links to the tuples for ExecQual to				 * use.				 */				outerTupleSlot = node->mj_OuterTupleSlot;				econtext->ecxt_outertuple = outerTupleSlot;				innerTupleSlot = node->mj_InnerTupleSlot;				econtext->ecxt_innertuple = innerTupleSlot;				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.					 */					TupleTableSlot *result;					node->mj_MatchedInner = true;		/* do it only once */					result = MJFillInner(node);					if (result)						return result;				}				/*				 * now we get the next inner tuple, if any.  If there's none,				 * advance to next outer tuple (which may be able to join to				 * previously marked tuples).				 */				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;					break;				}				/*				 * Load up the new inner tuple's comparison values.  If we				 * see that it contains a NULL and hence can't match any				 * outer tuple, we can skip the comparison and assume the				 * new tuple is greater than current outer.				 */				if (!MJEvalInnerValues(node, innerTupleSlot))				{					node->mj_JoinState = EXEC_MJ_NEXTOUTER;					break;				}				/*				 * Test the new inner tuple to see if it matches outer.				 *				 * If they do match, then we join them and move on to the next				 * inner tuple (EXEC_MJ_JOINTUPLES).				 *				 * If they do not match then advance to next outer tuple.				 */				compareResult = MJCompare(node);				MJ_DEBUG_COMPARE(compareResult);				if (compareResult == 0)					node->mj_JoinState = EXEC_MJ_JOINTUPLES;				else				{					Assert(compareResult < 0);					node->mj_JoinState = EXEC_MJ_NEXTOUTER;				}				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 (or possibly				 * the end of the inner stream)				 * 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.					 */					TupleTableSlot *result;					node->mj_MatchedOuter = true;		/* do it only once */					result = MJFillOuter(node);					if (result)						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;				}				/* Compute join values and check for unmatchability */				if (MJEvalOuterValues(node))				{					/* Go test the new tuple against the marked tuple */					node->mj_JoinState = EXEC_MJ_TESTOUTER;				}				else				{					/* Can't match, so fetch next outer tuple */					node->mj_JoinState = EXEC_MJ_NEXTOUTER;				}				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 tuple with the inner tuples.				 *				 * 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 are done				 * with the marked tuples, and we have to look for a				 * match to the current inner tuple.  So we will				 * proceed to skip outer tuples until outer >= inner				 * (EXEC_MJ_SKIP_TEST).				 *				 *		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 must compare the outer tuple with the marked inner				 * tuple.  (We can ignore the result of MJEvalInnerValues,				 * since the marked inner tuple is certainly matchable.)				 */				innerTupleSlot = node->mj_MarkedTupleSlot;				(void) MJEvalInnerValues(node, innerTupleSlot);				compareResult = MJCompare(node);				MJ_DEBUG_COMPARE(compareResult);				if (compareResult == 0)				{					/*					 * the merge clause matched so now we restore the inner					 * scan position to the first mark, and go join that tuple					 * (and any following ones) to the new outer.					 *					 * 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);					/*					 * ExecRestrPos probably should give us back a new Slot,					 * but since it doesn't, use the marked slot.  (The					 * previously returned mj_InnerTupleSlot cannot be assumed					 * to hold the required tuple.)					 */					node->mj_InnerTupleSlot = innerTupleSlot;					/* we need not do MJEvalInnerValues again */					node->mj_JoinState = EXEC_MJ_JOINTUPLES;				}				else				{					/* ----------------					 *	if the new outer tuple didn't match the marked inner					 *	tuple then we have a case like:					 *					 *			 outer inner					 *			   4	 4	- marked tuple					 * new outer - 5	 4					 *			   6	 5	- inner tuple					 *			   7					 *					 *	which means that all subsequent outer tuples will be					 *	larger than our marked inner tuples.  So we need not					 *	revisit any of the marked tuples but can proceed to					 *	look for a match to the current inner.	If there's					 *	no more inners, we are done.					 * ----------------					 */					Assert(compareResult > 0);					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;					}					/* reload comparison data for current inner */					if (MJEvalInnerValues(node, innerTupleSlot))					{						/* proceed to compare it to the current outer */						node->mj_JoinState = EXEC_MJ_SKIP_TEST;					}					else					{						/*						 * current inner can't possibly match any outer;						 * better to advance the inner scan than the outer.						 */						node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;					}				}				break;				/*----------------------------------------------------------				 * EXEC_MJ_SKIP means compare tuples and if they do not				 * match, skip whichever is lesser.				 *				 * 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.				 *				 * On the other hand:				 *				 *				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.				 *----------------------------------------------------------				 */			case EXEC_MJ_SKIP_TEST:				MJ_printf("ExecMergeJoin: EXEC_MJ_SKIP_TEST\n");				/*				 * before we advance, make sure the current tuples do not				 * satisfy the mergeclauses.  If they do, then we update the				 * marked tuple position and go join them.				 */				compareResult = MJCompare(node);				MJ_DEBUG_COMPARE(compareResult);				if (compareResult == 0)				{					ExecMarkPos(innerPlan);					MarkInnerTuple(node->mj_InnerTupleSlot, node);					node->mj_JoinState = EXEC_MJ_JOINTUPLES;				}				else if (compareResult < 0)					node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;				else					/* compareResult > 0 */					node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;				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.					 */					TupleTableSlot *result;					node->mj_MatchedOuter = true;		/* do it only once */					result = MJFillOuter(node);					if (result)

⌨️ 快捷键说明

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