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