ExecReScan for MergeJoin.
Marked inner tuple now is copied into mergestate->mj_MarkedTupleSlot - no more tricks arround ttc_shouldfree.
This commit is contained in:
parent
b0571ebf65
commit
0a1e28494e
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user