]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/nodeNestloop.c
Make some small planner API cleanups.
[postgresql] / src / backend / executor / nodeNestloop.c
index e66bcdade716aadbee0074c4210cc549ff82bb8f..fc6667ef8262f2de2c7e3a2079ac528bd72629a9 100644 (file)
@@ -3,7 +3,7 @@
  * nodeNestloop.c
  *       routines to support nest-loop joins
  *
- * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
@@ -23,6 +23,7 @@
 
 #include "executor/execdebug.h"
 #include "executor/nodeNestloop.h"
+#include "miscadmin.h"
 #include "utils/memutils.h"
 
 
  *                        are prepared to return the first tuple.
  * ----------------------------------------------------------------
  */
-TupleTableSlot *
-ExecNestLoop(NestLoopState *node)
+static TupleTableSlot *
+ExecNestLoop(PlanState *pstate)
 {
+       NestLoopState *node = castNode(NestLoopState, pstate);
        NestLoop   *nl;
        PlanState  *innerPlan;
        PlanState  *outerPlan;
        TupleTableSlot *outerTupleSlot;
        TupleTableSlot *innerTupleSlot;
-       List       *joinqual;
-       List       *otherqual;
+       ExprState  *joinqual;
+       ExprState  *otherqual;
        ExprContext *econtext;
        ListCell   *lc;
 
+       CHECK_FOR_INTERRUPTS();
+
        /*
         * get information from the node
         */
@@ -81,27 +85,9 @@ ExecNestLoop(NestLoopState *node)
        innerPlan = innerPlanState(node);
        econtext = node->js.ps.ps_ExprContext;
 
-       /*
-        * Check to see if we're still projecting out tuples from a previous join
-        * tuple (because there is a function-returning-set in the projection
-        * expressions).  If so, try to project another one.
-        */
-       if (node->js.ps.ps_TupFromTlist)
-       {
-               TupleTableSlot *result;
-               ExprDoneCond isDone;
-
-               result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-               if (isDone == ExprMultipleResult)
-                       return result;
-               /* Done with that source tuple... */
-               node->js.ps.ps_TupFromTlist = false;
-       }
-
        /*
         * Reset per-tuple memory context to free any expression evaluation
-        * storage allocated in the previous tuple cycle.  Note this can't happen
-        * until we're done projecting out tuples from a join tuple.
+        * storage allocated in the previous tuple cycle.
         */
        ResetExprContext(econtext);
 
@@ -194,26 +180,16 @@ ExecNestLoop(NestLoopState *node)
 
                                ENL1_printf("testing qualification for outer-join tuple");
 
-                               if (otherqual == NIL || ExecQual(otherqual, econtext, false))
+                               if (otherqual == NULL || ExecQual(otherqual, econtext))
                                {
                                        /*
                                         * qualification was satisfied so we project and return
                                         * the slot containing the result tuple using
                                         * ExecProject().
                                         */
-                                       TupleTableSlot *result;
-                                       ExprDoneCond isDone;
-
                                        ENL1_printf("qualification succeeded, projecting tuple");
 
-                                       result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-
-                                       if (isDone != ExprEndResult)
-                                       {
-                                               node->js.ps.ps_TupFromTlist =
-                                                       (isDone == ExprMultipleResult);
-                                               return result;
-                                       }
+                                       return ExecProject(node->js.ps.ps_ProjInfo);
                                }
                                else
                                        InstrCountFiltered2(node, 1);
@@ -235,7 +211,7 @@ ExecNestLoop(NestLoopState *node)
                 */
                ENL1_printf("testing qualification");
 
-               if (ExecQual(joinqual, econtext, false))
+               if (ExecQual(joinqual, econtext))
                {
                        node->nl_MatchedOuter = true;
 
@@ -247,31 +223,22 @@ ExecNestLoop(NestLoopState *node)
                        }
 
                        /*
-                        * In a semijoin, we'll consider returning the first match, but
-                        * after that we're done with this outer tuple.
+                        * If we only need to join to the first matching inner tuple, then
+                        * consider returning this one, but after that continue with next
+                        * outer tuple.
                         */
-                       if (node->js.jointype == JOIN_SEMI)
+                       if (node->js.single_match)
                                node->nl_NeedNewOuter = true;
 
-                       if (otherqual == NIL || ExecQual(otherqual, econtext, false))
+                       if (otherqual == NULL || ExecQual(otherqual, econtext))
                        {
                                /*
                                 * qualification was satisfied so we project and return the
                                 * slot containing the result tuple using ExecProject().
                                 */
-                               TupleTableSlot *result;
-                               ExprDoneCond isDone;
-
                                ENL1_printf("qualification succeeded, projecting tuple");
 
-                               result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
-
-                               if (isDone != ExprEndResult)
-                               {
-                                       node->js.ps.ps_TupFromTlist =
-                                               (isDone == ExprMultipleResult);
-                                       return result;
-                               }
+                               return ExecProject(node->js.ps.ps_ProjInfo);
                        }
                        else
                                InstrCountFiltered2(node, 1);
@@ -309,6 +276,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
        nlstate = makeNode(NestLoopState);
        nlstate->js.ps.plan = (Plan *) node;
        nlstate->js.ps.state = estate;
+       nlstate->js.ps.ExecProcNode = ExecNestLoop;
 
        /*
         * Miscellaneous initialization
@@ -317,20 +285,6 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
         */
        ExecAssignExprContext(estate, &nlstate->js.ps);
 
-       /*
-        * initialize child expressions
-        */
-       nlstate->js.ps.targetlist = (List *)
-               ExecInitExpr((Expr *) node->join.plan.targetlist,
-                                        (PlanState *) nlstate);
-       nlstate->js.ps.qual = (List *)
-               ExecInitExpr((Expr *) node->join.plan.qual,
-                                        (PlanState *) nlstate);
-       nlstate->js.jointype = node->join.jointype;
-       nlstate->js.joinqual = (List *)
-               ExecInitExpr((Expr *) node->join.joinqual,
-                                        (PlanState *) nlstate);
-
        /*
         * initialize child nodes
         *
@@ -348,10 +302,27 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
        innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, eflags);
 
        /*
-        * tuple table initialization
+        * Initialize result slot, type and projection.
+        */
+       ExecInitResultTupleSlotTL(&nlstate->js.ps, &TTSOpsVirtual);
+       ExecAssignProjectionInfo(&nlstate->js.ps, NULL);
+
+       /*
+        * initialize child expressions
         */
-       ExecInitResultTupleSlot(estate, &nlstate->js.ps);
+       nlstate->js.ps.qual =
+               ExecInitQual(node->join.plan.qual, (PlanState *) nlstate);
+       nlstate->js.jointype = node->join.jointype;
+       nlstate->js.joinqual =
+               ExecInitQual(node->join.joinqual, (PlanState *) nlstate);
 
+       /*
+        * detect whether we need only consider the first matching inner tuple
+        */
+       nlstate->js.single_match = (node->join.inner_unique ||
+                                                               node->join.jointype == JOIN_SEMI);
+
+       /* set up null tuples for outer joins, if needed */
        switch (node->join.jointype)
        {
                case JOIN_INNER:
@@ -361,23 +332,17 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
                case JOIN_ANTI:
                        nlstate->nl_NullInnerTupleSlot =
                                ExecInitNullTupleSlot(estate,
-                                                                ExecGetResultType(innerPlanState(nlstate)));
+                                                                         ExecGetResultType(innerPlanState(nlstate)),
+                                                                         &TTSOpsVirtual);
                        break;
                default:
                        elog(ERROR, "unrecognized join type: %d",
                                 (int) node->join.jointype);
        }
 
-       /*
-        * initialize tuple type and projection info
-        */
-       ExecAssignResultTypeFromTL(&nlstate->js.ps);
-       ExecAssignProjectionInfo(&nlstate->js.ps, NULL);
-
        /*
         * finally, wipe the current outer tuple clean.
         */
-       nlstate->js.ps.ps_TupFromTlist = false;
        nlstate->nl_NeedNewOuter = true;
        nlstate->nl_MatchedOuter = false;
 
@@ -441,7 +406,6 @@ ExecReScanNestLoop(NestLoopState *node)
         * outer Vars are used as run-time keys...
         */
 
-       node->js.ps.ps_TupFromTlist = false;
        node->nl_NeedNewOuter = true;
        node->nl_MatchedOuter = false;
 }