]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeMergejoin.c
Performance fix for new anti-join code in nodeMergejoin.c: after finding a
[postgresql] / src / backend / executor / nodeMergejoin.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeMergejoin.c
4  *        routines supporting merge joins
5  *
6  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.93 2008/08/15 19:20:42 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  *              ExecMergeJoin                   mergejoin outer and inner relations.
18  *              ExecInitMergeJoin               creates and initializes run time states
19  *              ExecEndMergeJoin                cleans up the node.
20  *
21  * NOTES
22  *
23  *              Merge-join is done by joining the inner and outer tuples satisfying
24  *              join clauses of the form ((= outerKey innerKey) ...).
25  *              The join clause list is provided by the query planner and may contain
26  *              more than one (= outerKey innerKey) clause (for composite sort key).
27  *
28  *              However, the query executor needs to know whether an outer
29  *              tuple is "greater/smaller" than an inner tuple so that it can
30  *              "synchronize" the two relations. For example, consider the following
31  *              relations:
32  *
33  *                              outer: (0 ^1 1 2 5 5 5 6 6 7)   current tuple: 1
34  *                              inner: (1 ^3 5 5 5 5 6)                 current tuple: 3
35  *
36  *              To continue the merge-join, the executor needs to scan both inner
37  *              and outer relations till the matching tuples 5. It needs to know
38  *              that currently inner tuple 3 is "greater" than outer tuple 1 and
39  *              therefore it should scan the outer relation first to find a
40  *              matching tuple and so on.
41  *
42  *              Therefore, rather than directly executing the merge join clauses,
43  *              we evaluate the left and right key expressions separately and then
44  *              compare the columns one at a time (see MJCompare).      The planner
45  *              passes us enough information about the sort ordering of the inputs
46  *              to allow us to determine how to make the comparison.  We may use the
47  *              appropriate btree comparison function, since Postgres' only notion
48  *              of ordering is specified by btree opfamilies.
49  *
50  *
51  *              Consider the above relations and suppose that the executor has
52  *              just joined the first outer "5" with the last inner "5". The
53  *              next step is of course to join the second outer "5" with all
54  *              the inner "5's". This requires repositioning the inner "cursor"
55  *              to point at the first inner "5". This is done by "marking" the
56  *              first inner 5 so we can restore the "cursor" to it before joining
57  *              with the second outer 5. The access method interface provides
58  *              routines to mark and restore to a tuple.
59  *
60  *
61  *              Essential operation of the merge join algorithm is as follows:
62  *
63  *              Join {
64  *                      get initial outer and inner tuples                              INITIALIZE
65  *                      do forever {
66  *                              while (outer != inner) {                                        SKIP_TEST
67  *                                      if (outer < inner)
68  *                                              advance outer                                           SKIPOUTER_ADVANCE
69  *                                      else
70  *                                              advance inner                                           SKIPINNER_ADVANCE
71  *                              }
72  *                              mark inner position                                                     SKIP_TEST
73  *                              do forever {
74  *                                      while (outer == inner) {
75  *                                              join tuples                                                     JOINTUPLES
76  *                                              advance inner position                          NEXTINNER
77  *                                      }
78  *                                      advance outer position                                  NEXTOUTER
79  *                                      if (outer == mark)                                              TESTOUTER
80  *                                              restore inner position to mark          TESTOUTER
81  *                                      else
82  *                                              break   // return to top of outer loop
83  *                              }
84  *                      }
85  *              }
86  *
87  *              The merge join operation is coded in the fashion
88  *              of a state machine.  At each state, we do something and then
89  *              proceed to another state.  This state is stored in the node's
90  *              execution state information and is preserved across calls to
91  *              ExecMergeJoin. -cim 10/31/89
92  */
93 #include "postgres.h"
94
95 #include "access/nbtree.h"
96 #include "catalog/pg_amop.h"
97 #include "executor/execdebug.h"
98 #include "executor/execdefs.h"
99 #include "executor/nodeMergejoin.h"
100 #include "miscadmin.h"
101 #include "utils/acl.h"
102 #include "utils/lsyscache.h"
103 #include "utils/memutils.h"
104 #include "utils/syscache.h"
105
106
107 /*
108  * Runtime data for each mergejoin clause
109  */
110 typedef struct MergeJoinClauseData
111 {
112         /* Executable expression trees */
113         ExprState  *lexpr;                      /* left-hand (outer) input expression */
114         ExprState  *rexpr;                      /* right-hand (inner) input expression */
115
116         /*
117          * If we have a current left or right input tuple, the values of the
118          * expressions are loaded into these fields:
119          */
120         Datum           ldatum;                 /* current left-hand value */
121         Datum           rdatum;                 /* current right-hand value */
122         bool            lisnull;                /* and their isnull flags */
123         bool            risnull;
124
125         /*
126          * The comparison strategy in use, and the lookup info to let us call the
127          * btree comparison support function.
128          */
129         bool            reverse;                /* if true, negate the cmpfn's output */
130         bool            nulls_first;    /* if true, nulls sort low */
131         FmgrInfo        cmpfinfo;
132 } MergeJoinClauseData;
133
134
135 #define MarkInnerTuple(innerTupleSlot, mergestate) \
136         ExecCopySlot((mergestate)->mj_MarkedTupleSlot, (innerTupleSlot))
137
138
139 /*
140  * MJExamineQuals
141  *
142  * This deconstructs the list of mergejoinable expressions, which is given
143  * to us by the planner in the form of a list of "leftexpr = rightexpr"
144  * expression trees in the order matching the sort columns of the inputs.
145  * We build an array of MergeJoinClause structs containing the information
146  * we will need at runtime.  Each struct essentially tells us how to compare
147  * the two expressions from the original clause.
148  *
149  * In addition to the expressions themselves, the planner passes the btree
150  * opfamily OID, btree strategy number (BTLessStrategyNumber or
151  * BTGreaterStrategyNumber), and nulls-first flag that identify the intended
152  * sort ordering for each merge key.  The mergejoinable operator is an
153  * equality operator in this opfamily, and the two inputs are guaranteed to be
154  * ordered in either increasing or decreasing (respectively) order according
155  * to this opfamily, with nulls at the indicated end of the range.      This
156  * allows us to obtain the needed comparison function from the opfamily.
157  */
158 static MergeJoinClause
159 MJExamineQuals(List *mergeclauses,
160                            Oid *mergefamilies,
161                            int *mergestrategies,
162                            bool *mergenullsfirst,
163                            PlanState *parent)
164 {
165         MergeJoinClause clauses;
166         int                     nClauses = list_length(mergeclauses);
167         int                     iClause;
168         ListCell   *cl;
169
170         clauses = (MergeJoinClause) palloc0(nClauses * sizeof(MergeJoinClauseData));
171
172         iClause = 0;
173         foreach(cl, mergeclauses)
174         {
175                 OpExpr     *qual = (OpExpr *) lfirst(cl);
176                 MergeJoinClause clause = &clauses[iClause];
177                 Oid                     opfamily = mergefamilies[iClause];
178                 StrategyNumber opstrategy = mergestrategies[iClause];
179                 bool            nulls_first = mergenullsfirst[iClause];
180                 int                     op_strategy;
181                 Oid                     op_lefttype;
182                 Oid                     op_righttype;
183                 RegProcedure cmpproc;
184                 AclResult       aclresult;
185
186                 if (!IsA(qual, OpExpr))
187                         elog(ERROR, "mergejoin clause is not an OpExpr");
188
189                 /*
190                  * Prepare the input expressions for execution.
191                  */
192                 clause->lexpr = ExecInitExpr((Expr *) linitial(qual->args), parent);
193                 clause->rexpr = ExecInitExpr((Expr *) lsecond(qual->args), parent);
194
195                 /* Extract the operator's declared left/right datatypes */
196                 get_op_opfamily_properties(qual->opno, opfamily,
197                                                                    &op_strategy,
198                                                                    &op_lefttype,
199                                                                    &op_righttype);
200                 if (op_strategy != BTEqualStrategyNumber)               /* should not happen */
201                         elog(ERROR, "cannot merge using non-equality operator %u",
202                                  qual->opno);
203
204                 /* And get the matching support procedure (comparison function) */
205                 cmpproc = get_opfamily_proc(opfamily,
206                                                                         op_lefttype,
207                                                                         op_righttype,
208                                                                         BTORDER_PROC);
209                 if (!RegProcedureIsValid(cmpproc))              /* should not happen */
210                         elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
211                                  BTORDER_PROC, op_lefttype, op_righttype, opfamily);
212
213                 /* Check permission to call cmp function */
214                 aclresult = pg_proc_aclcheck(cmpproc, GetUserId(), ACL_EXECUTE);
215                 if (aclresult != ACLCHECK_OK)
216                         aclcheck_error(aclresult, ACL_KIND_PROC,
217                                                    get_func_name(cmpproc));
218
219                 /* Set up the fmgr lookup information */
220                 fmgr_info(cmpproc, &(clause->cmpfinfo));
221
222                 /* Fill the additional comparison-strategy flags */
223                 if (opstrategy == BTLessStrategyNumber)
224                         clause->reverse = false;
225                 else if (opstrategy == BTGreaterStrategyNumber)
226                         clause->reverse = true;
227                 else    /* planner screwed up */
228                         elog(ERROR, "unsupported mergejoin strategy %d", opstrategy);
229
230                 clause->nulls_first = nulls_first;
231
232                 iClause++;
233         }
234
235         return clauses;
236 }
237
238 /*
239  * MJEvalOuterValues
240  *
241  * Compute the values of the mergejoined expressions for the current
242  * outer tuple.  We also detect whether it's impossible for the current
243  * outer tuple to match anything --- this is true if it yields a NULL
244  * input, since we assume mergejoin operators are strict.
245  *
246  * We evaluate the values in OuterEContext, which can be reset each
247  * time we move to a new tuple.
248  */
249 static bool
250 MJEvalOuterValues(MergeJoinState *mergestate)
251 {
252         ExprContext *econtext = mergestate->mj_OuterEContext;
253         bool            canmatch = true;
254         int                     i;
255         MemoryContext oldContext;
256
257         ResetExprContext(econtext);
258
259         oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
260
261         econtext->ecxt_outertuple = mergestate->mj_OuterTupleSlot;
262
263         for (i = 0; i < mergestate->mj_NumClauses; i++)
264         {
265                 MergeJoinClause clause = &mergestate->mj_Clauses[i];
266
267                 clause->ldatum = ExecEvalExpr(clause->lexpr, econtext,
268                                                                           &clause->lisnull, NULL);
269                 if (clause->lisnull)
270                         canmatch = false;
271         }
272
273         MemoryContextSwitchTo(oldContext);
274
275         return canmatch;
276 }
277
278 /*
279  * MJEvalInnerValues
280  *
281  * Same as above, but for the inner tuple.      Here, we have to be prepared
282  * to load data from either the true current inner, or the marked inner,
283  * so caller must tell us which slot to load from.
284  */
285 static bool
286 MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
287 {
288         ExprContext *econtext = mergestate->mj_InnerEContext;
289         bool            canmatch = true;
290         int                     i;
291         MemoryContext oldContext;
292
293         ResetExprContext(econtext);
294
295         oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
296
297         econtext->ecxt_innertuple = innerslot;
298
299         for (i = 0; i < mergestate->mj_NumClauses; i++)
300         {
301                 MergeJoinClause clause = &mergestate->mj_Clauses[i];
302
303                 clause->rdatum = ExecEvalExpr(clause->rexpr, econtext,
304                                                                           &clause->risnull, NULL);
305                 if (clause->risnull)
306                         canmatch = false;
307         }
308
309         MemoryContextSwitchTo(oldContext);
310
311         return canmatch;
312 }
313
314 /*
315  * MJCompare
316  *
317  * Compare the mergejoinable values of the current two input tuples
318  * and return 0 if they are equal (ie, the mergejoin equalities all
319  * succeed), +1 if outer > inner, -1 if outer < inner.
320  *
321  * MJEvalOuterValues and MJEvalInnerValues must already have been called
322  * for the current outer and inner tuples, respectively.
323  */
324 static int32
325 MJCompare(MergeJoinState *mergestate)
326 {
327         int32           result = 0;
328         bool            nulleqnull = false;
329         ExprContext *econtext = mergestate->js.ps.ps_ExprContext;
330         int                     i;
331         MemoryContext oldContext;
332         FunctionCallInfoData fcinfo;
333
334         /*
335          * Call the comparison functions in short-lived context, in case they leak
336          * memory.
337          */
338         ResetExprContext(econtext);
339
340         oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
341
342         for (i = 0; i < mergestate->mj_NumClauses; i++)
343         {
344                 MergeJoinClause clause = &mergestate->mj_Clauses[i];
345                 Datum           fresult;
346
347                 /*
348                  * Deal with null inputs.
349                  */
350                 if (clause->lisnull)
351                 {
352                         if (clause->risnull)
353                         {
354                                 nulleqnull = true;              /* NULL "=" NULL */
355                                 continue;
356                         }
357                         if (clause->nulls_first)
358                                 result = -1;    /* NULL "<" NOT_NULL */
359                         else
360                                 result = 1;             /* NULL ">" NOT_NULL */
361                         break;
362                 }
363                 if (clause->risnull)
364                 {
365                         if (clause->nulls_first)
366                                 result = 1;             /* NOT_NULL ">" NULL */
367                         else
368                                 result = -1;    /* NOT_NULL "<" NULL */
369                         break;
370                 }
371
372                 /*
373                  * OK to call the comparison function.
374                  */
375                 InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2,
376                                                                  NULL, NULL);
377                 fcinfo.arg[0] = clause->ldatum;
378                 fcinfo.arg[1] = clause->rdatum;
379                 fcinfo.argnull[0] = false;
380                 fcinfo.argnull[1] = false;
381                 fresult = FunctionCallInvoke(&fcinfo);
382                 if (fcinfo.isnull)
383                 {
384                         nulleqnull = true;      /* treat like NULL = NULL */
385                         continue;
386                 }
387                 result = DatumGetInt32(fresult);
388
389                 if (clause->reverse)
390                         result = -result;
391
392                 if (result != 0)
393                         break;
394         }
395
396         /*
397          * If we had any null comparison results or NULL-vs-NULL inputs, we do not
398          * want to report that the tuples are equal.  Instead, if result is still
399          * 0, change it to +1.  This will result in advancing the inner side of
400          * the join.
401          */
402         if (nulleqnull && result == 0)
403                 result = 1;
404
405         MemoryContextSwitchTo(oldContext);
406
407         return result;
408 }
409
410
411 /*
412  * Generate a fake join tuple with nulls for the inner tuple,
413  * and return it if it passes the non-join quals.
414  */
415 static TupleTableSlot *
416 MJFillOuter(MergeJoinState *node)
417 {
418         ExprContext *econtext = node->js.ps.ps_ExprContext;
419         List       *otherqual = node->js.ps.qual;
420
421         ResetExprContext(econtext);
422
423         econtext->ecxt_outertuple = node->mj_OuterTupleSlot;
424         econtext->ecxt_innertuple = node->mj_NullInnerTupleSlot;
425
426         if (ExecQual(otherqual, econtext, false))
427         {
428                 /*
429                  * qualification succeeded.  now form the desired projection tuple and
430                  * return the slot containing it.
431                  */
432                 TupleTableSlot *result;
433                 ExprDoneCond isDone;
434
435                 MJ_printf("ExecMergeJoin: returning outer fill tuple\n");
436
437                 result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
438
439                 if (isDone != ExprEndResult)
440                 {
441                         node->js.ps.ps_TupFromTlist =
442                                 (isDone == ExprMultipleResult);
443                         return result;
444                 }
445         }
446
447         return NULL;
448 }
449
450 /*
451  * Generate a fake join tuple with nulls for the outer tuple,
452  * and return it if it passes the non-join quals.
453  */
454 static TupleTableSlot *
455 MJFillInner(MergeJoinState *node)
456 {
457         ExprContext *econtext = node->js.ps.ps_ExprContext;
458         List       *otherqual = node->js.ps.qual;
459
460         ResetExprContext(econtext);
461
462         econtext->ecxt_outertuple = node->mj_NullOuterTupleSlot;
463         econtext->ecxt_innertuple = node->mj_InnerTupleSlot;
464
465         if (ExecQual(otherqual, econtext, false))
466         {
467                 /*
468                  * qualification succeeded.  now form the desired projection tuple and
469                  * return the slot containing it.
470                  */
471                 TupleTableSlot *result;
472                 ExprDoneCond isDone;
473
474                 MJ_printf("ExecMergeJoin: returning inner fill tuple\n");
475
476                 result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
477
478                 if (isDone != ExprEndResult)
479                 {
480                         node->js.ps.ps_TupFromTlist =
481                                 (isDone == ExprMultipleResult);
482                         return result;
483                 }
484         }
485
486         return NULL;
487 }
488
489
490 /* ----------------------------------------------------------------
491  *              ExecMergeTupleDump
492  *
493  *              This function is called through the MJ_dump() macro
494  *              when EXEC_MERGEJOINDEBUG is defined
495  * ----------------------------------------------------------------
496  */
497 #ifdef EXEC_MERGEJOINDEBUG
498
499 static void
500 ExecMergeTupleDumpOuter(MergeJoinState *mergestate)
501 {
502         TupleTableSlot *outerSlot = mergestate->mj_OuterTupleSlot;
503
504         printf("==== outer tuple ====\n");
505         if (TupIsNull(outerSlot))
506                 printf("(nil)\n");
507         else
508                 MJ_debugtup(outerSlot);
509 }
510
511 static void
512 ExecMergeTupleDumpInner(MergeJoinState *mergestate)
513 {
514         TupleTableSlot *innerSlot = mergestate->mj_InnerTupleSlot;
515
516         printf("==== inner tuple ====\n");
517         if (TupIsNull(innerSlot))
518                 printf("(nil)\n");
519         else
520                 MJ_debugtup(innerSlot);
521 }
522
523 static void
524 ExecMergeTupleDumpMarked(MergeJoinState *mergestate)
525 {
526         TupleTableSlot *markedSlot = mergestate->mj_MarkedTupleSlot;
527
528         printf("==== marked tuple ====\n");
529         if (TupIsNull(markedSlot))
530                 printf("(nil)\n");
531         else
532                 MJ_debugtup(markedSlot);
533 }
534
535 static void
536 ExecMergeTupleDump(MergeJoinState *mergestate)
537 {
538         printf("******** ExecMergeTupleDump ********\n");
539
540         ExecMergeTupleDumpOuter(mergestate);
541         ExecMergeTupleDumpInner(mergestate);
542         ExecMergeTupleDumpMarked(mergestate);
543
544         printf("******** \n");
545 }
546 #endif
547
548 /* ----------------------------------------------------------------
549  *              ExecMergeJoin
550  * ----------------------------------------------------------------
551  */
552 TupleTableSlot *
553 ExecMergeJoin(MergeJoinState *node)
554 {
555         EState     *estate;
556         List       *joinqual;
557         List       *otherqual;
558         bool            qualResult;
559         int32           compareResult;
560         PlanState  *innerPlan;
561         TupleTableSlot *innerTupleSlot;
562         PlanState  *outerPlan;
563         TupleTableSlot *outerTupleSlot;
564         ExprContext *econtext;
565         bool            doFillOuter;
566         bool            doFillInner;
567
568         /*
569          * get information from node
570          */
571         estate = node->js.ps.state;
572         innerPlan = innerPlanState(node);
573         outerPlan = outerPlanState(node);
574         econtext = node->js.ps.ps_ExprContext;
575         joinqual = node->js.joinqual;
576         otherqual = node->js.ps.qual;
577         doFillOuter = node->mj_FillOuter;
578         doFillInner = node->mj_FillInner;
579
580         /*
581          * Check to see if we're still projecting out tuples from a previous join
582          * tuple (because there is a function-returning-set in the projection
583          * expressions).  If so, try to project another one.
584          */
585         if (node->js.ps.ps_TupFromTlist)
586         {
587                 TupleTableSlot *result;
588                 ExprDoneCond isDone;
589
590                 result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
591                 if (isDone == ExprMultipleResult)
592                         return result;
593                 /* Done with that source tuple... */
594                 node->js.ps.ps_TupFromTlist = false;
595         }
596
597         /*
598          * Reset per-tuple memory context to free any expression evaluation
599          * storage allocated in the previous tuple cycle.  Note this can't happen
600          * until we're done projecting out tuples from a join tuple.
601          */
602         ResetExprContext(econtext);
603
604         /*
605          * ok, everything is setup.. let's go to work
606          */
607         for (;;)
608         {
609                 MJ_dump(node);
610
611                 /*
612                  * get the current state of the join and do things accordingly.
613                  */
614                 switch (node->mj_JoinState)
615                 {
616                                 /*
617                                  * EXEC_MJ_INITIALIZE_OUTER means that this is the first time
618                                  * ExecMergeJoin() has been called and so we have to fetch the
619                                  * first matchable tuple for both outer and inner subplans. We
620                                  * do the outer side in INITIALIZE_OUTER state, then advance
621                                  * to INITIALIZE_INNER state for the inner subplan.
622                                  */
623                         case EXEC_MJ_INITIALIZE_OUTER:
624                                 MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE_OUTER\n");
625
626                                 outerTupleSlot = ExecProcNode(outerPlan);
627                                 node->mj_OuterTupleSlot = outerTupleSlot;
628                                 if (TupIsNull(outerTupleSlot))
629                                 {
630                                         MJ_printf("ExecMergeJoin: nothing in outer subplan\n");
631                                         if (doFillInner)
632                                         {
633                                                 /*
634                                                  * Need to emit right-join tuples for remaining inner
635                                                  * tuples.      We set MatchedInner = true to force the
636                                                  * ENDOUTER state to advance inner.
637                                                  */
638                                                 node->mj_JoinState = EXEC_MJ_ENDOUTER;
639                                                 node->mj_MatchedInner = true;
640                                                 break;
641                                         }
642                                         /* Otherwise we're done. */
643                                         return NULL;
644                                 }
645
646                                 /* Compute join values and check for unmatchability */
647                                 if (MJEvalOuterValues(node))
648                                 {
649                                         /* OK to go get the first inner tuple */
650                                         node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER;
651                                 }
652                                 else
653                                 {
654                                         /* Stay in same state to fetch next outer tuple */
655                                         if (doFillOuter)
656                                         {
657                                                 /*
658                                                  * Generate a fake join tuple with nulls for the inner
659                                                  * tuple, and return it if it passes the non-join
660                                                  * quals.
661                                                  */
662                                                 TupleTableSlot *result;
663
664                                                 result = MJFillOuter(node);
665                                                 if (result)
666                                                         return result;
667                                         }
668                                 }
669                                 break;
670
671                         case EXEC_MJ_INITIALIZE_INNER:
672                                 MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE_INNER\n");
673
674                                 innerTupleSlot = ExecProcNode(innerPlan);
675                                 node->mj_InnerTupleSlot = innerTupleSlot;
676                                 if (TupIsNull(innerTupleSlot))
677                                 {
678                                         MJ_printf("ExecMergeJoin: nothing in inner subplan\n");
679                                         if (doFillOuter)
680                                         {
681                                                 /*
682                                                  * Need to emit left-join tuples for all outer tuples,
683                                                  * including the one we just fetched.  We set
684                                                  * MatchedOuter = false to force the ENDINNER state to
685                                                  * emit first tuple before advancing outer.
686                                                  */
687                                                 node->mj_JoinState = EXEC_MJ_ENDINNER;
688                                                 node->mj_MatchedOuter = false;
689                                                 break;
690                                         }
691                                         /* Otherwise we're done. */
692                                         return NULL;
693                                 }
694
695                                 /* Compute join values and check for unmatchability */
696                                 if (MJEvalInnerValues(node, innerTupleSlot))
697                                 {
698                                         /*
699                                          * OK, we have the initial tuples.      Begin by skipping
700                                          * non-matching tuples.
701                                          */
702                                         node->mj_JoinState = EXEC_MJ_SKIP_TEST;
703                                 }
704                                 else
705                                 {
706                                         /* Mark before advancing, if wanted */
707                                         if (node->mj_ExtraMarks)
708                                                 ExecMarkPos(innerPlan);
709                                         /* Stay in same state to fetch next inner tuple */
710                                         if (doFillInner)
711                                         {
712                                                 /*
713                                                  * Generate a fake join tuple with nulls for the outer
714                                                  * tuple, and return it if it passes the non-join
715                                                  * quals.
716                                                  */
717                                                 TupleTableSlot *result;
718
719                                                 result = MJFillInner(node);
720                                                 if (result)
721                                                         return result;
722                                         }
723                                 }
724                                 break;
725
726                                 /*
727                                  * EXEC_MJ_JOINTUPLES means we have two tuples which satisfied
728                                  * the merge clause so we join them and then proceed to get
729                                  * the next inner tuple (EXEC_MJ_NEXTINNER).
730                                  */
731                         case EXEC_MJ_JOINTUPLES:
732                                 MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
733
734                                 /*
735                                  * Set the next state machine state.  The right things will
736                                  * happen whether we return this join tuple or just fall
737                                  * through to continue the state machine execution.
738                                  */
739                                 node->mj_JoinState = EXEC_MJ_NEXTINNER;
740
741                                 /*
742                                  * Check the extra qual conditions to see if we actually want
743                                  * to return this join tuple.  If not, can proceed with merge.
744                                  * We must distinguish the additional joinquals (which must
745                                  * pass to consider the tuples "matched" for outer-join logic)
746                                  * from the otherquals (which must pass before we actually
747                                  * return the tuple).
748                                  *
749                                  * We don't bother with a ResetExprContext here, on the
750                                  * assumption that we just did one while checking the merge
751                                  * qual.  One per tuple should be sufficient.  We do have to
752                                  * set up the econtext links to the tuples for ExecQual to
753                                  * use.
754                                  */
755                                 outerTupleSlot = node->mj_OuterTupleSlot;
756                                 econtext->ecxt_outertuple = outerTupleSlot;
757                                 innerTupleSlot = node->mj_InnerTupleSlot;
758                                 econtext->ecxt_innertuple = innerTupleSlot;
759
760                                 qualResult = (joinqual == NIL ||
761                                                           ExecQual(joinqual, econtext, false));
762                                 MJ_DEBUG_QUAL(joinqual, qualResult);
763
764                                 if (qualResult)
765                                 {
766                                         node->mj_MatchedOuter = true;
767                                         node->mj_MatchedInner = true;
768
769                                         /* In an antijoin, we never return a matched tuple */
770                                         if (node->js.jointype == JOIN_ANTI)
771                                         {
772                                                 node->mj_JoinState = EXEC_MJ_NEXTOUTER;
773                                                 break;
774                                         }
775
776                                         /*
777                                          * In a semijoin, we'll consider returning the first match,
778                                          * but after that we're done with this outer tuple.
779                                          */
780                                         if (node->js.jointype == JOIN_SEMI)
781                                                 node->mj_JoinState = EXEC_MJ_NEXTOUTER;
782
783                                         qualResult = (otherqual == NIL ||
784                                                                   ExecQual(otherqual, econtext, false));
785                                         MJ_DEBUG_QUAL(otherqual, qualResult);
786
787                                         if (qualResult)
788                                         {
789                                                 /*
790                                                  * qualification succeeded.  now form the desired
791                                                  * projection tuple and return the slot containing it.
792                                                  */
793                                                 TupleTableSlot *result;
794                                                 ExprDoneCond isDone;
795
796                                                 MJ_printf("ExecMergeJoin: returning tuple\n");
797
798                                                 result = ExecProject(node->js.ps.ps_ProjInfo,
799                                                                                          &isDone);
800
801                                                 if (isDone != ExprEndResult)
802                                                 {
803                                                         node->js.ps.ps_TupFromTlist =
804                                                                 (isDone == ExprMultipleResult);
805                                                         return result;
806                                                 }
807                                         }
808                                 }
809                                 break;
810
811                                 /*
812                                  * EXEC_MJ_NEXTINNER means advance the inner scan to the next
813                                  * tuple. If the tuple is not nil, we then proceed to test it
814                                  * against the join qualification.
815                                  *
816                                  * Before advancing, we check to see if we must emit an
817                                  * outer-join fill tuple for this inner tuple.
818                                  */
819                         case EXEC_MJ_NEXTINNER:
820                                 MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\n");
821
822                                 if (doFillInner && !node->mj_MatchedInner)
823                                 {
824                                         /*
825                                          * Generate a fake join tuple with nulls for the outer
826                                          * tuple, and return it if it passes the non-join quals.
827                                          */
828                                         TupleTableSlot *result;
829
830                                         node->mj_MatchedInner = true;           /* do it only once */
831
832                                         result = MJFillInner(node);
833                                         if (result)
834                                                 return result;
835                                 }
836
837                                 /*
838                                  * now we get the next inner tuple, if any.  If there's none,
839                                  * advance to next outer tuple (which may be able to join to
840                                  * previously marked tuples).
841                                  *
842                                  * NB: must NOT do "extraMarks" here, since we may need to
843                                  * return to previously marked tuples.
844                                  */
845                                 innerTupleSlot = ExecProcNode(innerPlan);
846                                 node->mj_InnerTupleSlot = innerTupleSlot;
847                                 MJ_DEBUG_PROC_NODE(innerTupleSlot);
848                                 node->mj_MatchedInner = false;
849
850                                 if (TupIsNull(innerTupleSlot))
851                                 {
852                                         node->mj_JoinState = EXEC_MJ_NEXTOUTER;
853                                         break;
854                                 }
855
856                                 /*
857                                  * Load up the new inner tuple's comparison values.  If we see
858                                  * that it contains a NULL and hence can't match any outer
859                                  * tuple, we can skip the comparison and assume the new tuple
860                                  * is greater than current outer.
861                                  */
862                                 if (!MJEvalInnerValues(node, innerTupleSlot))
863                                 {
864                                         node->mj_JoinState = EXEC_MJ_NEXTOUTER;
865                                         break;
866                                 }
867
868                                 /*
869                                  * Test the new inner tuple to see if it matches outer.
870                                  *
871                                  * If they do match, then we join them and move on to the next
872                                  * inner tuple (EXEC_MJ_JOINTUPLES).
873                                  *
874                                  * If they do not match then advance to next outer tuple.
875                                  */
876                                 compareResult = MJCompare(node);
877                                 MJ_DEBUG_COMPARE(compareResult);
878
879                                 if (compareResult == 0)
880                                         node->mj_JoinState = EXEC_MJ_JOINTUPLES;
881                                 else
882                                 {
883                                         Assert(compareResult < 0);
884                                         node->mj_JoinState = EXEC_MJ_NEXTOUTER;
885                                 }
886                                 break;
887
888                                 /*-------------------------------------------
889                                  * EXEC_MJ_NEXTOUTER means
890                                  *
891                                  *                              outer inner
892                                  * outer tuple -  5             5  - marked tuple
893                                  *                                5             5
894                                  *                                6             6  - inner tuple
895                                  *                                7             7
896                                  *
897                                  * we know we just bumped into the
898                                  * first inner tuple > current outer tuple (or possibly
899                                  * the end of the inner stream)
900                                  * so get a new outer tuple and then
901                                  * proceed to test it against the marked tuple
902                                  * (EXEC_MJ_TESTOUTER)
903                                  *
904                                  * Before advancing, we check to see if we must emit an
905                                  * outer-join fill tuple for this outer tuple.
906                                  *------------------------------------------------
907                                  */
908                         case EXEC_MJ_NEXTOUTER:
909                                 MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n");
910
911                                 if (doFillOuter && !node->mj_MatchedOuter)
912                                 {
913                                         /*
914                                          * Generate a fake join tuple with nulls for the inner
915                                          * tuple, and return it if it passes the non-join quals.
916                                          */
917                                         TupleTableSlot *result;
918
919                                         node->mj_MatchedOuter = true;           /* do it only once */
920
921                                         result = MJFillOuter(node);
922                                         if (result)
923                                                 return result;
924                                 }
925
926                                 /*
927                                  * now we get the next outer tuple, if any
928                                  */
929                                 outerTupleSlot = ExecProcNode(outerPlan);
930                                 node->mj_OuterTupleSlot = outerTupleSlot;
931                                 MJ_DEBUG_PROC_NODE(outerTupleSlot);
932                                 node->mj_MatchedOuter = false;
933
934                                 /*
935                                  * if the outer tuple is null then we are done with the join,
936                                  * unless we have inner tuples we need to null-fill.
937                                  */
938                                 if (TupIsNull(outerTupleSlot))
939                                 {
940                                         MJ_printf("ExecMergeJoin: end of outer subplan\n");
941                                         innerTupleSlot = node->mj_InnerTupleSlot;
942                                         if (doFillInner && !TupIsNull(innerTupleSlot))
943                                         {
944                                                 /*
945                                                  * Need to emit right-join tuples for remaining inner
946                                                  * tuples.
947                                                  */
948                                                 node->mj_JoinState = EXEC_MJ_ENDOUTER;
949                                                 break;
950                                         }
951                                         /* Otherwise we're done. */
952                                         return NULL;
953                                 }
954
955                                 /* Compute join values and check for unmatchability */
956                                 if (MJEvalOuterValues(node))
957                                 {
958                                         /* Go test the new tuple against the marked tuple */
959                                         node->mj_JoinState = EXEC_MJ_TESTOUTER;
960                                 }
961                                 else
962                                 {
963                                         /* Can't match, so fetch next outer tuple */
964                                         node->mj_JoinState = EXEC_MJ_NEXTOUTER;
965                                 }
966                                 break;
967
968                                 /*--------------------------------------------------------
969                                  * EXEC_MJ_TESTOUTER If the new outer tuple and the marked
970                                  * tuple satisfy the merge clause then we know we have
971                                  * duplicates in the outer scan so we have to restore the
972                                  * inner scan to the marked tuple and proceed to join the
973                                  * new outer tuple with the inner tuples.
974                                  *
975                                  * This is the case when
976                                  *                                                outer inner
977                                  *                                                      4         5  - marked tuple
978                                  *                       outer tuple -  5         5
979                                  *               new outer tuple -      5         5
980                                  *                                                      6         8  - inner tuple
981                                  *                                                      7        12
982                                  *
983                                  *                              new outer tuple == marked tuple
984                                  *
985                                  * If the outer tuple fails the test, then we are done
986                                  * with the marked tuples, and we have to look for a
987                                  * match to the current inner tuple.  So we will
988                                  * proceed to skip outer tuples until outer >= inner
989                                  * (EXEC_MJ_SKIP_TEST).
990                                  *
991                                  *              This is the case when
992                                  *
993                                  *                                                outer inner
994                                  *                                                      5         5  - marked tuple
995                                  *                       outer tuple -  5         5
996                                  *               new outer tuple -      6         8  - inner tuple
997                                  *                                                      7        12
998                                  *
999                                  *                              new outer tuple > marked tuple
1000                                  *
1001                                  *---------------------------------------------------------
1002                                  */
1003                         case EXEC_MJ_TESTOUTER:
1004                                 MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");
1005
1006                                 /*
1007                                  * Here we must compare the outer tuple with the marked inner
1008                                  * tuple.  (We can ignore the result of MJEvalInnerValues,
1009                                  * since the marked inner tuple is certainly matchable.)
1010                                  */
1011                                 innerTupleSlot = node->mj_MarkedTupleSlot;
1012                                 (void) MJEvalInnerValues(node, innerTupleSlot);
1013
1014                                 compareResult = MJCompare(node);
1015                                 MJ_DEBUG_COMPARE(compareResult);
1016
1017                                 if (compareResult == 0)
1018                                 {
1019                                         /*
1020                                          * the merge clause matched so now we restore the inner
1021                                          * scan position to the first mark, and go join that tuple
1022                                          * (and any following ones) to the new outer.
1023                                          *
1024                                          * NOTE: we do not need to worry about the MatchedInner
1025                                          * state for the rescanned inner tuples.  We know all of
1026                                          * them will match this new outer tuple and therefore
1027                                          * won't be emitted as fill tuples.  This works *only*
1028                                          * because we require the extra joinquals to be nil when
1029                                          * doing a right or full join --- otherwise some of the
1030                                          * rescanned tuples might fail the extra joinquals.
1031                                          */
1032                                         ExecRestrPos(innerPlan);
1033
1034                                         /*
1035                                          * ExecRestrPos probably should give us back a new Slot,
1036                                          * but since it doesn't, use the marked slot.  (The
1037                                          * previously returned mj_InnerTupleSlot cannot be assumed
1038                                          * to hold the required tuple.)
1039                                          */
1040                                         node->mj_InnerTupleSlot = innerTupleSlot;
1041                                         /* we need not do MJEvalInnerValues again */
1042
1043                                         node->mj_JoinState = EXEC_MJ_JOINTUPLES;
1044                                 }
1045                                 else
1046                                 {
1047                                         /* ----------------
1048                                          *      if the new outer tuple didn't match the marked inner
1049                                          *      tuple then we have a case like:
1050                                          *
1051                                          *                       outer inner
1052                                          *                         4     4      - marked tuple
1053                                          * new outer - 5         4
1054                                          *                         6     5      - inner tuple
1055                                          *                         7
1056                                          *
1057                                          *      which means that all subsequent outer tuples will be
1058                                          *      larger than our marked inner tuples.  So we need not
1059                                          *      revisit any of the marked tuples but can proceed to
1060                                          *      look for a match to the current inner.  If there's
1061                                          *      no more inners, we are done.
1062                                          * ----------------
1063                                          */
1064                                         Assert(compareResult > 0);
1065                                         innerTupleSlot = node->mj_InnerTupleSlot;
1066                                         if (TupIsNull(innerTupleSlot))
1067                                         {
1068                                                 if (doFillOuter)
1069                                                 {
1070                                                         /*
1071                                                          * Need to emit left-join tuples for remaining
1072                                                          * outer tuples.
1073                                                          */
1074                                                         node->mj_JoinState = EXEC_MJ_ENDINNER;
1075                                                         break;
1076                                                 }
1077                                                 /* Otherwise we're done. */
1078                                                 return NULL;
1079                                         }
1080
1081                                         /* reload comparison data for current inner */
1082                                         if (MJEvalInnerValues(node, innerTupleSlot))
1083                                         {
1084                                                 /* proceed to compare it to the current outer */
1085                                                 node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1086                                         }
1087                                         else
1088                                         {
1089                                                 /*
1090                                                  * current inner can't possibly match any outer;
1091                                                  * better to advance the inner scan than the outer.
1092                                                  */
1093                                                 node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
1094                                         }
1095                                 }
1096                                 break;
1097
1098                                 /*----------------------------------------------------------
1099                                  * EXEC_MJ_SKIP means compare tuples and if they do not
1100                                  * match, skip whichever is lesser.
1101                                  *
1102                                  * For example:
1103                                  *
1104                                  *                              outer inner
1105                                  *                                5             5
1106                                  *                                5             5
1107                                  * outer tuple -  6             8  - inner tuple
1108                                  *                                7    12
1109                                  *                                8    14
1110                                  *
1111                                  * we have to advance the outer scan
1112                                  * until we find the outer 8.
1113                                  *
1114                                  * On the other hand:
1115                                  *
1116                                  *                              outer inner
1117                                  *                                5             5
1118                                  *                                5             5
1119                                  * outer tuple - 12             8  - inner tuple
1120                                  *                               14    10
1121                                  *                               17    12
1122                                  *
1123                                  * we have to advance the inner scan
1124                                  * until we find the inner 12.
1125                                  *----------------------------------------------------------
1126                                  */
1127                         case EXEC_MJ_SKIP_TEST:
1128                                 MJ_printf("ExecMergeJoin: EXEC_MJ_SKIP_TEST\n");
1129
1130                                 /*
1131                                  * before we advance, make sure the current tuples do not
1132                                  * satisfy the mergeclauses.  If they do, then we update the
1133                                  * marked tuple position and go join them.
1134                                  */
1135                                 compareResult = MJCompare(node);
1136                                 MJ_DEBUG_COMPARE(compareResult);
1137
1138                                 if (compareResult == 0)
1139                                 {
1140                                         ExecMarkPos(innerPlan);
1141
1142                                         MarkInnerTuple(node->mj_InnerTupleSlot, node);
1143
1144                                         node->mj_JoinState = EXEC_MJ_JOINTUPLES;
1145                                 }
1146                                 else if (compareResult < 0)
1147                                         node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
1148                                 else
1149                                         /* compareResult > 0 */
1150                                         node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
1151                                 break;
1152
1153                                 /*
1154                                  * SKIPOUTER_ADVANCE: advance over an outer tuple that is
1155                                  * known not to join to any inner tuple.
1156                                  *
1157                                  * Before advancing, we check to see if we must emit an
1158                                  * outer-join fill tuple for this outer tuple.
1159                                  */
1160                         case EXEC_MJ_SKIPOUTER_ADVANCE:
1161                                 MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_ADVANCE\n");
1162
1163                                 if (doFillOuter && !node->mj_MatchedOuter)
1164                                 {
1165                                         /*
1166                                          * Generate a fake join tuple with nulls for the inner
1167                                          * tuple, and return it if it passes the non-join quals.
1168                                          */
1169                                         TupleTableSlot *result;
1170
1171                                         node->mj_MatchedOuter = true;           /* do it only once */
1172
1173                                         result = MJFillOuter(node);
1174                                         if (result)
1175                                                 return result;
1176                                 }
1177
1178                                 /*
1179                                  * now we get the next outer tuple, if any
1180                                  */
1181                                 outerTupleSlot = ExecProcNode(outerPlan);
1182                                 node->mj_OuterTupleSlot = outerTupleSlot;
1183                                 MJ_DEBUG_PROC_NODE(outerTupleSlot);
1184                                 node->mj_MatchedOuter = false;
1185
1186                                 /*
1187                                  * if the outer tuple is null then we are done with the join,
1188                                  * unless we have inner tuples we need to null-fill.
1189                                  */
1190                                 if (TupIsNull(outerTupleSlot))
1191                                 {
1192                                         MJ_printf("ExecMergeJoin: end of outer subplan\n");
1193                                         innerTupleSlot = node->mj_InnerTupleSlot;
1194                                         if (doFillInner && !TupIsNull(innerTupleSlot))
1195                                         {
1196                                                 /*
1197                                                  * Need to emit right-join tuples for remaining inner
1198                                                  * tuples.
1199                                                  */
1200                                                 node->mj_JoinState = EXEC_MJ_ENDOUTER;
1201                                                 break;
1202                                         }
1203                                         /* Otherwise we're done. */
1204                                         return NULL;
1205                                 }
1206
1207                                 /* Compute join values and check for unmatchability */
1208                                 if (MJEvalOuterValues(node))
1209                                 {
1210                                         /* Go test the new tuple against the current inner */
1211                                         node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1212                                 }
1213                                 else
1214                                 {
1215                                         /* Can't match, so fetch next outer tuple */
1216                                         node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
1217                                 }
1218                                 break;
1219
1220                                 /*
1221                                  * SKIPINNER_ADVANCE: advance over an inner tuple that is
1222                                  * known not to join to any outer tuple.
1223                                  *
1224                                  * Before advancing, we check to see if we must emit an
1225                                  * outer-join fill tuple for this inner tuple.
1226                                  */
1227                         case EXEC_MJ_SKIPINNER_ADVANCE:
1228                                 MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_ADVANCE\n");
1229
1230                                 if (doFillInner && !node->mj_MatchedInner)
1231                                 {
1232                                         /*
1233                                          * Generate a fake join tuple with nulls for the outer
1234                                          * tuple, and return it if it passes the non-join quals.
1235                                          */
1236                                         TupleTableSlot *result;
1237
1238                                         node->mj_MatchedInner = true;           /* do it only once */
1239
1240                                         result = MJFillInner(node);
1241                                         if (result)
1242                                                 return result;
1243                                 }
1244
1245                                 /* Mark before advancing, if wanted */
1246                                 if (node->mj_ExtraMarks)
1247                                         ExecMarkPos(innerPlan);
1248
1249                                 /*
1250                                  * now we get the next inner tuple, if any
1251                                  */
1252                                 innerTupleSlot = ExecProcNode(innerPlan);
1253                                 node->mj_InnerTupleSlot = innerTupleSlot;
1254                                 MJ_DEBUG_PROC_NODE(innerTupleSlot);
1255                                 node->mj_MatchedInner = false;
1256
1257                                 /*
1258                                  * if the inner tuple is null then we are done with the join,
1259                                  * unless we have outer tuples we need to null-fill.
1260                                  */
1261                                 if (TupIsNull(innerTupleSlot))
1262                                 {
1263                                         MJ_printf("ExecMergeJoin: end of inner subplan\n");
1264                                         outerTupleSlot = node->mj_OuterTupleSlot;
1265                                         if (doFillOuter && !TupIsNull(outerTupleSlot))
1266                                         {
1267                                                 /*
1268                                                  * Need to emit left-join tuples for remaining outer
1269                                                  * tuples.
1270                                                  */
1271                                                 node->mj_JoinState = EXEC_MJ_ENDINNER;
1272                                                 break;
1273                                         }
1274                                         /* Otherwise we're done. */
1275                                         return NULL;
1276                                 }
1277
1278                                 /* Compute join values and check for unmatchability */
1279                                 if (MJEvalInnerValues(node, innerTupleSlot))
1280                                 {
1281                                         /* proceed to compare it to the current outer */
1282                                         node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1283                                 }
1284                                 else
1285                                 {
1286                                         /*
1287                                          * current inner can't possibly match any outer; better to
1288                                          * advance the inner scan than the outer.
1289                                          */
1290                                         node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
1291                                 }
1292                                 break;
1293
1294                                 /*
1295                                  * EXEC_MJ_ENDOUTER means we have run out of outer tuples, but
1296                                  * are doing a right/full join and therefore must null-fill
1297                                  * any remaing unmatched inner tuples.
1298                                  */
1299                         case EXEC_MJ_ENDOUTER:
1300                                 MJ_printf("ExecMergeJoin: EXEC_MJ_ENDOUTER\n");
1301
1302                                 Assert(doFillInner);
1303
1304                                 if (!node->mj_MatchedInner)
1305                                 {
1306                                         /*
1307                                          * Generate a fake join tuple with nulls for the outer
1308                                          * tuple, and return it if it passes the non-join quals.
1309                                          */
1310                                         TupleTableSlot *result;
1311
1312                                         node->mj_MatchedInner = true;           /* do it only once */
1313
1314                                         result = MJFillInner(node);
1315                                         if (result)
1316                                                 return result;
1317                                 }
1318
1319                                 /* Mark before advancing, if wanted */
1320                                 if (node->mj_ExtraMarks)
1321                                         ExecMarkPos(innerPlan);
1322
1323                                 /*
1324                                  * now we get the next inner tuple, if any
1325                                  */
1326                                 innerTupleSlot = ExecProcNode(innerPlan);
1327                                 node->mj_InnerTupleSlot = innerTupleSlot;
1328                                 MJ_DEBUG_PROC_NODE(innerTupleSlot);
1329                                 node->mj_MatchedInner = false;
1330
1331                                 if (TupIsNull(innerTupleSlot))
1332                                 {
1333                                         MJ_printf("ExecMergeJoin: end of inner subplan\n");
1334                                         return NULL;
1335                                 }
1336
1337                                 /* Else remain in ENDOUTER state and process next tuple. */
1338                                 break;
1339
1340                                 /*
1341                                  * EXEC_MJ_ENDINNER means we have run out of inner tuples, but
1342                                  * are doing a left/full join and therefore must null- fill
1343                                  * any remaing unmatched outer tuples.
1344                                  */
1345                         case EXEC_MJ_ENDINNER:
1346                                 MJ_printf("ExecMergeJoin: EXEC_MJ_ENDINNER\n");
1347
1348                                 Assert(doFillOuter);
1349
1350                                 if (!node->mj_MatchedOuter)
1351                                 {
1352                                         /*
1353                                          * Generate a fake join tuple with nulls for the inner
1354                                          * tuple, and return it if it passes the non-join quals.
1355                                          */
1356                                         TupleTableSlot *result;
1357
1358                                         node->mj_MatchedOuter = true;           /* do it only once */
1359
1360                                         result = MJFillOuter(node);
1361                                         if (result)
1362                                                 return result;
1363                                 }
1364
1365                                 /*
1366                                  * now we get the next outer tuple, if any
1367                                  */
1368                                 outerTupleSlot = ExecProcNode(outerPlan);
1369                                 node->mj_OuterTupleSlot = outerTupleSlot;
1370                                 MJ_DEBUG_PROC_NODE(outerTupleSlot);
1371                                 node->mj_MatchedOuter = false;
1372
1373                                 if (TupIsNull(outerTupleSlot))
1374                                 {
1375                                         MJ_printf("ExecMergeJoin: end of outer subplan\n");
1376                                         return NULL;
1377                                 }
1378
1379                                 /* Else remain in ENDINNER state and process next tuple. */
1380                                 break;
1381
1382                                 /*
1383                                  * broken state value?
1384                                  */
1385                         default:
1386                                 elog(ERROR, "unrecognized mergejoin state: %d",
1387                                          (int) node->mj_JoinState);
1388                 }
1389         }
1390 }
1391
1392 /* ----------------------------------------------------------------
1393  *              ExecInitMergeJoin
1394  * ----------------------------------------------------------------
1395  */
1396 MergeJoinState *
1397 ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
1398 {
1399         MergeJoinState *mergestate;
1400
1401         /* check for unsupported flags */
1402         Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
1403
1404         MJ1_printf("ExecInitMergeJoin: %s\n",
1405                            "initializing node");
1406
1407         /*
1408          * create state structure
1409          */
1410         mergestate = makeNode(MergeJoinState);
1411         mergestate->js.ps.plan = (Plan *) node;
1412         mergestate->js.ps.state = estate;
1413
1414         /*
1415          * Miscellaneous initialization
1416          *
1417          * create expression context for node
1418          */
1419         ExecAssignExprContext(estate, &mergestate->js.ps);
1420
1421         /*
1422          * we need two additional econtexts in which we can compute the join
1423          * expressions from the left and right input tuples.  The node's regular
1424          * econtext won't do because it gets reset too often.
1425          */
1426         mergestate->mj_OuterEContext = CreateExprContext(estate);
1427         mergestate->mj_InnerEContext = CreateExprContext(estate);
1428
1429         /*
1430          * initialize child expressions
1431          */
1432         mergestate->js.ps.targetlist = (List *)
1433                 ExecInitExpr((Expr *) node->join.plan.targetlist,
1434                                          (PlanState *) mergestate);
1435         mergestate->js.ps.qual = (List *)
1436                 ExecInitExpr((Expr *) node->join.plan.qual,
1437                                          (PlanState *) mergestate);
1438         mergestate->js.jointype = node->join.jointype;
1439         mergestate->js.joinqual = (List *)
1440                 ExecInitExpr((Expr *) node->join.joinqual,
1441                                          (PlanState *) mergestate);
1442         /* mergeclauses are handled below */
1443
1444         /*
1445          * initialize child nodes
1446          *
1447          * inner child must support MARK/RESTORE.
1448          */
1449         outerPlanState(mergestate) = ExecInitNode(outerPlan(node), estate, eflags);
1450         innerPlanState(mergestate) = ExecInitNode(innerPlan(node), estate,
1451                                                                                           eflags | EXEC_FLAG_MARK);
1452
1453         /*
1454          * For certain types of inner child nodes, it is advantageous to issue
1455          * MARK every time we advance past an inner tuple we will never return to.
1456          * For other types, MARK on a tuple we cannot return to is a waste of
1457          * cycles.      Detect which case applies and set mj_ExtraMarks if we want to
1458          * issue "unnecessary" MARK calls.
1459          *
1460          * Currently, only Material wants the extra MARKs, and it will be helpful
1461          * only if eflags doesn't specify REWIND.
1462          */
1463         if (IsA(innerPlan(node), Material) &&
1464                 (eflags & EXEC_FLAG_REWIND) == 0)
1465                 mergestate->mj_ExtraMarks = true;
1466         else
1467                 mergestate->mj_ExtraMarks = false;
1468
1469 #define MERGEJOIN_NSLOTS 4
1470
1471         /*
1472          * tuple table initialization
1473          */
1474         ExecInitResultTupleSlot(estate, &mergestate->js.ps);
1475
1476         mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate);
1477         ExecSetSlotDescriptor(mergestate->mj_MarkedTupleSlot,
1478                                                   ExecGetResultType(innerPlanState(mergestate)));
1479
1480         switch (node->join.jointype)
1481         {
1482                 case JOIN_INNER:
1483                 case JOIN_SEMI:
1484                         mergestate->mj_FillOuter = false;
1485                         mergestate->mj_FillInner = false;
1486                         break;
1487                 case JOIN_LEFT:
1488                 case JOIN_ANTI:
1489                         mergestate->mj_FillOuter = true;
1490                         mergestate->mj_FillInner = false;
1491                         mergestate->mj_NullInnerTupleSlot =
1492                                 ExecInitNullTupleSlot(estate,
1493                                                           ExecGetResultType(innerPlanState(mergestate)));
1494                         break;
1495                 case JOIN_RIGHT:
1496                         mergestate->mj_FillOuter = false;
1497                         mergestate->mj_FillInner = true;
1498                         mergestate->mj_NullOuterTupleSlot =
1499                                 ExecInitNullTupleSlot(estate,
1500                                                           ExecGetResultType(outerPlanState(mergestate)));
1501
1502                         /*
1503                          * Can't handle right or full join with non-nil extra joinclauses.
1504                          * This should have been caught by planner.
1505                          */
1506                         if (node->join.joinqual != NIL)
1507                                 ereport(ERROR,
1508                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1509                                                  errmsg("RIGHT JOIN is only supported with merge-joinable join conditions")));
1510                         break;
1511                 case JOIN_FULL:
1512                         mergestate->mj_FillOuter = true;
1513                         mergestate->mj_FillInner = true;
1514                         mergestate->mj_NullOuterTupleSlot =
1515                                 ExecInitNullTupleSlot(estate,
1516                                                           ExecGetResultType(outerPlanState(mergestate)));
1517                         mergestate->mj_NullInnerTupleSlot =
1518                                 ExecInitNullTupleSlot(estate,
1519                                                           ExecGetResultType(innerPlanState(mergestate)));
1520
1521                         /*
1522                          * Can't handle right or full join with non-nil extra joinclauses.
1523                          */
1524                         if (node->join.joinqual != NIL)
1525                                 ereport(ERROR,
1526                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1527                                                  errmsg("FULL JOIN is only supported with merge-joinable join conditions")));
1528                         break;
1529                 default:
1530                         elog(ERROR, "unrecognized join type: %d",
1531                                  (int) node->join.jointype);
1532         }
1533
1534         /*
1535          * initialize tuple type and projection info
1536          */
1537         ExecAssignResultTypeFromTL(&mergestate->js.ps);
1538         ExecAssignProjectionInfo(&mergestate->js.ps, NULL);
1539
1540         /*
1541          * preprocess the merge clauses
1542          */
1543         mergestate->mj_NumClauses = list_length(node->mergeclauses);
1544         mergestate->mj_Clauses = MJExamineQuals(node->mergeclauses,
1545                                                                                         node->mergeFamilies,
1546                                                                                         node->mergeStrategies,
1547                                                                                         node->mergeNullsFirst,
1548                                                                                         (PlanState *) mergestate);
1549
1550         /*
1551          * initialize join state
1552          */
1553         mergestate->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
1554         mergestate->js.ps.ps_TupFromTlist = false;
1555         mergestate->mj_MatchedOuter = false;
1556         mergestate->mj_MatchedInner = false;
1557         mergestate->mj_OuterTupleSlot = NULL;
1558         mergestate->mj_InnerTupleSlot = NULL;
1559
1560         /*
1561          * initialization successful
1562          */
1563         MJ1_printf("ExecInitMergeJoin: %s\n",
1564                            "node initialized");
1565
1566         return mergestate;
1567 }
1568
1569 int
1570 ExecCountSlotsMergeJoin(MergeJoin *node)
1571 {
1572         return ExecCountSlotsNode(outerPlan((Plan *) node)) +
1573                 ExecCountSlotsNode(innerPlan((Plan *) node)) +
1574                 MERGEJOIN_NSLOTS;
1575 }
1576
1577 /* ----------------------------------------------------------------
1578  *              ExecEndMergeJoin
1579  *
1580  * old comments
1581  *              frees storage allocated through C routines.
1582  * ----------------------------------------------------------------
1583  */
1584 void
1585 ExecEndMergeJoin(MergeJoinState *node)
1586 {
1587         MJ1_printf("ExecEndMergeJoin: %s\n",
1588                            "ending node processing");
1589
1590         /*
1591          * Free the exprcontext
1592          */
1593         ExecFreeExprContext(&node->js.ps);
1594
1595         /*
1596          * clean out the tuple table
1597          */
1598         ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
1599         ExecClearTuple(node->mj_MarkedTupleSlot);
1600
1601         /*
1602          * shut down the subplans
1603          */
1604         ExecEndNode(innerPlanState(node));
1605         ExecEndNode(outerPlanState(node));
1606
1607         MJ1_printf("ExecEndMergeJoin: %s\n",
1608                            "node processing ended");
1609 }
1610
1611 void
1612 ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt)
1613 {
1614         ExecClearTuple(node->mj_MarkedTupleSlot);
1615
1616         node->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
1617         node->js.ps.ps_TupFromTlist = false;
1618         node->mj_MatchedOuter = false;
1619         node->mj_MatchedInner = false;
1620         node->mj_OuterTupleSlot = NULL;
1621         node->mj_InnerTupleSlot = NULL;
1622
1623         /*
1624          * if chgParam of subnodes is not null then plans will be re-scanned by
1625          * first ExecProcNode.
1626          */
1627         if (((PlanState *) node)->lefttree->chgParam == NULL)
1628                 ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
1629         if (((PlanState *) node)->righttree->chgParam == NULL)
1630                 ExecReScan(((PlanState *) node)->righttree, exprCtxt);
1631
1632 }