LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeProjectSet.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 100.0 % 89 89 89 2
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 5 5 1 4
Baseline: 16@8cea358b128 Branches: 82.7 % 52 43 9 43
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (120,180] days: 100.0 % 2 2 2
(240..) days: 100.0 % 87 87 87
Function coverage date bins:
(240..) days: 100.0 % 5 5 1 4
Branch coverage date bins:
(240..) days: 82.7 % 52 43 9 43

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

Generated by: LCOV version 2.1-beta2-3-g6141622