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 17:13:01 Functions: 100.0 % 5 5 1 4
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 100.0 % 90 90 1 3 86 2
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 100.0 % 5 5 1 4

 Age         Owner                  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 *
 2092 andres                     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                 : 
 2084                            51          948841 :     CHECK_FOR_INTERRUPTS();
                                 52                 : 
 2272                            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                 :      */
 2009                            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                 :      */
 2272                            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                 :      */
 2009                            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                 :          */
 2272                            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 */
 2011 tgl                       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                 :      */
 2272 andres                    150         1008069 :     node->pending_srf_tuples = false;
                                151                 : 
 2217                           152         1008069 :     hassrf = hasresult = false;
                                153         2843185 :     for (argno = 0; argno < node->nelems; argno++)
                                154                 :     {
                                155         1835419 :         Node       *elem = node->elems[argno];
 2272                           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                 :         }
 2217                           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                 : 
 2272                           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. */
 2217                           188          726659 :             *result = ExecEvalExpr((ExprState *) elem, econtext, isnull);
 2272                           189          726659 :             *isdone = ExprSingleResult;
                                190                 :         }
                                191                 :     }
                                192                 : 
 2011 tgl                       193         1007766 :     MemoryContextSwitchTo(oldcontext);
                                194                 : 
                                195                 :     /* ProjectSet should not be used if there's no SRFs */
 2272 andres                    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;
 2092                           235            3505 :     state->ps.ExecProcNode = ExecProjectSet;
                                236                 : 
 2272                           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                 :      */
 1606                           259            3505 :     ExecInitResultTupleSlotTL(&state->ps, &TTSOpsVirtual);
                                260                 : 
                                261                 :     /* Create workspace for per-tlist-entry expr state & SRF-is-done state */
 2272                           262            3505 :     state->nelems = list_length(node->plan.targetlist);
 2217                           263            3505 :     state->elems = (Node **)
                                264            3505 :         palloc(sizeof(Node *) * state->nelems);
 2272                           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                 :      */
 2217                           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                 : 
 1058 tgl                       280            4500 :         if ((IsA(expr, FuncExpr) && ((FuncExpr *) expr)->funcretset) ||
                                281             762 :             (IsA(expr, OpExpr) && ((OpExpr *) expr)->opretset))
                                282                 :         {
 2217 andres                    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 */
 1878                           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                 :      */
 2009                           307            3503 :     state->argcontext = AllocSetContextCreate(CurrentMemoryContext,
                                308                 :                                               "tSRF function arguments",
                                309                 :                                               ALLOCSET_DEFAULT_SIZES);
                                310                 : 
 2272                           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                 : {
  276 tgl                       342 GNC       39712 :     PlanState  *outerPlan = outerPlanState(node);
                                343                 : 
 2272 andres                    344 ECB             :     /* Forget any incompletely-evaluated SRFs */
 2272 andres                    345 GIC       39712 :     node->pending_srf_tuples = false;
                                346                 : 
 2272 andres                    347 ECB             :     /*
                                348                 :      * If chgParam of subnode is not null then plan will be re-scanned by
                                349                 :      * first ExecProcNode.
                                350                 :      */
  276 tgl                       351 GNC       39712 :     if (outerPlan->chgParam == NULL)
                                352           39712 :         ExecReScan(outerPlan);
 2272 andres                    353 CBC       39712 : }
        

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