LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeFunctionscan.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: bed3ffbf9d952be6c7d739d068cdce44c046dfb7 vs 574581b50ac9c63dd9e4abebb731a3b67e5b50f6 Lines: 98.2 % 163 160 3 3 157 1
Current Date: 2026-05-05 10:23:31 +0900 Functions: 83.3 % 6 5 1 1 4
Baseline: lcov-20260505-025707-baseline Branches: 88.8 % 98 87 11 87
Baseline Date: 2026-05-05 10:27:06 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 3 3 3
(360..) days: 98.1 % 160 157 3 157
Function coverage date bins:
(360..) days: 83.3 % 6 5 1 1 4
Branch coverage date bins:
(360..) days: 88.8 % 98 87 11 87

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * nodeFunctionscan.c
                                  4                 :                :  *    Support routines for scanning RangeFunctions (functions in rangetable).
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *    src/backend/executor/nodeFunctionscan.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : /*
                                 16                 :                :  * INTERFACE ROUTINES
                                 17                 :                :  *      ExecFunctionScan        scans a function.
                                 18                 :                :  *      ExecFunctionNext        retrieve next tuple in sequential order.
                                 19                 :                :  *      ExecInitFunctionScan    creates and initializes a functionscan node.
                                 20                 :                :  *      ExecEndFunctionScan     releases any storage allocated.
                                 21                 :                :  *      ExecReScanFunctionScan  rescans the function
                                 22                 :                :  */
                                 23                 :                : #include "postgres.h"
                                 24                 :                : 
                                 25                 :                : #include "catalog/pg_type.h"
                                 26                 :                : #include "executor/nodeFunctionscan.h"
                                 27                 :                : #include "funcapi.h"
                                 28                 :                : #include "nodes/nodeFuncs.h"
                                 29                 :                : #include "utils/memutils.h"
                                 30                 :                : #include "utils/tuplestore.h"
                                 31                 :                : 
                                 32                 :                : 
                                 33                 :                : /*
                                 34                 :                :  * Runtime data for each function being scanned.
                                 35                 :                :  */
                                 36                 :                : typedef struct FunctionScanPerFuncState
                                 37                 :                : {
                                 38                 :                :     SetExprState *setexpr;      /* state of the expression being evaluated */
                                 39                 :                :     TupleDesc   tupdesc;        /* desc of the function result type */
                                 40                 :                :     int         colcount;       /* expected number of result columns */
                                 41                 :                :     Tuplestorestate *tstore;    /* holds the function result set */
                                 42                 :                :     int64       rowcount;       /* # of rows in result set, -1 if not known */
                                 43                 :                :     TupleTableSlot *func_slot;  /* function result slot (or NULL) */
                                 44                 :                : } FunctionScanPerFuncState;
                                 45                 :                : 
                                 46                 :                : static TupleTableSlot *FunctionNext(FunctionScanState *node);
                                 47                 :                : 
                                 48                 :                : 
                                 49                 :                : /* ----------------------------------------------------------------
                                 50                 :                :  *                      Scan Support
                                 51                 :                :  * ----------------------------------------------------------------
                                 52                 :                :  */
                                 53                 :                : /* ----------------------------------------------------------------
                                 54                 :                :  *      FunctionNext
                                 55                 :                :  *
                                 56                 :                :  *      This is a workhorse for ExecFunctionScan
                                 57                 :                :  * ----------------------------------------------------------------
                                 58                 :                :  */
                                 59                 :                : static TupleTableSlot *
 8552 tgl@sss.pgh.pa.us          60                 :CBC    11241414 : FunctionNext(FunctionScanState *node)
                                 61                 :                : {
                                 62                 :                :     EState     *estate;
                                 63                 :                :     ScanDirection direction;
                                 64                 :                :     TupleTableSlot *scanslot;
                                 65                 :                :     bool        alldone;
                                 66                 :                :     int64       oldpos;
                                 67                 :                :     int         funcno;
                                 68                 :                :     int         att;
                                 69                 :                : 
                                 70                 :                :     /*
                                 71                 :                :      * get information from the estate and scan state
                                 72                 :                :      */
                                 73                 :       11241414 :     estate = node->ss.ps.state;
 8759                            74                 :       11241414 :     direction = estate->es_direction;
 4548                            75                 :       11241414 :     scanslot = node->ss.ss_ScanTupleSlot;
                                 76                 :                : 
                                 77         [ +  + ]:       11241414 :     if (node->simple)
                                 78                 :                :     {
                                 79                 :                :         /*
                                 80                 :                :          * Fast path for the trivial case: the function return type and scan
                                 81                 :                :          * result type are the same, so we fetch the function result straight
                                 82                 :                :          * into the scan result slot. No need to update ordinality or
                                 83                 :                :          * rowcounts either.
                                 84                 :                :          */
                                 85                 :       11226814 :         Tuplestorestate *tstore = node->funcstates[0].tstore;
                                 86                 :                : 
                                 87                 :                :         /*
                                 88                 :                :          * If first time through, read all tuples from function and put them
                                 89                 :                :          * in a tuplestore. Subsequent calls just fetch tuples from
                                 90                 :                :          * tuplestore.
                                 91                 :                :          */
                                 92         [ +  + ]:       11226814 :         if (tstore == NULL)
                                 93                 :                :         {
                                 94                 :          97494 :             node->funcstates[0].tstore = tstore =
 3339 andres@anarazel.de         95                 :         100278 :                 ExecMakeTableFunctionResult(node->funcstates[0].setexpr,
                                 96                 :                :                                             node->ss.ps.ps_ExprContext,
                                 97                 :                :                                             node->argcontext,
 4548 tgl@sss.pgh.pa.us          98                 :         100278 :                                             node->funcstates[0].tupdesc,
 3240                            99                 :         100278 :                                             node->eflags & EXEC_FLAG_BACKWARD);
                                100                 :                : 
                                101                 :                :             /*
                                102                 :                :              * paranoia - cope if the function, which may have constructed the
                                103                 :                :              * tuplestore itself, didn't leave it pointing at the start. This
                                104                 :                :              * call is fast, so the overhead shouldn't be an issue.
                                105                 :                :              */
 4548                           106                 :          97494 :             tuplestore_rescan(tstore);
                                107                 :                :         }
                                108                 :                : 
                                109                 :                :         /*
                                110                 :                :          * Get the next tuple from tuplestore.
                                111                 :                :          */
                                112                 :       11224030 :         (void) tuplestore_gettupleslot(tstore,
                                113                 :                :                                        ScanDirectionIsForward(direction),
                                114                 :                :                                        false,
                                115                 :                :                                        scanslot);
                                116                 :       11224030 :         return scanslot;
                                117                 :                :     }
                                118                 :                : 
                                119                 :                :     /*
                                120                 :                :      * Increment or decrement ordinal counter before checking for end-of-data,
                                121                 :                :      * so that we can move off either end of the result by 1 (and no more than
                                122                 :                :      * 1) without losing correct count.  See PortalRunSelect for why we can
                                123                 :                :      * assume that we won't be called repeatedly in the end-of-data state.
                                124                 :                :      */
                                125                 :          14600 :     oldpos = node->ordinal;
 4663 stark@mit.edu             126         [ +  + ]:          14600 :     if (ScanDirectionIsForward(direction))
                                127                 :          14560 :         node->ordinal++;
                                128                 :                :     else
                                129                 :             40 :         node->ordinal--;
                                130                 :                : 
                                131                 :                :     /*
                                132                 :                :      * Main loop over functions.
                                133                 :                :      *
                                134                 :                :      * We fetch the function results into func_slots (which match the function
                                135                 :                :      * return types), and then copy the values to scanslot (which matches the
                                136                 :                :      * scan result type), setting the ordinal column (if any) as well.
                                137                 :                :      */
 4548 tgl@sss.pgh.pa.us         138                 :          14600 :     ExecClearTuple(scanslot);
                                139                 :          14600 :     att = 0;
                                140                 :          14600 :     alldone = true;
                                141         [ +  + ]:          34774 :     for (funcno = 0; funcno < node->nfuncs; funcno++)
                                142                 :                :     {
                                143                 :          20174 :         FunctionScanPerFuncState *fs = &node->funcstates[funcno];
                                144                 :                :         int         i;
                                145                 :                : 
                                146                 :                :         /*
                                147                 :                :          * If first time through, read all tuples from function and put them
                                148                 :                :          * in a tuplestore. Subsequent calls just fetch tuples from
                                149                 :                :          * tuplestore.
                                150                 :                :          */
                                151         [ +  + ]:          20174 :         if (fs->tstore == NULL)
                                152                 :                :         {
                                153                 :           1524 :             fs->tstore =
 3339 andres@anarazel.de        154                 :           1524 :                 ExecMakeTableFunctionResult(fs->setexpr,
                                155                 :                :                                             node->ss.ps.ps_ExprContext,
                                156                 :                :                                             node->argcontext,
                                157                 :                :                                             fs->tupdesc,
 3240 tgl@sss.pgh.pa.us         158                 :           1524 :                                             node->eflags & EXEC_FLAG_BACKWARD);
                                159                 :                : 
                                160                 :                :             /*
                                161                 :                :              * paranoia - cope if the function, which may have constructed the
                                162                 :                :              * tuplestore itself, didn't leave it pointing at the start. This
                                163                 :                :              * call is fast, so the overhead shouldn't be an issue.
                                164                 :                :              */
 4548                           165                 :           1524 :             tuplestore_rescan(fs->tstore);
                                166                 :                :         }
                                167                 :                : 
                                168                 :                :         /*
                                169                 :                :          * Get the next tuple from tuplestore.
                                170                 :                :          *
                                171                 :                :          * If we have a rowcount for the function, and we know the previous
                                172                 :                :          * read position was out of bounds, don't try the read. This allows
                                173                 :                :          * backward scan to work when there are mixed row counts present.
                                174                 :                :          */
                                175   [ +  +  +  + ]:          20174 :         if (fs->rowcount != -1 && fs->rowcount < oldpos)
                                176                 :             50 :             ExecClearTuple(fs->func_slot);
                                177                 :                :         else
                                178                 :          20124 :             (void) tuplestore_gettupleslot(fs->tstore,
                                179                 :                :                                            ScanDirectionIsForward(direction),
                                180                 :                :                                            false,
                                181                 :                :                                            fs->func_slot);
                                182                 :                : 
                                183   [ +  -  +  + ]:          20174 :         if (TupIsNull(fs->func_slot))
                                184                 :                :         {
                                185                 :                :             /*
                                186                 :                :              * If we ran out of data for this function in the forward
                                187                 :                :              * direction then we now know how many rows it returned. We need
                                188                 :                :              * to know this in order to handle backwards scans. The row count
                                189                 :                :              * we store is actually 1+ the actual number, because we have to
                                190                 :                :              * position the tuplestore 1 off its end sometimes.
                                191                 :                :              */
                                192   [ +  +  +  + ]:           1743 :             if (ScanDirectionIsForward(direction) && fs->rowcount == -1)
                                193                 :           1492 :                 fs->rowcount = node->ordinal;
                                194                 :                : 
                                195                 :                :             /*
                                196                 :                :              * populate the result cols with nulls
                                197                 :                :              */
                                198         [ +  + ]:           4144 :             for (i = 0; i < fs->colcount; i++)
                                199                 :                :             {
                                200                 :           2401 :                 scanslot->tts_values[att] = (Datum) 0;
                                201                 :           2401 :                 scanslot->tts_isnull[att] = true;
                                202                 :           2401 :                 att++;
                                203                 :                :             }
                                204                 :                :         }
                                205                 :                :         else
                                206                 :                :         {
                                207                 :                :             /*
                                208                 :                :              * we have a result, so just copy it to the result cols.
                                209                 :                :              */
                                210                 :          18431 :             slot_getallattrs(fs->func_slot);
                                211                 :                : 
                                212         [ +  + ]:          45960 :             for (i = 0; i < fs->colcount; i++)
                                213                 :                :             {
                                214                 :          27529 :                 scanslot->tts_values[att] = fs->func_slot->tts_values[i];
                                215                 :          27529 :                 scanslot->tts_isnull[att] = fs->func_slot->tts_isnull[i];
                                216                 :          27529 :                 att++;
                                217                 :                :             }
                                218                 :                : 
                                219                 :                :             /*
                                220                 :                :              * We're not done until every function result is exhausted; we pad
                                221                 :                :              * the shorter results with nulls until then.
                                222                 :                :              */
                                223                 :          18431 :             alldone = false;
                                224                 :                :         }
                                225                 :                :     }
                                226                 :                : 
                                227                 :                :     /*
                                228                 :                :      * ordinal col is always last, per spec.
                                229                 :                :      */
                                230         [ +  + ]:          14600 :     if (node->ordinality)
                                231                 :                :     {
                                232                 :          11964 :         scanslot->tts_values[att] = Int64GetDatumFast(node->ordinal);
                                233                 :          11964 :         scanslot->tts_isnull[att] = false;
                                234                 :                :     }
                                235                 :                : 
                                236                 :                :     /*
                                237                 :                :      * If alldone, we just return the previously-cleared scanslot.  Otherwise,
                                238                 :                :      * finish creating the virtual tuple.
                                239                 :                :      */
                                240         [ +  + ]:          14600 :     if (!alldone)
 4663 stark@mit.edu             241                 :          13281 :         ExecStoreVirtualTuple(scanslot);
                                242                 :                : 
                                243                 :          14600 :     return scanslot;
                                244                 :                : }
                                245                 :                : 
                                246                 :                : /*
                                247                 :                :  * FunctionRecheck -- access method routine to recheck a tuple in EvalPlanQual
                                248                 :                :  */
                                249                 :                : static bool
 6035 tgl@sss.pgh.pa.us         250                 :UBC           0 : FunctionRecheck(FunctionScanState *node, TupleTableSlot *slot)
                                251                 :                : {
                                252                 :                :     /* nothing to check */
                                253                 :              0 :     return true;
                                254                 :                : }
                                255                 :                : 
                                256                 :                : /* ----------------------------------------------------------------
                                257                 :                :  *      ExecFunctionScan(node)
                                258                 :                :  *
                                259                 :                :  *      Scans the function sequentially and returns the next qualifying
                                260                 :                :  *      tuple.
                                261                 :                :  *      We call the ExecScan() routine and pass it the appropriate
                                262                 :                :  *      access method functions.
                                263                 :                :  * ----------------------------------------------------------------
                                264                 :                :  */
                                265                 :                : static TupleTableSlot *
 3214 andres@anarazel.de        266                 :CBC    10076632 : ExecFunctionScan(PlanState *pstate)
                                267                 :                : {
                                268                 :       10076632 :     FunctionScanState *node = castNode(FunctionScanState, pstate);
                                269                 :                : 
 6035 tgl@sss.pgh.pa.us         270                 :       10076632 :     return ExecScan(&node->ss,
                                271                 :                :                     (ExecScanAccessMtd) FunctionNext,
                                272                 :                :                     (ExecScanRecheckMtd) FunctionRecheck);
                                273                 :                : }
                                274                 :                : 
                                275                 :                : /* ----------------------------------------------------------------
                                276                 :                :  *      ExecInitFunctionScan
                                277                 :                :  * ----------------------------------------------------------------
                                278                 :                :  */
                                279                 :                : FunctionScanState *
 7371                           280                 :          44399 : ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
                                281                 :                : {
                                282                 :                :     FunctionScanState *scanstate;
 4548                           283                 :          44399 :     int         nfuncs = list_length(node->functions);
                                284                 :                :     TupleDesc   scan_tupdesc;
                                285                 :                :     int         i,
                                286                 :                :                 natts;
                                287                 :                :     ListCell   *lc;
                                288                 :                : 
                                289                 :                :     /* check for unsupported flags */
 6425                           290         [ -  + ]:          44399 :     Assert(!(eflags & EXEC_FLAG_MARK));
                                291                 :                : 
                                292                 :                :     /*
                                293                 :                :      * FunctionScan should not have any children.
                                294                 :                :      */
 8552                           295         [ -  + ]:          44399 :     Assert(outerPlan(node) == NULL);
                                296         [ -  + ]:          44399 :     Assert(innerPlan(node) == NULL);
                                297                 :                : 
                                298                 :                :     /*
                                299                 :                :      * create new ScanState for node
                                300                 :                :      */
 8759                           301                 :          44399 :     scanstate = makeNode(FunctionScanState);
 8552                           302                 :          44399 :     scanstate->ss.ps.plan = (Plan *) node;
                                303                 :          44399 :     scanstate->ss.ps.state = estate;
 3214 andres@anarazel.de        304                 :          44399 :     scanstate->ss.ps.ExecProcNode = ExecFunctionScan;
 6397 tgl@sss.pgh.pa.us         305                 :          44399 :     scanstate->eflags = eflags;
                                306                 :                : 
                                307                 :                :     /*
                                308                 :                :      * are we adding an ordinality column?
                                309                 :                :      */
 4548                           310                 :          44399 :     scanstate->ordinality = node->funcordinality;
                                311                 :                : 
                                312                 :          44399 :     scanstate->nfuncs = nfuncs;
                                313   [ +  +  +  + ]:          44399 :     if (nfuncs == 1 && !node->funcordinality)
                                314                 :          43423 :         scanstate->simple = true;
                                315                 :                :     else
                                316                 :            976 :         scanstate->simple = false;
                                317                 :                : 
                                318                 :                :     /*
                                319                 :                :      * Ordinal 0 represents the "before the first row" position.
                                320                 :                :      *
                                321                 :                :      * We need to track ordinal position even when not adding an ordinality
                                322                 :                :      * column to the result, in order to handle backwards scanning properly
                                323                 :                :      * with multiple functions with different result sizes. (We can't position
                                324                 :                :      * any individual function's tuplestore any more than 1 place beyond its
                                325                 :                :      * end, so when scanning backwards, we need to know when to start
                                326                 :                :      * including the function in the scan again.)
                                327                 :                :      */
                                328                 :          44399 :     scanstate->ordinal = 0;
                                329                 :                : 
                                330                 :                :     /*
                                331                 :                :      * Miscellaneous initialization
                                332                 :                :      *
                                333                 :                :      * create expression context for node
                                334                 :                :      */
 8552                           335                 :          44399 :     ExecAssignExprContext(estate, &scanstate->ss.ps);
                                336                 :                : 
  146 michael@paquier.xyz       337                 :GNC       44399 :     scanstate->funcstates = palloc_array(FunctionScanPerFuncState, nfuncs);
                                338                 :                : 
 4548 tgl@sss.pgh.pa.us         339                 :CBC       44399 :     natts = 0;
                                340                 :          44399 :     i = 0;
                                341   [ +  -  +  +  :          88999 :     foreach(lc, node->functions)
                                              +  + ]
                                342                 :                :     {
                                343                 :          44604 :         RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
                                344                 :          44604 :         Node       *funcexpr = rtfunc->funcexpr;
                                345                 :          44604 :         int         colcount = rtfunc->funccolcount;
                                346                 :          44604 :         FunctionScanPerFuncState *fs = &scanstate->funcstates[i];
                                347                 :                :         TupleDesc   tupdesc;
                                348                 :                : 
 3339 andres@anarazel.de        349                 :          44600 :         fs->setexpr =
                                350                 :          44604 :             ExecInitTableFunctionResult((Expr *) funcexpr,
                                351                 :                :                                         scanstate->ss.ps.ps_ExprContext,
                                352                 :                :                                         &scanstate->ss.ps);
                                353                 :                : 
                                354                 :                :         /*
                                355                 :                :          * Don't allocate the tuplestores; the actual calls to the functions
                                356                 :                :          * do that.  NULL means that we have not called the function yet (or
                                357                 :                :          * need to call it again after a rescan).
                                358                 :                :          */
 4548 tgl@sss.pgh.pa.us         359                 :          44600 :         fs->tstore = NULL;
                                360                 :          44600 :         fs->rowcount = -1;
                                361                 :                : 
                                362                 :                :         /*
                                363                 :                :          * Now build a tupdesc showing the result type we expect from the
                                364                 :                :          * function.  If we have a coldeflist then that takes priority (note
                                365                 :                :          * the parser enforces that there is one if the function's nominal
                                366                 :                :          * output type is RECORD).  Otherwise use get_expr_result_type.
                                367                 :                :          *
                                368                 :                :          * Note that if the function returns a named composite type, that may
                                369                 :                :          * now contain more or different columns than it did when the plan was
                                370                 :                :          * made.  For both that and the RECORD case, we need to check tuple
                                371                 :                :          * compatibility.  ExecMakeTableFunctionResult handles some of this,
                                372                 :                :          * and CheckVarSlotCompatibility provides a backstop.
                                373                 :                :          */
  790                           374         [ +  + ]:          44600 :         if (rtfunc->funccolnames != NIL)
                                375                 :                :         {
 4548                           376                 :            944 :             tupdesc = BuildDescFromLists(rtfunc->funccolnames,
                                377                 :            472 :                                          rtfunc->funccoltypes,
                                378                 :            472 :                                          rtfunc->funccoltypmods,
                                379                 :            472 :                                          rtfunc->funccolcollations);
                                380                 :                : 
                                381                 :                :             /*
                                382                 :                :              * For RECORD results, make sure a typmod has been assigned.  (The
                                383                 :                :              * function should do this for itself, but let's cover things in
                                384                 :                :              * case it doesn't.)
                                385                 :                :              */
                                386                 :            472 :             BlessTupleDesc(tupdesc);
                                387                 :                :         }
                                388                 :                :         else
                                389                 :                :         {
                                390                 :                :             TypeFuncClass functypclass;
                                391                 :                :             Oid         funcrettype;
                                392                 :                : 
  790                           393                 :          44128 :             functypclass = get_expr_result_type(funcexpr,
                                394                 :                :                                                 &funcrettype,
                                395                 :                :                                                 &tupdesc);
                                396                 :                : 
                                397   [ +  +  +  + ]:          44128 :             if (functypclass == TYPEFUNC_COMPOSITE ||
                                398                 :                :                 functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
                                399                 :                :             {
                                400                 :                :                 /* Composite data type, e.g. a table's row type */
                                401         [ -  + ]:          22515 :                 Assert(tupdesc);
                                402                 :                :                 /* Must copy it out of typcache for safety */
                                403                 :          22515 :                 tupdesc = CreateTupleDescCopy(tupdesc);
                                404                 :                :             }
                                405         [ +  - ]:          21613 :             else if (functypclass == TYPEFUNC_SCALAR)
                                406                 :                :             {
                                407                 :                :                 /* Base data type, i.e. scalar */
                                408                 :          21613 :                 tupdesc = CreateTemplateTupleDesc(1);
                                409                 :          21613 :                 TupleDescInitEntry(tupdesc,
                                410                 :                :                                    (AttrNumber) 1,
                                411                 :                :                                    NULL,    /* don't care about the name here */
                                412                 :                :                                    funcrettype,
                                413                 :                :                                    -1,
                                414                 :                :                                    0);
                                415                 :          21613 :                 TupleDescInitEntryCollation(tupdesc,
                                416                 :                :                                             (AttrNumber) 1,
                                417                 :                :                                             exprCollation(funcexpr));
   50 drowley@postgresql.o      418                 :GNC       21613 :                 TupleDescFinalize(tupdesc);
                                419                 :                :             }
                                420                 :                :             else
                                421                 :                :             {
                                422                 :                :                 /* crummy error message, but parser should have caught this */
  790 tgl@sss.pgh.pa.us         423         [ #  # ]:UBC           0 :                 elog(ERROR, "function in FROM has unsupported return type");
                                424                 :                :             }
                                425                 :                :         }
                                426                 :                : 
 4548 tgl@sss.pgh.pa.us         427                 :CBC       44600 :         fs->tupdesc = tupdesc;
                                428                 :          44600 :         fs->colcount = colcount;
                                429                 :                : 
                                430                 :                :         /*
                                431                 :                :          * We only need separate slots for the function results if we are
                                432                 :                :          * doing ordinality or multiple functions; otherwise, we'll fetch
                                433                 :                :          * function results directly into the scan slot.
                                434                 :                :          */
                                435         [ +  + ]:          44600 :         if (!scanstate->simple)
                                436                 :                :         {
 2728 andres@anarazel.de        437                 :           1181 :             fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc,
                                438                 :                :                                                    &TTSOpsMinimalTuple);
                                439                 :                :         }
                                440                 :                :         else
 4548 tgl@sss.pgh.pa.us         441                 :          43419 :             fs->func_slot = NULL;
                                442                 :                : 
                                443                 :          44600 :         natts += colcount;
                                444                 :          44600 :         i++;
                                445                 :                :     }
                                446                 :                : 
                                447                 :                :     /*
                                448                 :                :      * Create the combined TupleDesc
                                449                 :                :      *
                                450                 :                :      * If there is just one function without ordinality, the scan result
                                451                 :                :      * tupdesc is the same as the function result tupdesc --- except that we
                                452                 :                :      * may stuff new names into it below, so drop any rowtype label.
                                453                 :                :      */
                                454         [ +  + ]:          44395 :     if (scanstate->simple)
                                455                 :                :     {
                                456                 :          43419 :         scan_tupdesc = CreateTupleDescCopy(scanstate->funcstates[0].tupdesc);
                                457                 :          43419 :         scan_tupdesc->tdtypeid = RECORDOID;
                                458                 :          43419 :         scan_tupdesc->tdtypmod = -1;
                                459                 :                :     }
                                460                 :                :     else
                                461                 :                :     {
                                462                 :            976 :         AttrNumber  attno = 0;
                                463                 :                : 
                                464         [ +  + ]:            976 :         if (node->funcordinality)
                                465                 :            929 :             natts++;
                                466                 :                : 
 2723 andres@anarazel.de        467                 :            976 :         scan_tupdesc = CreateTemplateTupleDesc(natts);
                                468                 :                : 
 4548 tgl@sss.pgh.pa.us         469         [ +  + ]:           2157 :         for (i = 0; i < nfuncs; i++)
                                470                 :                :         {
                                471                 :           1181 :             TupleDesc   tupdesc = scanstate->funcstates[i].tupdesc;
                                472                 :           1181 :             int         colcount = scanstate->funcstates[i].colcount;
                                473                 :                :             int         j;
                                474                 :                : 
                                475         [ +  + ]:           2788 :             for (j = 1; j <= colcount; j++)
                                476                 :           1607 :                 TupleDescCopyEntry(scan_tupdesc, ++attno, tupdesc, j);
                                477                 :                :         }
                                478                 :                : 
                                479                 :                :         /* If doing ordinality, add a column of type "bigint" at the end */
                                480         [ +  + ]:            976 :         if (node->funcordinality)
                                481                 :                :         {
                                482                 :            929 :             TupleDescInitEntry(scan_tupdesc,
                                483                 :                :                                ++attno,
                                484                 :                :                                NULL,    /* don't care about the name here */
                                485                 :                :                                INT8OID,
                                486                 :                :                                -1,
                                487                 :                :                                0);
                                488                 :                :         }
                                489                 :                : 
   50 drowley@postgresql.o      490                 :GNC         976 :         TupleDescFinalize(scan_tupdesc);
 4548 tgl@sss.pgh.pa.us         491         [ -  + ]:CBC         976 :         Assert(attno == natts);
                                492                 :                :     }
                                493                 :                : 
                                494                 :                :     /*
                                495                 :                :      * Initialize scan slot and type.
                                496                 :                :      */
 2728 andres@anarazel.de        497                 :          44395 :     ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc,
                                498                 :                :                           &TTSOpsMinimalTuple, 0);
                                499                 :                : 
                                500                 :                :     /*
                                501                 :                :      * Initialize result slot, type and projection.
                                502                 :                :      */
 2734                           503                 :          44395 :     ExecInitResultTypeTL(&scanstate->ss.ps);
 7653 tgl@sss.pgh.pa.us         504                 :          44395 :     ExecAssignScanProjectionInfo(&scanstate->ss);
                                505                 :                : 
                                506                 :                :     /*
                                507                 :                :      * initialize child expressions
                                508                 :                :      */
 3000 andres@anarazel.de        509                 :          44395 :     scanstate->ss.ps.qual =
                                510                 :          44395 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
                                511                 :                : 
                                512                 :                :     /*
                                513                 :                :      * Create a memory context that ExecMakeTableFunctionResult can use to
                                514                 :                :      * evaluate function arguments in.  We can't use the per-tuple context for
                                515                 :                :      * this because it gets reset too often; but we don't want to leak
                                516                 :                :      * evaluation results into the query-lifespan context either.  We just
                                517                 :                :      * need one context, because we evaluate each function separately.
                                518                 :                :      */
 4338 tgl@sss.pgh.pa.us         519                 :          44395 :     scanstate->argcontext = AllocSetContextCreate(CurrentMemoryContext,
                                520                 :                :                                                   "Table function arguments",
                                521                 :                :                                                   ALLOCSET_DEFAULT_SIZES);
                                522                 :                : 
 8552                           523                 :          44395 :     return scanstate;
                                524                 :                : }
                                525                 :                : 
                                526                 :                : /* ----------------------------------------------------------------
                                527                 :                :  *      ExecEndFunctionScan
                                528                 :                :  *
                                529                 :                :  *      frees any storage allocated through C routines.
                                530                 :                :  * ----------------------------------------------------------------
                                531                 :                :  */
                                532                 :                : void
                                533                 :          41490 : ExecEndFunctionScan(FunctionScanState *node)
                                534                 :                : {
                                535                 :                :     int         i;
                                536                 :                : 
                                537                 :                :     /*
                                538                 :                :      * Release slots and tuplestore resources
                                539                 :                :      */
 4548                           540         [ +  + ]:          83177 :     for (i = 0; i < node->nfuncs; i++)
                                541                 :                :     {
                                542                 :          41687 :         FunctionScanPerFuncState *fs = &node->funcstates[i];
                                543                 :                : 
                                544         [ +  + ]:          41687 :         if (fs->tstore != NULL)
                                545                 :                :         {
                                546                 :          37076 :             tuplestore_end(node->funcstates[i].tstore);
                                547                 :          37076 :             fs->tstore = NULL;
                                548                 :                :         }
                                549                 :                :     }
 8759                           550                 :          41490 : }
                                551                 :                : 
                                552                 :                : /* ----------------------------------------------------------------
                                553                 :                :  *      ExecReScanFunctionScan
                                554                 :                :  *
                                555                 :                :  *      Rescans the relation.
                                556                 :                :  * ----------------------------------------------------------------
                                557                 :                :  */
                                558                 :                : void
 5776                           559                 :          72640 : ExecReScanFunctionScan(FunctionScanState *node)
                                560                 :                : {
 4548                           561                 :          72640 :     FunctionScan *scan = (FunctionScan *) node->ss.ps.plan;
                                562                 :                :     int         i;
                                563                 :          72640 :     Bitmapset  *chgparam = node->ss.ps.chgParam;
                                564                 :                : 
 2734 andres@anarazel.de        565         [ +  + ]:          72640 :     if (node->ss.ps.ps_ResultTupleSlot)
                                566                 :          32089 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 4548 tgl@sss.pgh.pa.us         567         [ +  + ]:         145353 :     for (i = 0; i < node->nfuncs; i++)
                                568                 :                :     {
                                569                 :          72713 :         FunctionScanPerFuncState *fs = &node->funcstates[i];
                                570                 :                : 
                                571         [ +  + ]:          72713 :         if (fs->func_slot)
                                572                 :            750 :             ExecClearTuple(fs->func_slot);
                                573                 :                :     }
                                574                 :                : 
                                575                 :          72640 :     ExecScanReScan(&node->ss);
                                576                 :                : 
                                577                 :                :     /*
                                578                 :                :      * Here we have a choice whether to drop the tuplestores (and recompute
                                579                 :                :      * the function outputs) or just rescan them.  We must recompute if an
                                580                 :                :      * expression contains changed parameters, else we rescan.
                                581                 :                :      *
                                582                 :                :      * XXX maybe we should recompute if the function is volatile?  But in
                                583                 :                :      * general the executor doesn't conditionalize its actions on that.
                                584                 :                :      */
                                585         [ +  + ]:          72640 :     if (chgparam)
                                586                 :                :     {
                                587                 :                :         ListCell   *lc;
                                588                 :                : 
                                589                 :          70825 :         i = 0;
                                590   [ +  -  +  +  :         141707 :         foreach(lc, scan->functions)
                                              +  + ]
                                591                 :                :         {
                                592                 :          70882 :             RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
                                593                 :                : 
                                594         [ +  + ]:          70882 :             if (bms_overlap(chgparam, rtfunc->funcparams))
                                595                 :                :             {
                                596         [ +  + ]:          67886 :                 if (node->funcstates[i].tstore != NULL)
                                597                 :                :                 {
                                598                 :          61813 :                     tuplestore_end(node->funcstates[i].tstore);
                                599                 :          61813 :                     node->funcstates[i].tstore = NULL;
                                600                 :                :                 }
                                601                 :          67886 :                 node->funcstates[i].rowcount = -1;
                                602                 :                :             }
                                603                 :          70882 :             i++;
                                604                 :                :         }
                                605                 :                :     }
                                606                 :                : 
                                607                 :                :     /* Reset ordinality counter */
                                608                 :          72640 :     node->ordinal = 0;
                                609                 :                : 
                                610                 :                :     /* Make sure we rewind any remaining tuplestores */
                                611         [ +  + ]:         145353 :     for (i = 0; i < node->nfuncs; i++)
                                612                 :                :     {
                                613         [ +  + ]:          72713 :         if (node->funcstates[i].tstore != NULL)
                                614                 :           4383 :             tuplestore_rescan(node->funcstates[i].tstore);
                                615                 :                :     }
 8759                           616                 :          72640 : }
        

Generated by: LCOV version 2.5.0-beta