LCOV - code coverage report
Current view: top level - src/backend/executor - nodeProjectSet.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 84 84 100.0 %
Date: 2019-11-22 06:06:53 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-2019, 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     1505200 : ExecProjectSet(PlanState *pstate)
      44             : {
      45     1505200 :     ProjectSetState *node = castNode(ProjectSetState, pstate);
      46             :     TupleTableSlot *outerTupleSlot;
      47             :     TupleTableSlot *resultSlot;
      48             :     PlanState  *outerPlan;
      49             :     ExprContext *econtext;
      50             : 
      51     1505200 :     CHECK_FOR_INTERRUPTS();
      52             : 
      53     1505200 :     econtext = node->ps.ps_ExprContext;
      54             : 
      55             :     /*
      56             :      * Reset per-tuple context to free expression-evaluation storage allocated
      57             :      * for a potentially previously returned tuple. Note that the SRF argument
      58             :      * context has a different lifetime and is reset below.
      59             :      */
      60     1505200 :     ResetExprContext(econtext);
      61             : 
      62             :     /*
      63             :      * Check to see if we're still projecting out tuples from a previous scan
      64             :      * tuple (because there is a function-returning-set in the projection
      65             :      * expressions).  If so, try to project another one.
      66             :      */
      67     1505200 :     if (node->pending_srf_tuples)
      68             :     {
      69     1462380 :         resultSlot = ExecProjectSRF(node, true);
      70             : 
      71     1462380 :         if (resultSlot != NULL)
      72     1405682 :             return resultSlot;
      73             :     }
      74             : 
      75             :     /*
      76             :      * Reset argument context to free any expression evaluation storage
      77             :      * allocated in the previous tuple cycle.  Note this can't happen until
      78             :      * we're done projecting out tuples from a scan tuple, as ValuePerCall
      79             :      * functions are allowed to reference the arguments for each returned
      80             :      * tuple.
      81             :      */
      82       99518 :     MemoryContextReset(node->argcontext);
      83             : 
      84             :     /*
      85             :      * Get another input tuple and project SRFs from it.
      86             :      */
      87             :     for (;;)
      88             :     {
      89             :         /*
      90             :          * Retrieve tuples from the outer plan until there are no more.
      91             :          */
      92      130266 :         outerPlan = outerPlanState(node);
      93      114892 :         outerTupleSlot = ExecProcNode(outerPlan);
      94             : 
      95      114892 :         if (TupIsNull(outerTupleSlot))
      96       42420 :             return NULL;
      97             : 
      98             :         /*
      99             :          * Prepare to compute projection expressions, which will expect to
     100             :          * access the input tuples as varno OUTER.
     101             :          */
     102       72472 :         econtext->ecxt_outertuple = outerTupleSlot;
     103             : 
     104             :         /* Evaluate the expressions */
     105       72472 :         resultSlot = ExecProjectSRF(node, false);
     106             : 
     107             :         /*
     108             :          * Return the tuple unless the projection produced no rows (due to an
     109             :          * empty set), in which case we must loop back to see if there are
     110             :          * more outerPlan tuples.
     111             :          */
     112       72116 :         if (resultSlot)
     113       56742 :             return resultSlot;
     114             :     }
     115             : 
     116             :     return NULL;
     117             : }
     118             : 
     119             : /* ----------------------------------------------------------------
     120             :  *      ExecProjectSRF
     121             :  *
     122             :  *      Project a targetlist containing one or more set-returning functions.
     123             :  *
     124             :  *      'continuing' indicates whether to continue projecting rows for the
     125             :  *      same input tuple; or whether a new input tuple is being projected.
     126             :  *
     127             :  *      Returns NULL if no output tuple has been produced.
     128             :  *
     129             :  * ----------------------------------------------------------------
     130             :  */
     131             : static TupleTableSlot *
     132     1534852 : ExecProjectSRF(ProjectSetState *node, bool continuing)
     133             : {
     134     1534852 :     TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot;
     135     1534852 :     ExprContext *econtext = node->ps.ps_ExprContext;
     136             :     MemoryContext oldcontext;
     137             :     bool        hassrf PG_USED_FOR_ASSERTS_ONLY;
     138             :     bool        hasresult;
     139             :     int         argno;
     140             : 
     141     1534852 :     ExecClearTuple(resultSlot);
     142             : 
     143             :     /* Call SRFs, as well as plain expressions, in per-tuple context */
     144     1534852 :     oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
     145             : 
     146             :     /*
     147             :      * Assume no further tuples are produced unless an ExprMultipleResult is
     148             :      * encountered from a set returning function.
     149             :      */
     150     1534852 :     node->pending_srf_tuples = false;
     151             : 
     152     1534852 :     hassrf = hasresult = false;
     153     4153022 :     for (argno = 0; argno < node->nelems; argno++)
     154             :     {
     155     2618526 :         Node       *elem = node->elems[argno];
     156     2618526 :         ExprDoneCond *isdone = &node->elemdone[argno];
     157     2618526 :         Datum      *result = &resultSlot->tts_values[argno];
     158     2618526 :         bool       *isnull = &resultSlot->tts_isnull[argno];
     159             : 
     160     2618526 :         if (continuing && *isdone == ExprEndResult)
     161             :         {
     162             :             /*
     163             :              * If we're continuing to project output rows from a source tuple,
     164             :              * return NULLs once the SRF has been exhausted.
     165             :              */
     166          14 :             *result = (Datum) 0;
     167          14 :             *isnull = true;
     168          14 :             hassrf = true;
     169             :         }
     170     2618512 :         else if (IsA(elem, SetExprState))
     171             :         {
     172             :             /*
     173             :              * Evaluate SRF - possibly continuing previously started output.
     174             :              */
     175     1550024 :             *result = ExecMakeFunctionResultSet((SetExprState *) elem,
     176             :                                                 econtext, node->argcontext,
     177             :                                                 isnull, isdone);
     178             : 
     179     1549668 :             if (*isdone != ExprEndResult)
     180     1474256 :                 hasresult = true;
     181     1549668 :             if (*isdone == ExprMultipleResult)
     182     1474256 :                 node->pending_srf_tuples = true;
     183     1549668 :             hassrf = true;
     184             :         }
     185             :         else
     186             :         {
     187             :             /* Non-SRF tlist expression, just evaluate normally. */
     188     1068488 :             *result = ExecEvalExpr((ExprState *) elem, econtext, isnull);
     189     1068488 :             *isdone = ExprSingleResult;
     190             :         }
     191             :     }
     192             : 
     193     1534496 :     MemoryContextSwitchTo(oldcontext);
     194             : 
     195             :     /* ProjectSet should not be used if there's no SRFs */
     196             :     Assert(hassrf);
     197             : 
     198             :     /*
     199             :      * If all the SRFs returned ExprEndResult, we consider that as no row
     200             :      * being produced.
     201             :      */
     202     1534496 :     if (hasresult)
     203             :     {
     204     1462424 :         ExecStoreVirtualTuple(resultSlot);
     205     1462424 :         return resultSlot;
     206             :     }
     207             : 
     208       72072 :     return NULL;
     209             : }
     210             : 
     211             : /* ----------------------------------------------------------------
     212             :  *      ExecInitProjectSet
     213             :  *
     214             :  *      Creates the run-time state information for the ProjectSet node
     215             :  *      produced by the planner and initializes outer relations
     216             :  *      (child nodes).
     217             :  * ----------------------------------------------------------------
     218             :  */
     219             : ProjectSetState *
     220        4008 : ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
     221             : {
     222             :     ProjectSetState *state;
     223             :     ListCell   *lc;
     224             :     int         off;
     225             : 
     226             :     /* check for unsupported flags */
     227             :     Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)));
     228             : 
     229             :     /*
     230             :      * create state structure
     231             :      */
     232        4008 :     state = makeNode(ProjectSetState);
     233        4008 :     state->ps.plan = (Plan *) node;
     234        4008 :     state->ps.state = estate;
     235        4008 :     state->ps.ExecProcNode = ExecProjectSet;
     236             : 
     237        4008 :     state->pending_srf_tuples = false;
     238             : 
     239             :     /*
     240             :      * Miscellaneous initialization
     241             :      *
     242             :      * create expression context for node
     243             :      */
     244        4008 :     ExecAssignExprContext(estate, &state->ps);
     245             : 
     246             :     /*
     247             :      * initialize child nodes
     248             :      */
     249        4008 :     outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
     250             : 
     251             :     /*
     252             :      * we don't use inner plan
     253             :      */
     254             :     Assert(innerPlan(node) == NULL);
     255             : 
     256             :     /*
     257             :      * tuple table and result type initialization
     258             :      */
     259        4008 :     ExecInitResultTupleSlotTL(&state->ps, &TTSOpsVirtual);
     260             : 
     261             :     /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
     262        4008 :     state->nelems = list_length(node->plan.targetlist);
     263        4008 :     state->elems = (Node **)
     264        4008 :         palloc(sizeof(Node *) * state->nelems);
     265        4008 :     state->elemdone = (ExprDoneCond *)
     266        4008 :         palloc(sizeof(ExprDoneCond) * state->nelems);
     267             : 
     268             :     /*
     269             :      * Build expressions to evaluate targetlist.  We can't use
     270             :      * ExecBuildProjectionInfo here, since that doesn't deal with SRFs.
     271             :      * Instead compile each expression separately, using
     272             :      * ExecInitFunctionResultSet where applicable.
     273             :      */
     274        4008 :     off = 0;
     275        9068 :     foreach(lc, node->plan.targetlist)
     276             :     {
     277        5062 :         TargetEntry *te = (TargetEntry *) lfirst(lc);
     278        5062 :         Expr       *expr = te->expr;
     279             : 
     280        6048 :         if ((IsA(expr, FuncExpr) &&((FuncExpr *) expr)->funcretset) ||
     281         990 :             (IsA(expr, OpExpr) &&((OpExpr *) expr)->opretset))
     282             :         {
     283        8158 :             state->elems[off] = (Node *)
     284        4080 :                 ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext,
     285             :                                           &state->ps);
     286             :         }
     287             :         else
     288             :         {
     289             :             Assert(!expression_returns_set((Node *) expr));
     290         982 :             state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps);
     291             :         }
     292             : 
     293        5060 :         off++;
     294             :     }
     295             : 
     296             :     /* We don't support any qual on ProjectSet nodes */
     297             :     Assert(node->plan.qual == NIL);
     298             : 
     299             :     /*
     300             :      * Create a memory context that ExecMakeFunctionResultSet can use to
     301             :      * evaluate function arguments in.  We can't use the per-tuple context for
     302             :      * this because it gets reset too often; but we don't want to leak
     303             :      * evaluation results into the query-lifespan context either.  We use one
     304             :      * context for the arguments of all tSRFs, as they have roughly equivalent
     305             :      * lifetimes.
     306             :      */
     307        4006 :     state->argcontext = AllocSetContextCreate(CurrentMemoryContext,
     308             :                                               "tSRF function arguments",
     309             :                                               ALLOCSET_DEFAULT_SIZES);
     310             : 
     311        4006 :     return state;
     312             : }
     313             : 
     314             : /* ----------------------------------------------------------------
     315             :  *      ExecEndProjectSet
     316             :  *
     317             :  *      frees up storage allocated through C routines
     318             :  * ----------------------------------------------------------------
     319             :  */
     320             : void
     321        3646 : ExecEndProjectSet(ProjectSetState *node)
     322             : {
     323             :     /*
     324             :      * Free the exprcontext
     325             :      */
     326        3646 :     ExecFreeExprContext(&node->ps);
     327             : 
     328             :     /*
     329             :      * clean out the tuple table
     330             :      */
     331        3646 :     ExecClearTuple(node->ps.ps_ResultTupleSlot);
     332             : 
     333             :     /*
     334             :      * shut down subplans
     335             :      */
     336        3646 :     ExecEndNode(outerPlanState(node));
     337        3646 : }
     338             : 
     339             : void
     340       39446 : ExecReScanProjectSet(ProjectSetState *node)
     341             : {
     342             :     /* Forget any incompletely-evaluated SRFs */
     343       39446 :     node->pending_srf_tuples = false;
     344             : 
     345             :     /*
     346             :      * If chgParam of subnode is not null then plan will be re-scanned by
     347             :      * first ExecProcNode.
     348             :      */
     349       39446 :     if (node->ps.lefttree->chgParam == NULL)
     350       39446 :         ExecReScan(node->ps.lefttree);
     351       39446 : }

Generated by: LCOV version 1.13