LCOV - code coverage report
Current view: top level - src/backend/executor - nodeProjectSet.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 87 87 100.0 %
Date: 2017-09-29 15:12:54 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * nodeProjectSet.c
       4             :  *    support for evaluating targetlists containing set-returning functions
       5             :  *
       6             :  * DESCRIPTION
       7             :  *
       8             :  *      ProjectSet nodes are inserted by the planner to evaluate set-returning
       9             :  *      functions in the targetlist.  It's guaranteed that all set-returning
      10             :  *      functions are directly at the top level of the targetlist, i.e. they
      11             :  *      can't be inside more-complex expressions.  If that'd otherwise be
      12             :  *      the case, the planner adds additional ProjectSet nodes.
      13             :  *
      14             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
      15             :  * Portions Copyright (c) 1994, Regents of the University of California
      16             :  *
      17             :  * IDENTIFICATION
      18             :  *    src/backend/executor/nodeProjectSet.c
      19             :  *
      20             :  *-------------------------------------------------------------------------
      21             :  */
      22             : 
      23             : #include "postgres.h"
      24             : 
      25             : #include "executor/executor.h"
      26             : #include "executor/nodeProjectSet.h"
      27             : #include "miscadmin.h"
      28             : #include "nodes/nodeFuncs.h"
      29             : #include "utils/memutils.h"
      30             : 
      31             : 
      32             : static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
      33             : 
      34             : 
      35             : /* ----------------------------------------------------------------
      36             :  *      ExecProjectSet(node)
      37             :  *
      38             :  *      Return tuples after evaluating the targetlist (which contains set
      39             :  *      returning functions).
      40             :  * ----------------------------------------------------------------
      41             :  */
      42             : static TupleTableSlot *
      43       17253 : ExecProjectSet(PlanState *pstate)
      44             : {
      45       17253 :     ProjectSetState *node = castNode(ProjectSetState, pstate);
      46             :     TupleTableSlot *outerTupleSlot;
      47             :     TupleTableSlot *resultSlot;
      48             :     PlanState  *outerPlan;
      49             :     ExprContext *econtext;
      50             : 
      51       17253 :     CHECK_FOR_INTERRUPTS();
      52             : 
      53       17253 :     econtext = node->ps.ps_ExprContext;
      54             : 
      55             :     /*
      56             :      * Check to see if we're still projecting out tuples from a previous scan
      57             :      * tuple (because there is a function-returning-set in the projection
      58             :      * expressions).  If so, try to project another one.
      59             :      */
      60       17253 :     if (node->pending_srf_tuples)
      61             :     {
      62       16843 :         resultSlot = ExecProjectSRF(node, true);
      63             : 
      64       16843 :         if (resultSlot != NULL)
      65       13732 :             return resultSlot;
      66             :     }
      67             : 
      68             :     /*
      69             :      * Reset per-tuple memory context to free any expression evaluation
      70             :      * storage allocated in the previous tuple cycle.  Note this can't happen
      71             :      * until we're done projecting out tuples from a scan tuple.
      72             :      */
      73        3521 :     ResetExprContext(econtext);
      74             : 
      75             :     /*
      76             :      * Get another input tuple and project SRFs from it.
      77             :      */
      78             :     for (;;)
      79             :     {
      80             :         /*
      81             :          * Retrieve tuples from the outer plan until there are no more.
      82             :          */
      83        7063 :         outerPlan = outerPlanState(node);
      84        7063 :         outerTupleSlot = ExecProcNode(outerPlan);
      85             : 
      86        7063 :         if (TupIsNull(outerTupleSlot))
      87         392 :             return NULL;
      88             : 
      89             :         /*
      90             :          * Prepare to compute projection expressions, which will expect to
      91             :          * access the input tuples as varno OUTER.
      92             :          */
      93        6671 :         econtext->ecxt_outertuple = outerTupleSlot;
      94             : 
      95             :         /* Evaluate the expressions */
      96        6671 :         resultSlot = ExecProjectSRF(node, false);
      97             : 
      98             :         /*
      99             :          * Return the tuple unless the projection produced no rows (due to an
     100             :          * empty set), in which case we must loop back to see if there are
     101             :          * more outerPlan tuples.
     102             :          */
     103        6664 :         if (resultSlot)
     104        3122 :             return resultSlot;
     105        3542 :     }
     106             : 
     107             :     return NULL;
     108             : }
     109             : 
     110             : /* ----------------------------------------------------------------
     111             :  *      ExecProjectSRF
     112             :  *
     113             :  *      Project a targetlist containing one or more set-returning functions.
     114             :  *
     115             :  *      'continuing' indicates whether to continue projecting rows for the
     116             :  *      same input tuple; or whether a new input tuple is being projected.
     117             :  *
     118             :  *      Returns NULL if no output tuple has been produced.
     119             :  *
     120             :  * ----------------------------------------------------------------
     121             :  */
     122             : static TupleTableSlot *
     123       23514 : ExecProjectSRF(ProjectSetState *node, bool continuing)
     124             : {
     125       23514 :     TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot;
     126       23514 :     ExprContext *econtext = node->ps.ps_ExprContext;
     127             :     bool        hassrf PG_USED_FOR_ASSERTS_ONLY;
     128             :     bool        hasresult;
     129             :     int         argno;
     130             : 
     131       23514 :     ExecClearTuple(resultSlot);
     132             : 
     133             :     /*
     134             :      * Assume no further tuples are produced unless an ExprMultipleResult is
     135             :      * encountered from a set returning function.
     136             :      */
     137       23514 :     node->pending_srf_tuples = false;
     138             : 
     139       23514 :     hassrf = hasresult = false;
     140       57298 :     for (argno = 0; argno < node->nelems; argno++)
     141             :     {
     142       33791 :         Node       *elem = node->elems[argno];
     143       33791 :         ExprDoneCond *isdone = &node->elemdone[argno];
     144       33791 :         Datum      *result = &resultSlot->tts_values[argno];
     145       33791 :         bool       *isnull = &resultSlot->tts_isnull[argno];
     146             : 
     147       33791 :         if (continuing && *isdone == ExprEndResult)
     148             :         {
     149             :             /*
     150             :              * If we're continuing to project output rows from a source tuple,
     151             :              * return NULLs once the SRF has been exhausted.
     152             :              */
     153           3 :             *result = (Datum) 0;
     154           3 :             *isnull = true;
     155           3 :             hassrf = true;
     156             :         }
     157       33788 :         else if (IsA(elem, SetExprState))
     158             :         {
     159             :             /*
     160             :              * Evaluate SRF - possibly continuing previously started output.
     161             :              */
     162       25463 :             *result = ExecMakeFunctionResultSet((SetExprState *) elem,
     163             :                                                 econtext, isnull, isdone);
     164             : 
     165       25456 :             if (*isdone != ExprEndResult)
     166       18084 :                 hasresult = true;
     167       25456 :             if (*isdone == ExprMultipleResult)
     168       18084 :                 node->pending_srf_tuples = true;
     169       25456 :             hassrf = true;
     170             :         }
     171             :         else
     172             :         {
     173             :             /* Non-SRF tlist expression, just evaluate normally. */
     174        8325 :             *result = ExecEvalExpr((ExprState *) elem, econtext, isnull);
     175        8325 :             *isdone = ExprSingleResult;
     176             :         }
     177             :     }
     178             : 
     179             :     /* ProjectSet should not be used if there's no SRFs */
     180       23507 :     Assert(hassrf);
     181             : 
     182             :     /*
     183             :      * If all the SRFs returned EndResult, we consider that as no row being
     184             :      * produced.
     185             :      */
     186       23507 :     if (hasresult)
     187             :     {
     188       16854 :         ExecStoreVirtualTuple(resultSlot);
     189       16854 :         return resultSlot;
     190             :     }
     191             : 
     192        6653 :     return NULL;
     193             : }
     194             : 
     195             : /* ----------------------------------------------------------------
     196             :  *      ExecInitProjectSet
     197             :  *
     198             :  *      Creates the run-time state information for the ProjectSet node
     199             :  *      produced by the planner and initializes outer relations
     200             :  *      (child nodes).
     201             :  * ----------------------------------------------------------------
     202             :  */
     203             : ProjectSetState *
     204         227 : ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
     205             : {
     206             :     ProjectSetState *state;
     207             :     ListCell   *lc;
     208             :     int         off;
     209             : 
     210             :     /* check for unsupported flags */
     211         227 :     Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)));
     212             : 
     213             :     /*
     214             :      * create state structure
     215             :      */
     216         227 :     state = makeNode(ProjectSetState);
     217         227 :     state->ps.plan = (Plan *) node;
     218         227 :     state->ps.state = estate;
     219         227 :     state->ps.ExecProcNode = ExecProjectSet;
     220             : 
     221         227 :     state->pending_srf_tuples = false;
     222             : 
     223             :     /*
     224             :      * Miscellaneous initialization
     225             :      *
     226             :      * create expression context for node
     227             :      */
     228         227 :     ExecAssignExprContext(estate, &state->ps);
     229             : 
     230             :     /*
     231             :      * tuple table initialization
     232             :      */
     233         227 :     ExecInitResultTupleSlot(estate, &state->ps);
     234             : 
     235             :     /* We don't support any qual on ProjectSet nodes */
     236         227 :     Assert(node->plan.qual == NIL);
     237             : 
     238             :     /*
     239             :      * initialize child nodes
     240             :      */
     241         227 :     outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
     242             : 
     243             :     /*
     244             :      * we don't use inner plan
     245             :      */
     246         227 :     Assert(innerPlan(node) == NULL);
     247             : 
     248             :     /*
     249             :      * initialize tuple type and projection info
     250             :      */
     251         227 :     ExecAssignResultTypeFromTL(&state->ps);
     252             : 
     253             :     /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
     254         227 :     state->nelems = list_length(node->plan.targetlist);
     255         227 :     state->elems = (Node **)
     256         227 :         palloc(sizeof(Node *) * state->nelems);
     257         227 :     state->elemdone = (ExprDoneCond *)
     258         227 :         palloc(sizeof(ExprDoneCond) * state->nelems);
     259             : 
     260             :     /*
     261             :      * Build expressions to evaluate targetlist.  We can't use
     262             :      * ExecBuildProjectionInfo here, since that doesn't deal with SRFs.
     263             :      * Instead compile each expression separately, using
     264             :      * ExecInitFunctionResultSet where applicable.
     265             :      */
     266         227 :     off = 0;
     267         635 :     foreach(lc, node->plan.targetlist)
     268             :     {
     269         408 :         TargetEntry *te = (TargetEntry *) lfirst(lc);
     270         408 :         Expr       *expr = te->expr;
     271             : 
     272         574 :         if ((IsA(expr, FuncExpr) &&((FuncExpr *) expr)->funcretset) ||
     273         167 :             (IsA(expr, OpExpr) &&((OpExpr *) expr)->opretset))
     274             :         {
     275         486 :             state->elems[off] = (Node *)
     276         243 :                 ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext,
     277             :                                           &state->ps);
     278             :         }
     279             :         else
     280             :         {
     281         165 :             Assert(!expression_returns_set((Node *) expr));
     282         165 :             state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps);
     283             :         }
     284             : 
     285         408 :         off++;
     286             :     }
     287             : 
     288         227 :     return state;
     289             : }
     290             : 
     291             : /* ----------------------------------------------------------------
     292             :  *      ExecEndProjectSet
     293             :  *
     294             :  *      frees up storage allocated through C routines
     295             :  * ----------------------------------------------------------------
     296             :  */
     297             : void
     298         219 : ExecEndProjectSet(ProjectSetState *node)
     299             : {
     300             :     /*
     301             :      * Free the exprcontext
     302             :      */
     303         219 :     ExecFreeExprContext(&node->ps);
     304             : 
     305             :     /*
     306             :      * clean out the tuple table
     307             :      */
     308         219 :     ExecClearTuple(node->ps.ps_ResultTupleSlot);
     309             : 
     310             :     /*
     311             :      * shut down subplans
     312             :      */
     313         219 :     ExecEndNode(outerPlanState(node));
     314         219 : }
     315             : 
     316             : void
     317         214 : ExecReScanProjectSet(ProjectSetState *node)
     318             : {
     319             :     /* Forget any incompletely-evaluated SRFs */
     320         214 :     node->pending_srf_tuples = false;
     321             : 
     322             :     /*
     323             :      * If chgParam of subnode is not null then plan will be re-scanned by
     324             :      * first ExecProcNode.
     325             :      */
     326         214 :     if (node->ps.lefttree->chgParam == NULL)
     327         214 :         ExecReScan(node->ps.lefttree);
     328         214 : }

Generated by: LCOV version 1.11