ExecReScan for MergeJoin.
authorVadim B. Mikheev
Fri, 27 Feb 1998 16:11:28 +0000 (16:11 +0000)
committerVadim B. Mikheev
Fri, 27 Feb 1998 16:11:28 +0000 (16:11 +0000)
Marked inner tuple now is copied into mergestate->mj_MarkedTupleSlot -
no more tricks arround ttc_shouldfree.

src/backend/executor/execAmi.c
src/backend/executor/nodeMergejoin.c

index b2851d83b4a18a6c7d8879101109c81df17936a5..0497c922ef1c2d918c5e3fcaaff4755db2e15918 100644 (file)
@@ -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:
index 005047f337f80c0aa6380b305358bd6cf59ebda3..211160b9e4a2210e8e60742139057049a06302dd 100644 (file)
@@ -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"
 
 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);
+
+}