📄 nodemergejoin.c
字号:
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 current inner */ node->mj_JoinState = EXEC_MJ_SKIP_TEST; } else { /* Can't match, so fetch next outer tuple */ node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE; } 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. */ 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 */ 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; } /* Compute join values and check for unmatchability */ 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_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. */ 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 */ 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. */ 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 (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); /* * we need two additional econtexts in which we can compute the join * expressions from the left and right input tuples. The node's regular * econtext won't do because it gets reset too often. */ mergestate->mj_OuterEContext = CreateExprContext(estate); mergestate->mj_InnerEContext = CreateExprContext(estate); /* * 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); /* mergeclauses are handled below */ /* * 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: mergestate->mj_FillOuter = false; mergestate->mj_FillInner = false; break; case JOIN_LEFT: mergestate->mj_FillOuter = true; mergestate->mj_FillInner = false; mergestate->mj_NullInnerTupleSlot = ExecInitNullTupleSlot(estate, ExecGetResultType(innerPlanState(mergestate))); break; case JOIN_RIGHT: mergestate->mj_FillOuter = false; mergestate->mj_FillInner = true; 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_FillOuter = true; mergestate->mj_FillInner = true; 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); /* * preprocess the merge clauses */ mergestate->mj_NumClauses = list_length(node->mergeclauses); mergestate->mj_Clauses = MJExamineQuals(node->mergeclauses, (PlanState *) mergestate); /* * initialize join state */ mergestate->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER; 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_OUTER; 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 + -