mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-10-03 05:06:50 +02:00
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
|
* 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/nodeAgg.h"
|
||||||
#include "executor/nodeResult.h"
|
#include "executor/nodeResult.h"
|
||||||
#include "executor/nodeUnique.h"
|
#include "executor/nodeUnique.h"
|
||||||
|
#include "executor/nodeMergejoin.h"
|
||||||
#include "executor/nodeSubplan.h"
|
#include "executor/nodeSubplan.h"
|
||||||
#include "executor/execdebug.h"
|
#include "executor/execdebug.h"
|
||||||
#include "optimizer/internal.h" /* for _TEMP_RELATION_ID_ */
|
#include "optimizer/internal.h" /* for _TEMP_RELATION_ID_ */
|
||||||
@ -366,6 +367,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
ExecReScanSort((Sort *) node, exprCtxt, parent);
|
ExecReScanSort((Sort *) node, exprCtxt, parent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_MergeJoin:
|
||||||
|
ExecReScanMergeJoin((MergeJoin *) node, exprCtxt, parent);
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tee is never used
|
* Tee is never used
|
||||||
case T_Tee:
|
case T_Tee:
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 "postgres.h"
|
||||||
|
|
||||||
|
#include "access/heapam.h"
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "executor/execdefs.h"
|
#include "executor/execdefs.h"
|
||||||
#include "executor/nodeMergejoin.h"
|
#include "executor/nodeMergejoin.h"
|
||||||
@ -86,46 +87,14 @@
|
|||||||
|
|
||||||
static bool MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext);
|
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) \
|
#define MarkInnerTuple(innerTupleSlot, mergestate) \
|
||||||
{ \
|
{ \
|
||||||
bool shouldFree; \
|
ExecStoreTuple(heap_copytuple(innerTupleSlot->val), \
|
||||||
shouldFree = ExecSetSlotPolicy(innerTupleSlot, false); \
|
|
||||||
ExecStoreTuple(innerTupleSlot->val, \
|
|
||||||
mergestate->mj_MarkedTupleSlot, \
|
mergestate->mj_MarkedTupleSlot, \
|
||||||
innerTupleSlot->ttc_buffer, \
|
InvalidBuffer, \
|
||||||
shouldFree); \
|
true); \
|
||||||
ExecIncrSlotBufferRefcnt(innerTupleSlot); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RestoreInnerTuple(innerTupleSlot, markedTupleSlot) \
|
|
||||||
ExecStoreTuple(markedTupleSlot->val, \
|
|
||||||
innerTupleSlot, \
|
|
||||||
markedTupleSlot->ttc_buffer, \
|
|
||||||
false); \
|
|
||||||
ExecIncrSlotBufferRefcnt(innerTupleSlot)
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* MJFormOSortopI
|
* MJFormOSortopI
|
||||||
*
|
*
|
||||||
@ -467,8 +436,6 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
TupleTableSlot *outerTupleSlot;
|
TupleTableSlot *outerTupleSlot;
|
||||||
|
|
||||||
TupleTableSlot *markedTupleSlot;
|
|
||||||
|
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -528,8 +495,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
* means that this is the first time ExecMergeJoin() has
|
* means that this is the first time ExecMergeJoin() has
|
||||||
* been called and so we have to initialize the inner,
|
* been called and so we have to initialize the inner,
|
||||||
* outer and marked tuples as well as various stuff in the
|
* outer and marked tuples as well as various stuff in the
|
||||||
* expression context. ********************************
|
* expression context.
|
||||||
*
|
* ********************************
|
||||||
*/
|
*/
|
||||||
case EXEC_MJ_INITIALIZE:
|
case EXEC_MJ_INITIALIZE:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n");
|
||||||
@ -560,19 +527,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
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 =
|
mergestate->mj_MarkedTupleSlot->ttc_tupleDescriptor =
|
||||||
innerTupleSlot->ttc_tupleDescriptor;
|
innerTupleSlot->ttc_tupleDescriptor;
|
||||||
/*
|
|
||||||
mergestate->mj_MarkedTupleSlot->ttc_execTupDescriptor =
|
|
||||||
innerTupleSlot->ttc_execTupDescriptor;
|
|
||||||
*/
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* initialize merge join state to skip inner tuples.
|
* initialize merge join state to skip inner tuples.
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -584,15 +541,14 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
* ******************************** EXEC_MJ_JOINMARK means
|
* ******************************** EXEC_MJ_JOINMARK means
|
||||||
* we have just found a new outer tuple and a possible
|
* we have just found a new outer tuple and a possible
|
||||||
* matching inner tuple. This is the case after the
|
* matching inner tuple. This is the case after the
|
||||||
* INITIALIZE, SKIPOUTER or SKIPINNER states. ********************************
|
* INITIALIZE, SKIPOUTER or SKIPINNER states.
|
||||||
*
|
* ********************************
|
||||||
*/
|
*/
|
||||||
case EXEC_MJ_JOINMARK:
|
case EXEC_MJ_JOINMARK:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_JOINMARK\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_JOINMARK\n");
|
||||||
ExecMarkPos(innerPlan);
|
ExecMarkPos(innerPlan);
|
||||||
|
|
||||||
innerTupleSlot = econtext->ecxt_innertuple;
|
MarkInnerTuple(econtext->ecxt_innertuple, mergestate);
|
||||||
MarkInnerTuple(innerTupleSlot, mergestate);
|
|
||||||
|
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
|
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
|
||||||
break;
|
break;
|
||||||
@ -724,8 +680,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ******************************** EXEC_MJ_TESTOUTER If
|
* ******************************** EXEC_MJ_TESTOUTER
|
||||||
* the new outer tuple and the marked tuple satisify the
|
* If the new outer tuple and the marked tuple satisify the
|
||||||
* merge clause then we know we have duplicates in the
|
* merge clause then we know we have duplicates in the
|
||||||
* outer scan so we have to restore the inner scan to the
|
* outer scan so we have to restore the inner scan to the
|
||||||
* marked tuple and proceed to join the new outer tuples
|
* marked tuple and proceed to join the new outer tuples
|
||||||
@ -749,12 +705,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
*
|
*
|
||||||
* new outer tuple > marked tuple
|
* new outer tuple > marked tuple
|
||||||
*
|
*
|
||||||
****************************
|
* ****************************
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
case EXEC_MJ_TESTOUTER:
|
case EXEC_MJ_TESTOUTER:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");
|
||||||
@ -765,29 +716,32 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
innerTupleSlot = econtext->ecxt_innertuple;
|
innerTupleSlot = econtext->ecxt_innertuple;
|
||||||
markedTupleSlot = mergestate->mj_MarkedTupleSlot;
|
econtext->ecxt_innertuple = mergestate->mj_MarkedTupleSlot;
|
||||||
econtext->ecxt_innertuple = markedTupleSlot;
|
|
||||||
|
|
||||||
qualResult = ExecQual((List *) mergeclauses, econtext);
|
qualResult = ExecQual((List *) mergeclauses, econtext);
|
||||||
MJ_DEBUG_QUAL(mergeclauses, qualResult);
|
MJ_DEBUG_QUAL(mergeclauses, qualResult);
|
||||||
|
|
||||||
if (qualResult)
|
if (qualResult)
|
||||||
{
|
{
|
||||||
/* ----------------
|
/*
|
||||||
* the merge clause matched so now we juggle the slots
|
* the merge clause matched so now we juggle the slots
|
||||||
* back the way they were and proceed to JOINTEST.
|
* 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);
|
ExecRestrPos(innerPlan);
|
||||||
|
#if 0
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
|
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
|
||||||
|
#endif
|
||||||
|
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* if the inner tuple was nil and the new outer
|
* if the inner tuple was nil and the new outer
|
||||||
* tuple didn't match the marked outer tuple then
|
* tuple didn't match the marked outer tuple then
|
||||||
@ -809,12 +763,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* continue on to skip outer tuples */
|
||||||
* restore the inner tuple and continue on to
|
|
||||||
* skip outer tuples.
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER;
|
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -853,9 +802,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
if (qualResult)
|
if (qualResult)
|
||||||
{
|
{
|
||||||
ExecMarkPos(innerPlan);
|
ExecMarkPos(innerPlan);
|
||||||
innerTupleSlot = econtext->ecxt_innertuple;
|
|
||||||
|
|
||||||
MarkInnerTuple(innerTupleSlot, mergestate);
|
MarkInnerTuple(econtext->ecxt_innertuple, mergestate);
|
||||||
|
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||||
break;
|
break;
|
||||||
@ -958,9 +906,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
if (qualResult)
|
if (qualResult)
|
||||||
{
|
{
|
||||||
ExecMarkPos(innerPlan);
|
ExecMarkPos(innerPlan);
|
||||||
innerTupleSlot = econtext->ecxt_innertuple;
|
|
||||||
|
|
||||||
MarkInnerTuple(innerTupleSlot, mergestate);
|
MarkInnerTuple(econtext->ecxt_innertuple, mergestate);
|
||||||
|
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||||
break;
|
break;
|
||||||
@ -1074,10 +1021,11 @@ bool
|
|||||||
ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
||||||
{
|
{
|
||||||
MergeJoinState *mergestate;
|
MergeJoinState *mergestate;
|
||||||
List *joinclauses;
|
List *joinclauses;
|
||||||
RegProcedure rightsortop;
|
RegProcedure rightsortop;
|
||||||
RegProcedure leftsortop;
|
RegProcedure leftsortop;
|
||||||
RegProcedure sortop;
|
RegProcedure sortop;
|
||||||
|
TupleTableSlot *mjSlot;
|
||||||
|
|
||||||
List *OSortopI;
|
List *OSortopI;
|
||||||
List *ISortopO;
|
List *ISortopO;
|
||||||
@ -1120,7 +1068,13 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &mergestate->jstate);
|
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.
|
* get merge sort operators.
|
||||||
@ -1245,7 +1199,35 @@ ExecEndMergeJoin(MergeJoin *node)
|
|||||||
*/
|
*/
|
||||||
ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot);
|
ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot);
|
||||||
ExecClearTuple(mergestate->mj_MarkedTupleSlot);
|
ExecClearTuple(mergestate->mj_MarkedTupleSlot);
|
||||||
|
pfree (mergestate->mj_MarkedTupleSlot);
|
||||||
|
mergestate->mj_MarkedTupleSlot = NULL;
|
||||||
|
|
||||||
MJ1_printf("ExecEndMergeJoin: %s\n",
|
MJ1_printf("ExecEndMergeJoin: %s\n",
|
||||||
"node processing ended");
|
"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…
Reference in New Issue
Block a user