📄 nodemergejoin.c
字号:
outerPlan = outerPlan((Plan *) node); econtext = mergestate->jstate.cs_ExprContext; mergeclauses = node->mergeclauses; qual = node->join.qual; if (ScanDirectionIsForward(direction)) { outerSkipQual = mergestate->mj_OuterSkipQual; innerSkipQual = mergestate->mj_InnerSkipQual; } else { outerSkipQual = mergestate->mj_InnerSkipQual; innerSkipQual = mergestate->mj_OuterSkipQual; } /* ---------------- * ok, everything is setup.. let's go to work * ---------------- */ if (mergestate->jstate.cs_TupFromTlist) { TupleTableSlot *result; ProjectionInfo *projInfo; bool isDone; projInfo = mergestate->jstate.cs_ProjInfo; result = ExecProject(projInfo, &isDone); if (!isDone) return result; } for (;;) { /* ---------------- * get the current state of the join and do things accordingly. * Note: The join states are highlighted with 32-* comments for * improved readability. * ---------------- */ MJ_dump(econtext, mergestate); switch (mergestate->mj_JoinState) { /* * EXEC_MJ_INITIALIZE means that this is the first time * ExecMergeJoin() has been called and so we have to * initialize the inner, outer and marked tuples as well * as various stuff in the expression context. */ case EXEC_MJ_INITIALIZE: MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n"); /* * Note: at this point, if either of our inner or outer * tuples are nil, then the join ends immediately because * we know one of the subplans is empty. */ innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node); if (TupIsNull(innerTupleSlot)) { MJ_printf("ExecMergeJoin: **** inner tuple is nil ****\n"); return NULL; } outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node); if (TupIsNull(outerTupleSlot)) { MJ_printf("ExecMergeJoin: **** outer tuple is nil ****\n"); return NULL; } /* ---------------- * store the inner and outer tuple in the merge state * ---------------- */ econtext->ecxt_innertuple = innerTupleSlot; econtext->ecxt_outertuple = outerTupleSlot; mergestate->mj_MarkedTupleSlot->ttc_tupleDescriptor = innerTupleSlot->ttc_tupleDescriptor; /* ---------------- * initialize merge join state to skip inner tuples. * ---------------- */ mergestate->mj_JoinState = EXEC_MJ_SKIPINNER; break; /* * EXEC_MJ_JOINMARK means we have just found a new outer * tuple and a possible matching inner tuple. This is the * case after the INITIALIZE, SKIPOUTER or SKIPINNER * states. */ case EXEC_MJ_JOINMARK: MJ_printf("ExecMergeJoin: EXEC_MJ_JOINMARK\n"); ExecMarkPos(innerPlan); MarkInnerTuple(econtext->ecxt_innertuple, mergestate); mergestate->mj_JoinState = EXEC_MJ_JOINTEST; break; /* * EXEC_MJ_JOINTEST means we have two tuples which might * satisfy the merge clause, so we test them. * * 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"); qualResult = ExecQual((List *) mergeclauses, econtext); MJ_DEBUG_QUAL(mergeclauses, qualResult); if (qualResult) mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES; else mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER; break; /* * EXEC_MJ_JOINTUPLES means we have two tuples which * satisified 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"); mergestate->mj_JoinState = EXEC_MJ_NEXTINNER; qualResult = ExecQual((List *) qual, econtext); MJ_DEBUG_QUAL(qual, qualResult); if (qualResult) { /* ---------------- * qualification succeeded. now form the desired * projection tuple and return the slot containing it. * ---------------- */ ProjectionInfo *projInfo; TupleTableSlot *result; bool isDone; MJ_printf("ExecMergeJoin: **** returning tuple ****\n"); projInfo = mergestate->jstate.cs_ProjInfo; result = ExecProject(projInfo, &isDone); mergestate->jstate.cs_TupFromTlist = !isDone; 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. */ case EXEC_MJ_NEXTINNER: MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\n"); /* ---------------- * now we get the next inner tuple, if any * ---------------- */ innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node); MJ_DEBUG_PROC_NODE(innerTupleSlot); econtext->ecxt_innertuple = innerTupleSlot; if (TupIsNull(innerTupleSlot)) mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER; else mergestate->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) *------------------------------------------------ */ case EXEC_MJ_NEXTOUTER: MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n"); outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node); MJ_DEBUG_PROC_NODE(outerTupleSlot); econtext->ecxt_outertuple = outerTupleSlot; /* ---------------- * if the outer tuple is null then we know * we are done with the join * ---------------- */ if (TupIsNull(outerTupleSlot)) { MJ_printf("ExecMergeJoin: **** outer tuple is nil ****\n"); return NULL; } mergestate->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 * by using the marked tuple in place of the inner tuple. * ---------------- */ innerTupleSlot = econtext->ecxt_innertuple; econtext->ecxt_innertuple = mergestate->mj_MarkedTupleSlot; qualResult = ExecQual((List *) mergeclauses, econtext); MJ_DEBUG_QUAL(mergeclauses, qualResult); if (qualResult) { /* * the merge clause matched so now we juggle the slots * back the way they were and proceed to JOINTEST. * * I can't understand why we have to go to JOINTEST and * compare outer tuple with the same inner one again * -> go to JOINTUPLES... - vadim 02/27/98 */ ExecRestrPos(innerPlan);#if 0 mergestate->mj_JoinState = EXEC_MJ_JOINTEST;#endif mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES; } else { econtext->ecxt_innertuple = innerTupleSlot; /* ---------------- * if the inner tuple was nil and the new outer * tuple didn't match the marked outer tuple then * we may 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 inner tuples. * ---------------- */ if (TupIsNull(innerTupleSlot)) {#ifdef ENABLE_OUTER_JOINS if (isLeftJoin) { /* continue on to null fill outer tuples */ mergestate->mj_JoinState = EXEC_MJ_FILLOUTER; break; }#endif MJ_printf("ExecMergeJoin: **** weird case 1 ****\n"); return NULL; } /* continue on to skip outer tuples */ mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER; } 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. *---------------------------------------------------------- */ case EXEC_MJ_SKIPOUTER: MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER\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. * ---------------- */ qualResult = ExecQual((List *) mergeclauses, econtext); MJ_DEBUG_QUAL(mergeclauses, qualResult); if (qualResult) { ExecMarkPos(innerPlan); MarkInnerTuple(econtext->ecxt_innertuple, mergestate); mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES; break; } /* ---------------- * ok, now test the skip qualification * ---------------- */ compareResult = MergeCompare(mergeclauses, outerSkipQual, econtext); MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult); /* ---------------- * compareResult is true as long as we should * continue skipping tuples. * ---------------- */ if (compareResult) {#ifdef ENABLE_OUTER_JOINS /* ---------------- * if this is a left or full outer join, then fill * ---------------- */ if (isLeftJoin) { mergestate->mj_JoinState = EXEC_MJ_FILLOUTER; break; }#endif outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node); MJ_DEBUG_PROC_NODE(outerTupleSlot); econtext->ecxt_outertuple = outerTupleSlot; /* ---------------- * if the outer tuple is null then we know * we are done with the join * ---------------- */ if (TupIsNull(outerTupleSlot)) { MJ_printf("ExecMergeJoin: **** outerTuple is nil ****\n"); return NULL; } /* ---------------- * otherwise test the new tuple against the skip qual. * (we remain in the EXEC_MJ_SKIPOUTER state) * ---------------- */ 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) mergestate->mj_JoinState = EXEC_MJ_SKIPINNER; else mergestate->mj_JoinState = EXEC_MJ_JOINMARK; break; /*----------------------------------------------------------- * EXEC_MJ_SKIPINNER means skip over tuples in the inner plan * until we find an inner tuple > current outer tuple. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -