📄 nodemergejoin.c
字号:
* 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. * *------------------------------------------------------- */ case EXEC_MJ_SKIPINNER: MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER\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, innerSkipQual, econtext); MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult); /* ---------------- * compareResult is true as long as we should * continue skipping tuples. * ---------------- */ if (compareResult) {#ifdef ENABLE_OUTER_JOINS /* ---------------- * if this is a right or full outer join, then fill * ---------------- */ if (isRightJoin) { mergestate->mj_JoinState = EXEC_MJ_FILLINNER; break; }#endif /* ---------------- * now try and get a new inner tuple * ---------------- */ innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node); MJ_DEBUG_PROC_NODE(innerTupleSlot); econtext->ecxt_innertuple = innerTupleSlot; /* ---------------- * if the inner tuple is null then we know * we have to restore the inner scan * and advance to the next outer tuple * ---------------- */ if (TupIsNull(innerTupleSlot)) { /* ---------------- * this is an interesting case.. all our * inner tuples are smaller then our outer * tuples so we never found an inner tuple * to mark. * * outer inner * outer tuple - 5 4 * 5 4 * 6 nil - inner tuple * 7 * * This means the join should end. * ---------------- */ MJ_printf("ExecMergeJoin: **** weird case 2 ****\n"); return NULL; } /* ---------------- * otherwise test the new tuple against the skip qual. * (we remain in the EXEC_MJ_SKIPINNER state) * ---------------- */ break; } /* ---------------- * compare finally failed and we have stopped skipping * inner tuples so now check the outer skip qual * to see if we should now skip outer tuples... * ---------------- */ compareResult = MergeCompare(mergeclauses, outerSkipQual, econtext); MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult); if (compareResult) mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER; else mergestate->mj_JoinState = EXEC_MJ_JOINMARK; break;#ifdef ENABLE_OUTER_JOINS /* * EXEC_MJ_FILLINNER means we have an unmatched inner * tuple which must be null-expanded into the projection * tuple. get the next inner tuple and reset markers * (EXEC_MJ_JOINMARK). */ case EXEC_MJ_FILLINNER: MJ_printf("ExecMergeJoin: EXEC_MJ_FILLINNER\n"); mergestate->mj_JoinState = EXEC_MJ_JOINMARK; /* ---------------- * project the inner tuple into the result * ---------------- */ MJ_printf("ExecMergeJoin: project inner tuple into the result (not yet implemented)\n"); /* ---------------- * now skip this inner tuple * ---------------- */ innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node); MJ_DEBUG_PROC_NODE(innerTupleSlot); econtext->ecxt_innertuple = innerTupleSlot; /* ---------------- * if the inner tuple is null then we know * we have to restore the inner scan * and advance to the next outer tuple * ---------------- */ if (TupIsNull(innerTupleSlot)) { if (isLeftJoin && !TupIsNull(outerTupleSlot)) { mergestate->mj_JoinState = EXEC_MJ_FILLOUTER; MJ_printf("ExecMergeJoin: try to complete outer fill\n"); break; } MJ_printf("ExecMergeJoin: **** weird case 2 ****\n"); return NULL; } /* ---------------- * otherwise test the new tuple against the skip qual. * (we move to the EXEC_MJ_JOINMARK state) * ---------------- */ break; /* * EXEC_MJ_FILLOUTER means we have an unmatched outer * tuple which must be null-expanded into the projection * tuple. get the next outer tuple and reset markers * (EXEC_MJ_JOINMARK). */ case EXEC_MJ_FILLOUTER: MJ_printf("ExecMergeJoin: EXEC_MJ_FILLOUTER\n"); mergestate->mj_JoinState = EXEC_MJ_JOINMARK; /* ---------------- * project the outer tuple into the result * ---------------- */ MJ_printf("ExecMergeJoin: project outer tuple into the result (not yet implemented)\n"); /* ---------------- * now skip this outer tuple * ---------------- */ 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 left half of the join * ---------------- */ if (TupIsNull(outerTupleSlot)) { if (isRightJoin && !TupIsNull(innerTupleSlot)) { mergestate->mj_JoinState = EXEC_MJ_FILLINNER; MJ_printf("ExecMergeJoin: try to complete inner fill\n"); break; } MJ_printf("ExecMergeJoin: **** outerTuple is nil ****\n"); return NULL; } /* ---------------- * otherwise test the new tuple against the skip qual. * (we move to the EXEC_MJ_JOINMARK state) * ---------------- */ break;#endif /* * if we get here it means our code is fouled up and so we * just end the join prematurely. */ default: elog(NOTICE, "ExecMergeJoin: invalid join state. aborting"); return NULL; } }}/* ---------------------------------------------------------------- * ExecInitMergeJoin * * old comments * Creates the run-time state information for the node and * sets the relation id to contain relevant decriptors. * ---------------------------------------------------------------- */boolExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent){ MergeJoinState *mergestate; List *joinclauses; TupleTableSlot *mjSlot; MJ1_printf("ExecInitMergeJoin: %s\n", "initializing node"); /* ---------------- * assign the node's execution state and * get the range table and direction from it * ---------------- */ node->join.state = estate; /* ---------------- * create new merge state for node * ---------------- */ mergestate = makeNode(MergeJoinState); mergestate->mj_OuterSkipQual = NIL; mergestate->mj_InnerSkipQual = NIL; mergestate->mj_JoinState = 0; mergestate->mj_MarkedTupleSlot = NULL; node->mergestate = mergestate; /* ---------------- * Miscellaneous initialization * * + assign node's base_id * + assign debugging hooks and * + create expression context for node * ---------------- */ ExecAssignNodeBaseInfo(estate, &mergestate->jstate, parent); ExecAssignExprContext(estate, &mergestate->jstate);#define MERGEJOIN_NSLOTS 2 /* ---------------- * tuple table initialization * ---------------- */ ExecInitResultTupleSlot(estate, &mergestate->jstate); mjSlot = (TupleTableSlot *) palloc(sizeof(TupleTableSlot)); mjSlot->val = NULL; mjSlot->ttc_shouldFree = true; mjSlot->ttc_tupleDescriptor = NULL; mjSlot->ttc_whichplan = -1; mjSlot->ttc_descIsNew = true; mergestate->mj_MarkedTupleSlot = mjSlot; /* ---------------- * form merge skip qualifications * ---------------- */ joinclauses = node->mergeclauses; mergestate->mj_OuterSkipQual = MJFormSkipQual(joinclauses, "<"); mergestate->mj_InnerSkipQual = MJFormSkipQual(joinclauses, ">"); 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; /* ---------------- * initialize subplans * ---------------- */ ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node); ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node); /* ---------------- * initialize tuple type and projection info * ---------------- */ ExecAssignResultTypeFromTL((Plan *) node, &mergestate->jstate); ExecAssignProjectionInfo((Plan *) node, &mergestate->jstate); mergestate->jstate.cs_TupFromTlist = false; /* ---------------- * initialization successful * ---------------- */ MJ1_printf("ExecInitMergeJoin: %s\n", "node initialized"); return TRUE;}intExecCountSlotsMergeJoin(MergeJoin *node){ return ExecCountSlotsNode(outerPlan((Plan *) node)) + ExecCountSlotsNode(innerPlan((Plan *) node)) + MERGEJOIN_NSLOTS;}/* ---------------------------------------------------------------- * ExecEndMergeJoin * * old comments * frees storage allocated through C routines. * ---------------------------------------------------------------- */voidExecEndMergeJoin(MergeJoin *node){ MergeJoinState *mergestate; MJ1_printf("ExecEndMergeJoin: %s\n", "ending node processing"); /* ---------------- * get state information from the node * ---------------- */ mergestate = node->mergestate; /* ---------------- * Free the projection info and the scan attribute info * * Note: we don't ExecFreeResultType(mergestate) * because the rule manager depends on the tupType * returned by ExecMain(). So for now, this * is freed at end-transaction time. -cim 6/2/91 * ---------------- */ ExecFreeProjectionInfo(&mergestate->jstate); /* ---------------- * shut down the subplans * ---------------- */ ExecEndNode((Plan *) innerPlan((Plan *) node), (Plan *) node); ExecEndNode((Plan *) outerPlan((Plan *) node), (Plan *) node); /* ---------------- * clean out the tuple table so that we don't try and * pfree the marked tuples.. see HACK ALERT at the top of * this file. * ---------------- */ ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot); ExecClearTuple(mergestate->mj_MarkedTupleSlot); pfree(mergestate->mj_MarkedTupleSlot); mergestate->mj_MarkedTupleSlot = NULL; MJ1_printf("ExecEndMergeJoin: %s\n", "node processing ended");}voidExecReScanMergeJoin(MergeJoin *node, ExprContext *exprCtxt, Plan *parent){ MergeJoinState *mergestate = node->mergestate; TupleTableSlot *mjSlot = mergestate->mj_MarkedTupleSlot; ExecClearTuple(mjSlot); mjSlot->val = NULL; mjSlot->ttc_shouldFree = true; mjSlot->ttc_tupleDescriptor = NULL; mjSlot->ttc_whichplan = -1; mjSlot->ttc_descIsNew = true; mergestate->mj_JoinState = EXEC_MJ_INITIALIZE; /* * if chgParam of subnodes is not null then plans will be re-scanned * by first ExecProcNode. */ if (((Plan *) node)->lefttree->chgParam == NULL) ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node); if (((Plan *) node)->righttree->chgParam == NULL) ExecReScan(((Plan *) node)->righttree, exprCtxt, (Plan *) node);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -