LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeMergejoin.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 95.0 % 460 437 5 7 11 2 163 8 264 10 161 7
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 11 11 3 1 7 3
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a