00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include "access/htup_details.h"
00019 #include "executor/executor.h"
00020 #include "executor/hashjoin.h"
00021 #include "executor/nodeHash.h"
00022 #include "executor/nodeHashjoin.h"
00023 #include "miscadmin.h"
00024 #include "utils/memutils.h"
00025
00026
00027
00028
00029
00030 #define HJ_BUILD_HASHTABLE 1
00031 #define HJ_NEED_NEW_OUTER 2
00032 #define HJ_SCAN_BUCKET 3
00033 #define HJ_FILL_OUTER_TUPLE 4
00034 #define HJ_FILL_INNER_TUPLES 5
00035 #define HJ_NEED_NEW_BATCH 6
00036
00037
00038 #define HJ_FILL_OUTER(hjstate) ((hjstate)->hj_NullInnerTupleSlot != NULL)
00039
00040 #define HJ_FILL_INNER(hjstate) ((hjstate)->hj_NullOuterTupleSlot != NULL)
00041
00042 static TupleTableSlot *ExecHashJoinOuterGetTuple(PlanState *outerNode,
00043 HashJoinState *hjstate,
00044 uint32 *hashvalue);
00045 static TupleTableSlot *ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
00046 BufFile *file,
00047 uint32 *hashvalue,
00048 TupleTableSlot *tupleSlot);
00049 static bool ExecHashJoinNewBatch(HashJoinState *hjstate);
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 TupleTableSlot *
00062 ExecHashJoin(HashJoinState *node)
00063 {
00064 PlanState *outerNode;
00065 HashState *hashNode;
00066 List *joinqual;
00067 List *otherqual;
00068 ExprContext *econtext;
00069 ExprDoneCond isDone;
00070 HashJoinTable hashtable;
00071 TupleTableSlot *outerTupleSlot;
00072 uint32 hashvalue;
00073 int batchno;
00074
00075
00076
00077
00078 joinqual = node->js.joinqual;
00079 otherqual = node->js.ps.qual;
00080 hashNode = (HashState *) innerPlanState(node);
00081 outerNode = outerPlanState(node);
00082 hashtable = node->hj_HashTable;
00083 econtext = node->js.ps.ps_ExprContext;
00084
00085
00086
00087
00088
00089
00090 if (node->js.ps.ps_TupFromTlist)
00091 {
00092 TupleTableSlot *result;
00093
00094 result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
00095 if (isDone == ExprMultipleResult)
00096 return result;
00097
00098 node->js.ps.ps_TupFromTlist = false;
00099 }
00100
00101
00102
00103
00104
00105
00106 ResetExprContext(econtext);
00107
00108
00109
00110
00111 for (;;)
00112 {
00113 switch (node->hj_JoinState)
00114 {
00115 case HJ_BUILD_HASHTABLE:
00116
00117
00118
00119
00120 Assert(hashtable == NULL);
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 if (HJ_FILL_INNER(node))
00146 {
00147
00148 node->hj_FirstOuterTupleSlot = NULL;
00149 }
00150 else if (HJ_FILL_OUTER(node) ||
00151 (outerNode->plan->startup_cost < hashNode->ps.plan->total_cost &&
00152 !node->hj_OuterNotEmpty))
00153 {
00154 node->hj_FirstOuterTupleSlot = ExecProcNode(outerNode);
00155 if (TupIsNull(node->hj_FirstOuterTupleSlot))
00156 {
00157 node->hj_OuterNotEmpty = false;
00158 return NULL;
00159 }
00160 else
00161 node->hj_OuterNotEmpty = true;
00162 }
00163 else
00164 node->hj_FirstOuterTupleSlot = NULL;
00165
00166
00167
00168
00169 hashtable = ExecHashTableCreate((Hash *) hashNode->ps.plan,
00170 node->hj_HashOperators,
00171 HJ_FILL_INNER(node));
00172 node->hj_HashTable = hashtable;
00173
00174
00175
00176
00177 hashNode->hashtable = hashtable;
00178 (void) MultiExecProcNode((PlanState *) hashNode);
00179
00180
00181
00182
00183
00184
00185 if (hashtable->totalTuples == 0 && !HJ_FILL_OUTER(node))
00186 return NULL;
00187
00188
00189
00190
00191
00192 hashtable->nbatch_outstart = hashtable->nbatch;
00193
00194
00195
00196
00197
00198
00199 node->hj_OuterNotEmpty = false;
00200
00201 node->hj_JoinState = HJ_NEED_NEW_OUTER;
00202
00203
00204
00205 case HJ_NEED_NEW_OUTER:
00206
00207
00208
00209
00210 outerTupleSlot = ExecHashJoinOuterGetTuple(outerNode,
00211 node,
00212 &hashvalue);
00213 if (TupIsNull(outerTupleSlot))
00214 {
00215
00216 if (HJ_FILL_INNER(node))
00217 {
00218
00219 ExecPrepHashTableForUnmatched(node);
00220 node->hj_JoinState = HJ_FILL_INNER_TUPLES;
00221 }
00222 else
00223 node->hj_JoinState = HJ_NEED_NEW_BATCH;
00224 continue;
00225 }
00226
00227 econtext->ecxt_outertuple = outerTupleSlot;
00228 node->hj_MatchedOuter = false;
00229
00230
00231
00232
00233
00234 node->hj_CurHashValue = hashvalue;
00235 ExecHashGetBucketAndBatch(hashtable, hashvalue,
00236 &node->hj_CurBucketNo, &batchno);
00237 node->hj_CurSkewBucketNo = ExecHashGetSkewBucket(hashtable,
00238 hashvalue);
00239 node->hj_CurTuple = NULL;
00240
00241
00242
00243
00244
00245 if (batchno != hashtable->curbatch &&
00246 node->hj_CurSkewBucketNo == INVALID_SKEW_BUCKET_NO)
00247 {
00248
00249
00250
00251
00252 Assert(batchno > hashtable->curbatch);
00253 ExecHashJoinSaveTuple(ExecFetchSlotMinimalTuple(outerTupleSlot),
00254 hashvalue,
00255 &hashtable->outerBatchFile[batchno]);
00256
00257 continue;
00258 }
00259
00260
00261 node->hj_JoinState = HJ_SCAN_BUCKET;
00262
00263
00264
00265 case HJ_SCAN_BUCKET:
00266
00267
00268
00269
00270
00271
00272 CHECK_FOR_INTERRUPTS();
00273
00274
00275
00276
00277 if (!ExecScanHashBucket(node, econtext))
00278 {
00279
00280 node->hj_JoinState = HJ_FILL_OUTER_TUPLE;
00281 continue;
00282 }
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 if (joinqual == NIL || ExecQual(joinqual, econtext, false))
00297 {
00298 node->hj_MatchedOuter = true;
00299 HeapTupleHeaderSetMatch(HJTUPLE_MINTUPLE(node->hj_CurTuple));
00300
00301
00302 if (node->js.jointype == JOIN_ANTI)
00303 {
00304 node->hj_JoinState = HJ_NEED_NEW_OUTER;
00305 continue;
00306 }
00307
00308
00309
00310
00311
00312 if (node->js.jointype == JOIN_SEMI)
00313 node->hj_JoinState = HJ_NEED_NEW_OUTER;
00314
00315 if (otherqual == NIL ||
00316 ExecQual(otherqual, econtext, false))
00317 {
00318 TupleTableSlot *result;
00319
00320 result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
00321
00322 if (isDone != ExprEndResult)
00323 {
00324 node->js.ps.ps_TupFromTlist =
00325 (isDone == ExprMultipleResult);
00326 return result;
00327 }
00328 }
00329 else
00330 InstrCountFiltered2(node, 1);
00331 }
00332 else
00333 InstrCountFiltered1(node, 1);
00334 break;
00335
00336 case HJ_FILL_OUTER_TUPLE:
00337
00338
00339
00340
00341
00342
00343 node->hj_JoinState = HJ_NEED_NEW_OUTER;
00344
00345 if (!node->hj_MatchedOuter &&
00346 HJ_FILL_OUTER(node))
00347 {
00348
00349
00350
00351
00352 econtext->ecxt_innertuple = node->hj_NullInnerTupleSlot;
00353
00354 if (otherqual == NIL ||
00355 ExecQual(otherqual, econtext, false))
00356 {
00357 TupleTableSlot *result;
00358
00359 result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
00360
00361 if (isDone != ExprEndResult)
00362 {
00363 node->js.ps.ps_TupFromTlist =
00364 (isDone == ExprMultipleResult);
00365 return result;
00366 }
00367 }
00368 else
00369 InstrCountFiltered2(node, 1);
00370 }
00371 break;
00372
00373 case HJ_FILL_INNER_TUPLES:
00374
00375
00376
00377
00378
00379
00380 if (!ExecScanHashTableForUnmatched(node, econtext))
00381 {
00382
00383 node->hj_JoinState = HJ_NEED_NEW_BATCH;
00384 continue;
00385 }
00386
00387
00388
00389
00390
00391 econtext->ecxt_outertuple = node->hj_NullOuterTupleSlot;
00392
00393 if (otherqual == NIL ||
00394 ExecQual(otherqual, econtext, false))
00395 {
00396 TupleTableSlot *result;
00397
00398 result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
00399
00400 if (isDone != ExprEndResult)
00401 {
00402 node->js.ps.ps_TupFromTlist =
00403 (isDone == ExprMultipleResult);
00404 return result;
00405 }
00406 }
00407 else
00408 InstrCountFiltered2(node, 1);
00409 break;
00410
00411 case HJ_NEED_NEW_BATCH:
00412
00413
00414
00415
00416 if (!ExecHashJoinNewBatch(node))
00417 return NULL;
00418 node->hj_JoinState = HJ_NEED_NEW_OUTER;
00419 break;
00420
00421 default:
00422 elog(ERROR, "unrecognized hashjoin state: %d",
00423 (int) node->hj_JoinState);
00424 }
00425 }
00426 }
00427
00428
00429
00430
00431
00432
00433
00434 HashJoinState *
00435 ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
00436 {
00437 HashJoinState *hjstate;
00438 Plan *outerNode;
00439 Hash *hashNode;
00440 List *lclauses;
00441 List *rclauses;
00442 List *hoperators;
00443 ListCell *l;
00444
00445
00446 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
00447
00448
00449
00450
00451 hjstate = makeNode(HashJoinState);
00452 hjstate->js.ps.plan = (Plan *) node;
00453 hjstate->js.ps.state = estate;
00454
00455
00456
00457
00458
00459
00460 ExecAssignExprContext(estate, &hjstate->js.ps);
00461
00462
00463
00464
00465 hjstate->js.ps.targetlist = (List *)
00466 ExecInitExpr((Expr *) node->join.plan.targetlist,
00467 (PlanState *) hjstate);
00468 hjstate->js.ps.qual = (List *)
00469 ExecInitExpr((Expr *) node->join.plan.qual,
00470 (PlanState *) hjstate);
00471 hjstate->js.jointype = node->join.jointype;
00472 hjstate->js.joinqual = (List *)
00473 ExecInitExpr((Expr *) node->join.joinqual,
00474 (PlanState *) hjstate);
00475 hjstate->hashclauses = (List *)
00476 ExecInitExpr((Expr *) node->hashclauses,
00477 (PlanState *) hjstate);
00478
00479
00480
00481
00482
00483
00484
00485
00486 outerNode = outerPlan(node);
00487 hashNode = (Hash *) innerPlan(node);
00488
00489 outerPlanState(hjstate) = ExecInitNode(outerNode, estate, eflags);
00490 innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate, eflags);
00491
00492
00493
00494
00495 ExecInitResultTupleSlot(estate, &hjstate->js.ps);
00496 hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate);
00497
00498
00499 switch (node->join.jointype)
00500 {
00501 case JOIN_INNER:
00502 case JOIN_SEMI:
00503 break;
00504 case JOIN_LEFT:
00505 case JOIN_ANTI:
00506 hjstate->hj_NullInnerTupleSlot =
00507 ExecInitNullTupleSlot(estate,
00508 ExecGetResultType(innerPlanState(hjstate)));
00509 break;
00510 case JOIN_RIGHT:
00511 hjstate->hj_NullOuterTupleSlot =
00512 ExecInitNullTupleSlot(estate,
00513 ExecGetResultType(outerPlanState(hjstate)));
00514 break;
00515 case JOIN_FULL:
00516 hjstate->hj_NullOuterTupleSlot =
00517 ExecInitNullTupleSlot(estate,
00518 ExecGetResultType(outerPlanState(hjstate)));
00519 hjstate->hj_NullInnerTupleSlot =
00520 ExecInitNullTupleSlot(estate,
00521 ExecGetResultType(innerPlanState(hjstate)));
00522 break;
00523 default:
00524 elog(ERROR, "unrecognized join type: %d",
00525 (int) node->join.jointype);
00526 }
00527
00528
00529
00530
00531
00532
00533
00534
00535 {
00536 HashState *hashstate = (HashState *) innerPlanState(hjstate);
00537 TupleTableSlot *slot = hashstate->ps.ps_ResultTupleSlot;
00538
00539 hjstate->hj_HashTupleSlot = slot;
00540 }
00541
00542
00543
00544
00545 ExecAssignResultTypeFromTL(&hjstate->js.ps);
00546 ExecAssignProjectionInfo(&hjstate->js.ps, NULL);
00547
00548 ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot,
00549 ExecGetResultType(outerPlanState(hjstate)));
00550
00551
00552
00553
00554 hjstate->hj_HashTable = NULL;
00555 hjstate->hj_FirstOuterTupleSlot = NULL;
00556
00557 hjstate->hj_CurHashValue = 0;
00558 hjstate->hj_CurBucketNo = 0;
00559 hjstate->hj_CurSkewBucketNo = INVALID_SKEW_BUCKET_NO;
00560 hjstate->hj_CurTuple = NULL;
00561
00562
00563
00564
00565
00566
00567
00568 lclauses = NIL;
00569 rclauses = NIL;
00570 hoperators = NIL;
00571 foreach(l, hjstate->hashclauses)
00572 {
00573 FuncExprState *fstate = (FuncExprState *) lfirst(l);
00574 OpExpr *hclause;
00575
00576 Assert(IsA(fstate, FuncExprState));
00577 hclause = (OpExpr *) fstate->xprstate.expr;
00578 Assert(IsA(hclause, OpExpr));
00579 lclauses = lappend(lclauses, linitial(fstate->args));
00580 rclauses = lappend(rclauses, lsecond(fstate->args));
00581 hoperators = lappend_oid(hoperators, hclause->opno);
00582 }
00583 hjstate->hj_OuterHashKeys = lclauses;
00584 hjstate->hj_InnerHashKeys = rclauses;
00585 hjstate->hj_HashOperators = hoperators;
00586
00587 ((HashState *) innerPlanState(hjstate))->hashkeys = rclauses;
00588
00589 hjstate->js.ps.ps_TupFromTlist = false;
00590 hjstate->hj_JoinState = HJ_BUILD_HASHTABLE;
00591 hjstate->hj_MatchedOuter = false;
00592 hjstate->hj_OuterNotEmpty = false;
00593
00594 return hjstate;
00595 }
00596
00597
00598
00599
00600
00601
00602
00603 void
00604 ExecEndHashJoin(HashJoinState *node)
00605 {
00606
00607
00608
00609 if (node->hj_HashTable)
00610 {
00611 ExecHashTableDestroy(node->hj_HashTable);
00612 node->hj_HashTable = NULL;
00613 }
00614
00615
00616
00617
00618 ExecFreeExprContext(&node->js.ps);
00619
00620
00621
00622
00623 ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
00624 ExecClearTuple(node->hj_OuterTupleSlot);
00625 ExecClearTuple(node->hj_HashTupleSlot);
00626
00627
00628
00629
00630 ExecEndNode(outerPlanState(node));
00631 ExecEndNode(innerPlanState(node));
00632 }
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 static TupleTableSlot *
00647 ExecHashJoinOuterGetTuple(PlanState *outerNode,
00648 HashJoinState *hjstate,
00649 uint32 *hashvalue)
00650 {
00651 HashJoinTable hashtable = hjstate->hj_HashTable;
00652 int curbatch = hashtable->curbatch;
00653 TupleTableSlot *slot;
00654
00655 if (curbatch == 0)
00656 {
00657
00658
00659
00660
00661 slot = hjstate->hj_FirstOuterTupleSlot;
00662 if (!TupIsNull(slot))
00663 hjstate->hj_FirstOuterTupleSlot = NULL;
00664 else
00665 slot = ExecProcNode(outerNode);
00666
00667 while (!TupIsNull(slot))
00668 {
00669
00670
00671
00672 ExprContext *econtext = hjstate->js.ps.ps_ExprContext;
00673
00674 econtext->ecxt_outertuple = slot;
00675 if (ExecHashGetHashValue(hashtable, econtext,
00676 hjstate->hj_OuterHashKeys,
00677 true,
00678 HJ_FILL_OUTER(hjstate),
00679 hashvalue))
00680 {
00681
00682 hjstate->hj_OuterNotEmpty = true;
00683
00684 return slot;
00685 }
00686
00687
00688
00689
00690
00691 slot = ExecProcNode(outerNode);
00692 }
00693 }
00694 else if (curbatch < hashtable->nbatch)
00695 {
00696 BufFile *file = hashtable->outerBatchFile[curbatch];
00697
00698
00699
00700
00701
00702 if (file == NULL)
00703 return NULL;
00704
00705 slot = ExecHashJoinGetSavedTuple(hjstate,
00706 file,
00707 hashvalue,
00708 hjstate->hj_OuterTupleSlot);
00709 if (!TupIsNull(slot))
00710 return slot;
00711 }
00712
00713
00714 return NULL;
00715 }
00716
00717
00718
00719
00720
00721
00722
00723 static bool
00724 ExecHashJoinNewBatch(HashJoinState *hjstate)
00725 {
00726 HashJoinTable hashtable = hjstate->hj_HashTable;
00727 int nbatch;
00728 int curbatch;
00729 BufFile *innerFile;
00730 TupleTableSlot *slot;
00731 uint32 hashvalue;
00732
00733 nbatch = hashtable->nbatch;
00734 curbatch = hashtable->curbatch;
00735
00736 if (curbatch > 0)
00737 {
00738
00739
00740
00741
00742 if (hashtable->outerBatchFile[curbatch])
00743 BufFileClose(hashtable->outerBatchFile[curbatch]);
00744 hashtable->outerBatchFile[curbatch] = NULL;
00745 }
00746 else
00747 {
00748
00749
00750
00751
00752
00753
00754 hashtable->skewEnabled = false;
00755 hashtable->skewBucket = NULL;
00756 hashtable->skewBucketNums = NULL;
00757 hashtable->nSkewBuckets = 0;
00758 hashtable->spaceUsedSkew = 0;
00759 }
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778 curbatch++;
00779 while (curbatch < nbatch &&
00780 (hashtable->outerBatchFile[curbatch] == NULL ||
00781 hashtable->innerBatchFile[curbatch] == NULL))
00782 {
00783 if (hashtable->outerBatchFile[curbatch] &&
00784 HJ_FILL_OUTER(hjstate))
00785 break;
00786 if (hashtable->innerBatchFile[curbatch] &&
00787 HJ_FILL_INNER(hjstate))
00788 break;
00789 if (hashtable->innerBatchFile[curbatch] &&
00790 nbatch != hashtable->nbatch_original)
00791 break;
00792 if (hashtable->outerBatchFile[curbatch] &&
00793 nbatch != hashtable->nbatch_outstart)
00794 break;
00795
00796
00797 if (hashtable->innerBatchFile[curbatch])
00798 BufFileClose(hashtable->innerBatchFile[curbatch]);
00799 hashtable->innerBatchFile[curbatch] = NULL;
00800 if (hashtable->outerBatchFile[curbatch])
00801 BufFileClose(hashtable->outerBatchFile[curbatch]);
00802 hashtable->outerBatchFile[curbatch] = NULL;
00803 curbatch++;
00804 }
00805
00806 if (curbatch >= nbatch)
00807 return false;
00808
00809 hashtable->curbatch = curbatch;
00810
00811
00812
00813
00814 ExecHashTableReset(hashtable);
00815
00816 innerFile = hashtable->innerBatchFile[curbatch];
00817
00818 if (innerFile != NULL)
00819 {
00820 if (BufFileSeek(innerFile, 0, 0L, SEEK_SET))
00821 ereport(ERROR,
00822 (errcode_for_file_access(),
00823 errmsg("could not rewind hash-join temporary file: %m")));
00824
00825 while ((slot = ExecHashJoinGetSavedTuple(hjstate,
00826 innerFile,
00827 &hashvalue,
00828 hjstate->hj_HashTupleSlot)))
00829 {
00830
00831
00832
00833
00834 ExecHashTableInsert(hashtable, slot, hashvalue);
00835 }
00836
00837
00838
00839
00840
00841 BufFileClose(innerFile);
00842 hashtable->innerBatchFile[curbatch] = NULL;
00843 }
00844
00845
00846
00847
00848 if (hashtable->outerBatchFile[curbatch] != NULL)
00849 {
00850 if (BufFileSeek(hashtable->outerBatchFile[curbatch], 0, 0L, SEEK_SET))
00851 ereport(ERROR,
00852 (errcode_for_file_access(),
00853 errmsg("could not rewind hash-join temporary file: %m")));
00854 }
00855
00856 return true;
00857 }
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870 void
00871 ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue,
00872 BufFile **fileptr)
00873 {
00874 BufFile *file = *fileptr;
00875 size_t written;
00876
00877 if (file == NULL)
00878 {
00879
00880 file = BufFileCreateTemp(false);
00881 *fileptr = file;
00882 }
00883
00884 written = BufFileWrite(file, (void *) &hashvalue, sizeof(uint32));
00885 if (written != sizeof(uint32))
00886 ereport(ERROR,
00887 (errcode_for_file_access(),
00888 errmsg("could not write to hash-join temporary file: %m")));
00889
00890 written = BufFileWrite(file, (void *) tuple, tuple->t_len);
00891 if (written != tuple->t_len)
00892 ereport(ERROR,
00893 (errcode_for_file_access(),
00894 errmsg("could not write to hash-join temporary file: %m")));
00895 }
00896
00897
00898
00899
00900
00901
00902
00903
00904 static TupleTableSlot *
00905 ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
00906 BufFile *file,
00907 uint32 *hashvalue,
00908 TupleTableSlot *tupleSlot)
00909 {
00910 uint32 header[2];
00911 size_t nread;
00912 MinimalTuple tuple;
00913
00914
00915
00916
00917
00918
00919 nread = BufFileRead(file, (void *) header, sizeof(header));
00920 if (nread == 0)
00921 {
00922 ExecClearTuple(tupleSlot);
00923 return NULL;
00924 }
00925 if (nread != sizeof(header))
00926 ereport(ERROR,
00927 (errcode_for_file_access(),
00928 errmsg("could not read from hash-join temporary file: %m")));
00929 *hashvalue = header[0];
00930 tuple = (MinimalTuple) palloc(header[1]);
00931 tuple->t_len = header[1];
00932 nread = BufFileRead(file,
00933 (void *) ((char *) tuple + sizeof(uint32)),
00934 header[1] - sizeof(uint32));
00935 if (nread != header[1] - sizeof(uint32))
00936 ereport(ERROR,
00937 (errcode_for_file_access(),
00938 errmsg("could not read from hash-join temporary file: %m")));
00939 return ExecStoreMinimalTuple(tuple, tupleSlot, true);
00940 }
00941
00942
00943 void
00944 ExecReScanHashJoin(HashJoinState *node)
00945 {
00946
00947
00948
00949
00950
00951
00952
00953 if (node->hj_HashTable != NULL)
00954 {
00955 if (node->hj_HashTable->nbatch == 1 &&
00956 node->js.ps.righttree->chgParam == NULL)
00957 {
00958
00959
00960
00961
00962
00963
00964 if (HJ_FILL_INNER(node))
00965 ExecHashTableResetMatchFlags(node->hj_HashTable);
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976 node->hj_OuterNotEmpty = false;
00977
00978
00979 node->hj_JoinState = HJ_NEED_NEW_OUTER;
00980 }
00981 else
00982 {
00983
00984 ExecHashTableDestroy(node->hj_HashTable);
00985 node->hj_HashTable = NULL;
00986 node->hj_JoinState = HJ_BUILD_HASHTABLE;
00987
00988
00989
00990
00991
00992 if (node->js.ps.righttree->chgParam == NULL)
00993 ExecReScan(node->js.ps.righttree);
00994 }
00995 }
00996
00997
00998 node->hj_CurHashValue = 0;
00999 node->hj_CurBucketNo = 0;
01000 node->hj_CurSkewBucketNo = INVALID_SKEW_BUCKET_NO;
01001 node->hj_CurTuple = NULL;
01002
01003 node->js.ps.ps_TupFromTlist = false;
01004 node->hj_MatchedOuter = false;
01005 node->hj_FirstOuterTupleSlot = NULL;
01006
01007
01008
01009
01010
01011 if (node->js.ps.lefttree->chgParam == NULL)
01012 ExecReScan(node->js.ps.lefttree);
01013 }