77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.13 1998/02/26 04:31:30 momjian Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.14 1998/02/27 16:11:28 vadim Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
7777 */
7878#include "postgres.h"
7979
80+ #include "access/heapam.h"
8081#include "executor/executor.h"
8182#include "executor/execdefs.h"
8283#include "executor/nodeMergejoin.h"
8687
8788static bool MergeCompare (List * eqQual ,List * compareQual ,ExprContext * econtext );
8889
89- /* ----------------------------------------------------------------
90- *MarkInnerTuple and RestoreInnerTuple macros
91- *
92- *when we "mark" a tuple, we place a pointer to it
93- *in the marked tuple slot. now there are two pointers
94- *to this tuple and we don't want it to be freed until
95- *next time we mark a tuple, so we move the policy to
96- *the marked tuple slot and set the inner tuple slot policy
97- *to false.
98- *
99- *But, when we restore the inner tuple, the marked tuple
100- *retains the policy. Basically once a tuple is marked, it
101- *should only be freed when we mark another tuple. -cim 9/27/90
102- *
103- *Note: now that we store buffers in the tuple table,
104- * we have to also increment buffer reference counts
105- * correctly whenever we propagate an additional pointer
106- * to a buffer item. Later, when ExecStoreTuple() is
107- * called again on this slot, the refcnt is decremented
108- * when the old tuple is replaced.
109- * ----------------------------------------------------------------
110- */
11190#define MarkInnerTuple (innerTupleSlot ,mergestate ) \
11291{ \
113- bool shouldFree; \
114- shouldFree = ExecSetSlotPolicy(innerTupleSlot, false); \
115- ExecStoreTuple(innerTupleSlot->val, \
92+ ExecStoreTuple(heap_copytuple(innerTupleSlot->val), \
11693 mergestate->mj_MarkedTupleSlot, \
117- innerTupleSlot->ttc_buffer, \
118- shouldFree); \
119- ExecIncrSlotBufferRefcnt(innerTupleSlot); \
94+ InvalidBuffer, \
95+ true); \
12096}
12197
122- #define RestoreInnerTuple (innerTupleSlot ,markedTupleSlot ) \
123- ExecStoreTuple(markedTupleSlot->val, \
124- innerTupleSlot, \
125- markedTupleSlot->ttc_buffer, \
126- false); \
127- ExecIncrSlotBufferRefcnt(innerTupleSlot)
128-
12998/* ----------------------------------------------------------------
13099 *MJFormOSortopI
131100 *
@@ -467,8 +436,6 @@ ExecMergeJoin(MergeJoin *node)
467436Plan * outerPlan ;
468437TupleTableSlot * outerTupleSlot ;
469438
470- TupleTableSlot * markedTupleSlot ;
471-
472439ExprContext * econtext ;
473440
474441/* ----------------
@@ -528,8 +495,8 @@ ExecMergeJoin(MergeJoin *node)
528495 * means that this is the first time ExecMergeJoin() has
529496 * been called and so we have to initialize the inner,
530497 * outer and marked tuples as well as various stuff in the
531- * expression context. ********************************
532- *
498+ * expression context.
499+ * ********************************
533500 */
534501case EXEC_MJ_INITIALIZE :
535502MJ_printf ("ExecMergeJoin: EXEC_MJ_INITIALIZE\n" );
@@ -560,19 +527,9 @@ ExecMergeJoin(MergeJoin *node)
560527econtext -> ecxt_innertuple = innerTupleSlot ;
561528econtext -> ecxt_outertuple = outerTupleSlot ;
562529
563- /* ----------------
564- * set the marked tuple to nil
565- * and initialize its tuple descriptor atttributes.
566- *-jeff 10 july 1991
567- * ----------------
568- */
569- ExecClearTuple (mergestate -> mj_MarkedTupleSlot );
570530mergestate -> mj_MarkedTupleSlot -> ttc_tupleDescriptor =
571531innerTupleSlot -> ttc_tupleDescriptor ;
572- /*
573- mergestate->mj_MarkedTupleSlot->ttc_execTupDescriptor =
574- innerTupleSlot->ttc_execTupDescriptor;
575- */
532+
576533/* ----------------
577534 *initialize merge join state to skip inner tuples.
578535 * ----------------
@@ -584,15 +541,14 @@ ExecMergeJoin(MergeJoin *node)
584541 * ******************************** EXEC_MJ_JOINMARK means
585542 * we have just found a new outer tuple and a possible
586543 * matching inner tuple. This is the case after the
587- * INITIALIZE, SKIPOUTER or SKIPINNER states.********************************
588- *
544+ * INITIALIZE, SKIPOUTER or SKIPINNER states.
545+ * ********************************
589546 */
590547case EXEC_MJ_JOINMARK :
591548MJ_printf ("ExecMergeJoin: EXEC_MJ_JOINMARK\n" );
592549ExecMarkPos (innerPlan );
593550
594- innerTupleSlot = econtext -> ecxt_innertuple ;
595- MarkInnerTuple (innerTupleSlot ,mergestate );
551+ MarkInnerTuple (econtext -> ecxt_innertuple ,mergestate );
596552
597553mergestate -> mj_JoinState = EXEC_MJ_JOINTEST ;
598554break ;
@@ -724,8 +680,8 @@ ExecMergeJoin(MergeJoin *node)
724680break ;
725681
726682/*
727- * ******************************** EXEC_MJ_TESTOUTERIf
728- * the new outer tuple and the marked tuple satisify the
683+ * ******************************** EXEC_MJ_TESTOUTER
684+ *If the new outer tuple and the marked tuple satisify the
729685 * merge clause then we know we have duplicates in the
730686 * outer scan so we have to restore the inner scan to the
731687 * marked tuple and proceed to join the new outer tuples
@@ -749,12 +705,7 @@ ExecMergeJoin(MergeJoin *node)
749705 *
750706 * new outer tuple > marked tuple
751707 *
752- ****************************
753- *
754- *
755- *
756- *
757- *
708+ * ****************************
758709 */
759710case EXEC_MJ_TESTOUTER :
760711MJ_printf ("ExecMergeJoin: EXEC_MJ_TESTOUTER\n" );
@@ -765,29 +716,32 @@ ExecMergeJoin(MergeJoin *node)
765716 * ----------------
766717 */
767718innerTupleSlot = econtext -> ecxt_innertuple ;
768- markedTupleSlot = mergestate -> mj_MarkedTupleSlot ;
769- econtext -> ecxt_innertuple = markedTupleSlot ;
719+ econtext -> ecxt_innertuple = mergestate -> mj_MarkedTupleSlot ;
770720
771721qualResult = ExecQual ((List * )mergeclauses ,econtext );
772722MJ_DEBUG_QUAL (mergeclauses ,qualResult );
773723
774724if (qualResult )
775725{
776- /*----------------
726+ /*
777727 *the merge clause matched so now we juggle the slots
778728 *back the way they were and proceed to JOINTEST.
779- * ----------------
729+ *
730+ * I can't understand why we have to go to JOINTEST
731+ * and compare outer tuple with the same inner one
732+ * again -> go to JOINTUPLES...- vadim 02/27/98
780733 */
781- econtext -> ecxt_innertuple = innerTupleSlot ;
782-
783- RestoreInnerTuple (innerTupleSlot ,markedTupleSlot );
784734
785735ExecRestrPos (innerPlan );
736+ #if 0
786737mergestate -> mj_JoinState = EXEC_MJ_JOINTEST ;
738+ #endif
739+ mergestate -> mj_JoinState = EXEC_MJ_JOINTUPLES ;
787740
788741}
789742else
790743{
744+ econtext -> ecxt_innertuple = innerTupleSlot ;
791745/* ----------------
792746 *if the inner tuple was nil and the new outer
793747 *tuple didn't match the marked outer tuple then
@@ -809,12 +763,7 @@ ExecMergeJoin(MergeJoin *node)
809763return NULL ;
810764}
811765
812- /* ----------------
813- *restore the inner tuple and continue on to
814- *skip outer tuples.
815- * ----------------
816- */
817- econtext -> ecxt_innertuple = innerTupleSlot ;
766+ /*continue on to skip outer tuples */
818767mergestate -> mj_JoinState = EXEC_MJ_SKIPOUTER ;
819768}
820769break ;
@@ -853,9 +802,8 @@ ExecMergeJoin(MergeJoin *node)
853802if (qualResult )
854803{
855804ExecMarkPos (innerPlan );
856- innerTupleSlot = econtext -> ecxt_innertuple ;
857805
858- MarkInnerTuple (innerTupleSlot ,mergestate );
806+ MarkInnerTuple (econtext -> ecxt_innertuple ,mergestate );
859807
860808mergestate -> mj_JoinState = EXEC_MJ_JOINTUPLES ;
861809break ;
@@ -958,9 +906,8 @@ ExecMergeJoin(MergeJoin *node)
958906if (qualResult )
959907{
960908ExecMarkPos (innerPlan );
961- innerTupleSlot = econtext -> ecxt_innertuple ;
962909
963- MarkInnerTuple (innerTupleSlot ,mergestate );
910+ MarkInnerTuple (econtext -> ecxt_innertuple ,mergestate );
964911
965912mergestate -> mj_JoinState = EXEC_MJ_JOINTUPLES ;
966913break ;
@@ -1074,10 +1021,11 @@ bool
10741021ExecInitMergeJoin (MergeJoin * node ,EState * estate ,Plan * parent )
10751022{
10761023MergeJoinState * mergestate ;
1077- List * joinclauses ;
1078- RegProcedure rightsortop ;
1079- RegProcedure leftsortop ;
1080- RegProcedure sortop ;
1024+ List * joinclauses ;
1025+ RegProcedure rightsortop ;
1026+ RegProcedure leftsortop ;
1027+ RegProcedure sortop ;
1028+ TupleTableSlot * mjSlot ;
10811029
10821030List * OSortopI ;
10831031List * ISortopO ;
@@ -1120,8 +1068,14 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
11201068 * ----------------
11211069 */
11221070ExecInitResultTupleSlot (estate ,& mergestate -> jstate );
1123- ExecInitMarkedTupleSlot (estate ,mergestate );
1124-
1071+ mjSlot = (TupleTableSlot * )palloc (sizeof (TupleTableSlot ));
1072+ mjSlot -> val = NULL ;
1073+ mjSlot -> ttc_shouldFree = true;
1074+ mjSlot -> ttc_tupleDescriptor = NULL ;
1075+ mjSlot -> ttc_whichplan = -1 ;
1076+ mjSlot -> ttc_descIsNew = true;
1077+ mergestate -> mj_MarkedTupleSlot = mjSlot ;
1078+
11251079/* ----------------
11261080 *get merge sort operators.
11271081 *
@@ -1245,7 +1199,35 @@ ExecEndMergeJoin(MergeJoin *node)
12451199 */
12461200ExecClearTuple (mergestate -> jstate .cs_ResultTupleSlot );
12471201ExecClearTuple (mergestate -> mj_MarkedTupleSlot );
1248-
1202+ pfree (mergestate -> mj_MarkedTupleSlot );
1203+ mergestate -> mj_MarkedTupleSlot = NULL ;
1204+
12491205MJ1_printf ("ExecEndMergeJoin: %s\n" ,
12501206"node processing ended" );
12511207}
1208+
1209+ void
1210+ ExecReScanMergeJoin (MergeJoin * node ,ExprContext * exprCtxt ,Plan * parent )
1211+ {
1212+ MergeJoinState * mergestate = node -> mergestate ;
1213+ TupleTableSlot * mjSlot = mergestate -> mj_MarkedTupleSlot ;
1214+
1215+ ExecClearTuple (mjSlot );
1216+ mjSlot -> val = NULL ;
1217+ mjSlot -> ttc_shouldFree = true;
1218+ mjSlot -> ttc_tupleDescriptor = NULL ;
1219+ mjSlot -> ttc_whichplan = -1 ;
1220+ mjSlot -> ttc_descIsNew = true;
1221+
1222+ mergestate -> mj_JoinState = EXEC_MJ_INITIALIZE ;
1223+
1224+ /*
1225+ * if chgParam of subnodes is not null then plans will be re-scanned by
1226+ * first ExecProcNode.
1227+ */
1228+ if (((Plan * )node )-> lefttree -> chgParam == NULL )
1229+ ExecReScan (((Plan * )node )-> lefttree ,exprCtxt , (Plan * )node );
1230+ if (((Plan * )node )-> righttree -> chgParam == NULL )
1231+ ExecReScan (((Plan * )node )-> righttree ,exprCtxt , (Plan * )node );
1232+
1233+ }