88 *
99 *
1010 * 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 $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -56,9 +56,7 @@ ExecHashJoin(HashJoinState *node)
5656HashJoinTable hashtable ;
5757HeapTuple curtuple ;
5858TupleTableSlot * outerTupleSlot ;
59- TupleTableSlot * innerTupleSlot ;
6059int i ;
61- bool hashPhaseDone ;
6260
6361/*
6462 * get information from HashJoin node
@@ -69,7 +67,6 @@ ExecHashJoin(HashJoinState *node)
6967otherqual = node -> js .ps .qual ;
7068hashNode = (HashState * )innerPlanState (node );
7169outerNode = outerPlanState (node );
72- hashPhaseDone = node -> hj_hashdone ;
7370dir = estate -> es_direction ;
7471
7572/*
@@ -114,34 +111,30 @@ ExecHashJoin(HashJoinState *node)
114111/*
115112 * if this is the first call, build the hash table for inner relation
116113 */
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 ;
127122
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 );
135128
136129/*
137130 * Open temp files for outer batches, if needed. Note that file
138131 * buffers are palloc'd in regular executor context.
139132 */
140133for (i = 0 ;i < hashtable -> nbatch ;i ++ )
141134hashtable -> outerBatchFile [i ]= BufFileCreateTemp (false);
135+
136+ node -> hj_hashdone = true;
142137}
143- else if (hashtable == NULL )
144- return NULL ;
145138
146139/*
147140 * Now get an outer tuple and probe into the hash table for matches
@@ -159,11 +152,7 @@ ExecHashJoin(HashJoinState *node)
159152node );
160153if (TupIsNull (outerTupleSlot ))
161154{
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 */
167156return NULL ;
168157}
169158
@@ -410,8 +399,8 @@ ExecInitHashJoin(HashJoin *node, EState *estate)
410399 */
411400
412401hjstate -> hj_hashdone = false;
413-
414402hjstate -> hj_HashTable = (HashJoinTable )NULL ;
403+
415404hjstate -> hj_CurBucketNo = 0 ;
416405hjstate -> hj_CurTuple = (HashJoinTuple )NULL ;
417406
461450ExecEndHashJoin (HashJoinState * node )
462451{
463452/*
464- *free hash table in case we end plan before all tuples are retrieved
453+ *Free hash table
465454 */
466455if (node -> hj_HashTable )
467456{
@@ -682,21 +671,41 @@ ExecHashJoinSaveTuple(HeapTuple heapTuple,
682671void
683672ExecReScanHashJoin (HashJoinState * node ,ExprContext * exprCtxt )
684673{
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+ */
685678if (!node -> hj_hashdone )
686679return ;
687-
688- node -> hj_hashdone = false;
680+ Assert (node -> hj_HashTable != NULL );
689681
690682/*
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.
693688 */
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
695695{
696+ /* must destroy and rebuild hash table */
697+ node -> hj_hashdone = false;
696698ExecHashTableDestroy (node -> hj_HashTable );
697699node -> 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 );
698706}
699707
708+ /* Always reset intra-tuple state */
700709node -> hj_CurBucketNo = 0 ;
701710node -> hj_CurTuple = (HashJoinTuple )NULL ;
702711
@@ -706,11 +715,9 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
706715node -> hj_MatchedOuter = false;
707716
708717/*
709- * if chgParam ofsubnodes is not null thenplans will be re-scanned
718+ * if chgParam ofsubnode is not null thenplan will be re-scanned
710719 * by first ExecProcNode.
711720 */
712721if (((PlanState * )node )-> lefttree -> chgParam == NULL )
713722ExecReScan (((PlanState * )node )-> lefttree ,exprCtxt );
714- if (((PlanState * )node )-> righttree -> chgParam == NULL )
715- ExecReScan (((PlanState * )node )-> righttree ,exprCtxt );
716723}