~ubuntu-branches/ubuntu/maverick/postgresql-8.4/maverick-updates

« back to all changes in this revision

Viewing changes to src/backend/executor/nodeMergejoin.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2010-10-05 20:41:08 UTC
  • mfrom: (1.2.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20101005204108-e32jzj8hiexjffss
Tags: 8.4.5-0ubuntu10.10
* New upstream security/bug fix update: (LP: #655293)
  - Use a separate interpreter for each calling SQL userid in PL/Perl
    and PL/Tcl.
    This change prevents security problems that can be caused by
    subverting Perl or Tcl code that will be executed later in the same
    session under another SQL user identity (for example, within a
    SECURITY DEFINER function). Most scripting languages offer numerous
    ways that that might be done, such as redefining standard functions
    or operators called by the target function. Without this change,
    any SQL user with Perl or Tcl language usage rights can do
    essentially anything with the SQL privileges of the target
    function's owner.
    The cost of this change is that intentional communication among
    Perl and Tcl functions becomes more difficult. To provide an escape
    hatch, PL/PerlU and PL/TclU functions continue to use only one
    interpreter per session. This is not considered a security issue
    since all such functions execute at the trust level of a database
    superuser already.
    It is likely that third-party procedural languages that claim to
    offer trusted execution have similar security issues. We advise
    contacting the authors of any PL you are depending on for
    security-critical purposes.
    Our thanks to Tim Bunce for pointing out this issue
    (CVE-2010-3433).
  - Prevent possible crashes in pg_get_expr() by disallowing it from
    being called with an argument that is not one of the system catalog
    columns it's intended to be used with.
  - Fix incorrect placement of placeholder evaluation.
    This bug could result in query outputs being non-null when they
    should be null, in cases where the inner side of an outer join is a
    sub-select with non-strict expressions in its output list.
  - Fix possible duplicate scans of UNION ALL member relations.
  - Fix "cannot handle unplanned sub-select" error.
    This occurred when a sub-select contains a join alias reference
    that expands into an expression containing another sub-select.
  - Fix mishandling of whole-row Vars that reference a view or
    sub-select and appear within a nested sub-select.
  - Fix mishandling of cross-type IN comparisons.
    This could result in failures if the planner tried to implement an
    IN join with a sort-then-unique-then-plain-join plan.
  - Fix computation of "ANALYZE" statistics for tsvector columns.
    The original coding could produce incorrect statistics, leading to
    poor plan choices later.
  - Improve planner's estimate of memory used by array_agg(),
    string_agg(), and similar aggregate functions.
    The previous drastic underestimate could lead to out-of-memory
    failures due to inappropriate choice of a hash-aggregation plan.
  - Fix failure to mark cached plans as transient.
    If a plan is prepared while "CREATE INDEX CONCURRENTLY" is in
    progress for one of the referenced tables, it is supposed to be
    re-planned once the index is ready for use. This was not happening
    reliably.
  - Reduce PANIC to ERROR in some occasionally-reported btree failure
    cases, and provide additional detail in the resulting error
    messages.
    This should improve the system's robustness with corrupted indexes.
  - Fix incorrect search logic for partial-match queries with GIN
    indexes.
    Cases involving AND/OR combination of several GIN index conditions
    didn't always give the right answer, and were sometimes much slower
    than necessary.
  - Prevent show_session_authorization() from crashing within
    autovacuum processes.
  - Defend against functions returning setof record where not all the
    returned rows are actually of the same rowtype.
  - Fix possible corruption of pending trigger event lists during
    subtransaction rollback.
    This could lead to a crash or incorrect firing of triggers.
  - Fix possible failure when hashing a pass-by-reference function
    result.
  - Improve merge join's handling of NULLs in the join columns.
    A merge join can now stop entirely upon reaching the first NULL, if
    the sort order is such that NULLs sort high.
  - Take care to fsync the contents of lockfiles (both "postmaster.pid"
    and the socket lockfile) while writing them.
    This omission could result in corrupted lockfile contents if the
    machine crashes shortly after postmaster start. That could in turn
    prevent subsequent attempts to start the postmaster from
    succeeding, until the lockfile is manually removed.
  - Avoid recursion while assigning XIDs to heavily-nested
    subtransactions.
    The original coding could result in a crash if there was limited
    stack space.
  - Avoid holding open old WAL segments in the walwriter process.
    The previous coding would prevent removal of no-longer-needed
    segments.
  - Fix log_line_prefix's %i escape, which could produce junk early in
    backend startup.
  - Prevent misinterpretation of partially-specified relation options
    for TOAST tables.
    In particular, fillfactor would be read as zero if any other
    reloption had been set for the table, leading to serious bloat.
  - Fix inheritance count tracking in "ALTER TABLE ... ADD CONSTRAINT"
  - Fix possible data corruption in "ALTER TABLE ... SET TABLESPACE"
    when archiving is enabled.
  - Allow "CREATE DATABASE" and "ALTER DATABASE ... SET TABLESPACE" to
    be interrupted by query-cancel.
  - Improve "CREATE INDEX"'s checking of whether proposed index
    expressions are immutable.
  - Fix "REASSIGN OWNED" to handle operator classes and families.
  - Fix possible core dump when comparing two empty tsquery values.
  - Fix LIKE's handling of patterns containing % followed by _.
    We've fixed this before, but there were still some
    incorrectly-handled cases.
  - Re-allow input of Julian dates prior to 0001-01-01 AD.
    Input such as 'J100000'::date worked before 8.4, but was
    unintentionally broken by added error-checking.
  - Fix PL/pgSQL to throw an error, not crash, if a cursor is closed
    within a FOR loop that is iterating over that cursor.
  - In PL/Python, defend against null pointer results from
    PyCObject_AsVoidPtr and PyCObject_FromVoidPtr.
  - In libpq, fix full SSL certificate verification for the case where
    both host and hostaddr are specified.
  - Make psql recognize "DISCARD ALL" as a command that should not be
    encased in a transaction block in autocommit-off mode.
  - Fix some issues in pg_dump's handling of SQL/MED objects.
    Notably, pg_dump would always fail if run by a non-superuser, which
    was not intended.
  - Improve pg_dump and pg_restore's handling of non-seekable archive
    files.
    This is important for proper functioning of parallel restore.
  - Improve parallel pg_restore's ability to cope with selective
    restore (-L option).
    The original code tended to fail if the -L file commanded a
    non-default restore ordering.
  - Fix ecpg to process data from RETURNING clauses correctly.
  - Fix some memory leaks in ecpg.
  - Improve "contrib/dblink"'s handling of tables containing dropped
    columns.
  - Fix connection leak after "duplicate connection name" errors in
    "contrib/dblink".
  - Fix "contrib/dblink" to handle connection names longer than 62
    bytes correctly.
  - Add hstore(text, text) function to "contrib/hstore".
    This function is the recommended substitute for the now-deprecated
    => operator. It was back-patched so that future-proofed code can be
    used with older server versions. Note that the patch will be
    effective only after "contrib/hstore" is installed or reinstalled
    in a particular database. Users might prefer to execute the "CREATE
    FUNCTION" command by hand, instead.
  - Update build infrastructure and documentation to reflect the source
    code repository's move from CVS to Git.
* debian/postgresql-8.4.preinst: Add missing debhelper token.
* debian/control: Bump Standards-Version to 3.9.1 (no changes necessary).

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
 *
9
9
 *
10
10
 * IDENTIFICATION
11
 
 *        $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.97.2.1 2010/01/05 23:25:44 tgl Exp $
 
11
 *        $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.97.2.2 2010/05/28 01:14:11 tgl Exp $
12
12
 *
13
13
 *-------------------------------------------------------------------------
14
14
 */
131
131
        FmgrInfo        cmpfinfo;
132
132
} MergeJoinClauseData;
133
133
 
 
134
/* Result type for MJEvalOuterValues and MJEvalInnerValues */
 
135
typedef enum
 
136
{
 
137
        MJEVAL_MATCHABLE,                       /* normal, potentially matchable tuple */
 
138
        MJEVAL_NONMATCHABLE,            /* tuple cannot join because it has a null */
 
139
        MJEVAL_ENDOFJOIN                        /* end of input (physical or effective) */
 
140
} MJEvalResult;
 
141
 
134
142
 
135
143
#define MarkInnerTuple(innerTupleSlot, mergestate) \
136
144
        ExecCopySlot((mergestate)->mj_MarkedTupleSlot, (innerTupleSlot))
241
249
 * Compute the values of the mergejoined expressions for the current
242
250
 * outer tuple.  We also detect whether it's impossible for the current
243
251
 * outer tuple to match anything --- this is true if it yields a NULL
244
 
 * input, since we assume mergejoin operators are strict.
 
252
 * input, since we assume mergejoin operators are strict.  If the NULL
 
253
 * is in the first join column, and that column sorts nulls last, then
 
254
 * we can further conclude that no following tuple can match anything
 
255
 * either, since they must all have nulls in the first column.  However,
 
256
 * that case is only interesting if we're not in FillOuter mode, else
 
257
 * we have to visit all the tuples anyway.
 
258
 *
 
259
 * For the convenience of callers, we also make this routine responsible
 
260
 * for testing for end-of-input (null outer tuple), and returning
 
261
 * MJEVAL_ENDOFJOIN when that's seen.  This allows the same code to be used
 
262
 * for both real end-of-input and the effective end-of-input represented by
 
263
 * a first-column NULL.
245
264
 *
246
265
 * We evaluate the values in OuterEContext, which can be reset each
247
266
 * time we move to a new tuple.
248
267
 */
249
 
static bool
 
268
static MJEvalResult
250
269
MJEvalOuterValues(MergeJoinState *mergestate)
251
270
{
252
271
        ExprContext *econtext = mergestate->mj_OuterEContext;
253
 
        bool            canmatch = true;
 
272
        MJEvalResult result = MJEVAL_MATCHABLE;
254
273
        int                     i;
255
274
        MemoryContext oldContext;
256
275
 
 
276
        /* Check for end of outer subplan */
 
277
        if (TupIsNull(mergestate->mj_OuterTupleSlot))
 
278
                return MJEVAL_ENDOFJOIN;
 
279
 
257
280
        ResetExprContext(econtext);
258
281
 
259
282
        oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
267
290
                clause->ldatum = ExecEvalExpr(clause->lexpr, econtext,
268
291
                                                                          &clause->lisnull, NULL);
269
292
                if (clause->lisnull)
270
 
                        canmatch = false;
 
293
                {
 
294
                        /* match is impossible; can we end the join early? */
 
295
                        if (i == 0 && !clause->nulls_first && !mergestate->mj_FillOuter)
 
296
                                result = MJEVAL_ENDOFJOIN;
 
297
                        else if (result == MJEVAL_MATCHABLE)
 
298
                                result = MJEVAL_NONMATCHABLE;
 
299
                }
271
300
        }
272
301
 
273
302
        MemoryContextSwitchTo(oldContext);
274
303
 
275
 
        return canmatch;
 
304
        return result;
276
305
}
277
306
 
