From b79cb1eea1e33251683ffee217cbc8d6fb5e2f5f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 28 Nov 2005 17:14:23 +0000 Subject: [PATCH] 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. --- src/backend/executor/nodeHashjoin.c | 50 ++++++++++++----------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 86c63da4f7..ee2809a8b4 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -8,7 +8,7 @@ * * * 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) * outer join, we can quit without scanning the outer relation. */ if (hashtable->totalTuples == 0 && node->js.jointype != JOIN_LEFT) - { - ExecHashTableDestroy(hashtable); - node->hj_HashTable = NULL; - node->hj_FirstOuterTupleSlot = NULL; return NULL; - } /* * need to remember whether nbatch has increased since we began @@ -487,7 +482,6 @@ ExecEndHashJoin(HashJoinState *node) { ExecHashTableDestroy(node->hj_HashTable); node->hj_HashTable = NULL; - node->hj_FirstOuterTupleSlot = NULL; } /* @@ -803,13 +797,6 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate, void 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, * primarily because batch temp files may have already been released. But @@ -817,24 +804,26 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt) * inner subnode, then we can just re-use the existing hash table without * rebuilding it. */ - if (node->hj_HashTable->nbatch == 1 && - ((PlanState *) node)->righttree->chgParam == NULL) + if (node->hj_HashTable != 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; - node->hj_FirstOuterTupleSlot = NULL; + if (node->hj_HashTable->nbatch == 1 && + ((PlanState *) node)->righttree->chgParam == 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 - * first ExecProcNode. - */ - if (((PlanState *) node)->righttree->chgParam == NULL) - ExecReScan(((PlanState *) node)->righttree, exprCtxt); + /* + * if chgParam of subnode is not null then plan will be re-scanned + * by first ExecProcNode. + */ + if (((PlanState *) node)->righttree->chgParam == NULL) + ExecReScan(((PlanState *) node)->righttree, exprCtxt); + } } /* Always reset intra-tuple state */ @@ -846,6 +835,7 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt) node->js.ps.ps_TupFromTlist = false; node->hj_NeedNewOuter = true; node->hj_MatchedOuter = false; + node->hj_FirstOuterTupleSlot = NULL; /* * if chgParam of subnode is not null then plan will be re-scanned by