8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.50 2003/05/05 17:57:47 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.51 2003/05/30 20:23:10 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -56,9 +56,7 @@ ExecHashJoin(HashJoinState *node)
56
56
HashJoinTable hashtable ;
57
57
HeapTuple curtuple ;
58
58
TupleTableSlot * outerTupleSlot ;
59
- TupleTableSlot * innerTupleSlot ;
60
59
int i ;
61
- bool hashPhaseDone ;
62
60
63
61
/*
64
62
* get information from HashJoin node
@@ -69,7 +67,6 @@ ExecHashJoin(HashJoinState *node)
69
67
otherqual = node -> js .ps .qual ;
70
68
hashNode = (HashState * ) innerPlanState (node );
71
69
outerNode = outerPlanState (node );
72
- hashPhaseDone = node -> hj_hashdone ;
73
70
dir = estate -> es_direction ;
74
71
75
72
/*
@@ -114,34 +111,30 @@ ExecHashJoin(HashJoinState *node)
114
111
/*
115
112
* if this is the first call, build the hash table for inner relation
116
113
*/
117
- if (!hashPhaseDone )
118
- { /* if the hash phase not completed */
119
- if (hashtable == NULL )
120
- { /* if the hash table has not been created */
121
-
122
- /*
123
- * create the hash table
124
- */
125
- hashtable = ExecHashTableCreate ((Hash * ) hashNode -> ps .plan );
126
- node -> hj_HashTable = hashtable ;
114
+ if (!node -> hj_hashdone )
115
+ {
116
+ /*
117
+ * create the hash table
118
+ */
119
+ Assert (hashtable == NULL );
120
+ hashtable = ExecHashTableCreate ((Hash * ) hashNode -> ps .plan );
121
+ node -> hj_HashTable = hashtable ;
127
122
128
- /*
129
- * execute the Hash node, to build the hash table
130
- */
131
- hashNode -> hashtable = hashtable ;
132
- innerTupleSlot = ExecProcNode ((PlanState * ) hashNode );
133
- }
134
- node -> hj_hashdone = true;
123
+ /*
124
+ * execute the Hash node, to build the hash table
125
+ */
126
+ hashNode -> hashtable = hashtable ;
127
+ (void ) ExecProcNode ((PlanState * ) hashNode );
135
128
136
129
/*
137
130
* Open temp files for outer batches, if needed. Note that file
138
131
* buffers are palloc'd in regular executor context.
139
132
*/
140
133
for (i = 0 ; i < hashtable -> nbatch ; i ++ )
141
134
hashtable -> outerBatchFile [i ] = BufFileCreateTemp (false);
135
+
136
+ node -> hj_hashdone = true;
142
137
}
143
- else if (hashtable == NULL )
144
- return NULL ;
145
138
146
139
/*
147
140
* Now get an outer tuple and probe into the hash table for matches
@@ -159,11 +152,7 @@ ExecHashJoin(HashJoinState *node)
159
152
node );
160
153
if (TupIsNull (outerTupleSlot ))
161
154
{
162
- /*
163
- * when the last batch runs out, clean up and exit
164
- */
165
- ExecHashTableDestroy (hashtable );
166
- node -> hj_HashTable = NULL ;
155
+ /* end of join */
167
156
return NULL ;
168
157
}
169
158
@@ -410,8 +399,8 @@ ExecInitHashJoin(HashJoin *node, EState *estate)
410
399
*/
411
400
412
401
hjstate -> hj_hashdone = false;
413
-
414
402
hjstate -> hj_HashTable = (HashJoinTable ) NULL ;
403
+
415
404
hjstate -> hj_CurBucketNo = 0 ;
416
405
hjstate -> hj_CurTuple = (HashJoinTuple ) NULL ;
417
406
461
450
ExecEndHashJoin (HashJoinState * node )
462
451
{
463
452
/*
464
- * free hash table in case we end plan before all tuples are retrieved
453
+ * Free hash table
465
454
*/
466
455
if (node -> hj_HashTable )
467
456
{
@@ -682,21 +671,41 @@ ExecHashJoinSaveTuple(HeapTuple heapTuple,
682
671
void
683
672
ExecReScanHashJoin (HashJoinState * node , ExprContext * exprCtxt )
684
673
{
674
+ /*
675
+ * If we haven't yet built the hash table then we can just return;
676
+ * nothing done yet, so nothing to undo.
677
+ */
685
678
if (!node -> hj_hashdone )
686
679
return ;
687
-
688
- node -> hj_hashdone = false;
680
+ Assert (node -> hj_HashTable != NULL );
689
681
690
682
/*
691
- * Unfortunately, currently we have to destroy hashtable in all
692
- * cases...
683
+ * In a multi-batch join, we currently have to do rescans the hard way,
684
+ * primarily because batch temp files may have already been released.
685
+ * But if it's a single-batch join, and there is no parameter change
686
+ * for the inner subnode, then we can just re-use the existing hash
687
+ * table without rebuilding it.
693
688
*/
694
- if (node -> hj_HashTable )
689
+ if (node -> hj_HashTable -> nbatch == 0 &&
690
+ ((PlanState * ) node )-> righttree -> chgParam == NULL )
691
+ {
692
+ /* okay to reuse the hash table; needn't rescan inner, either */
693
+ }
694
+ else
695
695
{
696
+ /* must destroy and rebuild hash table */
697
+ node -> hj_hashdone = false;
696
698
ExecHashTableDestroy (node -> hj_HashTable );
697
699
node -> hj_HashTable = NULL ;
700
+ /*
701
+ * if chgParam of subnode is not null then plan will be re-scanned
702
+ * by first ExecProcNode.
703
+ */
704
+ if (((PlanState * ) node )-> righttree -> chgParam == NULL )
705
+ ExecReScan (((PlanState * ) node )-> righttree , exprCtxt );
698
706
}
699
707
708
+ /* Always reset intra-tuple state */
700
709
node -> hj_CurBucketNo = 0 ;
701
710
node -> hj_CurTuple = (HashJoinTuple ) NULL ;
702
711
@@ -706,11 +715,9 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
706
715
node -> hj_MatchedOuter = false;
707
716
708
717
/*
709
- * if chgParam of subnodes is not null then plans will be re-scanned
718
+ * if chgParam of subnode is not null then plan will be re-scanned
710
719
* by first ExecProcNode.
711
720
*/
712
721
if (((PlanState * ) node )-> lefttree -> chgParam == NULL )
713
722
ExecReScan (((PlanState * ) node )-> lefttree , exprCtxt );
714
- if (((PlanState * ) node )-> righttree -> chgParam == NULL )
715
- ExecReScan (((PlanState * ) node )-> righttree , exprCtxt );
716
723
}
0 commit comments