Minor refactoring to eliminate duplicate code and make startup a
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 14 May 2005 21:29:23 +0000 (21:29 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 14 May 2005 21:29:23 +0000 (21:29 +0000)
tad faster.

src/backend/executor/nodeMergejoin.c
src/include/nodes/execnodes.h

index be4a97574e5faaf1dc9b1c62e15b984fa22df7fe..6eb2bcc364db7db1e75524da5ef1f4a5a8773941 100644 (file)
@@ -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)));
index 9d47c17ad23f687eb267765e69be24b4ab6806e8..b92eb1722f1c25ab53290d31676eb93ea5cc58f2 100644 (file)
@@ -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;