278
307
/*
282
311
 * to load data from either the true current inner, or the marked inner,
283
312
 * so caller must tell us which slot to load from.
284
313
 */
285
 
static bool
 
314
static MJEvalResult
286
315
MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
287
316
{
288
317
        ExprContext *econtext = mergestate->mj_InnerEContext;
289
 
        bool            canmatch = true;
 
318
        MJEvalResult result = MJEVAL_MATCHABLE;
290
319
        int                     i;
291
320
        MemoryContext oldContext;
292
321
 
 
322
        /* Check for end of inner subplan */
 
323
        if (TupIsNull(innerslot))
 
324
                return MJEVAL_ENDOFJOIN;
 
325
 
293
326
        ResetExprContext(econtext);
294
327
 
295
328
        oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
303
336
                clause->rdatum = ExecEvalExpr(clause->rexpr, econtext,
304
337
                                                                          &clause->risnull, NULL);
305
338
                if (clause->risnull)
306
 
                        canmatch = false;
 
339
                {
 
340
                        /* match is impossible; can we end the join early? */
 
341
                        if (i == 0 && !clause->nulls_first && !mergestate->mj_FillInner)
 
342
                                result = MJEVAL_ENDOFJOIN;
 
343
                        else if (result == MJEVAL_MATCHABLE)
 
344
                                result = MJEVAL_NONMATCHABLE;
 
345
                }
307
346
        }
