From: Vadim B. Mikheev Date: Fri, 27 Feb 1998 16:11:28 +0000 (+0000) Subject: ExecReScan for MergeJoin. X-Git-Tag: REL6_3~36 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0a1e28494e1a55a2a700bbfce0d839019a6d3fb5;p=postgresql ExecReScan for MergeJoin. Marked inner tuple now is copied into mergestate->mj_MarkedTupleSlot - no more tricks arround ttc_shouldfree. --- diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index b2851d83b4..0497c922ef 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.19 1998/02/26 04:31:08 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.20 1998/02/27 16:11:26 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -44,6 +44,7 @@ #include "executor/nodeAgg.h" #include "executor/nodeResult.h" #include "executor/nodeUnique.h" +#include "executor/nodeMergejoin.h" #include "executor/nodeSubplan.h" #include "executor/execdebug.h" #include "optimizer/internal.h" /* for _TEMP_RELATION_ID_ */ @@ -366,6 +367,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent) ExecReScanSort((Sort *) node, exprCtxt, parent); break; + case T_MergeJoin: + ExecReScanMergeJoin((MergeJoin *) node, exprCtxt, parent); + break; + /* * Tee is never used case T_Tee: diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index 005047f337..211160b9e4 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.13 1998/02/26 04:31:30 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.14 1998/02/27 16:11:28 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -77,6 +77,7 @@ */ #include "postgres.h" +#include "access/heapam.h" #include "executor/executor.h" #include "executor/execdefs.h" #include "executor/nodeMergejoin.h" @@ -86,46 +87,14 @@ static bool MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext); -/* ---------------------------------------------------------------- - * MarkInnerTuple and RestoreInnerTuple macros - * - * when we "mark" a tuple, we place a pointer to it - * in the marked tuple slot. now there are two pointers - * to this tuple and we don't want it to be freed until - * next time we mark a tuple, so we move the policy to - * the marked tuple slot and set the inner tuple slot policy - * to false. - * - * But, when we restore the inner tuple, the marked tuple - * retains the policy. Basically once a tuple is marked, it - * should only be freed when we mark another tuple. -cim 9/27/90 - * - * Note: now that we store buffers in the tuple table, - * we have to also increment buffer reference counts - * correctly whenever we propagate an additional pointer - * to a buffer item. Later, when ExecStoreTuple() is - * called again on this slot, the refcnt is decremented - * when the old tuple is replaced. - * ---------------------------------------------------------------- - */ #define MarkInnerTuple(innerTupleSlot, mergestate) \ { \ - bool shouldFree; \ - shouldFree = ExecSetSlotPolicy(innerTupleSlot, false); \ - ExecStoreTuple(innerTupleSlot->val, \ + ExecStoreTuple(heap_copytuple(innerTupleSlot->val), \ mergestate->mj_MarkedTupleSlot, \ - innerTupleSlot->ttc_buffer, \ - shouldFree); \ - ExecIncrSlotBufferRefcnt(innerTupleSlot); \ + InvalidBuffer, \ + true); \ } -#define RestoreInnerTuple(innerTupleSlot, markedTupleSlot) \ - ExecStoreTuple(markedTupleSlot->val, \ - innerTupleSlot, \ - markedTupleSlot->ttc_buffer, \ - false); \ - ExecIncrSlotBufferRefcnt(innerTupleSlot) - /* ---------------------------------------------------------------- * MJFormOSortopI * @@ -467,8 +436,6 @@ ExecMergeJoin(MergeJoin *node) Plan *outerPlan; TupleTableSlot *outerTupleSlot; - TupleTableSlot *markedTupleSlot; - ExprContext *econtext; /* ---------------- @@ -528,8 +495,8 @@ ExecMergeJoin(MergeJoin *node) * 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. ******************************** - * + * expression context. + * ******************************** */ case EXEC_MJ_INITIALIZE: MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n"); @@ -560,19 +527,9 @@ ExecMergeJoin(MergeJoin *node) econtext->ecxt_innertuple = innerTupleSlot; econtext->ecxt_outertuple = outerTupleSlot; - /* ---------------- - * set the marked tuple to nil - * and initialize its tuple descriptor atttributes. - * -jeff 10 july 1991 - * ---------------- - */ - ExecClearTuple(mergestate->mj_MarkedTupleSlot); mergestate->mj_MarkedTupleSlot->ttc_tupleDescriptor = innerTupleSlot->ttc_tupleDescriptor; -/* - mergestate->mj_MarkedTupleSlot->ttc_execTupDescriptor = - innerTupleSlot->ttc_execTupDescriptor; -*/ + /* ---------------- * initialize merge join state to skip inner tuples. * ---------------- @@ -584,15 +541,14 @@ ExecMergeJoin(MergeJoin *node) * ******************************** 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. ******************************** - * + * INITIALIZE, SKIPOUTER or SKIPINNER states. + * ******************************** */ case EXEC_MJ_JOINMARK: MJ_printf("ExecMergeJoin: EXEC_MJ_JOINMARK\n"); ExecMarkPos(innerPlan); - innerTupleSlot = econtext->ecxt_innertuple; - MarkInnerTuple(innerTupleSlot, mergestate); + MarkInnerTuple(econtext->ecxt_innertuple, mergestate); mergestate->mj_JoinState = EXEC_MJ_JOINTEST; break; @@ -724,8 +680,8 @@ ExecMergeJoin(MergeJoin *node) break; /* - * ******************************** EXEC_MJ_TESTOUTER If - * the new outer tuple and the marked tuple satisify the + * ******************************** EXEC_MJ_TESTOUTER + * If the new outer tuple and the marked tuple satisify 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 @@ -749,12 +705,7 @@ ExecMergeJoin(MergeJoin *node) * * new outer tuple > marked tuple * - **************************** - * - * - * - * - * + * **************************** */ case EXEC_MJ_TESTOUTER: MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n"); @@ -765,29 +716,32 @@ ExecMergeJoin(MergeJoin *node) * ---------------- */ innerTupleSlot = econtext->ecxt_innertuple; - markedTupleSlot = mergestate->mj_MarkedTupleSlot; - econtext->ecxt_innertuple = markedTupleSlot; + 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 */ - econtext->ecxt_innertuple = innerTupleSlot; - - RestoreInnerTuple(innerTupleSlot, markedTupleSlot); 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 @@ -809,12 +763,7 @@ ExecMergeJoin(MergeJoin *node) return NULL; } - /* ---------------- - * restore the inner tuple and continue on to - * skip outer tuples. - * ---------------- - */ - econtext->ecxt_innertuple = innerTupleSlot; + /* continue on to skip outer tuples */ mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER; } break; @@ -853,9 +802,8 @@ ExecMergeJoin(MergeJoin *node) if (qualResult) { ExecMarkPos(innerPlan); - innerTupleSlot = econtext->ecxt_innertuple; - MarkInnerTuple(innerTupleSlot, mergestate); + MarkInnerTuple(econtext->ecxt_innertuple, mergestate); mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES; break; @@ -958,9 +906,8 @@ ExecMergeJoin(MergeJoin *node) if (qualResult) { ExecMarkPos(innerPlan); - innerTupleSlot = econtext->ecxt_innertuple; - MarkInnerTuple(innerTupleSlot, mergestate); + MarkInnerTuple(econtext->ecxt_innertuple, mergestate); mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES; break; @@ -1074,10 +1021,11 @@ bool ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent) { MergeJoinState *mergestate; - List *joinclauses; - RegProcedure rightsortop; - RegProcedure leftsortop; - RegProcedure sortop; + List *joinclauses; + RegProcedure rightsortop; + RegProcedure leftsortop; + RegProcedure sortop; + TupleTableSlot *mjSlot; List *OSortopI; List *ISortopO; @@ -1120,8 +1068,14 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent) * ---------------- */ ExecInitResultTupleSlot(estate, &mergestate->jstate); - ExecInitMarkedTupleSlot(estate, mergestate); - + 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; + /* ---------------- * get merge sort operators. * @@ -1245,7 +1199,35 @@ ExecEndMergeJoin(MergeJoin *node) */ 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"); } + +void +ExecReScanMergeJoin(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); + +}