From fabef3044adbf167e08ff3015923a2ba0dc98546 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 14 May 2005 21:29:23 +0000 Subject: [PATCH] Minor refactoring to eliminate duplicate code and make startup a tad faster. --- src/backend/executor/nodeMergejoin.c | 369 +++++++++++---------------- src/include/nodes/execnodes.h | 6 +- 2 files changed, 161 insertions(+), 214 deletions(-) diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index be4a97574e..6eb2bcc364 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.72 2005/05/13 21:20:16 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.73 2005/05/14 21:29:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -525,6 +525,86 @@ MJCompare(MergeJoinState *mergestate) return result; } + +/* + * Generate a fake join tuple with nulls for the inner tuple, + * and return it if it passes the non-join quals. + */ +static TupleTableSlot * +MJFillOuter(MergeJoinState *node) +{ + ExprContext *econtext = node->js.ps.ps_ExprContext; + List *otherqual = node->js.ps.qual; + + ResetExprContext(econtext); + + econtext->ecxt_outertuple = node->mj_OuterTupleSlot; + econtext->ecxt_innertuple = node->mj_NullInnerTupleSlot; + + if (ExecQual(otherqual, econtext, false)) + { + /* + * qualification succeeded. now form the desired projection tuple + * and return the slot containing it. + */ + TupleTableSlot *result; + ExprDoneCond isDone; + + MJ_printf("ExecMergeJoin: returning outer fill tuple\n"); + + result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); + + if (isDone != ExprEndResult) + { + node->js.ps.ps_TupFromTlist = + (isDone == ExprMultipleResult); + return result; + } + } + + return NULL; +} + +/* + * Generate a fake join tuple with nulls for the outer tuple, + * and return it if it passes the non-join quals. + */ +static TupleTableSlot * +MJFillInner(MergeJoinState *node) +{ + ExprContext *econtext = node->js.ps.ps_ExprContext; + List *otherqual = node->js.ps.qual; + + ResetExprContext(econtext); + + econtext->ecxt_outertuple = node->mj_NullOuterTupleSlot; + econtext->ecxt_innertuple = node->mj_InnerTupleSlot; + + if (ExecQual(otherqual, econtext, false)) + { + /* + * qualification succeeded. now form the desired projection tuple + * and return the slot containing it. + */ + TupleTableSlot *result; + ExprDoneCond isDone; + + MJ_printf("ExecMergeJoin: returning inner fill tuple\n"); + + result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); + + if (isDone != ExprEndResult) + { + node->js.ps.ps_TupFromTlist = + (isDone == ExprMultipleResult); + return result; + } + } + + return NULL; +} + + /* ---------------------------------------------------------------- * ExecMergeTupleDump * @@ -612,33 +692,8 @@ ExecMergeJoin(MergeJoinState *node) econtext = node->js.ps.ps_ExprContext; joinqual = node->js.joinqual; otherqual = node->js.ps.qual; - - switch (node->js.jointype) - { - case JOIN_INNER: - case JOIN_IN: - doFillOuter = false; - doFillInner = false; - break; - case JOIN_LEFT: - doFillOuter = true; - doFillInner = false; - break; - case JOIN_FULL: - doFillOuter = true; - doFillInner = true; - break; - case JOIN_RIGHT: - doFillOuter = false; - doFillInner = true; - break; - default: - elog(ERROR, "unrecognized join type: %d", - (int) node->js.jointype); - doFillOuter = false; /* keep compiler quiet */ - doFillInner = false; - break; - } + doFillOuter = node->mj_FillOuter; + doFillInner = node->mj_FillInner; /* * Check to see if we're still projecting out tuples from a previous @@ -707,15 +762,27 @@ ExecMergeJoin(MergeJoinState *node) } /* Compute join values and check for unmatchability */ - if (!MJEvalOuterValues(node) && !doFillOuter) + if (MJEvalOuterValues(node)) { - /* Stay in same state to fetch next outer tuple */ - node->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER; + /* OK to go get the first inner tuple */ + node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER; } else { - /* OK to go get the first inner tuple */ - node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER; + /* Stay in same state to fetch next outer tuple */ + if (doFillOuter) + { + /* + * Generate a fake join tuple with nulls for the inner + * tuple, and return it if it passes the non-join + * quals. + */ + TupleTableSlot *result; + + result = MJFillOuter(node); + if (result) + return result; + } } break; @@ -745,12 +812,7 @@ ExecMergeJoin(MergeJoinState *node) } /* Compute join values and check for unmatchability */ - if (!MJEvalInnerValues(node, innerTupleSlot) && !doFillInner) - { - /* Stay in same state to fetch next inner tuple */ - node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER; - } - else + if (MJEvalInnerValues(node, innerTupleSlot)) { /* * OK, we have the initial tuples. Begin by skipping @@ -758,6 +820,23 @@ ExecMergeJoin(MergeJoinState *node) */ node->mj_JoinState = EXEC_MJ_SKIP_TEST; } + else + { + /* Stay in same state to fetch next inner tuple */ + if (doFillInner) + { + /* + * Generate a fake join tuple with nulls for the outer + * tuple, and return it if it passes the non-join + * quals. + */ + TupleTableSlot *result; + + result = MJFillInner(node); + if (result) + return result; + } + } break; /* @@ -856,37 +935,13 @@ ExecMergeJoin(MergeJoinState *node) * tuple, and return it if it passes the non-join * quals. */ - node->mj_MatchedInner = true; /* do it only once */ - - ResetExprContext(econtext); - - outerTupleSlot = node->mj_NullOuterTupleSlot; - econtext->ecxt_outertuple = outerTupleSlot; - innerTupleSlot = node->mj_InnerTupleSlot; - econtext->ecxt_innertuple = innerTupleSlot; + TupleTableSlot *result; - if (ExecQual(otherqual, econtext, false)) - { - /* - * qualification succeeded. now form the desired - * projection tuple and return the slot containing - * it. - */ - TupleTableSlot *result; - ExprDoneCond isDone; - - MJ_printf("ExecMergeJoin: returning fill tuple\n"); - - result = ExecProject(node->js.ps.ps_ProjInfo, - &isDone); + node->mj_MatchedInner = true; /* do it only once */ - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } + result = MJFillInner(node); + if (result) + return result; } /* @@ -961,37 +1016,13 @@ ExecMergeJoin(MergeJoinState *node) * tuple, and return it if it passes the non-join * quals. */ - node->mj_MatchedOuter = true; /* do it only once */ + TupleTableSlot *result; - ResetExprContext(econtext); - - outerTupleSlot = node->mj_OuterTupleSlot; - econtext->ecxt_outertuple = outerTupleSlot; - innerTupleSlot = node->mj_NullInnerTupleSlot; - econtext->ecxt_innertuple = innerTupleSlot; - - if (ExecQual(otherqual, econtext, false)) - { - /* - * qualification succeeded. now form the desired - * projection tuple and return the slot containing - * it. - */ - TupleTableSlot *result; - ExprDoneCond isDone; - - MJ_printf("ExecMergeJoin: returning fill tuple\n"); - - result = ExecProject(node->js.ps.ps_ProjInfo, - &isDone); + node->mj_MatchedOuter = true; /* do it only once */ - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } + result = MJFillOuter(node); + if (result) + return result; } /* @@ -1223,37 +1254,13 @@ ExecMergeJoin(MergeJoinState *node) * tuple, and return it if it passes the non-join * quals. */ - node->mj_MatchedOuter = true; /* do it only once */ - - ResetExprContext(econtext); - - outerTupleSlot = node->mj_OuterTupleSlot; - econtext->ecxt_outertuple = outerTupleSlot; - innerTupleSlot = node->mj_NullInnerTupleSlot; - econtext->ecxt_innertuple = innerTupleSlot; - - if (ExecQual(otherqual, econtext, false)) - { - /* - * qualification succeeded. now form the desired - * projection tuple and return the slot containing - * it. - */ - TupleTableSlot *result; - ExprDoneCond isDone; + TupleTableSlot *result; - MJ_printf("ExecMergeJoin: returning fill tuple\n"); - - result = ExecProject(node->js.ps.ps_ProjInfo, - &isDone); + node->mj_MatchedOuter = true; /* do it only once */ - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } + result = MJFillOuter(node); + if (result) + return result; } /* @@ -1311,37 +1318,13 @@ ExecMergeJoin(MergeJoinState *node) * tuple, and return it if it passes the non-join * quals. */ - node->mj_MatchedInner = true; /* do it only once */ - - ResetExprContext(econtext); - - outerTupleSlot = node->mj_NullOuterTupleSlot; - econtext->ecxt_outertuple = outerTupleSlot; - innerTupleSlot = node->mj_InnerTupleSlot; - econtext->ecxt_innertuple = innerTupleSlot; - - if (ExecQual(otherqual, econtext, false)) - { - /* - * qualification succeeded. now form the desired - * projection tuple and return the slot containing - * it. - */ - TupleTableSlot *result; - ExprDoneCond isDone; + TupleTableSlot *result; - MJ_printf("ExecMergeJoin: returning fill tuple\n"); - - result = ExecProject(node->js.ps.ps_ProjInfo, - &isDone); + node->mj_MatchedInner = true; /* do it only once */ - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } + result = MJFillInner(node); + if (result) + return result; } /* @@ -1402,37 +1385,13 @@ ExecMergeJoin(MergeJoinState *node) * tuple, and return it if it passes the non-join * quals. */ - node->mj_MatchedInner = true; /* do it only once */ - - ResetExprContext(econtext); - - outerTupleSlot = node->mj_NullOuterTupleSlot; - econtext->ecxt_outertuple = outerTupleSlot; - innerTupleSlot = node->mj_InnerTupleSlot; - econtext->ecxt_innertuple = innerTupleSlot; + TupleTableSlot *result; - if (ExecQual(otherqual, econtext, false)) - { - /* - * qualification succeeded. now form the desired - * projection tuple and return the slot containing - * it. - */ - TupleTableSlot *result; - ExprDoneCond isDone; - - MJ_printf("ExecMergeJoin: returning fill tuple\n"); - - result = ExecProject(node->js.ps.ps_ProjInfo, - &isDone); + node->mj_MatchedInner = true; /* do it only once */ - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } + result = MJFillInner(node); + if (result) + return result; } /* @@ -1469,37 +1428,13 @@ ExecMergeJoin(MergeJoinState *node) * tuple, and return it if it passes the non-join * quals. */ - node->mj_MatchedOuter = true; /* do it only once */ + TupleTableSlot *result; - ResetExprContext(econtext); - - outerTupleSlot = node->mj_OuterTupleSlot; - econtext->ecxt_outertuple = outerTupleSlot; - innerTupleSlot = node->mj_NullInnerTupleSlot; - econtext->ecxt_innertuple = innerTupleSlot; - - if (ExecQual(otherqual, econtext, false)) - { - /* - * qualification succeeded. now form the desired - * projection tuple and return the slot containing - * it. - */ - TupleTableSlot *result; - ExprDoneCond isDone; - - MJ_printf("ExecMergeJoin: returning fill tuple\n"); - - result = ExecProject(node->js.ps.ps_ProjInfo, - &isDone); + node->mj_MatchedOuter = true; /* do it only once */ - if (isDone != ExprEndResult) - { - node->js.ps.ps_TupFromTlist = - (isDone == ExprMultipleResult); - return result; - } - } + result = MJFillOuter(node); + if (result) + return result; } /* @@ -1601,13 +1536,19 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate) { case JOIN_INNER: case JOIN_IN: + mergestate->mj_FillOuter = false; + mergestate->mj_FillInner = false; break; case JOIN_LEFT: + mergestate->mj_FillOuter = true; + mergestate->mj_FillInner = false; mergestate->mj_NullInnerTupleSlot = ExecInitNullTupleSlot(estate, ExecGetResultType(innerPlanState(mergestate))); break; case JOIN_RIGHT: + mergestate->mj_FillOuter = false; + mergestate->mj_FillInner = true; mergestate->mj_NullOuterTupleSlot = ExecInitNullTupleSlot(estate, ExecGetResultType(outerPlanState(mergestate))); @@ -1622,6 +1563,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate) errmsg("RIGHT JOIN is only supported with merge-joinable join conditions"))); break; case JOIN_FULL: + mergestate->mj_FillOuter = true; + mergestate->mj_FillInner = true; mergestate->mj_NullOuterTupleSlot = ExecInitNullTupleSlot(estate, ExecGetResultType(outerPlanState(mergestate))); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 9d47c17ad2..b92eb1722f 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.132 2005/05/13 21:20:16 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.133 2005/05/14 21:29:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1031,6 +1031,8 @@ typedef struct NestLoopState * NumClauses number of mergejoinable join clauses * Clauses info for each mergejoinable clause * JoinState current "state" of join. see execdefs.h + * FillOuter true if should emit unjoined outer tuples anyway + * FillInner true if should emit unjoined inner tuples anyway * MatchedOuter true if found a join match for current outer tuple * MatchedInner true if found a join match for current inner tuple * OuterTupleSlot slot in tuple table for cur outer tuple @@ -1051,6 +1053,8 @@ typedef struct MergeJoinState int mj_NumClauses; MergeJoinClause mj_Clauses; /* array of length mj_NumClauses */ int mj_JoinState; + bool mj_FillOuter; + bool mj_FillInner; bool mj_MatchedOuter; bool mj_MatchedInner; TupleTableSlot *mj_OuterTupleSlot; -- 2.40.0