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 17:13:01 Functions: 100.0 % 11 11 3 1 7 3
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 100.0 % 2 2 2
Legend: Lines: hit not hit (240..) days: 95.0 % 458 435 5 7 11 2 163 6 264 10 154
Function coverage date bins:
(240..) days: 78.6 % 14 11 3 1 7 3

 Age         Owner                  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
 5933 tgl                       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;
 5951                           184            2325 :     int         nClauses = list_length(mergeclauses);
                                185                 :     int         iClause;
                                186                 :     ListCell   *cl;
                                187                 : 
 6540                           188            2325 :     clauses = (MergeJoinClause) palloc0(nClauses * sizeof(MergeJoinClauseData));
                                189                 : 
                                190            2325 :     iClause = 0;
 5951                           191            4950 :     foreach(cl, mergeclauses)
                                192                 :     {
                                193            2625 :         OpExpr     *qual = (OpExpr *) lfirst(cl);
 6540                           194            2625 :         MergeJoinClause clause = &clauses[iClause];
 5933                           195            2625 :         Oid         opfamily = mergefamilies[iClause];
 4443 peter_e                   196            2625 :         Oid         collation = mergecollations[iClause];
 5933 tgl                       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                 : 
 6540                           204            2625 :         if (!IsA(qual, OpExpr))
 6540 tgl                       205 UBC           0 :             elog(ERROR, "mergejoin clause is not an OpExpr");
                                206                 : 
                                207                 :         /*
                                208                 :          * Prepare the input expressions for execution.
                                209                 :          */
 6540 tgl                       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 */
 4141                           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 */
 4141 tgl                       221 UBC           0 :             elog(ERROR, "unsupported mergejoin strategy %d", opstrategy);
 4141 tgl                       222 CBC        2625 :         clause->ssup.ssup_nulls_first = nulls_first;
                                223                 : 
                                224                 :         /* Extract the operator's declared left/right datatypes */
 4511                           225            2625 :         get_op_opfamily_properties(qual->opno, opfamily, false,
                                226                 :                                    &op_strategy,
                                227                 :                                    &op_lefttype,
                                228                 :                                    &op_righttype);
 2118                           229            2625 :         if (op_strategy != BTEqualStrategyNumber)   /* should not happen */
 5932 tgl                       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                 :          */
 3002 rhaas                     239 CBC        2625 :         clause->ssup.abbreviate = false;
                                240                 : 
                                241                 :         /* And get the matching support or comparison function */
 3168                           242            2625 :         Assert(clause->ssup.comparator == NULL);
 4141 tgl                       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                 :         }
 3168 rhaas                     252            2625 :         if (clause->ssup.comparator == NULL)
                                253                 :         {
                                254                 :             /* support not available, get comparison func */
 4141 tgl                       255             199 :             sortfunc = get_opfamily_proc(opfamily,
                                256                 :                                          op_lefttype,
                                257                 :                                          op_righttype,
                                258                 :                                          BTORDER_PROC);
 3955 bruce                     259             199 :             if (!OidIsValid(sortfunc))  /* should not happen */
 4141 tgl                       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 */
 4141 tgl                       263 CBC         199 :             PrepareSortSupportComparisonShim(sortfunc, &clause->ssup);
                                264                 :         }
                                265                 : 
 6540                           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;
 4699                           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                 : 
 6540                           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);
 5951                           318         1031794 :         if (clause->lisnull)
                                319                 :         {
                                320                 :             /* match is impossible; can we end the join early? */
 4141                           321              18 :             if (i == 0 && !clause->ssup.ssup_nulls_first &&
                                322               6 :                 !mergestate->mj_FillOuter)
 4699 tgl                       323 UBC           0 :                 result = MJEVAL_ENDOFJOIN;
 4699 tgl                       324 CBC          18 :             else if (result == MJEVAL_MATCHABLE)
                                325              15 :                 result = MJEVAL_NONMATCHABLE;
                                326                 :         }
                                327                 :     }
                                328                 : 
 6540                           329          826585 :     MemoryContextSwitchTo(oldContext);
                                330                 : 
 4699                           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
 6540                           342         2499162 : MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
                                343                 : {
                                344         2499162 :     ExprContext *econtext = mergestate->mj_InnerEContext;
 4699                           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                 : 
 6540                           353         2496148 :     ResetExprContext(econtext);
                                354                 : 
 8306                           355         2496148 :     oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
                                356                 : 
 6540                           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);
 5951                           365         2554241 :         if (clause->risnull)
                                366                 :         {
                                367                 :             /* match is impossible; can we end the join early? */
 4141                           368              96 :             if (i == 0 && !clause->ssup.ssup_nulls_first &&
                                369              78 :                 !mergestate->mj_FillInner)
 4699                           370              42 :                 result = MJEVAL_ENDOFJOIN;
                                371              54 :             else if (result == MJEVAL_MATCHABLE)
                                372              48 :                 result = MJEVAL_NONMATCHABLE;
                                373                 :         }
                                374                 :     }
                                375                 : 
 6540                           376         2496148 :     MemoryContextSwitchTo(oldContext);
                                377                 : 
 4699                           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
 6540                           392         2881098 : MJCompare(MergeJoinState *mergestate)
                                393                 : {
 4141                           394         2881098 :     int         result = 0;
 6540                           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                 :          */
 4141                           415         2943748 :         if (clause->lisnull && clause->risnull)
                                416                 :         {
 3955 bruce                     417 UBC           0 :             nulleqnull = true;  /* NULL "=" NULL */
 5951 tgl                       418               0 :             continue;
                                419                 :         }
                                420                 : 
 4141 tgl                       421 CBC     2943748 :         result = ApplySortComparator(clause->ldatum, clause->lisnull,
                                422         2943748 :                                      clause->rdatum, clause->risnull,
                                423         2943748 :                                      &clause->ssup);
                                424                 : 
 5932                           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                 :      */
 4842                           438         2881098 :     if (result == 0 &&
                                439         1576812 :         (nulleqnull || mergestate->mj_ConstFalseJoin))
 6540                           440              24 :         result = 1;
                                441                 : 
 8306                           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 *
 6539                           453          130369 : MJFillOuter(MergeJoinState *node)
                                454                 : {
                                455          130369 :     ExprContext *econtext = node->js.ps.ps_ExprContext;
 2217 andres                    456          130369 :     ExprState  *otherqual = node->js.ps.qual;
                                457                 : 
 6539 tgl                       458          130369 :     ResetExprContext(econtext);
                                459                 : 
                                460          130369 :     econtext->ecxt_outertuple = node->mj_OuterTupleSlot;
                                461          130369 :     econtext->ecxt_innertuple = node->mj_NullInnerTupleSlot;
                                462                 : 
 2217 andres                    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                 : 
 2271                           471          128844 :         return ExecProject(node->js.ps.ps_ProjInfo);
                                472                 :     }
                                473                 :     else
 4217 tgl                       474            1525 :         InstrCountFiltered2(node, 1);
                                475                 : 
 6539                           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;
 2217 andres                    487            1689 :     ExprState  *otherqual = node->js.ps.qual;
                                488                 : 
 6539 tgl                       489            1689 :     ResetExprContext(econtext);
                                490                 : 
                                491            1689 :     econtext->ecxt_outertuple = node->mj_NullOuterTupleSlot;
                                492            1689 :     econtext->ecxt_innertuple = node->mj_InnerTupleSlot;
                                493                 : 
 2217 andres                    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                 : 
 2271                           502            1398 :         return ExecProject(node->js.ps.ps_ProjInfo);
                                503                 :     }
                                504                 :     else
 4217 tgl                       505             291 :         InstrCountFiltered2(node, 1);
                                506                 : 
 6539                           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
 4842                           520             823 : check_constant_qual(List *qual, bool *is_const_false)
                                521                 : {
                                522                 :     ListCell   *lc;
                                523                 : 
                                524             829 :     foreach(lc, qual)
                                525                 :     {
 4790 bruce                     526               6 :         Const      *con = (Const *) lfirst(lc);
                                527                 : 
 4842 tgl                       528               6 :         if (!con || !IsA(con, Const))
 4842 tgl                       529 UBC           0 :             return false;
 4842 tgl                       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 *
 2092 andres                    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                 : 
 2084                           615         1318969 :     CHECK_FOR_INTERRUPTS();
                                616                 : 
                                617                 :     /*
                                618                 :      * get information from node
                                619                 :      */
 7430 tgl                       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;
 6539                           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                 :      */
 8263                           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                 :          */
 7430                           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                 :                  */
 6540                           653            2239 :             case EXEC_MJ_INITIALIZE_OUTER:
                                654                 :                 MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE_OUTER\n");
                                655                 : 
 7430                           656            2239 :                 outerTupleSlot = ExecProcNode(outerPlan);
                                657            2239 :                 node->mj_OuterTupleSlot = outerTupleSlot;
                                658                 : 
                                659                 :                 /* Compute join values and check for unmatchability */
 4699                           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                 :                         }
 4699 tgl                       681 UBC           0 :                         break;
 4699 tgl                       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                 :                 }
 6540                           699            2202 :                 break;
                                700                 : 
                                701            2139 :             case EXEC_MJ_INITIALIZE_INNER:
                                702                 :                 MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE_INNER\n");
                                703                 : 
 7430                           704            2139 :                 innerTupleSlot = ExecProcNode(innerPlan);
                                705            2139 :                 node->mj_InnerTupleSlot = innerTupleSlot;
                                706                 : 
                                707                 :                 /* Compute join values and check for unmatchability */
 4699                           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)
 4699 tgl                       721 UBC           0 :                             ExecMarkPos(innerPlan);
                                722                 :                         /* Stay in same state to fetch next inner tuple */
 4699 tgl                       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                 :                         }
 4699 tgl                       736 UBC           0 :                         break;
 4699 tgl                       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                 :                 }
 9344 bruce                     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                 :                  */
 7430 tgl                       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                 :                  */
 6540                           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                 : 
 2217 andres                    792         1793866 :                 qualResult = (joinqual == NULL ||
                                793          217078 :                               ExecQual(joinqual, econtext));
                                794                 :                 MJ_DEBUG_QUAL(joinqual, qualResult);
                                795                 : 
 9344 bruce                     796         1576788 :                 if (qualResult)
                                797                 :                 {
 7430 tgl                       798         1360530 :                     node->mj_MatchedOuter = true;
                                799         1360530 :                     node->mj_MatchedInner = true;
                                800                 : 
                                801                 :                     /* In an antijoin, we never return a matched tuple */
 5351                           802         1360530 :                     if (node->js.jointype == JOIN_ANTI)
                                803                 :                     {
 5350                           804            5721 :                         node->mj_JoinState = EXEC_MJ_NEXTOUTER;
 5351                           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                 :                      */
    4 tgl                       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                 :                      */
 2193 tgl                       821 CBC     1325918 :                     if (node->js.single_match)
 5350                           822           14260 :                         node->mj_JoinState = EXEC_MJ_NEXTOUTER;
                                823                 : 
 2217 andres                    824 GIC     1466953 :                     qualResult = (otherqual == NULL ||
                                825          141035 :                                   ExecQual(otherqual, econtext));
                                826                 :                     MJ_DEBUG_QUAL(otherqual, qualResult);
                                827                 : 
 8244 tgl                       828         1325918 :                     if (qualResult)
 8263 tgl                       829 ECB             :                     {
 8053 bruce                     830                 :                         /*
                                831                 :                          * qualification succeeded.  now form the desired
 6385                           832                 :                          * projection tuple and return the slot containing it.
 8244 tgl                       833                 :                          */
                                834                 :                         MJ_printf("ExecMergeJoin: returning tuple\n");
                                835                 : 
 2271 andres                    836 CBC     1186535 :                         return ExecProject(node->js.ps.ps_ProjInfo);
                                837                 :                     }
                                838                 :                     else
 4217 tgl                       839 GIC      139383 :                         InstrCountFiltered2(node, 1);
                                840                 :                 }
                                841                 :                 else
                                842          216258 :                     InstrCountFiltered1(node, 1);
 9344 bruce                     843          355641 :                 break;
 9344 bruce                     844 ECB             : 
                                845                 :                 /*
                                846                 :                  * EXEC_MJ_NEXTINNER means advance the inner scan to the next
 6385                           847                 :                  * tuple. If the tuple is not nil, we then proceed to test it
                                848                 :                  * against the join qualification.
                                849                 :                  *
 8244 tgl                       850                 :                  * Before advancing, we check to see if we must emit an
                                851                 :                  * outer-join fill tuple for this inner tuple.
                                852                 :                  */
 9344 bruce                     853 GIC     1556805 :             case EXEC_MJ_NEXTINNER:
                                854                 :                 MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\n");
                                855                 : 
 7430 tgl                       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.
 8244 tgl                       861 ECB             :                      */
                                862                 :                     TupleTableSlot *result;
                                863                 : 
 2118 tgl                       864 LBC           0 :                     node->mj_MatchedInner = true;    /* do it only once */
                                865                 : 
 6539 tgl                       866 UIC           0 :                     result = MJFillInner(node);
                                867               0 :                     if (result)
                                868               0 :                         return result;
                                869                 :                 }
                                870                 : 
                                871                 :                 /*
 6385 bruce                     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).
 5802 tgl                       875                 :                  *
                                876                 :                  * NB: must NOT do "extraMarks" here, since we may need to
                                877                 :                  * return to previously marked tuples.
                                878                 :                  */
 7430 tgl                       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 */
 4699                           885         1556805 :                 switch (MJEvalInnerValues(node, innerTupleSlot))
                                886                 :                 {
 4699 tgl                       887 CBC     1554957 :                     case MJEVAL_MATCHABLE:
 4660 bruce                     888 ECB             : 
                                889                 :                         /*
 4699 tgl                       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                 :                          */
 4699 tgl                       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;
  428                           904          418322 :                         else if (compareResult < 0)
 4699                           905          418322 :                             node->mj_JoinState = EXEC_MJ_NEXTOUTER;
                                906                 :                         else    /* compareResult > 0 should not happen */
  428 tgl                       907 LBC           0 :                             elog(ERROR, "mergejoin input data is out of order");
 4699 tgl                       908 GIC     1554957 :                         break;
                                909              12 :                     case MJEVAL_NONMATCHABLE:
 4660 bruce                     910 ECB             : 
 4699 tgl                       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.
 4699 tgl                       915 EUB             :                          */
 4699 tgl                       916 CBC          12 :                         node->mj_JoinState = EXEC_MJ_NEXTOUTER;
                                917              12 :                         break;
 4699 tgl                       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
 4699 tgl                       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                 :                          */
 4699 tgl                       928 GIC        1836 :                         node->mj_InnerTupleSlot = NULL;
                                929            1836 :                         node->mj_JoinState = EXEC_MJ_NEXTOUTER;
                                930            1836 :                         break;
                                931                 :                 }
 9345 bruce                     932         1556805 :                 break;
                                933                 : 
                                934                 :                 /*-------------------------------------------
                                935                 :                  * EXEC_MJ_NEXTOUTER means
 8811 lockhart                  936 ECB             :                  *
 8810 bruce                     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                 :                  */
 9344 bruce                     954 GIC      471628 :             case EXEC_MJ_NEXTOUTER:
                                955                 :                 MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n");
                                956                 : 
 7430 tgl                       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.
 8244 tgl                       962 ECB             :                      */
                                963                 :                     TupleTableSlot *result;
                                964                 : 
 2118 tgl                       965 CBC       31497 :                     node->mj_MatchedOuter = true;    /* do it only once */
                                966                 : 
 6539 tgl                       967 GIC       31497 :                     result = MJFillOuter(node);
                                968           31497 :                     if (result)
                                969           31497 :                         return result;
                                970                 :                 }
                                971                 : 
                                972                 :                 /*
 8053 bruce                     973 ECB             :                  * now we get the next outer tuple, if any
                                974                 :                  */
 7430 tgl                       975 CBC      440131 :                 outerTupleSlot = ExecProcNode(outerPlan);
                                976          440131 :                 node->mj_OuterTupleSlot = outerTupleSlot;
 9345 bruce                     977 ECB             :                 MJ_DEBUG_PROC_NODE(outerTupleSlot);
 7430 tgl                       978 GIC      440131 :                 node->mj_MatchedOuter = false;
                                979                 : 
                                980                 :                 /* Compute join values and check for unmatchability */
 4699                           981          440131 :                 switch (MJEvalOuterValues(node))
                                982                 :                 {
 4699 tgl                       983 CBC      439397 :                     case MJEVAL_MATCHABLE:
 4699 tgl                       984 ECB             :                         /* Go test the new tuple against the marked tuple */
 4699 tgl                       985 GIC      439397 :                         node->mj_JoinState = EXEC_MJ_TESTOUTER;
 4699 tgl                       986 CBC      439397 :                         break;
 4699 tgl                       987 GIC           6 :                     case MJEVAL_NONMATCHABLE:
                                988                 :                         /* Can't match, so fetch next outer tuple */
 4699 tgl                       989 CBC           6 :                         node->mj_JoinState = EXEC_MJ_NEXTOUTER;
 4699 tgl                       990 GIC           6 :                         break;
 4699 tgl                       991 CBC         728 :                     case MJEVAL_ENDOFJOIN:
                                992                 :                         /* No more outer tuples */
 4699 tgl                       993 ECB             :                         MJ_printf("ExecMergeJoin: end of outer subplan\n");
 4699 tgl                       994 CBC         728 :                         innerTupleSlot = node->mj_InnerTupleSlot;
                                995             728 :                         if (doFillInner && !TupIsNull(innerTupleSlot))
                                996                 :                         {
 4699 tgl                       997 ECB             :                             /*
                                998                 :                              * Need to emit right-join tuples for remaining
                                999                 :                              * inner tuples.
                               1000                 :                              */
 4699 tgl                      1001 GIC          21 :                             node->mj_JoinState = EXEC_MJ_ENDOUTER;
 4699 tgl                      1002 CBC          21 :                             break;
 4699 tgl                      1003 ECB             :                         }
                               1004                 :                         /* Otherwise we're done. */
 4699 tgl                      1005 GIC         707 :                         return NULL;
                               1006                 :                 }
 9344 bruce                    1007          439424 :                 break;
                               1008                 : 
 8810 bruce                    1009 ECB             :                 /*--------------------------------------------------------
 8811 lockhart                 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.
 9344 bruce                    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                 :                  */
 9344 bruce                    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                 :                  */
 7430 tgl                      1052 CBC      439397 :                 innerTupleSlot = node->mj_MarkedTupleSlot;
 6540 tgl                      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                 :                 {
 8986 bruce                    1060 ECB             :                     /*
 6385                          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
 2193 tgl                      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                 :                      */
 2193 tgl                      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
 2193 tgl                      1089 ECB             :                          * be assumed to hold the required tuple.)
                               1090                 :                          */
 2193 tgl                      1091 CBC       69046 :                         node->mj_InnerTupleSlot = innerTupleSlot;
                               1092                 :                         /* we need not do MJEvalInnerValues again */
                               1093                 :                     }
                               1094                 : 
 7430 tgl                      1095 GIC       70489 :                     node->mj_JoinState = EXEC_MJ_JOINTUPLES;
                               1096                 :                 }
  428                          1097          368908 :                 else if (compareResult > 0)
                               1098                 :                 {
 9344 bruce                    1099 ECB             :                     /* ----------------
                               1100                 :                      *  if the new outer tuple didn't match the marked inner
                               1101                 :                      *  tuple then we have a case like:
                               1102                 :                      *
 8810                          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                 :                      */
 7430 tgl                      1116 GIC      368908 :                     innerTupleSlot = node->mj_InnerTupleSlot;
                               1117                 : 
                               1118                 :                     /* reload comparison data for current inner */
 4699                          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;
 4699 tgl                      1124 CBC      368527 :                             break;
 4699 tgl                      1125 GIC          12 :                         case MJEVAL_NONMATCHABLE:
                               1126                 : 
 8244 tgl                      1127 ECB             :                             /*
                               1128                 :                              * current inner can't possibly match any outer;
 4660 bruce                    1129                 :                              * better to advance the inner scan than the
                               1130                 :                              * outer.
 8244 tgl                      1131                 :                              */
 4699 tgl                      1132 CBC          12 :                             node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
 8811 lockhart                 1133              12 :                             break;
 4699 tgl                      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
 4699 tgl                      1140 ECB             :                                  * outer tuples.
                               1141                 :                                  */
 4699 tgl                      1142 CBC          70 :                                 node->mj_JoinState = EXEC_MJ_ENDINNER;
 4699 tgl                      1143 GIC          70 :                                 break;
 4699 tgl                      1144 ECB             :                             }
                               1145                 :                             /* Otherwise we're done. */
 4699 tgl                      1146 GIC         299 :                             return NULL;
                               1147                 :                     }
                               1148                 :                 }
                               1149                 :                 else            /* compareResult < 0 should not happen */
  428 tgl                      1150 LBC           0 :                     elog(ERROR, "mergejoin input data is out of order");
 9345 bruce                    1151 CBC      439098 :                 break;
                               1152                 : 
                               1153                 :                 /*----------------------------------------------------------
  410 dgustafsson              1154 ECB             :                  * EXEC_MJ_SKIP_TEST means compare tuples and if they do not
                               1155                 :                  * match, skip whichever is lesser.
                               1156                 :                  *
                               1157                 :                  * For example:
 9344 bruce                    1158 EUB             :                  *
 8810 bruce                    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                 :                  */
 6540 tgl                      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                 :                  */
 6540 tgl                      1190 CBC      886744 :                 compareResult = MJCompare(node);
                               1191                 :                 MJ_DEBUG_COMPARE(compareResult);
                               1192                 : 
 6540 tgl                      1193 GIC      886744 :                 if (compareResult == 0)
                               1194                 :                 {
 2193                          1195          369664 :                     if (!node->mj_SkipMarkRestore)
                               1196          352718 :                         ExecMarkPos(innerPlan);
                               1197                 : 
 6540 tgl                      1198 CBC      369664 :                     MarkInnerTuple(node->mj_InnerTupleSlot, node);
                               1199                 : 
 7430 tgl                      1200 GIC      369664 :                     node->mj_JoinState = EXEC_MJ_JOINTUPLES;
 9344 bruce                    1201 ECB             :                 }
 6540 tgl                      1202 GIC      517080 :                 else if (compareResult < 0)
 7430 tgl                      1203 CBC      385191 :                     node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
 6385 bruce                    1204 ECB             :                 else
                               1205                 :                     /* compareResult > 0 */
 6540 tgl                      1206 CBC      131889 :                     node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
 9345 bruce                    1207 GIC      886744 :                 break;
 9344 bruce                    1208 ECB             : 
                               1209                 :                 /*
  410 dgustafsson              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
 8244 tgl                      1214                 :                  * outer-join fill tuple for this outer tuple.
                               1215                 :                  */
 8244 tgl                      1216 GIC      448896 :             case EXEC_MJ_SKIPOUTER_ADVANCE:
                               1217                 :                 MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_ADVANCE\n");
                               1218                 : 
 7430                          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.
 8244 tgl                      1224 ECB             :                      */
                               1225                 :                     TupleTableSlot *result;
                               1226                 : 
 2118 tgl                      1227 CBC       65164 :                     node->mj_MatchedOuter = true;    /* do it only once */
                               1228                 : 
 6539 tgl                      1229 GIC       65164 :                     result = MJFillOuter(node);
                               1230           65164 :                     if (result)
                               1231           63705 :                         return result;
                               1232                 :                 }
                               1233                 : 
                               1234                 :                 /*
 8053 bruce                    1235 ECB             :                  * now we get the next outer tuple, if any
                               1236                 :                  */
 7430 tgl                      1237 CBC      385191 :                 outerTupleSlot = ExecProcNode(outerPlan);
                               1238          385191 :                 node->mj_OuterTupleSlot = outerTupleSlot;
 8244 tgl                      1239 ECB             :                 MJ_DEBUG_PROC_NODE(outerTupleSlot);
 7430 tgl                      1240 GIC      385191 :                 node->mj_MatchedOuter = false;
                               1241                 : 
                               1242                 :                 /* Compute join values and check for unmatchability */
 4699                          1243          385191 :                 switch (MJEvalOuterValues(node))
                               1244                 :                 {
 4699 tgl                      1245 CBC      385040 :                     case MJEVAL_MATCHABLE:
 4699 tgl                      1246 ECB             :                         /* Go test the new tuple against the current inner */
 4699 tgl                      1247 GIC      385040 :                         node->mj_JoinState = EXEC_MJ_SKIP_TEST;
 4699 tgl                      1248 CBC      385040 :                         break;
 4699 tgl                      1249 GIC           3 :                     case MJEVAL_NONMATCHABLE:
                               1250                 :                         /* Can't match, so fetch next outer tuple */
 4699 tgl                      1251 CBC           3 :                         node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
 4699 tgl                      1252 GIC           3 :                         break;
 4699 tgl                      1253 CBC         148 :                     case MJEVAL_ENDOFJOIN:
                               1254                 :                         /* No more outer tuples */
 4699 tgl                      1255 ECB             :                         MJ_printf("ExecMergeJoin: end of outer subplan\n");
 4699 tgl                      1256 CBC         148 :                         innerTupleSlot = node->mj_InnerTupleSlot;
                               1257             148 :                         if (doFillInner && !TupIsNull(innerTupleSlot))
                               1258                 :                         {
 4699 tgl                      1259 ECB             :                             /*
                               1260                 :                              * Need to emit right-join tuples for remaining
                               1261                 :                              * inner tuples.
                               1262                 :                              */
 4699 tgl                      1263 GIC          18 :                             node->mj_JoinState = EXEC_MJ_ENDOUTER;
 4699 tgl                      1264 CBC          18 :                             break;
 4699 tgl                      1265 ECB             :                         }
                               1266                 :                         /* Otherwise we're done. */
 4699 tgl                      1267 GIC         130 :                         return NULL;
                               1268                 :                 }
 9344 bruce                    1269          385061 :                 break;
                               1270                 : 
 8053 bruce                    1271 ECB             :                 /*
  410 dgustafsson              1272                 :                  * EXEC_MJ_SKIPINNER_ADVANCE: advance over an inner tuple that
                               1273                 :                  * is known not to join to any outer tuple.
                               1274                 :                  *
 8244 tgl                      1275                 :                  * Before advancing, we check to see if we must emit an
                               1276                 :                  * outer-join fill tuple for this inner tuple.
 8810 bruce                    1277                 :                  */
 8244 tgl                      1278 GIC      133194 :             case EXEC_MJ_SKIPINNER_ADVANCE:
                               1279                 :                 MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_ADVANCE\n");
                               1280                 : 
 7430                          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.
 8244 tgl                      1286 ECB             :                      */
                               1287                 :                     TupleTableSlot *result;
                               1288                 : 
 2118 tgl                      1289 CBC        1569 :                     node->mj_MatchedInner = true;    /* do it only once */
                               1290                 : 
 6539 tgl                      1291 GIC        1569 :                     result = MJFillInner(node);
                               1292            1569 :                     if (result)
                               1293            1281 :                         return result;
                               1294                 :                 }
                               1295                 : 
                               1296                 :                 /* Mark before advancing, if wanted */
 5802 tgl                      1297 CBC      131913 :                 if (node->mj_ExtraMarks)
 5802 tgl                      1298 GIC          48 :                     ExecMarkPos(innerPlan);
 5802 tgl                      1299 ECB             : 
 8053 bruce                    1300                 :                 /*
                               1301                 :                  * now we get the next inner tuple, if any
                               1302                 :                  */
 7430 tgl                      1303 GIC      131913 :                 innerTupleSlot = ExecProcNode(innerPlan);
                               1304          131913 :                 node->mj_InnerTupleSlot = innerTupleSlot;
 8811 lockhart                 1305 ECB             :                 MJ_DEBUG_PROC_NODE(innerTupleSlot);
 7430 tgl                      1306 CBC      131913 :                 node->mj_MatchedInner = false;
                               1307                 : 
                               1308                 :                 /* Compute join values and check for unmatchability */
 4699 tgl                      1309 GIC      131913 :                 switch (MJEvalInnerValues(node, innerTupleSlot))
                               1310                 :                 {
 4699 tgl                      1311 CBC      131207 :                     case MJEVAL_MATCHABLE:
 4699 tgl                      1312 ECB             :                         /* proceed to compare it to the current outer */
 4699 tgl                      1313 GIC      131207 :                         node->mj_JoinState = EXEC_MJ_SKIP_TEST;
 4699 tgl                      1314 CBC      131207 :                         break;
 4699 tgl                      1315 GIC          12 :                     case MJEVAL_NONMATCHABLE:
                               1316                 : 
 8244 tgl                      1317 ECB             :                         /*
                               1318                 :                          * current inner can't possibly match any outer;
 4699                          1319                 :                          * better to advance the inner scan than the outer.
                               1320                 :                          */
 4699 tgl                      1321 CBC          12 :                         node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
 8811 lockhart                 1322              12 :                         break;
 4699 tgl                      1323             694 :                     case MJEVAL_ENDOFJOIN:
                               1324                 :                         /* No more inner tuples */
                               1325                 :                         MJ_printf("ExecMergeJoin: end of inner subplan\n");
 4699 tgl                      1326 GIC         694 :                         outerTupleSlot = node->mj_OuterTupleSlot;
                               1327             694 :                         if (doFillOuter && !TupIsNull(outerTupleSlot))
                               1328                 :                         {
 4699 tgl                      1329 ECB             :                             /*
                               1330                 :                              * Need to emit left-join tuples for remaining
                               1331                 :                              * outer tuples.
                               1332                 :                              */
 4699 tgl                      1333 GIC         200 :                             node->mj_JoinState = EXEC_MJ_ENDINNER;
 4699 tgl                      1334 CBC         200 :                             break;
 4699 tgl                      1335 ECB             :                         }
                               1336                 :                         /* Otherwise we're done. */
 4699 tgl                      1337 GIC         494 :                         return NULL;
                               1338                 :                 }
 8811 lockhart                 1339          131419 :                 break;
                               1340                 : 
 8810 bruce                    1341 ECB             :                 /*
 6385                          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.
 8810                          1345                 :                  */
 8244 tgl                      1346 GIC         279 :             case EXEC_MJ_ENDOUTER:
 8244 tgl                      1347 ECB             :                 MJ_printf("ExecMergeJoin: EXEC_MJ_ENDOUTER\n");
                               1348                 : 
 8244 tgl                      1349 GIC         279 :                 Assert(doFillInner);
                               1350                 : 
 7430                          1351             279 :                 if (!node->mj_MatchedInner)
                               1352                 :                 {
                               1353                 :                     /*
 8244 tgl                      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                 :                      */
 6539                          1357                 :                     TupleTableSlot *result;
                               1358                 : 
 2118 tgl                      1359 CBC         108 :                     node->mj_MatchedInner = true;    /* do it only once */
                               1360                 : 
 6539 tgl                      1361 GIC         108 :                     result = MJFillInner(node);
                               1362             108 :                     if (result)
                               1363             105 :                         return result;
                               1364                 :                 }
                               1365                 : 
                               1366                 :                 /* Mark before advancing, if wanted */
 5802 tgl                      1367 CBC         174 :                 if (node->mj_ExtraMarks)
 5802 tgl                      1368 GIC          36 :                     ExecMarkPos(innerPlan);
 5802 tgl                      1369 ECB             : 
 8053 bruce                    1370                 :                 /*
                               1371                 :                  * now we get the next inner tuple, if any
                               1372                 :                  */
 7430 tgl                      1373 GIC         174 :                 innerTupleSlot = ExecProcNode(innerPlan);
                               1374             174 :                 node->mj_InnerTupleSlot = innerTupleSlot;
 8244 tgl                      1375 ECB             :                 MJ_DEBUG_PROC_NODE(innerTupleSlot);
 7430 tgl                      1376 CBC         174 :                 node->mj_MatchedInner = false;
                               1377                 : 
 8244 tgl                      1378 GIC         174 :                 if (TupIsNull(innerTupleSlot))
                               1379                 :                 {
                               1380                 :                     MJ_printf("ExecMergeJoin: end of inner subplan\n");
 8244 tgl                      1381 CBC         105 :                     return NULL;
 8244 tgl                      1382 ECB             :                 }
                               1383                 : 
                               1384                 :                 /* Else remain in ENDOUTER state and process next tuple. */
 8244 tgl                      1385 GIC          69 :                 break;
 8244 tgl                      1386 ECB             : 
                               1387                 :                 /*
                               1388                 :                  * EXEC_MJ_ENDINNER means we have run out of inner tuples, but
 6385 bruce                    1389                 :                  * are doing a left/full join and therefore must null- fill
                               1390                 :                  * any remaining unmatched outer tuples.
                               1391                 :                  */
 8244 tgl                      1392 GIC       67337 :             case EXEC_MJ_ENDINNER:
 8244 tgl                      1393 ECB             :                 MJ_printf("ExecMergeJoin: EXEC_MJ_ENDINNER\n");
                               1394                 : 
 8244 tgl                      1395 GIC       67337 :                 Assert(doFillOuter);
                               1396                 : 
 7430                          1397           67337 :                 if (!node->mj_MatchedOuter)
                               1398                 :                 {
                               1399                 :                     /*
 8244 tgl                      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                 :                      */
 6539                          1403                 :                     TupleTableSlot *result;
                               1404                 : 
 2118 tgl                      1405 CBC       33702 :                     node->mj_MatchedOuter = true;    /* do it only once */
                               1406                 : 
 6539 tgl                      1407 GIC       33702 :                     result = MJFillOuter(node);
                               1408           33702 :                     if (result)
                               1409           33636 :                         return result;
                               1410                 :                 }
                               1411                 : 
                               1412                 :                 /*
 8053 bruce                    1413 ECB             :                  * now we get the next outer tuple, if any
                               1414                 :                  */
 7430 tgl                      1415 CBC       33701 :                 outerTupleSlot = ExecProcNode(outerPlan);
                               1416           33701 :                 node->mj_OuterTupleSlot = outerTupleSlot;
 8811 lockhart                 1417 ECB             :                 MJ_DEBUG_PROC_NODE(outerTupleSlot);
 7430 tgl                      1418 GIC       33701 :                 node->mj_MatchedOuter = false;
                               1419                 : 
 8811 lockhart                 1420           33701 :                 if (TupIsNull(outerTupleSlot))
                               1421                 :                 {
                               1422                 :                     MJ_printf("ExecMergeJoin: end of outer subplan\n");
 8811 lockhart                 1423 CBC         289 :                     return NULL;
 8811 lockhart                 1424 ECB             :                 }
                               1425                 : 
 8244 tgl                      1426                 :                 /* Else remain in ENDINNER state and process next tuple. */
 8811 lockhart                 1427 GIC       33412 :                 break;
 8811 lockhart                 1428 ECB             : 
                               1429                 :                 /*
                               1430                 :                  * broken state value?
 8810 bruce                    1431                 :                  */
 9344 bruce                    1432 UIC           0 :             default:
 7202 tgl                      1433               0 :                 elog(ERROR, "unrecognized mergejoin state: %d",
                               1434                 :                      (int) node->mj_JoinState);
 9770 scrappy                  1435 ECB             :         }
                               1436                 :     }
                               1437                 : }
                               1438                 : 
                               1439                 : /* ----------------------------------------------------------------
 9345 bruce                    1440 EUB             :  *      ExecInitMergeJoin
 9770 scrappy                  1441                 :  * ----------------------------------------------------------------
                               1442                 :  */
                               1443                 : MergeJoinState *
 6249 tgl                      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 */
 6249 tgl                      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                 :      */
 9345 bruce                    1460            2325 :     mergestate = makeNode(MergeJoinState);
 7430 tgl                      1461 GIC        2325 :     mergestate->js.ps.plan = (Plan *) node;
                               1462            2325 :     mergestate->js.ps.state = estate;
 2092 andres                   1463            2325 :     mergestate->js.ps.ExecProcNode = ExecMergeJoin;
 1878                          1464            2325 :     mergestate->js.jointype = node->join.jointype;
                               1465            2325 :     mergestate->mj_ConstFalseJoin = false;
                               1466                 : 
                               1467                 :     /*
 8053 bruce                    1468 ECB             :      * Miscellaneous initialization
 9345                          1469                 :      *
 8053                          1470                 :      * create expression context for node
 9345                          1471                 :      */
 7430 tgl                      1472 CBC        2325 :     ExecAssignExprContext(estate, &mergestate->js.ps);
 7430 tgl                      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                 :      */
 6540 tgl                      1479 GIC        2325 :     mergestate->mj_OuterEContext = CreateExprContext(estate);
 6540 tgl                      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
 2193 tgl                      1487 ECB             :      * there are non-mergeclause joinquals, since the logic wouldn't work.
 8244                          1488                 :      */
 2193 tgl                      1489 GIC        2325 :     Assert(node->join.joinqual == NIL || !node->skip_mark_restore);
                               1490            2325 :     mergestate->mj_SkipMarkRestore = node->skip_mark_restore;
                               1491                 : 
 6249                          1492            2325 :     outerPlanState(mergestate) = ExecInitNode(outerPlan(node), estate, eflags);
 1878 andres                   1493            2325 :     outerDesc = ExecGetResultType(outerPlanState(mergestate));
 6249 tgl                      1494            2325 :     innerPlanState(mergestate) = ExecInitNode(innerPlan(node), estate,
 2193                          1495            2325 :                                               mergestate->mj_SkipMarkRestore ?
                               1496                 :                                               eflags :
 2193 tgl                      1497 ECB             :                                               (eflags | EXEC_FLAG_MARK));
 1878 andres                   1498 CBC        2325 :     innerDesc = ExecGetResultType(innerPlanState(mergestate));
                               1499                 : 
 5802 tgl                      1500 ECB             :     /*
                               1501                 :      * For certain types of inner child nodes, it is advantageous to issue
 5624 bruce                    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.
 5802 tgl                      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                 :      */
 5802 tgl                      1514 GIC        2325 :     if (IsA(innerPlan(node), Material) &&
 2193                          1515              77 :         (eflags & EXEC_FLAG_REWIND) == 0 &&
                               1516              77 :         !mergestate->mj_SkipMarkRestore)
 5802                          1517              77 :         mergestate->mj_ExtraMarks = true;
                               1518                 :     else
                               1519            2248 :         mergestate->mj_ExtraMarks = false;
                               1520                 : 
                               1521                 :     /*
 1878 andres                   1522 ECB             :      * Initialize result slot, type and projection.
                               1523                 :      */
 1606 andres                   1524 CBC        2325 :     ExecInitResultTupleSlotTL(&mergestate->js.ps, &TTSOpsVirtual);
 1878                          1525            2325 :     ExecAssignProjectionInfo(&mergestate->js.ps, NULL);
                               1526                 : 
 8053 bruce                    1527 ECB             :     /*
                               1528                 :      * tuple table initialization
                               1529                 :      */
 1606 andres                   1530 GIC        2325 :     innerOps = ExecGetResultSlotOps(innerPlanState(mergestate), NULL);
                               1531            2325 :     mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate, innerDesc,
 1606 andres                   1532 ECB             :                                                             innerOps);
 8244 tgl                      1533                 : 
                               1534                 :     /*
                               1535                 :      * initialize child expressions
                               1536                 :      */
 1878 andres                   1537 GIC        2325 :     mergestate->js.ps.qual =
 1878 andres                   1538 CBC        2325 :         ExecInitQual(node->join.plan.qual, (PlanState *) mergestate);
                               1539            2325 :     mergestate->js.joinqual =
 1878 andres                   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
 2193 tgl                      1545 ECB             :      */
 2193 tgl                      1546 CBC        4190 :     mergestate->js.single_match = (node->join.inner_unique ||
                               1547            1865 :                                    node->join.jointype == JOIN_SEMI);
 2193 tgl                      1548 ECB             : 
                               1549                 :     /* set up null tuples for outer joins, if needed */
 8244 tgl                      1550 GIC        2325 :     switch (node->join.jointype)
                               1551                 :     {
                               1552             870 :         case JOIN_INNER:
                               1553                 :         case JOIN_SEMI:
 6539 tgl                      1554 CBC         870 :             mergestate->mj_FillOuter = false;
                               1555             870 :             mergestate->mj_FillInner = false;
 8244 tgl                      1556 GIC         870 :             break;
                               1557             632 :         case JOIN_LEFT:
 5351 tgl                      1558 ECB             :         case JOIN_ANTI:
 6539 tgl                      1559 GIC         632 :             mergestate->mj_FillOuter = true;
 6539 tgl                      1560 CBC         632 :             mergestate->mj_FillInner = false;
 8244 tgl                      1561 GIC         632 :             mergestate->mj_NullInnerTupleSlot =
 1606 andres                   1562 CBC         632 :                 ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
 8244 tgl                      1563             632 :             break;
                               1564             709 :         case JOIN_RIGHT:
                               1565                 :         case JOIN_RIGHT_ANTI:
 6539                          1566             709 :             mergestate->mj_FillOuter = false;
 6539 tgl                      1567 GIC         709 :             mergestate->mj_FillInner = true;
 8244 tgl                      1568 CBC         709 :             mergestate->mj_NullOuterTupleSlot =
 1606 andres                   1569             709 :                 ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
 8053 bruce                    1570 ECB             : 
 8244 tgl                      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                 :              */
 4842 tgl                      1575 CBC         709 :             if (!check_constant_qual(node->join.joinqual,
 4842 tgl                      1576 ECB             :                                      &mergestate->mj_ConstFalseJoin))
 7202 tgl                      1577 LBC           0 :                 ereport(ERROR,
 7202 tgl                      1578 ECB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1579                 :                          errmsg("RIGHT JOIN is only supported with merge-joinable join conditions")));
 8244 tgl                      1580 GIC         709 :             break;
                               1581             114 :         case JOIN_FULL:
 6539                          1582             114 :             mergestate->mj_FillOuter = true;
                               1583             114 :             mergestate->mj_FillInner = true;
 8244 tgl                      1584 CBC         114 :             mergestate->mj_NullOuterTupleSlot =
 1606 andres                   1585 GIC         114 :                 ExecInitNullTupleSlot(estate, outerDesc, &TTSOpsVirtual);
 8244 tgl                      1586 GBC         114 :             mergestate->mj_NullInnerTupleSlot =
 1606 andres                   1587 GIC         114 :                 ExecInitNullTupleSlot(estate, innerDesc, &TTSOpsVirtual);
                               1588                 : 
 8244 tgl                      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                 :              */
 4842 tgl                      1593 CBC         114 :             if (!check_constant_qual(node->join.joinqual,
 4842 tgl                      1594 ECB             :                                      &mergestate->mj_ConstFalseJoin))
 7202 tgl                      1595 LBC           0 :                 ereport(ERROR,
 7202 tgl                      1596 ECB             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1597                 :                          errmsg("FULL JOIN is only supported with merge-joinable join conditions")));
 8244 tgl                      1598 GIC         114 :             break;
 8244 tgl                      1599 UIC           0 :         default:
 7202                          1600               0 :             elog(ERROR, "unrecognized join type: %d",
                               1601                 :                  (int) node->join.jointype);
 8244 tgl                      1602 ECB             :     }
                               1603                 : 
 8053 bruce                    1604 EUB             :     /*
                               1605                 :      * preprocess the merge clauses
                               1606                 :      */
 6540 tgl                      1607 CBC        2325 :     mergestate->mj_NumClauses = list_length(node->mergeclauses);
 6540 tgl                      1608 GBC        2325 :     mergestate->mj_Clauses = MJExamineQuals(node->mergeclauses,
 5933 tgl                      1609 EUB             :                                             node->mergeFamilies,
                               1610                 :                                             node->mergeCollations,
                               1611                 :                                             node->mergeStrategies,
                               1612                 :                                             node->mergeNullsFirst,
                               1613                 :                                             (PlanState *) mergestate);
                               1614                 : 
                               1615                 :     /*
 8053 bruce                    1616 ECB             :      * initialize join state
 9345                          1617                 :      */
 6540 tgl                      1618 GIC        2325 :     mergestate->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
 8244                          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                 :      */
 9345 bruce                    1627 ECB             :     MJ1_printf("ExecInitMergeJoin: %s\n",
                               1628                 :                "node initialized");
                               1629                 : 
 7430 tgl                      1630 CBC        2325 :     return mergestate;
 9770 scrappy                  1631 ECB             : }
                               1632                 : 
                               1633                 : /* ----------------------------------------------------------------
                               1634                 :  *      ExecEndMergeJoin
                               1635                 :  *
                               1636                 :  * old comments
                               1637                 :  *      frees storage allocated through C routines.
                               1638                 :  * ----------------------------------------------------------------
                               1639                 :  */
                               1640                 : void
 7430 tgl                      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);
 9345 bruce                    1650 ECB             : 
                               1651                 :     /*
                               1652                 :      * clean out the tuple table
                               1653                 :      */
 7430 tgl                      1654 GIC        2322 :     ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
                               1655            2322 :     ExecClearTuple(node->mj_MarkedTupleSlot);
                               1656                 : 
                               1657                 :     /*
 7420 tgl                      1658 ECB             :      * shut down the subplans
                               1659                 :      */
 7420 tgl                      1660 GIC        2322 :     ExecEndNode(innerPlanState(node));
                               1661            2322 :     ExecEndNode(outerPlanState(node));
                               1662                 : 
 9345 bruce                    1663 ECB             :     MJ1_printf("ExecEndMergeJoin: %s\n",
                               1664                 :                "node processing ended");
 9770 scrappy                  1665 GIC        2322 : }
                               1666                 : 
                               1667                 : void
 4654 tgl                      1668             197 : ExecReScanMergeJoin(MergeJoinState *node)
 9172 vadim4o                  1669 ECB             : {
  276 tgl                      1670 GNC         197 :     PlanState  *outerPlan = outerPlanState(node);
                               1671             197 :     PlanState  *innerPlan = innerPlanState(node);
                               1672                 : 
 7430 tgl                      1673 CBC         197 :     ExecClearTuple(node->mj_MarkedTupleSlot);
                               1674                 : 
 6540 tgl                      1675 GIC         197 :     node->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
 7430                          1676             197 :     node->mj_MatchedOuter = false;
 7430 tgl                      1677 CBC         197 :     node->mj_MatchedInner = false;
 7430 tgl                      1678 GIC         197 :     node->mj_OuterTupleSlot = NULL;
                               1679             197 :     node->mj_InnerTupleSlot = NULL;
 9172 vadim4o                  1680 ECB             : 
                               1681                 :     /*
 6385 bruce                    1682                 :      * if chgParam of subnodes is not null then plans will be re-scanned by
                               1683                 :      * first ExecProcNode.
                               1684                 :      */
  276 tgl                      1685 GNC         197 :     if (outerPlan->chgParam == NULL)
                               1686             185 :         ExecReScan(outerPlan);
                               1687             197 :     if (innerPlan->chgParam == NULL)
                               1688              12 :         ExecReScan(innerPlan);
 9172 vadim4o                  1689 CBC         197 : }
        

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