Commit b79cb1ee authored by Tom Lane's avatar Tom Lane

Recent changes to allow hash join to exit early given empty input from

one child or the other had a problem: they did not leave the node in a
state that ExecReScanHashJoin would understand.  In particular it would
tend to fail to reset the child plans when needed.  Per report from
Mario Weilguni.
parent d4fc4ac4
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.77 2005/11/22 18:17:10 momjian Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.78 2005/11/28 17:14:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -152,12 +152,7 @@ ExecHashJoin(HashJoinState *node) ...@@ -152,12 +152,7 @@ ExecHashJoin(HashJoinState *node)
* outer join, we can quit without scanning the outer relation. * outer join, we can quit without scanning the outer relation.
*/ */
if (hashtable->totalTuples == 0 && node->js.jointype != JOIN_LEFT) if (hashtable->totalTuples == 0 && node->js.jointype != JOIN_LEFT)
{
ExecHashTableDestroy(hashtable);
node->hj_HashTable = NULL;
node->hj_FirstOuterTupleSlot = NULL;
return NULL; return NULL;
}
/* /*
* need to remember whether nbatch has increased since we began * need to remember whether nbatch has increased since we began
...@@ -487,7 +482,6 @@ ExecEndHashJoin(HashJoinState *node) ...@@ -487,7 +482,6 @@ ExecEndHashJoin(HashJoinState *node)
{ {
ExecHashTableDestroy(node->hj_HashTable); ExecHashTableDestroy(node->hj_HashTable);
node->hj_HashTable = NULL; node->hj_HashTable = NULL;
node->hj_FirstOuterTupleSlot = NULL;
} }
/* /*
...@@ -803,13 +797,6 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate, ...@@ -803,13 +797,6 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
void void
ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt) ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
{ {
/*
* If we haven't yet built the hash table then we can just return; nothing
* done yet, so nothing to undo.
*/
if (node->hj_HashTable == NULL)
return;
/* /*
* In a multi-batch join, we currently have to do rescans the hard way, * In a multi-batch join, we currently have to do rescans the hard way,
* primarily because batch temp files may have already been released. But * primarily because batch temp files may have already been released. But
...@@ -817,24 +804,26 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt) ...@@ -817,24 +804,26 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
* inner subnode, then we can just re-use the existing hash table without * inner subnode, then we can just re-use the existing hash table without
* rebuilding it. * rebuilding it.
*/ */
if (node->hj_HashTable->nbatch == 1 && if (node->hj_HashTable != NULL)
((PlanState *) node)->righttree->chgParam == NULL)
{
/* okay to reuse the hash table; needn't rescan inner, either */
}
else
{ {
/* must destroy and rebuild hash table */ if (node->hj_HashTable->nbatch == 1 &&
ExecHashTableDestroy(node->hj_HashTable); ((PlanState *) node)->righttree->chgParam == NULL)
node->hj_HashTable = NULL; {
node->hj_FirstOuterTupleSlot = NULL; /* okay to reuse the hash table; needn't rescan inner, either */
}
else
{
/* must destroy and rebuild hash table */
ExecHashTableDestroy(node->hj_HashTable);
node->hj_HashTable = NULL;
/* /*
* if chgParam of subnode is not null then plan will be re-scanned by * if chgParam of subnode is not null then plan will be re-scanned
* first ExecProcNode. * by first ExecProcNode.
*/ */
if (((PlanState *) node)->righttree->chgParam == NULL) if (((PlanState *) node)->righttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->righttree, exprCtxt); ExecReScan(((PlanState *) node)->righttree, exprCtxt);
}
} }
/* Always reset intra-tuple state */ /* Always reset intra-tuple state */
...@@ -846,6 +835,7 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt) ...@@ -846,6 +835,7 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
node->js.ps.ps_TupFromTlist = false; node->js.ps.ps_TupFromTlist = false;
node->hj_NeedNewOuter = true; node->hj_NeedNewOuter = true;
node->hj_MatchedOuter = false; node->hj_MatchedOuter = false;
node->hj_FirstOuterTupleSlot = NULL;
/* /*
* if chgParam of subnode is not null then plan will be re-scanned by * if chgParam of subnode is not null then plan will be re-scanned by
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment