From 0a1e28494e1a55a2a700bbfce0d839019a6d3fb5 Mon Sep 17 00:00:00 2001
From: "Vadim B. Mikheev" <vadim4o@yahoo.com>
Date: Fri, 27 Feb 1998 16:11:28 +0000
Subject: [PATCH] ExecReScan for MergeJoin.

Marked inner tuple now is copied into mergestate->mj_MarkedTupleSlot -
no more tricks arround ttc_shouldfree.
---
 src/backend/executor/execAmi.c       |   7 +-
 src/backend/executor/nodeMergejoin.c | 156 ++++++++++++---------------
 2 files changed, 75 insertions(+), 88 deletions(-)

diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index b2851d83b4a..0497c922ef1 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 005047f337f..211160b9e4a 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);
+
+}
-- 
GitLab