LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeProjectSet.c (source / functions) Coverage Total Hit GIC GNC CBC ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 100.0 % 90 90 1 3 86 4
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 5 5 1 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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 CBC      948841 : ExecProjectSet(PlanState *pstate)
      44                 : {
      45          948841 :     ProjectSetState *node = castNode(ProjectSetState, pstate);
      46                 :     TupleTableSlot *outerTupleSlot;
      47                 :     TupleTableSlot *resultSlot;
      48                 :     PlanState  *outerPlan;
      49                 :     ExprContext *econtext;
      50                 : 
      51          948841 :     CHECK_FOR_INTERRUPTS();
      52                 : 
      53          948841 :     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          948841 :     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          948841 :     if (node->pending_srf_tuples)
      68                 :     {
      69          906183 :         resultSlot = ExecProjectSRF(node, true);
      70                 : 
      71          906183 :         if (resultSlot != NULL)
      72          835418 :             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          113423 :     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          144190 :         outerPlan = outerPlanState(node);
      93          144190 :         outerTupleSlot = ExecProcNode(outerPlan);
      94                 : 
      95          144190 :         if (TupIsNull(outerTupleSlot))
      96           42304 :             return NULL;
      97                 : 
      98                 :         /*
      99                 :          * Prepare to compute projection expressions, which will expect to
     100                 :          * access the input tuples as varno OUTER.
     101                 :          */
     102          101886 :         econtext->ecxt_outertuple = outerTupleSlot;
     103                 : 
     104                 :         /* Evaluate the expressions */
     105          101886 :         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          101583 :         if (resultSlot)
     113           70816 :             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         1008069 : ExecProjectSRF(ProjectSetState *node, bool continuing)
     133                 : {
     134         1008069 :     TupleTableSlot *resultSlot = node->ps.ps_ResultTupleSlot;
     135         1008069 :     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         1008069 :     ExecClearTuple(resultSlot);
     142                 : 
     143                 :     /* Call SRFs, as well as plain expressions, in per-tuple context */
     144         1008069 :     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         1008069 :     node->pending_srf_tuples = false;
     151                 : 
     152         1008069 :     hassrf = hasresult = false;
     153         2843185 :     for (argno = 0; argno < node->nelems; argno++)
     154                 :     {
     155         1835419 :         Node       *elem = node->elems[argno];
     156         1835419 :         ExprDoneCond *isdone = &node->elemdone[argno];
     157         1835419 :         Datum      *result = &resultSlot->tts_values[argno];
     158         1835419 :         bool       *isnull = &resultSlot->tts_isnull[argno];
     159                 : 
     160         1835419 :         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           15010 :             *result = (Datum) 0;
     167           15010 :             *isnull = true;
     168           15010 :             hassrf = true;
     169                 :         }
     170         1820409 :         else if (IsA(elem, SetExprState))
     171                 :         {
     172                 :             /*
     173                 :              * Evaluate SRF - possibly continuing previously started output.
     174                 :              */
     175         1093750 :             *result = ExecMakeFunctionResultSet((SetExprState *) elem,
     176                 :                                                 econtext, node->argcontext,
     177                 :                                                 isnull, isdone);
     178                 : 
     179         1093447 :             if (*isdone != ExprEndResult)
     180          989005 :                 hasresult = true;
     181         1093447 :             if (*isdone == ExprMultipleResult)
     182          989002 :                 node->pending_srf_tuples = true;
     183         1093447 :             hassrf = true;
     184                 :         }
     185                 :         else
     186                 :         {
     187                 :             /* Non-SRF tlist expression, just evaluate normally. */
     188          726659 :             *result = ExecEvalExpr((ExprState *) elem, econtext, isnull);
     189          726659 :             *isdone = ExprSingleResult;
     190                 :         }
     191                 :     }
     192                 : 
     193         1007766 :     MemoryContextSwitchTo(oldcontext);
     194                 : 
     195                 :     /* ProjectSet should not be used if there's no SRFs */
     196         1007766 :     Assert(hassrf);
     197                 : 
     198                 :     /*
     199                 :      * If all the SRFs returned ExprEndResult, we consider that as no row
     200                 :      * being produced.
     201                 :      */
     202         1007766 :     if (hasresult)
     203                 :     {
     204          906234 :         ExecStoreVirtualTuple(resultSlot);
     205          906234 :         return resultSlot;
     206                 :     }
     207                 : 
     208          101532 :     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            3505 : ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
     221                 : {
     222                 :     ProjectSetState *state;
     223                 :     ListCell   *lc;
     224                 :     int         off;
     225                 : 
     226                 :     /* check for unsupported flags */
     227            3505 :     Assert(!(eflags & (EXEC_FLAG_MARK | EXEC_FLAG_BACKWARD)));
     228                 : 
     229                 :     /*
     230                 :      * create state structure
     231                 :      */
     232            3505 :     state = makeNode(ProjectSetState);
     233            3505 :     state->ps.plan = (Plan *) node;
     234            3505 :     state->ps.state = estate;
     235            3505 :     state->ps.ExecProcNode = ExecProjectSet;
     236                 : 
     237            3505 :     state->pending_srf_tuples = false;
     238                 : 
     239                 :     /*
     240                 :      * Miscellaneous initialization
     241                 :      *
     242                 :      * create expression context for node
     243                 :      */
     244            3505 :     ExecAssignExprContext(estate, &state->ps);
     245                 : 
     246                 :     /*
     247                 :      * initialize child nodes
     248                 :      */
     249            3505 :     outerPlanState(state) = ExecInitNode(outerPlan(node), estate, eflags);
     250                 : 
     251                 :     /*
     252                 :      * we don't use inner plan
     253                 :      */
     254            3505 :     Assert(innerPlan(node) == NULL);
     255                 : 
     256                 :     /*
     257                 :      * tuple table and result type initialization
     258                 :      */
     259            3505 :     ExecInitResultTupleSlotTL(&state->ps, &TTSOpsVirtual);
     260                 : 
     261                 :     /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
     262            3505 :     state->nelems = list_length(node->plan.targetlist);
     263            3505 :     state->elems = (Node **)
     264            3505 :         palloc(sizeof(Node *) * state->nelems);
     265            3505 :     state->elemdone = (ExprDoneCond *)
     266            3505 :         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            3505 :     off = 0;
     275            8003 :     foreach(lc, node->plan.targetlist)
     276                 :     {
     277            4500 :         TargetEntry *te = (TargetEntry *) lfirst(lc);
     278            4500 :         Expr       *expr = te->expr;
     279                 : 
     280            4500 :         if ((IsA(expr, FuncExpr) && ((FuncExpr *) expr)->funcretset) ||
     281             762 :             (IsA(expr, OpExpr) && ((OpExpr *) expr)->opretset))
     282                 :         {
     283            3739 :             state->elems[off] = (Node *)
     284            3741 :                 ExecInitFunctionResultSet(expr, state->ps.ps_ExprContext,
     285                 :                                           &state->ps);
     286                 :         }
     287                 :         else
     288                 :         {
     289             759 :             Assert(!expression_returns_set((Node *) expr));
     290             759 :             state->elems[off] = (Node *) ExecInitExpr(expr, &state->ps);
     291                 :         }
     292                 : 
     293            4498 :         off++;
     294                 :     }
     295                 : 
     296                 :     /* We don't support any qual on ProjectSet nodes */
     297            3503 :     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            3503 :     state->argcontext = AllocSetContextCreate(CurrentMemoryContext,
     308                 :                                               "tSRF function arguments",
     309                 :                                               ALLOCSET_DEFAULT_SIZES);
     310                 : 
     311            3503 :     return state;
     312                 : }
     313                 : 
     314                 : /* ----------------------------------------------------------------
     315                 :  *      ExecEndProjectSet
     316                 :  *
     317                 :  *      frees up storage allocated through C routines
     318                 :  * ----------------------------------------------------------------
     319                 :  */
     320                 : void
     321            3197 : ExecEndProjectSet(ProjectSetState *node)
     322                 : {
     323                 :     /*
     324                 :      * Free the exprcontext
     325                 :      */
     326            3197 :     ExecFreeExprContext(&node->ps);
     327                 : 
     328                 :     /*
     329                 :      * clean out the tuple table
     330                 :      */
     331            3197 :     ExecClearTuple(node->ps.ps_ResultTupleSlot);
     332                 : 
     333                 :     /*
     334                 :      * shut down subplans
     335                 :      */
     336            3197 :     ExecEndNode(outerPlanState(node));
     337            3197 : }
     338                 : 
     339                 : void
     340           39712 : ExecReScanProjectSet(ProjectSetState *node)
     341                 : {
     342 GNC       39712 :     PlanState  *outerPlan = outerPlanState(node);
     343                 : 
     344 ECB             :     /* Forget any incompletely-evaluated SRFs */
     345 GIC       39712 :     node->pending_srf_tuples = false;
     346                 : 
     347 ECB             :     /*
     348                 :      * If chgParam of subnode is not null then plan will be re-scanned by
     349                 :      * first ExecProcNode.
     350                 :      */
     351 GNC       39712 :     if (outerPlan->chgParam == NULL)
     352           39712 :         ExecReScan(outerPlan);
     353 CBC       39712 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a