*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
#include "postgres.h"
+#include "access/heapam.h"
#include "executor/executor.h"
#include "executor/execdefs.h"
#include "executor/nodeMergejoin.h"
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
*
Plan *outerPlan;
TupleTableSlot *outerTupleSlot;
- TupleTableSlot *markedTupleSlot;
-
ExprContext *econtext;
/* ----------------
* 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");
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.
* ----------------
* ******************************** 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;
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
*
* new outer tuple > marked tuple
*
- ****************************
- *
- *
- *
- *
- *
+ * ****************************
*/
case EXEC_MJ_TESTOUTER:
MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");
* ----------------
*/
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
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;
if (qualResult)
{
ExecMarkPos(innerPlan);
- innerTupleSlot = econtext->ecxt_innertuple;
- MarkInnerTuple(innerTupleSlot, mergestate);
+ MarkInnerTuple(econtext->ecxt_innertuple, mergestate);
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
break;
if (qualResult)
{
ExecMarkPos(innerPlan);
- innerTupleSlot = econtext->ecxt_innertuple;
- MarkInnerTuple(innerTupleSlot, mergestate);
+ MarkInnerTuple(econtext->ecxt_innertuple, mergestate);
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
break;
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;
* ----------------
*/
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.
*
*/
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);
+
+}