00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093 #include "postgres.h"
00094
00095 #include "access/nbtree.h"
00096 #include "executor/execdebug.h"
00097 #include "executor/nodeMergejoin.h"
00098 #include "utils/lsyscache.h"
00099 #include "utils/memutils.h"
00100
00101
00102
00103
00104
00105 #define EXEC_MJ_INITIALIZE_OUTER 1
00106 #define EXEC_MJ_INITIALIZE_INNER 2
00107 #define EXEC_MJ_JOINTUPLES 3
00108 #define EXEC_MJ_NEXTOUTER 4
00109 #define EXEC_MJ_TESTOUTER 5
00110 #define EXEC_MJ_NEXTINNER 6
00111 #define EXEC_MJ_SKIP_TEST 7
00112 #define EXEC_MJ_SKIPOUTER_ADVANCE 8
00113 #define EXEC_MJ_SKIPINNER_ADVANCE 9
00114 #define EXEC_MJ_ENDOUTER 10
00115 #define EXEC_MJ_ENDINNER 11
00116
00117
00118
00119
00120 typedef struct MergeJoinClauseData
00121 {
00122
00123 ExprState *lexpr;
00124 ExprState *rexpr;
00125
00126
00127
00128
00129
00130 Datum ldatum;
00131 Datum rdatum;
00132 bool lisnull;
00133 bool risnull;
00134
00135
00136
00137
00138
00139 SortSupportData ssup;
00140 } MergeJoinClauseData;
00141
00142
00143 typedef enum
00144 {
00145 MJEVAL_MATCHABLE,
00146 MJEVAL_NONMATCHABLE,
00147 MJEVAL_ENDOFJOIN
00148 } MJEvalResult;
00149
00150
00151 #define MarkInnerTuple(innerTupleSlot, mergestate) \
00152 ExecCopySlot((mergestate)->mj_MarkedTupleSlot, (innerTupleSlot))
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 static MergeJoinClause
00175 MJExamineQuals(List *mergeclauses,
00176 Oid *mergefamilies,
00177 Oid *mergecollations,
00178 int *mergestrategies,
00179 bool *mergenullsfirst,
00180 PlanState *parent)
00181 {
00182 MergeJoinClause clauses;
00183 int nClauses = list_length(mergeclauses);
00184 int iClause;
00185 ListCell *cl;
00186
00187 clauses = (MergeJoinClause) palloc0(nClauses * sizeof(MergeJoinClauseData));
00188
00189 iClause = 0;
00190 foreach(cl, mergeclauses)
00191 {
00192 OpExpr *qual = (OpExpr *) lfirst(cl);
00193 MergeJoinClause clause = &clauses[iClause];
00194 Oid opfamily = mergefamilies[iClause];
00195 Oid collation = mergecollations[iClause];
00196 StrategyNumber opstrategy = mergestrategies[iClause];
00197 bool nulls_first = mergenullsfirst[iClause];
00198 int op_strategy;
00199 Oid op_lefttype;
00200 Oid op_righttype;
00201 Oid sortfunc;
00202
00203 if (!IsA(qual, OpExpr))
00204 elog(ERROR, "mergejoin clause is not an OpExpr");
00205
00206
00207
00208
00209 clause->lexpr = ExecInitExpr((Expr *) linitial(qual->args), parent);
00210 clause->rexpr = ExecInitExpr((Expr *) lsecond(qual->args), parent);
00211
00212
00213 clause->ssup.ssup_cxt = CurrentMemoryContext;
00214 clause->ssup.ssup_collation = collation;
00215 if (opstrategy == BTLessStrategyNumber)
00216 clause->ssup.ssup_reverse = false;
00217 else if (opstrategy == BTGreaterStrategyNumber)
00218 clause->ssup.ssup_reverse = true;
00219 else
00220 elog(ERROR, "unsupported mergejoin strategy %d", opstrategy);
00221 clause->ssup.ssup_nulls_first = nulls_first;
00222
00223
00224 get_op_opfamily_properties(qual->opno, opfamily, false,
00225 &op_strategy,
00226 &op_lefttype,
00227 &op_righttype);
00228 if (op_strategy != BTEqualStrategyNumber)
00229 elog(ERROR, "cannot merge using non-equality operator %u",
00230 qual->opno);
00231
00232
00233 sortfunc = get_opfamily_proc(opfamily,
00234 op_lefttype,
00235 op_righttype,
00236 BTSORTSUPPORT_PROC);
00237 if (OidIsValid(sortfunc))
00238 {
00239
00240 OidFunctionCall1(sortfunc, PointerGetDatum(&clause->ssup));
00241 Assert(clause->ssup.comparator != NULL);
00242 }
00243 else
00244 {
00245
00246 sortfunc = get_opfamily_proc(opfamily,
00247 op_lefttype,
00248 op_righttype,
00249 BTORDER_PROC);
00250 if (!OidIsValid(sortfunc))
00251 elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
00252 BTORDER_PROC, op_lefttype, op_righttype, opfamily);
00253
00254 PrepareSortSupportComparisonShim(sortfunc, &clause->ssup);
00255 }
00256
00257 iClause++;
00258 }
00259
00260 return clauses;
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 static MJEvalResult
00286 MJEvalOuterValues(MergeJoinState *mergestate)
00287 {
00288 ExprContext *econtext = mergestate->mj_OuterEContext;
00289 MJEvalResult result = MJEVAL_MATCHABLE;
00290 int i;
00291 MemoryContext oldContext;
00292
00293
00294 if (TupIsNull(mergestate->mj_OuterTupleSlot))
00295 return MJEVAL_ENDOFJOIN;
00296
00297 ResetExprContext(econtext);
00298
00299 oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
00300
00301 econtext->ecxt_outertuple = mergestate->mj_OuterTupleSlot;
00302
00303 for (i = 0; i < mergestate->mj_NumClauses; i++)
00304 {
00305 MergeJoinClause clause = &mergestate->mj_Clauses[i];
00306
00307 clause->ldatum = ExecEvalExpr(clause->lexpr, econtext,
00308 &clause->lisnull, NULL);
00309 if (clause->lisnull)
00310 {
00311
00312 if (i == 0 && !clause->ssup.ssup_nulls_first &&
00313 !mergestate->mj_FillOuter)
00314 result = MJEVAL_ENDOFJOIN;
00315 else if (result == MJEVAL_MATCHABLE)
00316 result = MJEVAL_NONMATCHABLE;
00317 }
00318 }
00319
00320 MemoryContextSwitchTo(oldContext);
00321
00322 return result;
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332 static MJEvalResult
00333 MJEvalInnerValues(MergeJoinState *mergestate, TupleTableSlot *innerslot)
00334 {
00335 ExprContext *econtext = mergestate->mj_InnerEContext;
00336 MJEvalResult result = MJEVAL_MATCHABLE;
00337 int i;
00338 MemoryContext oldContext;
00339
00340
00341 if (TupIsNull(innerslot))
00342 return MJEVAL_ENDOFJOIN;
00343
00344 ResetExprContext(econtext);
00345
00346 oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
00347
00348 econtext->ecxt_innertuple = innerslot;
00349
00350 for (i = 0; i < mergestate->mj_NumClauses; i++)
00351 {
00352 MergeJoinClause clause = &mergestate->mj_Clauses[i];
00353
00354 clause->rdatum = ExecEvalExpr(clause->rexpr, econtext,
00355 &clause->risnull, NULL);
00356 if (clause->risnull)
00357 {
00358
00359 if (i == 0 && !clause->ssup.ssup_nulls_first &&
00360 !mergestate->mj_FillInner)
00361 result = MJEVAL_ENDOFJOIN;
00362 else if (result == MJEVAL_MATCHABLE)
00363 result = MJEVAL_NONMATCHABLE;
00364 }
00365 }
00366
00367 MemoryContextSwitchTo(oldContext);
00368
00369 return result;
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 static int
00383 MJCompare(MergeJoinState *mergestate)
00384 {
00385 int result = 0;
00386 bool nulleqnull = false;
00387 ExprContext *econtext = mergestate->js.ps.ps_ExprContext;
00388 int i;
00389 MemoryContext oldContext;
00390
00391
00392
00393
00394
00395 ResetExprContext(econtext);
00396
00397 oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
00398
00399 for (i = 0; i < mergestate->mj_NumClauses; i++)
00400 {
00401 MergeJoinClause clause = &mergestate->mj_Clauses[i];
00402
00403
00404
00405
00406 if (clause->lisnull && clause->risnull)
00407 {
00408 nulleqnull = true;
00409 continue;
00410 }
00411
00412 result = ApplySortComparator(clause->ldatum, clause->lisnull,
00413 clause->rdatum, clause->risnull,
00414 &clause->ssup);
00415
00416 if (result != 0)
00417 break;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 if (result == 0 &&
00430 (nulleqnull || mergestate->mj_ConstFalseJoin))
00431 result = 1;
00432
00433 MemoryContextSwitchTo(oldContext);
00434
00435 return result;
00436 }
00437
00438
00439
00440
00441
00442
00443 static TupleTableSlot *
00444 MJFillOuter(MergeJoinState *node)
00445 {
00446 ExprContext *econtext = node->js.ps.ps_ExprContext;
00447 List *otherqual = node->js.ps.qual;
00448
00449 ResetExprContext(econtext);
00450
00451 econtext->ecxt_outertuple = node->mj_OuterTupleSlot;
00452 econtext->ecxt_innertuple = node->mj_NullInnerTupleSlot;
00453
00454 if (ExecQual(otherqual, econtext, false))
00455 {
00456
00457
00458
00459
00460 TupleTableSlot *result;
00461 ExprDoneCond isDone;
00462
00463 MJ_printf("ExecMergeJoin: returning outer fill tuple\n");
00464
00465 result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
00466
00467 if (isDone != ExprEndResult)
00468 {
00469 node->js.ps.ps_TupFromTlist =
00470 (isDone == ExprMultipleResult);
00471 return result;
00472 }
00473 }
00474 else
00475 InstrCountFiltered2(node, 1);
00476
00477 return NULL;
00478 }
00479
00480
00481
00482
00483
00484 static TupleTableSlot *
00485 MJFillInner(MergeJoinState *node)
00486 {
00487 ExprContext *econtext = node->js.ps.ps_ExprContext;
00488 List *otherqual = node->js.ps.qual;
00489
00490 ResetExprContext(econtext);
00491
00492 econtext->ecxt_outertuple = node->mj_NullOuterTupleSlot;
00493 econtext->ecxt_innertuple = node->mj_InnerTupleSlot;
00494
00495 if (ExecQual(otherqual, econtext, false))
00496 {
00497
00498
00499
00500
00501 TupleTableSlot *result;
00502 ExprDoneCond isDone;
00503
00504 MJ_printf("ExecMergeJoin: returning inner fill tuple\n");
00505
00506 result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
00507
00508 if (isDone != ExprEndResult)
00509 {
00510 node->js.ps.ps_TupFromTlist =
00511 (isDone == ExprMultipleResult);
00512 return result;
00513 }
00514 }
00515 else
00516 InstrCountFiltered2(node, 1);
00517
00518 return NULL;
00519 }
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 static bool
00531 check_constant_qual(List *qual, bool *is_const_false)
00532 {
00533 ListCell *lc;
00534
00535 foreach(lc, qual)
00536 {
00537 Const *con = (Const *) lfirst(lc);
00538
00539 if (!con || !IsA(con, Const))
00540 return false;
00541 if (con->constisnull || !DatumGetBool(con->constvalue))
00542 *is_const_false = true;
00543 }
00544 return true;
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 #ifdef EXEC_MERGEJOINDEBUG
00556
00557 static void
00558 ExecMergeTupleDumpOuter(MergeJoinState *mergestate)
00559 {
00560 TupleTableSlot *outerSlot = mergestate->mj_OuterTupleSlot;
00561
00562 printf("==== outer tuple ====\n");
00563 if (TupIsNull(outerSlot))
00564 printf("(nil)\n");
00565 else
00566 MJ_debugtup(outerSlot);
00567 }
00568
00569 static void
00570 ExecMergeTupleDumpInner(MergeJoinState *mergestate)
00571 {
00572 TupleTableSlot *innerSlot = mergestate->mj_InnerTupleSlot;
00573
00574 printf("==== inner tuple ====\n");
00575 if (TupIsNull(innerSlot))
00576 printf("(nil)\n");
00577 else
00578 MJ_debugtup(innerSlot);
00579 }
00580
00581 static void
00582 ExecMergeTupleDumpMarked(MergeJoinState *mergestate)
00583 {
00584 TupleTableSlot *markedSlot = mergestate->mj_MarkedTupleSlot;
00585
00586 printf("==== marked tuple ====\n");
00587 if (TupIsNull(markedSlot))
00588 printf("(nil)\n");
00589 else
00590 MJ_debugtup(markedSlot);
00591 }
00592
00593 static void
00594 ExecMergeTupleDump(MergeJoinState *mergestate)
00595 {
00596 printf("******** ExecMergeTupleDump ********\n");
00597
00598 ExecMergeTupleDumpOuter(mergestate);
00599 ExecMergeTupleDumpInner(mergestate);
00600 ExecMergeTupleDumpMarked(mergestate);
00601
00602 printf("******** \n");
00603 }
00604 #endif
00605
00606
00607
00608
00609
00610 TupleTableSlot *
00611 ExecMergeJoin(MergeJoinState *node)
00612 {
00613 List *joinqual;
00614 List *otherqual;
00615 bool qualResult;
00616 int compareResult;
00617 PlanState *innerPlan;
00618 TupleTableSlot *innerTupleSlot;
00619 PlanState *outerPlan;
00620 TupleTableSlot *outerTupleSlot;
00621 ExprContext *econtext;
00622 bool doFillOuter;
00623 bool doFillInner;
00624
00625
00626
00627
00628 innerPlan = innerPlanState(node);
00629 outerPlan = outerPlanState(node);
00630 econtext = node->js.ps.ps_ExprContext;
00631 joinqual = node->js.joinqual;
00632 otherqual = node->js.ps.qual;
00633 doFillOuter = node->mj_FillOuter;
00634 doFillInner = node->mj_FillInner;
00635
00636
00637
00638
00639
00640
00641 if (node->js.ps.ps_TupFromTlist)
00642 {
00643 TupleTableSlot *result;
00644 ExprDoneCond isDone;
00645
00646 result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
00647 if (isDone == ExprMultipleResult)
00648 return result;
00649
00650 node->js.ps.ps_TupFromTlist = false;
00651 }
00652
00653
00654
00655
00656
00657
00658 ResetExprContext(econtext);
00659
00660
00661
00662
00663 for (;;)
00664 {
00665 MJ_dump(node);
00666
00667
00668
00669
00670 switch (node->mj_JoinState)
00671 {
00672
00673
00674
00675
00676
00677
00678
00679 case EXEC_MJ_INITIALIZE_OUTER:
00680 MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE_OUTER\n");
00681
00682 outerTupleSlot = ExecProcNode(outerPlan);
00683 node->mj_OuterTupleSlot = outerTupleSlot;
00684
00685
00686 switch (MJEvalOuterValues(node))
00687 {
00688 case MJEVAL_MATCHABLE:
00689
00690 node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER;
00691 break;
00692 case MJEVAL_NONMATCHABLE:
00693
00694 if (doFillOuter)
00695 {
00696
00697
00698
00699
00700
00701 TupleTableSlot *result;
00702
00703 result = MJFillOuter(node);
00704 if (result)
00705 return result;
00706 }
00707 break;
00708 case MJEVAL_ENDOFJOIN:
00709
00710 MJ_printf("ExecMergeJoin: nothing in outer subplan\n");
00711 if (doFillInner)
00712 {
00713
00714
00715
00716
00717
00718 node->mj_JoinState = EXEC_MJ_ENDOUTER;
00719 node->mj_MatchedInner = true;
00720 break;
00721 }
00722
00723 return NULL;
00724 }
00725 break;
00726
00727 case EXEC_MJ_INITIALIZE_INNER:
00728 MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE_INNER\n");
00729
00730 innerTupleSlot = ExecProcNode(innerPlan);
00731 node->mj_InnerTupleSlot = innerTupleSlot;
00732
00733
00734 switch (MJEvalInnerValues(node, innerTupleSlot))
00735 {
00736 case MJEVAL_MATCHABLE:
00737
00738
00739
00740
00741
00742 node->mj_JoinState = EXEC_MJ_SKIP_TEST;
00743 break;
00744 case MJEVAL_NONMATCHABLE:
00745
00746 if (node->mj_ExtraMarks)
00747 ExecMarkPos(innerPlan);
00748
00749 if (doFillInner)
00750 {
00751
00752
00753
00754
00755
00756 TupleTableSlot *result;
00757
00758 result = MJFillInner(node);
00759 if (result)
00760 return result;
00761 }
00762 break;
00763 case MJEVAL_ENDOFJOIN:
00764
00765 MJ_printf("ExecMergeJoin: nothing in inner subplan\n");
00766 if (doFillOuter)
00767 {
00768
00769
00770
00771
00772
00773
00774
00775 node->mj_JoinState = EXEC_MJ_ENDINNER;
00776 node->mj_MatchedOuter = false;
00777 break;
00778 }
00779
00780 return NULL;
00781 }
00782 break;
00783
00784
00785
00786
00787
00788
00789 case EXEC_MJ_JOINTUPLES:
00790 MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
00791
00792
00793
00794
00795
00796
00797 node->mj_JoinState = EXEC_MJ_NEXTINNER;
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813 outerTupleSlot = node->mj_OuterTupleSlot;
00814 econtext->ecxt_outertuple = outerTupleSlot;
00815 innerTupleSlot = node->mj_InnerTupleSlot;
00816 econtext->ecxt_innertuple = innerTupleSlot;
00817
00818 qualResult = (joinqual == NIL ||
00819 ExecQual(joinqual, econtext, false));
00820 MJ_DEBUG_QUAL(joinqual, qualResult);
00821
00822 if (qualResult)
00823 {
00824 node->mj_MatchedOuter = true;
00825 node->mj_MatchedInner = true;
00826
00827
00828 if (node->js.jointype == JOIN_ANTI)
00829 {
00830 node->mj_JoinState = EXEC_MJ_NEXTOUTER;
00831 break;
00832 }
00833
00834
00835
00836
00837
00838 if (node->js.jointype == JOIN_SEMI)
00839 node->mj_JoinState = EXEC_MJ_NEXTOUTER;
00840
00841 qualResult = (otherqual == NIL ||
00842 ExecQual(otherqual, econtext, false));
00843 MJ_DEBUG_QUAL(otherqual, qualResult);
00844
00845 if (qualResult)
00846 {
00847
00848
00849
00850
00851 TupleTableSlot *result;
00852 ExprDoneCond isDone;
00853
00854 MJ_printf("ExecMergeJoin: returning tuple\n");
00855
00856 result = ExecProject(node->js.ps.ps_ProjInfo,
00857 &isDone);
00858
00859 if (isDone != ExprEndResult)
00860 {
00861 node->js.ps.ps_TupFromTlist =
00862 (isDone == ExprMultipleResult);
00863 return result;
00864 }
00865 }
00866 else
00867 InstrCountFiltered2(node, 1);
00868 }
00869 else
00870 InstrCountFiltered1(node, 1);
00871 break;
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881 case EXEC_MJ_NEXTINNER:
00882 MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\n");
00883
00884 if (doFillInner && !node->mj_MatchedInner)
00885 {
00886
00887
00888
00889
00890 TupleTableSlot *result;
00891
00892 node->mj_MatchedInner = true;
00893
00894 result = MJFillInner(node);
00895 if (result)
00896 return result;
00897 }
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907 innerTupleSlot = ExecProcNode(innerPlan);
00908 node->mj_InnerTupleSlot = innerTupleSlot;
00909 MJ_DEBUG_PROC_NODE(innerTupleSlot);
00910 node->mj_MatchedInner = false;
00911
00912
00913 switch (MJEvalInnerValues(node, innerTupleSlot))
00914 {
00915 case MJEVAL_MATCHABLE:
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927 compareResult = MJCompare(node);
00928 MJ_DEBUG_COMPARE(compareResult);
00929
00930 if (compareResult == 0)
00931 node->mj_JoinState = EXEC_MJ_JOINTUPLES;
00932 else
00933 {
00934 Assert(compareResult < 0);
00935 node->mj_JoinState = EXEC_MJ_NEXTOUTER;
00936 }
00937 break;
00938 case MJEVAL_NONMATCHABLE:
00939
00940
00941
00942
00943
00944
00945 node->mj_JoinState = EXEC_MJ_NEXTOUTER;
00946 break;
00947 case MJEVAL_ENDOFJOIN:
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957 node->mj_InnerTupleSlot = NULL;
00958 node->mj_JoinState = EXEC_MJ_NEXTOUTER;
00959 break;
00960 }
00961 break;
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983 case EXEC_MJ_NEXTOUTER:
00984 MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n");
00985
00986 if (doFillOuter && !node->mj_MatchedOuter)
00987 {
00988
00989
00990
00991
00992 TupleTableSlot *result;
00993
00994 node->mj_MatchedOuter = true;
00995
00996 result = MJFillOuter(node);
00997 if (result)
00998 return result;
00999 }
01000
01001
01002
01003
01004 outerTupleSlot = ExecProcNode(outerPlan);
01005 node->mj_OuterTupleSlot = outerTupleSlot;
01006 MJ_DEBUG_PROC_NODE(outerTupleSlot);
01007 node->mj_MatchedOuter = false;
01008
01009
01010 switch (MJEvalOuterValues(node))
01011 {
01012 case MJEVAL_MATCHABLE:
01013
01014 node->mj_JoinState = EXEC_MJ_TESTOUTER;
01015 break;
01016 case MJEVAL_NONMATCHABLE:
01017
01018 node->mj_JoinState = EXEC_MJ_NEXTOUTER;
01019 break;
01020 case MJEVAL_ENDOFJOIN:
01021
01022 MJ_printf("ExecMergeJoin: end of outer subplan\n");
01023 innerTupleSlot = node->mj_InnerTupleSlot;
01024 if (doFillInner && !TupIsNull(innerTupleSlot))
01025 {
01026
01027
01028
01029
01030 node->mj_JoinState = EXEC_MJ_ENDOUTER;
01031 break;
01032 }
01033
01034 return NULL;
01035 }
01036 break;
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073 case EXEC_MJ_TESTOUTER:
01074 MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");
01075
01076
01077
01078
01079
01080
01081 innerTupleSlot = node->mj_MarkedTupleSlot;
01082 (void) MJEvalInnerValues(node, innerTupleSlot);
01083
01084 compareResult = MJCompare(node);
01085 MJ_DEBUG_COMPARE(compareResult);
01086
01087 if (compareResult == 0)
01088 {
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106 ExecRestrPos(innerPlan);
01107
01108
01109
01110
01111
01112
01113
01114 node->mj_InnerTupleSlot = innerTupleSlot;
01115
01116
01117 node->mj_JoinState = EXEC_MJ_JOINTUPLES;
01118 }
01119 else
01120 {
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138 Assert(compareResult > 0);
01139 innerTupleSlot = node->mj_InnerTupleSlot;
01140
01141
01142 switch (MJEvalInnerValues(node, innerTupleSlot))
01143 {
01144 case MJEVAL_MATCHABLE:
01145
01146 node->mj_JoinState = EXEC_MJ_SKIP_TEST;
01147 break;
01148 case MJEVAL_NONMATCHABLE:
01149
01150
01151
01152
01153
01154
01155 node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
01156 break;
01157 case MJEVAL_ENDOFJOIN:
01158
01159 if (doFillOuter)
01160 {
01161
01162
01163
01164
01165 node->mj_JoinState = EXEC_MJ_ENDINNER;
01166 break;
01167 }
01168
01169 return NULL;
01170 }
01171 }
01172 break;
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203 case EXEC_MJ_SKIP_TEST:
01204 MJ_printf("ExecMergeJoin: EXEC_MJ_SKIP_TEST\n");
01205
01206
01207
01208
01209
01210
01211 compareResult = MJCompare(node);
01212 MJ_DEBUG_COMPARE(compareResult);
01213
01214 if (compareResult == 0)
01215 {
01216 ExecMarkPos(innerPlan);
01217
01218 MarkInnerTuple(node->mj_InnerTupleSlot, node);
01219
01220 node->mj_JoinState = EXEC_MJ_JOINTUPLES;
01221 }
01222 else if (compareResult < 0)
01223 node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
01224 else
01225
01226 node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
01227 break;
01228
01229
01230
01231
01232
01233
01234
01235
01236 case EXEC_MJ_SKIPOUTER_ADVANCE:
01237 MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_ADVANCE\n");
01238
01239 if (doFillOuter && !node->mj_MatchedOuter)
01240 {
01241
01242
01243
01244
01245 TupleTableSlot *result;
01246
01247 node->mj_MatchedOuter = true;
01248
01249 result = MJFillOuter(node);
01250 if (result)
01251 return result;
01252 }
01253
01254
01255
01256
01257 outerTupleSlot = ExecProcNode(outerPlan);
01258 node->mj_OuterTupleSlot = outerTupleSlot;
01259 MJ_DEBUG_PROC_NODE(outerTupleSlot);
01260 node->mj_MatchedOuter = false;
01261
01262
01263 switch (MJEvalOuterValues(node))
01264 {
01265 case MJEVAL_MATCHABLE:
01266
01267 node->mj_JoinState = EXEC_MJ_SKIP_TEST;
01268 break;
01269 case MJEVAL_NONMATCHABLE:
01270
01271 node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
01272 break;
01273 case MJEVAL_ENDOFJOIN:
01274
01275 MJ_printf("ExecMergeJoin: end of outer subplan\n");
01276 innerTupleSlot = node->mj_InnerTupleSlot;
01277 if (doFillInner && !TupIsNull(innerTupleSlot))
01278 {
01279
01280
01281
01282
01283 node->mj_JoinState = EXEC_MJ_ENDOUTER;
01284 break;
01285 }
01286
01287 return NULL;
01288 }
01289 break;
01290
01291
01292
01293
01294
01295
01296
01297
01298 case EXEC_MJ_SKIPINNER_ADVANCE:
01299 MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_ADVANCE\n");
01300
01301 if (doFillInner && !node->mj_MatchedInner)
01302 {
01303
01304
01305
01306
01307 TupleTableSlot *result;
01308
01309 node->mj_MatchedInner = true;
01310
01311 result = MJFillInner(node);
01312 if (result)
01313 return result;
01314 }
01315
01316
01317 if (node->mj_ExtraMarks)
01318 ExecMarkPos(innerPlan);
01319
01320
01321
01322
01323 innerTupleSlot = ExecProcNode(innerPlan);
01324 node->mj_InnerTupleSlot = innerTupleSlot;
01325 MJ_DEBUG_PROC_NODE(innerTupleSlot);
01326 node->mj_MatchedInner = false;
01327
01328
01329 switch (MJEvalInnerValues(node, innerTupleSlot))
01330 {
01331 case MJEVAL_MATCHABLE:
01332
01333 node->mj_JoinState = EXEC_MJ_SKIP_TEST;
01334 break;
01335 case MJEVAL_NONMATCHABLE:
01336
01337
01338
01339
01340
01341 node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
01342 break;
01343 case MJEVAL_ENDOFJOIN:
01344
01345 MJ_printf("ExecMergeJoin: end of inner subplan\n");
01346 outerTupleSlot = node->mj_OuterTupleSlot;
01347 if (doFillOuter && !TupIsNull(outerTupleSlot))
01348 {
01349
01350
01351
01352
01353 node->mj_JoinState = EXEC_MJ_ENDINNER;
01354 break;
01355 }
01356
01357 return NULL;
01358 }
01359 break;
01360
01361
01362
01363
01364
01365
01366 case EXEC_MJ_ENDOUTER:
01367 MJ_printf("ExecMergeJoin: EXEC_MJ_ENDOUTER\n");
01368
01369 Assert(doFillInner);
01370
01371 if (!node->mj_MatchedInner)
01372 {
01373
01374
01375
01376
01377 TupleTableSlot *result;
01378
01379 node->mj_MatchedInner = true;
01380
01381 result = MJFillInner(node);
01382 if (result)
01383 return result;
01384 }
01385
01386
01387 if (node->mj_ExtraMarks)
01388 ExecMarkPos(innerPlan);
01389
01390
01391
01392
01393 innerTupleSlot = ExecProcNode(innerPlan);
01394 node->mj_InnerTupleSlot = innerTupleSlot;
01395 MJ_DEBUG_PROC_NODE(innerTupleSlot);
01396 node->mj_MatchedInner = false;
01397
01398 if (TupIsNull(innerTupleSlot))
01399 {
01400 MJ_printf("ExecMergeJoin: end of inner subplan\n");
01401 return NULL;
01402 }
01403
01404
01405 break;
01406
01407
01408
01409
01410
01411
01412 case EXEC_MJ_ENDINNER:
01413 MJ_printf("ExecMergeJoin: EXEC_MJ_ENDINNER\n");
01414
01415 Assert(doFillOuter);
01416
01417 if (!node->mj_MatchedOuter)
01418 {
01419
01420
01421
01422
01423 TupleTableSlot *result;
01424
01425 node->mj_MatchedOuter = true;
01426
01427 result = MJFillOuter(node);
01428 if (result)
01429 return result;
01430 }
01431
01432
01433
01434
01435 outerTupleSlot = ExecProcNode(outerPlan);
01436 node->mj_OuterTupleSlot = outerTupleSlot;
01437 MJ_DEBUG_PROC_NODE(outerTupleSlot);
01438 node->mj_MatchedOuter = false;
01439
01440 if (TupIsNull(outerTupleSlot))
01441 {
01442 MJ_printf("ExecMergeJoin: end of outer subplan\n");
01443 return NULL;
01444 }
01445
01446
01447 break;
01448
01449
01450
01451
01452 default:
01453 elog(ERROR, "unrecognized mergejoin state: %d",
01454 (int) node->mj_JoinState);
01455 }
01456 }
01457 }
01458
01459
01460
01461
01462
01463 MergeJoinState *
01464 ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
01465 {
01466 MergeJoinState *mergestate;
01467
01468
01469 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
01470
01471 MJ1_printf("ExecInitMergeJoin: %s\n",
01472 "initializing node");
01473
01474
01475
01476
01477 mergestate = makeNode(MergeJoinState);
01478 mergestate->js.ps.plan = (Plan *) node;
01479 mergestate->js.ps.state = estate;
01480
01481
01482
01483
01484
01485
01486 ExecAssignExprContext(estate, &mergestate->js.ps);
01487
01488
01489
01490
01491
01492
01493 mergestate->mj_OuterEContext = CreateExprContext(estate);
01494 mergestate->mj_InnerEContext = CreateExprContext(estate);
01495
01496
01497
01498
01499 mergestate->js.ps.targetlist = (List *)
01500 ExecInitExpr((Expr *) node->join.plan.targetlist,
01501 (PlanState *) mergestate);
01502 mergestate->js.ps.qual = (List *)
01503 ExecInitExpr((Expr *) node->join.plan.qual,
01504 (PlanState *) mergestate);
01505 mergestate->js.jointype = node->join.jointype;
01506 mergestate->js.joinqual = (List *)
01507 ExecInitExpr((Expr *) node->join.joinqual,
01508 (PlanState *) mergestate);
01509 mergestate->mj_ConstFalseJoin = false;
01510
01511
01512
01513
01514
01515
01516
01517 outerPlanState(mergestate) = ExecInitNode(outerPlan(node), estate, eflags);
01518 innerPlanState(mergestate) = ExecInitNode(innerPlan(node), estate,
01519 eflags | EXEC_FLAG_MARK);
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531 if (IsA(innerPlan(node), Material) &&
01532 (eflags & EXEC_FLAG_REWIND) == 0)
01533 mergestate->mj_ExtraMarks = true;
01534 else
01535 mergestate->mj_ExtraMarks = false;
01536
01537
01538
01539
01540 ExecInitResultTupleSlot(estate, &mergestate->js.ps);
01541
01542 mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate);
01543 ExecSetSlotDescriptor(mergestate->mj_MarkedTupleSlot,
01544 ExecGetResultType(innerPlanState(mergestate)));
01545
01546 switch (node->join.jointype)
01547 {
01548 case JOIN_INNER:
01549 case JOIN_SEMI:
01550 mergestate->mj_FillOuter = false;
01551 mergestate->mj_FillInner = false;
01552 break;
01553 case JOIN_LEFT:
01554 case JOIN_ANTI:
01555 mergestate->mj_FillOuter = true;
01556 mergestate->mj_FillInner = false;
01557 mergestate->mj_NullInnerTupleSlot =
01558 ExecInitNullTupleSlot(estate,
01559 ExecGetResultType(innerPlanState(mergestate)));
01560 break;
01561 case JOIN_RIGHT:
01562 mergestate->mj_FillOuter = false;
01563 mergestate->mj_FillInner = true;
01564 mergestate->mj_NullOuterTupleSlot =
01565 ExecInitNullTupleSlot(estate,
01566 ExecGetResultType(outerPlanState(mergestate)));
01567
01568
01569
01570
01571
01572 if (!check_constant_qual(node->join.joinqual,
01573 &mergestate->mj_ConstFalseJoin))
01574 ereport(ERROR,
01575 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01576 errmsg("RIGHT JOIN is only supported with merge-joinable join conditions")));
01577 break;
01578 case JOIN_FULL:
01579 mergestate->mj_FillOuter = true;
01580 mergestate->mj_FillInner = true;
01581 mergestate->mj_NullOuterTupleSlot =
01582 ExecInitNullTupleSlot(estate,
01583 ExecGetResultType(outerPlanState(mergestate)));
01584 mergestate->mj_NullInnerTupleSlot =
01585 ExecInitNullTupleSlot(estate,
01586 ExecGetResultType(innerPlanState(mergestate)));
01587
01588
01589
01590
01591
01592 if (!check_constant_qual(node->join.joinqual,
01593 &mergestate->mj_ConstFalseJoin))
01594 ereport(ERROR,
01595 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01596 errmsg("FULL JOIN is only supported with merge-joinable join conditions")));
01597 break;
01598 default:
01599 elog(ERROR, "unrecognized join type: %d",
01600 (int) node->join.jointype);
01601 }
01602
01603
01604
01605
01606 ExecAssignResultTypeFromTL(&mergestate->js.ps);
01607 ExecAssignProjectionInfo(&mergestate->js.ps, NULL);
01608
01609
01610
01611
01612 mergestate->mj_NumClauses = list_length(node->mergeclauses);
01613 mergestate->mj_Clauses = MJExamineQuals(node->mergeclauses,
01614 node->mergeFamilies,
01615 node->mergeCollations,
01616 node->mergeStrategies,
01617 node->mergeNullsFirst,
01618 (PlanState *) mergestate);
01619
01620
01621
01622
01623 mergestate->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
01624 mergestate->js.ps.ps_TupFromTlist = false;
01625 mergestate->mj_MatchedOuter = false;
01626 mergestate->mj_MatchedInner = false;
01627 mergestate->mj_OuterTupleSlot = NULL;
01628 mergestate->mj_InnerTupleSlot = NULL;
01629
01630
01631
01632
01633 MJ1_printf("ExecInitMergeJoin: %s\n",
01634 "node initialized");
01635
01636 return mergestate;
01637 }
01638
01639
01640
01641
01642
01643
01644
01645
01646 void
01647 ExecEndMergeJoin(MergeJoinState *node)
01648 {
01649 MJ1_printf("ExecEndMergeJoin: %s\n",
01650 "ending node processing");
01651
01652
01653
01654
01655 ExecFreeExprContext(&node->js.ps);
01656
01657
01658
01659
01660 ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
01661 ExecClearTuple(node->mj_MarkedTupleSlot);
01662
01663
01664
01665
01666 ExecEndNode(innerPlanState(node));
01667 ExecEndNode(outerPlanState(node));
01668
01669 MJ1_printf("ExecEndMergeJoin: %s\n",
01670 "node processing ended");
01671 }
01672
01673 void
01674 ExecReScanMergeJoin(MergeJoinState *node)
01675 {
01676 ExecClearTuple(node->mj_MarkedTupleSlot);
01677
01678 node->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER;
01679 node->js.ps.ps_TupFromTlist = false;
01680 node->mj_MatchedOuter = false;
01681 node->mj_MatchedInner = false;
01682 node->mj_OuterTupleSlot = NULL;
01683 node->mj_InnerTupleSlot = NULL;
01684
01685
01686
01687
01688
01689 if (node->js.ps.lefttree->chgParam == NULL)
01690 ExecReScan(node->js.ps.lefttree);
01691 if (node->js.ps.righttree->chgParam == NULL)
01692 ExecReScan(node->js.ps.righttree);
01693
01694 }