131
131
FmgrInfo cmpfinfo;
132
132
} MergeJoinClauseData;
134
/* Result type for MJEvalOuterValues and MJEvalInnerValues */
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) */
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.
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.
246
265
* We evaluate the values in OuterEContext, which can be reset each
247
266
* time we move to a new tuple.
250
269
MJEvalOuterValues(MergeJoinState *mergestate)
252
271
ExprContext *econtext = mergestate->mj_OuterEContext;
253
bool canmatch = true;
272
MJEvalResult result = MJEVAL_MATCHABLE;
255
274
MemoryContext oldContext;
276
/* Check for end of outer subplan */
277
if (TupIsNull(mergestate->mj_OuterTupleSlot))
278
return MJEVAL_ENDOFJOIN;
257
280
ResetExprContext(econtext);
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)
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;
273
302
MemoryContextSwitchTo(oldContext);
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.
286
315
MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
288
317
ExprContext *econtext = mergestate->mj_InnerEContext;
289
bool canmatch = true;
318
MJEvalResult result = MJEVAL_MATCHABLE;
291
320
MemoryContext oldContext;
322
/* Check for end of inner subplan */
323
if (TupIsNull(innerslot))
324
return MJEVAL_ENDOFJOIN;
293
326
ResetExprContext(econtext);
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)
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;
309
348
MemoryContextSwitchTo(oldContext);
657
696
outerTupleSlot = ExecProcNode(outerPlan);
658
697
node->mj_OuterTupleSlot = outerTupleSlot;
659
if (TupIsNull(outerTupleSlot))
661
MJ_printf("ExecMergeJoin: nothing in outer subplan\n");
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.
669
node->mj_JoinState = EXEC_MJ_ENDOUTER;
670
node->mj_MatchedInner = true;
673
/* Otherwise we're done. */
677
699
/* Compute join values and check for unmatchability */
678
if (MJEvalOuterValues(node))
680
/* OK to go get the first inner tuple */
681
node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER;
685
/* Stay in same state to fetch next outer tuple */
689
* Generate a fake join tuple with nulls for the inner
690
* tuple, and return it if it passes the non-join
693
TupleTableSlot *result;
700
switch (MJEvalOuterValues(node))
702
case MJEVAL_MATCHABLE:
703
/* OK to go get the first inner tuple */
704
node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER;
706
case MJEVAL_NONMATCHABLE:
707
/* Stay in same state to fetch next outer tuple */
711
* Generate a fake join tuple with nulls for the
712
* inner tuple, and return it if it passes the
715
TupleTableSlot *result;
695
result = MJFillOuter(node);
717
result = MJFillOuter(node);
722
case MJEVAL_ENDOFJOIN:
723
/* No more outer tuples */
724
MJ_printf("ExecMergeJoin: nothing in outer subplan\n");
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.
732
node->mj_JoinState = EXEC_MJ_ENDOUTER;
733
node->mj_MatchedInner = true;
736
/* Otherwise we're done. */
705
744
innerTupleSlot = ExecProcNode(innerPlan);
706
745
node->mj_InnerTupleSlot = innerTupleSlot;
707
if (TupIsNull(innerTupleSlot))
709
MJ_printf("ExecMergeJoin: nothing in inner subplan\n");
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.
718
node->mj_JoinState = EXEC_MJ_ENDINNER;
719
node->mj_MatchedOuter = false;
722
/* Otherwise we're done. */
726
747
/* Compute join values and check for unmatchability */
727
if (MJEvalInnerValues(node, innerTupleSlot))
730
* OK, we have the initial tuples. Begin by skipping
731
* non-matching tuples.
733
node->mj_JoinState = EXEC_MJ_SKIP_TEST;
737
/* Mark before advancing, if wanted */
738
if (node->mj_ExtraMarks)
739
ExecMarkPos(innerPlan);
740
/* Stay in same state to fetch next inner tuple */
748
switch (MJEvalInnerValues(node, innerTupleSlot))
750
case MJEVAL_MATCHABLE:
744
* Generate a fake join tuple with nulls for the outer
745
* tuple, and return it if it passes the non-join
752
* OK, we have the initial tuples. Begin by skipping
753
* non-matching tuples.
748
TupleTableSlot *result;
755
node->mj_JoinState = EXEC_MJ_SKIP_TEST;
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 */
765
* Generate a fake join tuple with nulls for the
766
* outer tuple, and return it if it passes the
769
TupleTableSlot *result;
750
result = MJFillInner(node);
771
result = MJFillInner(node);
776
case MJEVAL_ENDOFJOIN:
777
/* No more inner tuples */
778
MJ_printf("ExecMergeJoin: nothing in inner subplan\n");
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
788
node->mj_JoinState = EXEC_MJ_ENDINNER;
789
node->mj_MatchedOuter = false;
792
/* Otherwise we're done. */
878
918
MJ_DEBUG_PROC_NODE(innerTupleSlot);
879
919
node->mj_MatchedInner = false;
881
if (TupIsNull(innerTupleSlot))
883
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
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.
893
if (!MJEvalInnerValues(node, innerTupleSlot))
895
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
900
* Test the new inner tuple to see if it matches outer.
902
* If they do match, then we join them and move on to the next
903
* inner tuple (EXEC_MJ_JOINTUPLES).
905
* If they do not match then advance to next outer tuple.
907
compareResult = MJCompare(node);
908
MJ_DEBUG_COMPARE(compareResult);
910
if (compareResult == 0)
911
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
914
Assert(compareResult < 0);
915
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
921
/* Compute join values and check for unmatchability */
922
switch (MJEvalInnerValues(node, innerTupleSlot))
924
case MJEVAL_MATCHABLE:
926
* Test the new inner tuple to see if it matches
929
* If they do match, then we join them and move on to
930
* the next inner tuple (EXEC_MJ_JOINTUPLES).
932
* If they do not match then advance to next outer
935
compareResult = MJCompare(node);
936
MJ_DEBUG_COMPARE(compareResult);
938
if (compareResult == 0)
939
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
942
Assert(compareResult < 0);
943
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
946
case MJEVAL_NONMATCHABLE:
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.
952
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
954
case MJEVAL_ENDOFJOIN:
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.)
963
node->mj_InnerTupleSlot = NULL;
964
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
962
1012
MJ_DEBUG_PROC_NODE(outerTupleSlot);
963
1013
node->mj_MatchedOuter = false;
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.
969
if (TupIsNull(outerTupleSlot))
971
MJ_printf("ExecMergeJoin: end of outer subplan\n");
972
innerTupleSlot = node->mj_InnerTupleSlot;
973
if (doFillInner && !TupIsNull(innerTupleSlot))
976
* Need to emit right-join tuples for remaining inner
979
node->mj_JoinState = EXEC_MJ_ENDOUTER;
982
/* Otherwise we're done. */
986
1015
/* Compute join values and check for unmatchability */
987
if (MJEvalOuterValues(node))
989
/* Go test the new tuple against the marked tuple */
990
node->mj_JoinState = EXEC_MJ_TESTOUTER;
994
/* Can't match, so fetch next outer tuple */
995
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
1016
switch (MJEvalOuterValues(node))
1018
case MJEVAL_MATCHABLE:
1019
/* Go test the new tuple against the marked tuple */
1020
node->mj_JoinState = EXEC_MJ_TESTOUTER;
1022
case MJEVAL_NONMATCHABLE:
1023
/* Can't match, so fetch next outer tuple */
1024
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
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))
1033
* Need to emit right-join tuples for remaining
1036
node->mj_JoinState = EXEC_MJ_ENDOUTER;
1039
/* Otherwise we're done. */
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
* ----------------
1099
1144
Assert(compareResult > 0);
1100
1145
innerTupleSlot = node->mj_InnerTupleSlot;
1101
if (TupIsNull(innerTupleSlot))
1106
* Need to emit left-join tuples for remaining
1109
node->mj_JoinState = EXEC_MJ_ENDINNER;
1112
/* Otherwise we're done. */
1116
1147
/* reload comparison data for current inner */
1117
if (MJEvalInnerValues(node, innerTupleSlot))
1119
/* proceed to compare it to the current outer */
1120
node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1125
* current inner can't possibly match any outer;
1126
* better to advance the inner scan than the outer.
1128
node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
1148
switch (MJEvalInnerValues(node, innerTupleSlot))
1150
case MJEVAL_MATCHABLE:
1151
/* proceed to compare it to the current outer */
1152
node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1154
case MJEVAL_NONMATCHABLE:
1156
* current inner can't possibly match any outer;
1157
* better to advance the inner scan than the outer.
1159
node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
1161
case MJEVAL_ENDOFJOIN:
1162
/* No more inner tuples */
1166
* Need to emit left-join tuples for remaining
1169
node->mj_JoinState = EXEC_MJ_ENDINNER;
1172
/* Otherwise we're done. */
1218
1263
MJ_DEBUG_PROC_NODE(outerTupleSlot);
1219
1264
node->mj_MatchedOuter = false;
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.
1225
if (TupIsNull(outerTupleSlot))
1227
MJ_printf("ExecMergeJoin: end of outer subplan\n");
1228
innerTupleSlot = node->mj_InnerTupleSlot;
1229
if (doFillInner && !TupIsNull(innerTupleSlot))
1232
* Need to emit right-join tuples for remaining inner
1235
node->mj_JoinState = EXEC_MJ_ENDOUTER;
1238
/* Otherwise we're done. */
1242
1266
/* Compute join values and check for unmatchability */
1243
if (MJEvalOuterValues(node))
1245
/* Go test the new tuple against the current inner */
1246
node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1250
/* Can't match, so fetch next outer tuple */
1251
node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
1267
switch (MJEvalOuterValues(node))
1269
case MJEVAL_MATCHABLE:
1270
/* Go test the new tuple against the current inner */
1271
node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1273
case MJEVAL_NONMATCHABLE:
1274
/* Can't match, so fetch next outer tuple */
1275
node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
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))
1284
* Need to emit right-join tuples for remaining
1287
node->mj_JoinState = EXEC_MJ_ENDOUTER;
1290
/* Otherwise we're done. */
1289
1329
MJ_DEBUG_PROC_NODE(innerTupleSlot);
1290
1330
node->mj_MatchedInner = false;
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.
1296
if (TupIsNull(innerTupleSlot))
1332
/* Compute join values and check for unmatchability */
1333
switch (MJEvalInnerValues(node, innerTupleSlot))
1298
MJ_printf("ExecMergeJoin: end of inner subplan\n");
1299
outerTupleSlot = node->mj_OuterTupleSlot;
1300
if (doFillOuter && !TupIsNull(outerTupleSlot))
1335
case MJEVAL_MATCHABLE:
1336
/* proceed to compare it to the current outer */
1337
node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1339
case MJEVAL_NONMATCHABLE:
1303
* Need to emit left-join tuples for remaining outer
1341
* current inner can't possibly match any outer;
1342
* better to advance the inner scan than the outer.
1306
node->mj_JoinState = EXEC_MJ_ENDINNER;
1344
node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
1309
/* Otherwise we're done. */
1313
/* Compute join values and check for unmatchability */
1314
if (MJEvalInnerValues(node, innerTupleSlot))
1316
/* proceed to compare it to the current outer */
1317
node->mj_JoinState = EXEC_MJ_SKIP_TEST;
1322
* current inner can't possibly match any outer; better to
1323
* advance the inner scan than the outer.
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))
1353
* Need to emit left-join tuples for remaining
1356
node->mj_JoinState = EXEC_MJ_ENDINNER;
1359
/* Otherwise we're done. */