308
347
 
309
348
        MemoryContextSwitchTo(oldContext);
310
349
 
311
 
        return canmatch;
 
350
        return result;
312
351
}
313
352
 
314
353
/*
656
695
 
657
696
                                outerTupleSlot = ExecProcNode(outerPlan);
658
697
                                node->mj_OuterTupleSlot = outerTupleSlot;
659
 
                                if (TupIsNull(outerTupleSlot))
660
 
                                {
661
 
                                        MJ_printf("ExecMergeJoin: nothing in outer subplan\n");
662
 
                                        if (doFillInner)
663
 
                                        {
664
 
                                                /*
665
 
                                                 * Need to emit right-join tuples for remaining inner
666
 
                                                 * tuples.      We set MatchedInner = true to force the
667
 
                                                 * ENDOUTER state to advance inner.
668
 
                                                 */
669
 
                                                node->mj_JoinState = EXEC_MJ_ENDOUTER;
670
 
                                                node->mj_MatchedInner = true;
671
 
                                                break;
672
 
                                        }
673
 
                                        /* Otherwise we're done. */
674
 
                                        return NULL;
675
 
                                }
676
698
 
677
699
                                /* Compute join values and check for unmatchability */
678
 
                                if (MJEvalOuterValues(node))
679
 
                                {
680
 
                                        /* OK to go get the first inner tuple */
681
 
                                        node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER;
682
 
                                }
