LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeFunctionscan.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 98.2 % 165 162 3 162
Current Date: 2023-04-08 15:15:32 Functions: 83.3 % 6 5 1 5
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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-2023, 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/builtins.h"
      30                 : #include "utils/memutils.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 *
      60 CBC     7482234 : 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         7482234 :     estate = node->ss.ps.state;
      74         7482234 :     direction = estate->es_direction;
      75         7482234 :     scanslot = node->ss.ss_ScanTupleSlot;
      76                 : 
      77         7482234 :     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         7472856 :         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         7472856 :         if (tstore == NULL)
      93                 :         {
      94           53135 :             node->funcstates[0].tstore = tstore =
      95           55665 :                 ExecMakeTableFunctionResult(node->funcstates[0].setexpr,
      96                 :                                             node->ss.ps.ps_ExprContext,
      97                 :                                             node->argcontext,
      98           55665 :                                             node->funcstates[0].tupdesc,
      99           55665 :                                             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                 :              */
     106           53135 :             tuplestore_rescan(tstore);
     107                 :         }
     108                 : 
     109                 :         /*
     110                 :          * Get the next tuple from tuplestore.
     111                 :          */
     112         7470326 :         (void) tuplestore_gettupleslot(tstore,
     113                 :                                        ScanDirectionIsForward(direction),
     114                 :                                        false,
     115                 :                                        scanslot);
     116         7470326 :         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            9378 :     oldpos = node->ordinal;
     126            9378 :     if (ScanDirectionIsForward(direction))
     127            9348 :         node->ordinal++;
     128                 :     else
     129              30 :         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                 :      */
     138            9378 :     ExecClearTuple(scanslot);
     139            9378 :     att = 0;
     140            9378 :     alldone = true;
     141           24225 :     for (funcno = 0; funcno < node->nfuncs; funcno++)
     142                 :     {
     143           14847 :         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           14847 :         if (fs->tstore == NULL)
     152                 :         {
     153             803 :             fs->tstore =
     154             803 :                 ExecMakeTableFunctionResult(fs->setexpr,
     155                 :                                             node->ss.ps.ps_ExprContext,
     156                 :                                             node->argcontext,
     157                 :                                             fs->tupdesc,
     158             803 :                                             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                 :              */
     165             803 :             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           14847 :         if (fs->rowcount != -1 && fs->rowcount < oldpos)
     176              36 :             ExecClearTuple(fs->func_slot);
     177                 :         else
     178           14811 :             (void) tuplestore_gettupleslot(fs->tstore,
     179                 :                                            ScanDirectionIsForward(direction),
     180                 :                                            false,
     181                 :                                            fs->func_slot);
     182                 : 
     183           14847 :         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             977 :             if (ScanDirectionIsForward(direction) && fs->rowcount == -1)
     193             791 :                 fs->rowcount = node->ordinal;
     194                 : 
     195                 :             /*
     196                 :              * populate the result cols with nulls
     197                 :              */
     198            2448 :             for (i = 0; i < fs->colcount; i++)
     199                 :             {
     200            1471 :                 scanslot->tts_values[att] = (Datum) 0;
     201            1471 :                 scanslot->tts_isnull[att] = true;
     202            1471 :                 att++;
     203                 :             }
     204                 :         }
     205                 :         else
     206                 :         {
     207                 :             /*
     208                 :              * we have a result, so just copy it to the result cols.
     209                 :              */
     210           13870 :             slot_getallattrs(fs->func_slot);
     211                 : 
     212           36565 :             for (i = 0; i < fs->colcount; i++)
     213                 :             {
     214           22695 :                 scanslot->tts_values[att] = fs->func_slot->tts_values[i];
     215           22695 :                 scanslot->tts_isnull[att] = fs->func_slot->tts_isnull[i];
     216           22695 :                 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           13870 :             alldone = false;
     224                 :         }
     225                 :     }
     226                 : 
     227                 :     /*
     228                 :      * ordinal col is always last, per spec.
     229                 :      */
     230            9378 :     if (node->ordinality)
     231                 :     {
     232            6762 :         scanslot->tts_values[att] = Int64GetDatumFast(node->ordinal);
     233            6762 :         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            9378 :     if (!alldone)
     241            8719 :         ExecStoreVirtualTuple(scanslot);
     242                 : 
     243            9378 :     return scanslot;
     244                 : }
     245                 : 
     246                 : /*
     247                 :  * FunctionRecheck -- access method routine to recheck a tuple in EvalPlanQual
     248                 :  */
     249                 : static bool
     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 *
     266 CBC     6962048 : ExecFunctionScan(PlanState *pstate)
     267                 : {
     268         6962048 :     FunctionScanState *node = castNode(FunctionScanState, pstate);
     269                 : 
     270         6962048 :     return ExecScan(&node->ss,
     271                 :                     (ExecScanAccessMtd) FunctionNext,
     272                 :                     (ExecScanRecheckMtd) FunctionRecheck);
     273                 : }
     274                 : 
     275                 : /* ----------------------------------------------------------------
     276                 :  *      ExecInitFunctionScan
     277                 :  * ----------------------------------------------------------------
     278                 :  */
     279                 : FunctionScanState *
     280           26789 : ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
     281                 : {
     282                 :     FunctionScanState *scanstate;
     283           26789 :     int         nfuncs = list_length(node->functions);
     284                 :     TupleDesc   scan_tupdesc;
     285                 :     int         i,
     286                 :                 natts;
     287                 :     ListCell   *lc;
     288                 : 
     289                 :     /* check for unsupported flags */
     290           26789 :     Assert(!(eflags & EXEC_FLAG_MARK));
     291                 : 
     292                 :     /*
     293                 :      * FunctionScan should not have any children.
     294                 :      */
     295           26789 :     Assert(outerPlan(node) == NULL);
     296           26789 :     Assert(innerPlan(node) == NULL);
     297                 : 
     298                 :     /*
     299                 :      * create new ScanState for node
     300                 :      */
     301           26789 :     scanstate = makeNode(FunctionScanState);
     302           26789 :     scanstate->ss.ps.plan = (Plan *) node;
     303           26789 :     scanstate->ss.ps.state = estate;
     304           26789 :     scanstate->ss.ps.ExecProcNode = ExecFunctionScan;
     305           26789 :     scanstate->eflags = eflags;
     306                 : 
     307                 :     /*
     308                 :      * are we adding an ordinality column?
     309                 :      */
     310           26789 :     scanstate->ordinality = node->funcordinality;
     311                 : 
     312           26789 :     scanstate->nfuncs = nfuncs;
     313           26789 :     if (nfuncs == 1 && !node->funcordinality)
     314           26445 :         scanstate->simple = true;
     315                 :     else
     316             344 :         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           26789 :     scanstate->ordinal = 0;
     329                 : 
     330                 :     /*
     331                 :      * Miscellaneous initialization
     332                 :      *
     333                 :      * create expression context for node
     334                 :      */
     335           26789 :     ExecAssignExprContext(estate, &scanstate->ss.ps);
     336                 : 
     337           26789 :     scanstate->funcstates = palloc(nfuncs * sizeof(FunctionScanPerFuncState));
     338                 : 
     339           26789 :     natts = 0;
     340           26789 :     i = 0;
     341           53730 :     foreach(lc, node->functions)
     342                 :     {
     343           26945 :         RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
     344           26945 :         Node       *funcexpr = rtfunc->funcexpr;
     345           26945 :         int         colcount = rtfunc->funccolcount;
     346           26945 :         FunctionScanPerFuncState *fs = &scanstate->funcstates[i];
     347                 :         TypeFuncClass functypclass;
     348                 :         Oid         funcrettype;
     349                 :         TupleDesc   tupdesc;
     350                 : 
     351           26941 :         fs->setexpr =
     352           26945 :             ExecInitTableFunctionResult((Expr *) funcexpr,
     353                 :                                         scanstate->ss.ps.ps_ExprContext,
     354                 :                                         &scanstate->ss.ps);
     355                 : 
     356                 :         /*
     357                 :          * Don't allocate the tuplestores; the actual calls to the functions
     358                 :          * do that.  NULL means that we have not called the function yet (or
     359                 :          * need to call it again after a rescan).
     360                 :          */
     361           26941 :         fs->tstore = NULL;
     362           26941 :         fs->rowcount = -1;
     363                 : 
     364                 :         /*
     365                 :          * Now determine if the function returns a simple or composite type,
     366                 :          * and build an appropriate tupdesc.  Note that in the composite case,
     367                 :          * the function may now return more columns than it did when the plan
     368                 :          * was made; we have to ignore any columns beyond "colcount".
     369                 :          */
     370           26941 :         functypclass = get_expr_result_type(funcexpr,
     371                 :                                             &funcrettype,
     372                 :                                             &tupdesc);
     373                 : 
     374           26941 :         if (functypclass == TYPEFUNC_COMPOSITE ||
     375                 :             functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
     376                 :         {
     377                 :             /* Composite data type, e.g. a table's row type */
     378           15948 :             Assert(tupdesc);
     379           15948 :             Assert(tupdesc->natts >= colcount);
     380                 :             /* Must copy it out of typcache for safety */
     381           15948 :             tupdesc = CreateTupleDescCopy(tupdesc);
     382                 :         }
     383           10993 :         else if (functypclass == TYPEFUNC_SCALAR)
     384                 :         {
     385                 :             /* Base data type, i.e. scalar */
     386           10643 :             tupdesc = CreateTemplateTupleDesc(1);
     387           10643 :             TupleDescInitEntry(tupdesc,
     388                 :                                (AttrNumber) 1,
     389                 :                                NULL,    /* don't care about the name here */
     390                 :                                funcrettype,
     391                 :                                -1,
     392                 :                                0);
     393           10643 :             TupleDescInitEntryCollation(tupdesc,
     394                 :                                         (AttrNumber) 1,
     395                 :                                         exprCollation(funcexpr));
     396                 :         }
     397             350 :         else if (functypclass == TYPEFUNC_RECORD)
     398                 :         {
     399             350 :             tupdesc = BuildDescFromLists(rtfunc->funccolnames,
     400                 :                                          rtfunc->funccoltypes,
     401                 :                                          rtfunc->funccoltypmods,
     402                 :                                          rtfunc->funccolcollations);
     403                 : 
     404                 :             /*
     405                 :              * For RECORD results, make sure a typmod has been assigned.  (The
     406                 :              * function should do this for itself, but let's cover things in
     407                 :              * case it doesn't.)
     408                 :              */
     409             350 :             BlessTupleDesc(tupdesc);
     410                 :         }
     411                 :         else
     412                 :         {
     413                 :             /* crummy error message, but parser should have caught this */
     414 UBC           0 :             elog(ERROR, "function in FROM has unsupported return type");
     415                 :         }
     416                 : 
     417 CBC       26941 :         fs->tupdesc = tupdesc;
     418           26941 :         fs->colcount = colcount;
     419                 : 
     420                 :         /*
     421                 :          * We only need separate slots for the function results if we are
     422                 :          * doing ordinality or multiple functions; otherwise, we'll fetch
     423                 :          * function results directly into the scan slot.
     424                 :          */
     425           26941 :         if (!scanstate->simple)
     426                 :         {
     427             500 :             fs->func_slot = ExecInitExtraTupleSlot(estate, fs->tupdesc,
     428                 :                                                    &TTSOpsMinimalTuple);
     429                 :         }
     430                 :         else
     431           26441 :             fs->func_slot = NULL;
     432                 : 
     433           26941 :         natts += colcount;
     434           26941 :         i++;
     435                 :     }
     436                 : 
     437                 :     /*
     438                 :      * Create the combined TupleDesc
     439                 :      *
     440                 :      * If there is just one function without ordinality, the scan result
     441                 :      * tupdesc is the same as the function result tupdesc --- except that we
     442                 :      * may stuff new names into it below, so drop any rowtype label.
     443                 :      */
     444           26785 :     if (scanstate->simple)
     445                 :     {
     446           26441 :         scan_tupdesc = CreateTupleDescCopy(scanstate->funcstates[0].tupdesc);
     447           26441 :         scan_tupdesc->tdtypeid = RECORDOID;
     448           26441 :         scan_tupdesc->tdtypmod = -1;
     449                 :     }
     450                 :     else
     451                 :     {
     452             344 :         AttrNumber  attno = 0;
     453                 : 
     454             344 :         if (node->funcordinality)
     455             308 :             natts++;
     456                 : 
     457             344 :         scan_tupdesc = CreateTemplateTupleDesc(natts);
     458                 : 
     459             844 :         for (i = 0; i < nfuncs; i++)
     460                 :         {
     461             500 :             TupleDesc   tupdesc = scanstate->funcstates[i].tupdesc;
     462             500 :             int         colcount = scanstate->funcstates[i].colcount;
     463                 :             int         j;
     464                 : 
     465            1320 :             for (j = 1; j <= colcount; j++)
     466             820 :                 TupleDescCopyEntry(scan_tupdesc, ++attno, tupdesc, j);
     467                 :         }
     468                 : 
     469                 :         /* If doing ordinality, add a column of type "bigint" at the end */
     470             344 :         if (node->funcordinality)
     471                 :         {
     472             308 :             TupleDescInitEntry(scan_tupdesc,
     473                 :                                ++attno,
     474                 :                                NULL,    /* don't care about the name here */
     475                 :                                INT8OID,
     476                 :                                -1,
     477                 :                                0);
     478                 :         }
     479                 : 
     480             344 :         Assert(attno == natts);
     481                 :     }
     482                 : 
     483                 :     /*
     484                 :      * Initialize scan slot and type.
     485                 :      */
     486           26785 :     ExecInitScanTupleSlot(estate, &scanstate->ss, scan_tupdesc,
     487                 :                           &TTSOpsMinimalTuple);
     488                 : 
     489                 :     /*
     490                 :      * Initialize result slot, type and projection.
     491                 :      */
     492           26785 :     ExecInitResultTypeTL(&scanstate->ss.ps);
     493           26785 :     ExecAssignScanProjectionInfo(&scanstate->ss);
     494                 : 
     495                 :     /*
     496                 :      * initialize child expressions
     497                 :      */
     498           26785 :     scanstate->ss.ps.qual =
     499           26785 :         ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
     500                 : 
     501                 :     /*
     502                 :      * Create a memory context that ExecMakeTableFunctionResult can use to
     503                 :      * evaluate function arguments in.  We can't use the per-tuple context for
     504                 :      * this because it gets reset too often; but we don't want to leak
     505                 :      * evaluation results into the query-lifespan context either.  We just
     506                 :      * need one context, because we evaluate each function separately.
     507                 :      */
     508           26785 :     scanstate->argcontext = AllocSetContextCreate(CurrentMemoryContext,
     509                 :                                                   "Table function arguments",
     510                 :                                                   ALLOCSET_DEFAULT_SIZES);
     511                 : 
     512           26785 :     return scanstate;
     513                 : }
     514                 : 
     515                 : /* ----------------------------------------------------------------
     516                 :  *      ExecEndFunctionScan
     517                 :  *
     518                 :  *      frees any storage allocated through C routines.
     519                 :  * ----------------------------------------------------------------
     520                 :  */
     521                 : void
     522           24172 : ExecEndFunctionScan(FunctionScanState *node)
     523                 : {
     524                 :     int         i;
     525                 : 
     526                 :     /*
     527                 :      * Free the exprcontext
     528                 :      */
     529           24172 :     ExecFreeExprContext(&node->ss.ps);
     530                 : 
     531                 :     /*
     532                 :      * clean out the tuple table
     533                 :      */
     534           24172 :     if (node->ss.ps.ps_ResultTupleSlot)
     535            8523 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     536           24172 :     ExecClearTuple(node->ss.ss_ScanTupleSlot);
     537                 : 
     538                 :     /*
     539                 :      * Release slots and tuplestore resources
     540                 :      */
     541           48494 :     for (i = 0; i < node->nfuncs; i++)
     542                 :     {
     543           24322 :         FunctionScanPerFuncState *fs = &node->funcstates[i];
     544                 : 
     545           24322 :         if (fs->func_slot)
     546             488 :             ExecClearTuple(fs->func_slot);
     547                 : 
     548           24322 :         if (fs->tstore != NULL)
     549                 :         {
     550           22233 :             tuplestore_end(node->funcstates[i].tstore);
     551           22233 :             fs->tstore = NULL;
     552                 :         }
     553                 :     }
     554           24172 : }
     555                 : 
     556                 : /* ----------------------------------------------------------------
     557                 :  *      ExecReScanFunctionScan
     558                 :  *
     559                 :  *      Rescans the relation.
     560                 :  * ----------------------------------------------------------------
     561                 :  */
     562                 : void
     563           38925 : ExecReScanFunctionScan(FunctionScanState *node)
     564                 : {
     565           38925 :     FunctionScan *scan = (FunctionScan *) node->ss.ps.plan;
     566                 :     int         i;
     567           38925 :     Bitmapset  *chgparam = node->ss.ps.chgParam;
     568                 : 
     569           38925 :     if (node->ss.ps.ps_ResultTupleSlot)
     570           20344 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     571           77904 :     for (i = 0; i < node->nfuncs; i++)
     572                 :     {
     573           38979 :         FunctionScanPerFuncState *fs = &node->funcstates[i];
     574                 : 
     575           38979 :         if (fs->func_slot)
     576             543 :             ExecClearTuple(fs->func_slot);
     577                 :     }
     578                 : 
     579           38925 :     ExecScanReScan(&node->ss);
     580                 : 
     581                 :     /*
     582                 :      * Here we have a choice whether to drop the tuplestores (and recompute
     583                 :      * the function outputs) or just rescan them.  We must recompute if an
     584                 :      * expression contains changed parameters, else we rescan.
     585                 :      *
     586                 :      * XXX maybe we should recompute if the function is volatile?  But in
     587                 :      * general the executor doesn't conditionalize its actions on that.
     588                 :      */
     589           38925 :     if (chgparam)
     590                 :     {
     591                 :         ListCell   *lc;
     592                 : 
     593           37055 :         i = 0;
     594           74152 :         foreach(lc, scan->functions)
     595                 :         {
     596           37097 :             RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc);
     597                 : 
     598           37097 :             if (bms_overlap(chgparam, rtfunc->funcparams))
     599                 :             {
     600           35853 :                 if (node->funcstates[i].tstore != NULL)
     601                 :                 {
     602           31616 :                     tuplestore_end(node->funcstates[i].tstore);
     603           31616 :                     node->funcstates[i].tstore = NULL;
     604                 :                 }
     605           35853 :                 node->funcstates[i].rowcount = -1;
     606                 :             }
     607           37097 :             i++;
     608                 :         }
     609                 :     }
     610                 : 
     611                 :     /* Reset ordinality counter */
     612           38925 :     node->ordinal = 0;
     613                 : 
     614                 :     /* Make sure we rewind any remaining tuplestores */
     615           77904 :     for (i = 0; i < node->nfuncs; i++)
     616                 :     {
     617           38979 :         if (node->funcstates[i].tstore != NULL)
     618            2847 :             tuplestore_rescan(node->funcstates[i].tstore);
     619                 :     }
     620           38925 : }
        

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