LCOV - code coverage report
Current view: top level - src/backend/executor - nodeFunctionscan.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 98.7 % 224 221
Test Date: 2026-01-26 10:56:24 Functions: 83.3 % 6 5
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 87.0 % 100 87

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

Generated by: LCOV version 2.3.2-1