683
 
                                else
684
 
                                {
685
 
                                        /* Stay in same state to fetch next outer tuple */
686
 
                                        if (doFillOuter)
687
 
                                        {
688
 
                                                /*
689
 
                                                 * Generate a fake join tuple with nulls for the inner
690
 
                                                 * tuple, and return it if it passes the non-join
691
 
                                                 * quals.
692
 
                                                 */
693
 
                                                TupleTableSlot *result;
 
700
                                switch (MJEvalOuterValues(node))
 
701
                                {
 
702
                                        case MJEVAL_MATCHABLE:
 
703
                                                /* OK to go get the first inner tuple */
 
704
                                                node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER;
 
705
                                                break;
 
706
                                        case MJEVAL_NONMATCHABLE:
 
707
                                                /* Stay in same state to fetch next outer tuple */
 
708
                                                if (doFillOuter)
 
709
                                                {
 
710
                                                        /*
 
711
                                                         * Generate a fake join tuple with nulls for the
 
712
                                                         * inner tuple, and return it if it passes the
 
713
                                                         * non-join quals.
 
714
                                                         */
 
715
                                                        TupleTableSlot *result;
694
716
 
695
 
                                                result = MJFillOuter(node);
696
 
                                                if (result)
697
 
                                                        return result;
698
 
                                        }
 
717
                                                        result = MJFillOuter(node);
 
718
                                                        if (result)
 
719
                                                                return result;
 
720
                                                }
 
721
                                                break;
 
722
                                        case MJEVAL_ENDOFJOIN:
 
723
                                                /* No more outer tuples */
 
724
                                                MJ_printf("ExecMergeJoin: nothing in outer subplan\n");
 
725
                                                if (doFillInner)
 
726
                                                {
 
727
                                                        /*
 
728
                                                         * Need to emit right-join tuples for remaining
 
729
                                                         * inner tuples. We set MatchedInner = true to
 
730
                                                         * force the ENDOUTER state to advance inner.
 
731
                                                         */
 
732
                                                        node->mj_JoinState = EXEC_MJ_ENDOUTER;
 
733
                                                        node->mj_MatchedInner = true;
 
734
                                                        break;
 
735
                                                }
 
736
                                                /* Otherwise we're done. */
 
737
                                                return NULL;
699
738
                                }
700
739
                                break;
701
740
 
704
743
 
705
744
                                innerTupleSlot = ExecProcNode(innerPlan);
706
745
                                node->mj_InnerTupleSlot = innerTupleSlot;
707
 
                                if (TupIsNull(innerTupleSlot))
708
 
                                {
709
 
                                        MJ_printf("ExecMergeJoin: nothing in inner subplan\n");
710
 
                                        if (doFillOuter)
711
 
                                        {
712
 
                                                /*
713
 
                                                 * Need to emit left-join tuples for all outer tuples,
714
 
                                                 * including the one we just fetched.  We set
715
 
                                                 * MatchedOuter = false to force the ENDINNER state to
716
 
                                                 * emit first tuple before advancing outer.
717
 
                                                 */
718
 
                                                node->mj_JoinState = EXEC_MJ_ENDINNER;
719
 
                                                node->mj_MatchedOuter = false;
720
 
                                                break;
721
 
                                        }
722
 
                                        /* Otherwise we're done. */
723
 
                                        return NULL;
724
 
                                }
725
746
 
726
747
                                /* Compute join values and check for unmatchability */
727
 
                                if (MJEvalInnerValues(node, innerTupleSlot))
728
 
                                {
729
 
                                        /*
730
 
                                         * OK, we have the initial tuples.      Begin by skipping
731
 
                                         * non-matching tuples.
732
 
                                         */
733
 
                                        node->mj_JoinState = EXEC_MJ_SKIP_TEST;
734
 
                                }
735
 
                                else
736
 
                                {
737
 
                                        /* Mark before advancing, if wanted */
738
 
                                        if (node->mj_ExtraMarks)
739
 
                                                ExecMarkPos(innerPlan);
740
 
                                        /* Stay in same state to fetch next inner tuple */
741
 
                                        if (doFillInner)
742
 
                                        {
 
748
                                switch (MJEvalInnerValues(node, innerTupleSlot))
 
749
                                {
 
750
                                        case MJEVAL_MATCHABLE:
743
751
                                                /*
744
 
                                                 * Generate a fake join tuple with nulls for the outer
745
 
                                                 * tuple, and return it if it passes the non-join
746
 
                                                 * quals.
 
752
                                                 * OK, we have the initial tuples.      Begin by skipping
 
753
                                                 * non-matching tuples.
747
754
                                                 */
748
 
                                                TupleTableSlot *result;
 
755
                                                node->mj_JoinState = EXEC_MJ_SKIP_TEST;
 
756
                                                break;
 
757
                                        case MJEVAL_NONMATCHABLE:
 
758
                                                /* Mark before advancing, if wanted */
 
759
                                                if (node->mj_ExtraMarks)
 
760
                                                        ExecMarkPos(innerPlan);
 
761
                                                /* Stay in same state to fetch next inner tuple */
 
762
                                                if (doFillInner)
 
763
                                                {
 
764
                                                        /*
 
765
                                                         * Generate a fake join tuple with nulls for the
 
766
                                                         * outer tuple, and return it if it passes the
 
767
                                                         * non-join quals.
 
768
                                                         */
 
769
                                                        TupleTableSlot *result;
749
770
 
750
 
                                                result = MJFillInner(node);
751
 
                                                if (result)
752
 
                                                        return result;
753
 
                                        }
 
771
                                                        result = MJFillInner(node);
 
772
                                                        if (result)
 
773
                                                                return result;
 
774
                                                }
 
775
                                                break;
 
776
                                        case MJEVAL_ENDOFJOIN:
 
777
                                                /* No more inner tuples */
 
778
                                                MJ_printf("ExecMergeJoin: nothing in inner subplan\n");
 
779
                                                if (doFillOuter)
 
780
                                                {
 
781
                                                        /*
 
782
                                                         * Need to emit left-join tuples for all outer
 
783
                                                         * tuples, including the one we just fetched.  We
 
784
                                                         * set MatchedOuter = false to force the ENDINNER
 
785
                                                         * state to emit first tuple before advancing
 
786
                                                         * outer.
 
787
                                                         */
 
788
                                                        node->mj_JoinState = EXEC_MJ_ENDINNER;
 
789
                                                        node->mj_MatchedOuter = false;
 
790
                                                        break;
 
791
                                                }
 
792
                                                /* Otherwise we're done. */
 
793
                                                return NULL;
754
794
                                }
755
795
                                break;
756
796
 
878
918
                                MJ_DEBUG_PROC_NODE(innerTupleSlot);
879
919
                                node->mj_MatchedInner = false;
880
920
 
881
 
                                if (TupIsNull(innerTupleSlot))
882
 
                                {
883
 
                                        node->mj_JoinState = EXEC_MJ_NEXTOUTER;
884
 
                                        break;
885
 
                                }
886
 
 
887
 
                                /*
888
 
                                 * Load up the new inner tuple's comparison values.  If we see
889
 
                                 * that it contains a NULL and hence can't match any outer
890
 
                                 * tuple, we can skip the comparison and assume the new tuple
891
 
                                 * is greater than current outer.
892
 
                                 */
893
 
                                if (!MJEvalInnerValues(node, innerTupleSlot))
894
 
                                {
895
 
                                        node->mj_JoinState = EXEC_MJ_NEXTOUTER;
896
 
                                        break;
897
 
                                }
898
 
 
899
 
                                /*
900
 
                                 * Test the new inner tuple to see if it matches outer.
901
 
                                 *
902
 
                                 * If they do match, then we join them and move on to the next
903
 
                                 * inner tuple (EXEC_MJ_JOINTUPLES).
904
 
                                 *
905
 
                                 * If they do not match then advance to next outer tuple.
906
 
                                 */
907
 
                                compareResult = MJCompare(node);
908
 
                                MJ_DEBUG_COMPARE(compareResult);
909
 
 
910
 
                                if (compareResult == 0)
911
 
                                        node->mj_JoinState = EXEC_MJ_JOINTUPLES;
912
 
                                else
913
 
                                {
914
 
                                        Assert(compareResult < 0);
915
 
                                        node->mj_JoinState = EXEC_MJ_NEXTOUTER;
 
921
                                /* Compute join values and check for unmatchability */
 
922
                                switch (MJEvalInnerValues(node, innerTupleSlot))
 
923
                                {
 
924
                                        case MJEVAL_MATCHABLE:
 
925
                                                /*
 
926
                                                 * Test the new inner tuple to see if it matches
 
927
                                                 * outer.
 
928
                                                 *
 
929
                                                 * If they do match, then we join them and move on to
 
930
                                                 * the next inner tuple (EXEC_MJ_JOINTUPLES).
 
931
                                                 *
 
932
                                                 * If they do not match then advance to next outer
 
933
                                                 * tuple.
 
934
                                                 */
 
935
                                                compareResult = MJCompare(node);
 
936
                                                MJ_DEBUG_COMPARE(compareResult);
 
937
 
 
938
                                                if (compareResult == 0)
 
939
                                                        node->mj_JoinState = EXEC_MJ_JOINTUPLES;
 
940
                                                else
 
941
                                                {
 
942
                                                        Assert(compareResult < 0);
 
943
                                                        node->mj_JoinState = EXEC_MJ_NEXTOUTER;
 
944
                                                }
 
945
                                                break;
 
946
                                        case MJEVAL_NONMATCHABLE:
 
947
                                                /*
 
948
                                                 * It contains a NULL and hence can't match any outer
 
949
                                                 * tuple, so we can skip the comparison and assume the
 
950
                                                 * new tuple is greater than current outer.
 
951
                                                 */
 
952
                                                node->mj_JoinState = EXEC_MJ_NEXTOUTER;
 
953
                                                break;
 
954
                                        case MJEVAL_ENDOFJOIN:
 
955
                                                /*
 
956
                                                 * No more inner tuples.  However, this might be
 
957
                                                 * only effective and not physical end of inner plan,
 
958
                                                 * so force mj_InnerTupleSlot to null to make sure we
 
959
                                                 * don't fetch more inner tuples.  (We need this hack
 
960
                                                 * because we are not transiting to a state where the
 
961
                                                 * inner plan is assumed to be exhausted.)
 
962
                                                 */
 
963
                                                node->mj_InnerTupleSlot = NULL;
 
964
                                                node->mj_JoinState = EXEC_MJ_NEXTOUTER;
 
965
                                                break;
916
966
                                }
917
967
                                break;
918
968
 
962
1012
                                MJ_DEBUG_PROC_NODE(outerTupleSlot);
963
1013
                                node->mj_MatchedOuter = false;
964
1014
 
965
 
                                /*
966
 
                                 * if the outer tuple is null then we are done with the join,
967
 
                                 * unless we have inner tuples we need to null-fill.
968
 
                                 */
969
 
                                if (TupIsNull(outerTupleSlot))
970
 
                                {
971
 
                                        MJ_printf("ExecMergeJoin: end of outer subplan\n");
972
 
                                        innerTupleSlot = node->mj_InnerTupleSlot;
973
 
                                        if (doFillInner && !TupIsNull(innerTupleSlot))
974
 
                                        {
975
 
                                                /*
976
 
                                                 * Need to emit right-join tuples for remaining inner
977
 
                                                 * tuples.
978
 
                                                 */
979
 
                                                node->mj_JoinState = EXEC_MJ_ENDOUTER;
980
 
                                                break;
981
 
                                        }
982
 
                                        /* Otherwise we're done. */
983
 
                                        return NULL;
984
 
                                }
985
 
 
986
1015
                                /* Compute join values and check for unmatchability */
987
 
                                if (MJEvalOuterValues(node))
988
 
                                {
989
 
                                        /* Go test the new tuple against the marked tuple */
990
 
                                        node->mj_JoinState = EXEC_MJ_TESTOUTER;
991
 
                                }
992
 
                                else
993
 
                                {
994
 
                                        /* Can't match, so fetch next outer tuple */
995
 
                                        node->mj_JoinState = EXEC_MJ_NEXTOUTER;
 
1016
                                switch (MJEvalOuterValues(node))
 
1017
                                {
 
1018
                                        case MJEVAL_MATCHABLE:
 
1019
                                                /* Go test the new tuple against the marked tuple */
 
1020
                                                node->mj_JoinState = EXEC_MJ_TESTOUTER;
 
1021
                                                break;
 
1022
                                        case MJEVAL_NONMATCHABLE:
 
1023
                                                /* Can't match, so fetch next outer tuple */
 
1024
                                                node->mj_JoinState = EXEC_MJ_NEXTOUTER;
 
1025
                                                break;
 
1026
                                        case MJEVAL_ENDOFJOIN:
 
1027
                                                /* No more outer tuples */
 
1028
                                                MJ_printf("ExecMergeJoin: end of outer subplan\n");
 
1029
                                                innerTupleSlot = node->mj_InnerTupleSlot;
 
1030
                                                if (doFillInner && !TupIsNull(innerTupleSlot))
 
1031
                                                {
 
1032
                                                        /*
 
1033
                                                         * Need to emit right-join tuples for remaining
 
1034
                                                         * inner tuples.
 
1035
                                                         */
 
1036
                                                        node->mj_JoinState = EXEC_MJ_ENDOUTER;
 
1037
                                                        break;
 
1038
                                                }
 
1039
                                                /* Otherwise we're done. */
 
1040
                                                return NULL;
996
1041
                                }
997
1042
                                break;
998
1043
 
1093
1138
                                         *      larger than our marked inner tuples.  So we need not
1094
1139
                                         *      revisit any of the marked tuples but can proceed to
1095
1140
                                         *      look for a match to the current inner.  If there's
1096
 
                                         *      no more inners, we are done.
 
1141
                                         *      no more inners, no more matches are possible.
1097
1142
                                         * ----------------
1098
1143
                                         */
1099
1144
                                        Assert(compareResult > 0);
1100
1145
                                        innerTupleSlot = node->mj_InnerTupleSlot;
1101
 
                                        if (TupIsNull(innerTupleSlot))
1102
 
                                        {
1103
 
                                                if (doFillOuter)
1104
 
                                                {
1105
 
                                                        /*
1106
 
                                                         * Need to emit left-join tuples for remaining
1107
 
                                                         * outer tuples.
1108
 
                                                         */
1109
 
                                                        node->mj_JoinState = EXEC_MJ_ENDINNER;
1110
 
                                                        break;
1111
 
                                                }
1112
 
                                                /* Otherwise we're done. */
1113
 
                                                return NULL;
1114
 
                                        }
1115
1146
 
1116
1147
                                        /* reload comparison data for current inner */
1117
 
                                        if (MJEvalInnerValues(node, innerTupleSlot))
1118
 
                                        {
1119
 
                                                /* proceed to compare it to the current outer */
1120
 
                                                node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1121
 
                                        }
1122
 
                                        else
1123
 
                                        {
1124
 
                                                /*
1125
 
                                                 * current inner can't possibly match any outer;
1126
 
                                                 * better to advance the inner scan than the outer.
1127
 
                                                 */
1128
 
                                                node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
 
1148
                                        switch (MJEvalInnerValues(node, innerTupleSlot))
 
1149
                                        {
 
1150
                                                case MJEVAL_MATCHABLE:
 
1151
                                                        /* proceed to compare it to the current outer */
 
1152
                                                        node->mj_JoinState = EXEC_MJ_SKIP_TEST;
 
1153
                                                        break;
 
1154
                                                case MJEVAL_NONMATCHABLE:
 
1155
                                                        /*
 
1156
                                                         * current inner can't possibly match any outer;
 
1157
                                                         * better to advance the inner scan than the outer.
 
1158
                                                         */
 
1159
                                                        node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
 
1160
                                                        break;
 
1161
                                                case MJEVAL_ENDOFJOIN:
 
1162
                                                        /* No more inner tuples */
 
1163
                                                        if (doFillOuter)
 
1164
                                                        {
 
1165
                                                                /*
 
1166
                                                                 * Need to emit left-join tuples for remaining
 
1167
                                                                 * outer tuples.
 
1168
                                                                 */
 
1169
                                                                node->mj_JoinState = EXEC_MJ_ENDINNER;
 
1170
                                                                break;
 
1171
                                                        }
 
1172
                                                        /* Otherwise we're done. */
 
1173
                                                        return NULL;
1129
1174
                                        }
1130
1175
                                }
1131
1176
                                break;
1218
1263
                                MJ_DEBUG_PROC_NODE(outerTupleSlot);
1219
1264
                                node->mj_MatchedOuter = false;
1220
1265
 
1221
 
                                /*
1222
 
                                 * if the outer tuple is null then we are done with the join,
1223
 
                                 * unless we have inner tuples we need to null-fill.
1224
 
                                 */
1225
 
                                if (TupIsNull(outerTupleSlot))
1226
 
                                {
1227
 
                                        MJ_printf("ExecMergeJoin: end of outer subplan\n");
1228
 
                                        innerTupleSlot = node->mj_InnerTupleSlot;
1229
 
                                        if (doFillInner && !TupIsNull(innerTupleSlot))
1230
 
                                        {
1231
 
                                                /*
1232
 
                                                 * Need to emit right-join tuples for remaining inner
1233
 
                                                 * tuples.
1234
 
                                                 */
1235
 
                                                node->mj_JoinState = EXEC_MJ_ENDOUTER;
1236
 
                                                break;
1237
 
                                        }
1238
 
                                        /* Otherwise we're done. */
1239
 
                                        return NULL;
1240
 
                                }
1241
 
 
1242
1266
                                /* Compute join values and check for unmatchability */
1243
 
                                if (MJEvalOuterValues(node))
1244
 
                                {
1245
 
                                        /* Go test the new tuple against the current inner */
1246
 
                                        node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1247
 
                                }
1248
 
                                else
1249
 
                                {
1250
 
                                        /* Can't match, so fetch next outer tuple */
1251
 
                                        node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
 
1267
                                switch (MJEvalOuterValues(node))
 
1268
                                {
 
1269
                                        case MJEVAL_MATCHABLE:
 
1270
                                                /* Go test the new tuple against the current inner */
 
1271
                                                node->mj_JoinState = EXEC_MJ_SKIP_TEST;
 
1272
                                                break;
 
1273
                                        case MJEVAL_NONMATCHABLE:
 
1274
                                                /* Can't match, so fetch next outer tuple */
 
1275
                                                node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
 
1276
                                                break;
 
1277
                                        case MJEVAL_ENDOFJOIN:
 
1278
                                                /* No more outer tuples */
 
1279
                                                MJ_printf("ExecMergeJoin: end of outer subplan\n");
 
1280
                                                innerTupleSlot = node->mj_InnerTupleSlot;
 
1281
                                                if (doFillInner && !TupIsNull(innerTupleSlot))
 
1282
                                                {
 
1283
                                                        /*
 
1284
                                                         * Need to emit right-join tuples for remaining
 
1285
                                                         * inner tuples.
 
1286
                                                         */
 
1287
                                                        node->mj_JoinState = EXEC_MJ_ENDOUTER;
 
1288
                                                        break;
 
1289
                                                }
 
1290
                                                /* Otherwise we're done. */
 
1291
                                                return NULL;
1252
1292
                                }
1253
1293
                                break;
1254
1294
 
1289
1329
                                MJ_DEBUG_PROC_NODE(innerTupleSlot);
1290
1330
                                node->mj_MatchedInner = false;
1291
1331
 
1292
 
                                /*
1293
 
                                 * if the inner tuple is null then we are done with the join,
1294
 
                                 * unless we have outer tuples we need to null-fill.
1295
 
                                 */
1296
 
                                if (TupIsNull(innerTupleSlot))
 
1332
                                /* Compute join values and check for unmatchability */
 
1333
                                switch (MJEvalInnerValues(node, innerTupleSlot))
1297
1334
                                {
1298
 
                                        MJ_printf("ExecMergeJoin: end of inner subplan\n");
1299
 
                                        outerTupleSlot = node->mj_OuterTupleSlot;
1300
 
                                        if (doFillOuter && !TupIsNull(outerTupleSlot))
1301
 
                                        {
 
1335
                                        case MJEVAL_MATCHABLE:
 
1336
                                                /* proceed to compare it to the current outer */
 
1337
                                                node->mj_JoinState = EXEC_MJ_SKIP_TEST;
 
1338
                                                break;
 
1339
                                        case MJEVAL_NONMATCHABLE:
1302
1340
                                                /*
1303
 
                                                 * Need to emit left-join tuples for remaining outer
1304
 
                                                 * tuples.
 
1341
                                                 * current inner can't possibly match any outer;
 
1342
                                                 * better to advance the inner scan than the outer.
1305
1343
                                                 */
1306
 
                                                node->mj_JoinState = EXEC_MJ_ENDINNER;
 
1344
                                                node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
1307
1345
                                                break;
1308
 
                                        }
1309
 
                                        /* Otherwise we're done. */
1310
 
                                        return NULL;
1311
 
                                }
1312
 
 
1313
 
                                /* Compute join values and check for unmatchability */
1314
 
                                if (MJEvalInnerValues(node, innerTupleSlot))
1315
 
                                {
1316
 
                                        /* proceed to compare it to the current outer */
1317
 
                                        node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1318
 
                                }
1319
 
                                else
1320
 
                                {
1321
 
                                        /*
1322
 
                                         * current inner can't possibly match any outer; better to
1323
 
                                         * advance the inner scan than the outer.
1324
 
                                         */
1325
 
                                        node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
 
1346
                                        case MJEVAL_ENDOFJOIN:
 
1347
                                                /* No more inner tuples */
 
1348
                                                MJ_printf("ExecMergeJoin: end of inner subplan\n");
 
1349
                                                outerTupleSlot = node->mj_OuterTupleSlot;
 
1350
                                                if (doFillOuter && !TupIsNull(outerTupleSlot))
 
1351
                                                {
 
1352
                                                        /*
 
1353
                                                         * Need to emit left-join tuples for remaining
 
1354
                                                         * outer tuples.
 
1355
                                                         */
 
1356
                                                        node->mj_JoinState = EXEC_MJ_ENDINNER;
 
1357
                                                        break;
 
1358
                                                }
 
1359
                                                /* Otherwise we're done. */
 
1360
                                                return NULL;
1326
1361
                                }
1327
1362
                                break;
1328
1363