LCOV - code coverage report
Current view: top level - src/backend/executor - execSRF.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 272 286 95.1 %
Date: 2023-12-05 08:11:01 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * execSRF.c
       4             :  *    Routines implementing the API for set-returning functions
       5             :  *
       6             :  * This file serves nodeFunctionscan.c and nodeProjectSet.c, providing
       7             :  * common code for calling set-returning functions according to the
       8             :  * ReturnSetInfo API.
       9             :  *
      10             :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
      11             :  * Portions Copyright (c) 1994, Regents of the University of California
      12             :  *
      13             :  *
      14             :  * IDENTIFICATION
      15             :  *    src/backend/executor/execSRF.c
      16             :  *
      17             :  *-------------------------------------------------------------------------
      18             :  */
      19             : #include "postgres.h"
      20             : 
      21             : #include "access/htup_details.h"
      22             : #include "catalog/objectaccess.h"
      23             : #include "catalog/pg_proc.h"
      24             : #include "executor/execdebug.h"
      25             : #include "funcapi.h"
      26             : #include "miscadmin.h"
      27             : #include "nodes/nodeFuncs.h"
      28             : #include "parser/parse_coerce.h"
      29             : #include "pgstat.h"
      30             : #include "utils/acl.h"
      31             : #include "utils/builtins.h"
      32             : #include "utils/lsyscache.h"
      33             : #include "utils/memutils.h"
      34             : #include "utils/typcache.h"
      35             : 
      36             : 
      37             : /* static function decls */
      38             : static void init_sexpr(Oid foid, Oid input_collation, Expr *node,
      39             :                        SetExprState *sexpr, PlanState *parent,
      40             :                        MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF);
      41             : static void ShutdownSetExpr(Datum arg);
      42             : static void ExecEvalFuncArgs(FunctionCallInfo fcinfo,
      43             :                              List *argList, ExprContext *econtext);
      44             : static void ExecPrepareTuplestoreResult(SetExprState *sexpr,
      45             :                                         ExprContext *econtext,
      46             :                                         Tuplestorestate *resultStore,
      47             :                                         TupleDesc resultDesc);
      48             : static void tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc);
      49             : 
      50             : 
      51             : /*
      52             :  * Prepare function call in FROM (ROWS FROM) for execution.
      53             :  *
      54             :  * This is used by nodeFunctionscan.c.
      55             :  */
      56             : SetExprState *
      57       59726 : ExecInitTableFunctionResult(Expr *expr,
      58             :                             ExprContext *econtext, PlanState *parent)
      59             : {
      60       59726 :     SetExprState *state = makeNode(SetExprState);
      61             : 
      62       59726 :     state->funcReturnsSet = false;
      63       59726 :     state->expr = expr;
      64       59726 :     state->func.fn_oid = InvalidOid;
      65             : 
      66             :     /*
      67             :      * Normally the passed expression tree will be a FuncExpr, since the
      68             :      * grammar only allows a function call at the top level of a table
      69             :      * function reference.  However, if the function doesn't return set then
      70             :      * the planner might have replaced the function call via constant-folding
      71             :      * or inlining.  So if we see any other kind of expression node, execute
      72             :      * it via the general ExecEvalExpr() code.  That code path will not
      73             :      * support set-returning functions buried in the expression, though.
      74             :      */
      75       59726 :     if (IsA(expr, FuncExpr))
      76             :     {
      77       59636 :         FuncExpr   *func = (FuncExpr *) expr;
      78             : 
      79       59636 :         state->funcReturnsSet = func->funcretset;
      80       59636 :         state->args = ExecInitExprList(func->args, parent);
      81             : 
      82       59636 :         init_sexpr(func->funcid, func->inputcollid, expr, state, parent,
      83       59636 :                    econtext->ecxt_per_query_memory, func->funcretset, false);
      84             :     }
      85             :     else
      86             :     {
      87          90 :         state->elidedFuncState = ExecInitExpr(expr, parent);
      88             :     }
      89             : 
      90       59718 :     return state;
      91             : }
      92             : 
      93             : /*
      94             :  *      ExecMakeTableFunctionResult
      95             :  *
      96             :  * Evaluate a table function, producing a materialized result in a Tuplestore
      97             :  * object.
      98             :  *
      99             :  * This is used by nodeFunctionscan.c.
     100             :  */
     101             : Tuplestorestate *
     102      121928 : ExecMakeTableFunctionResult(SetExprState *setexpr,
     103             :                             ExprContext *econtext,
     104             :                             MemoryContext argContext,
     105             :                             TupleDesc expectedDesc,
     106             :                             bool randomAccess)
     107             : {
     108      121928 :     Tuplestorestate *tupstore = NULL;
     109      121928 :     TupleDesc   tupdesc = NULL;
     110             :     Oid         funcrettype;
     111             :     bool        returnsTuple;
     112      121928 :     bool        returnsSet = false;
     113             :     FunctionCallInfo fcinfo;
     114             :     PgStat_FunctionCallUsage fcusage;
     115             :     ReturnSetInfo rsinfo;
     116             :     HeapTupleData tmptup;
     117             :     MemoryContext callerContext;
     118      121928 :     bool        first_time = true;
     119             : 
     120             :     /*
     121             :      * Execute per-tablefunc actions in appropriate context.
     122             :      *
     123             :      * The FunctionCallInfo needs to live across all the calls to a
     124             :      * ValuePerCall function, so it can't be allocated in the per-tuple
     125             :      * context. Similarly, the function arguments need to be evaluated in a
     126             :      * context that is longer lived than the per-tuple context: The argument
     127             :      * values would otherwise disappear when we reset that context in the
     128             :      * inner loop.  As the caller's CurrentMemoryContext is typically a
     129             :      * query-lifespan context, we don't want to leak memory there.  We require
     130             :      * the caller to pass a separate memory context that can be used for this,
     131             :      * and can be reset each time through to avoid bloat.
     132             :      */
     133      121928 :     MemoryContextReset(argContext);
     134      121928 :     callerContext = MemoryContextSwitchTo(argContext);
     135             : 
     136      121928 :     funcrettype = exprType((Node *) setexpr->expr);
     137             : 
     138      121928 :     returnsTuple = type_is_rowtype(funcrettype);
     139             : 
     140             :     /*
     141             :      * Prepare a resultinfo node for communication.  We always do this even if
     142             :      * not expecting a set result, so that we can pass expectedDesc.  In the
     143             :      * generic-expression case, the expression doesn't actually get to see the
     144             :      * resultinfo, but set it up anyway because we use some of the fields as
     145             :      * our own state variables.
     146             :      */
     147      121928 :     rsinfo.type = T_ReturnSetInfo;
     148      121928 :     rsinfo.econtext = econtext;
     149      121928 :     rsinfo.expectedDesc = expectedDesc;
     150      121928 :     rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize | SFRM_Materialize_Preferred);
     151      121928 :     if (randomAccess)
     152          78 :         rsinfo.allowedModes |= (int) SFRM_Materialize_Random;
     153      121928 :     rsinfo.returnMode = SFRM_ValuePerCall;
     154             :     /* isDone is filled below */
     155      121928 :     rsinfo.setResult = NULL;
     156      121928 :     rsinfo.setDesc = NULL;
     157             : 
     158      121928 :     fcinfo = palloc(SizeForFunctionCallInfo(list_length(setexpr->args)));
     159             : 
     160             :     /*
     161             :      * Normally the passed expression tree will be a SetExprState, since the
     162             :      * grammar only allows a function call at the top level of a table
     163             :      * function reference.  However, if the function doesn't return set then
     164             :      * the planner might have replaced the function call via constant-folding
     165             :      * or inlining.  So if we see any other kind of expression node, execute
     166             :      * it via the general ExecEvalExpr() code; the only difference is that we
     167             :      * don't get a chance to pass a special ReturnSetInfo to any functions
     168             :      * buried in the expression.
     169             :      */
     170      121928 :     if (!setexpr->elidedFuncState)
     171             :     {
     172             :         /*
     173             :          * This path is similar to ExecMakeFunctionResultSet.
     174             :          */
     175      121838 :         returnsSet = setexpr->funcReturnsSet;
     176      121838 :         InitFunctionCallInfoData(*fcinfo, &(setexpr->func),
     177             :                                  list_length(setexpr->args),
     178             :                                  setexpr->fcinfo->fncollation,
     179             :                                  NULL, (Node *) &rsinfo);
     180             :         /* evaluate the function's argument list */
     181             :         Assert(CurrentMemoryContext == argContext);
     182      121838 :         ExecEvalFuncArgs(fcinfo, setexpr->args, econtext);
     183             : 
     184             :         /*
     185             :          * If function is strict, and there are any NULL arguments, skip
     186             :          * calling the function and act like it returned NULL (or an empty
     187             :          * set, in the returns-set case).
     188             :          */
     189      121822 :         if (setexpr->func.fn_strict)
     190             :         {
     191             :             int         i;
     192             : 
     193      239336 :             for (i = 0; i < fcinfo->nargs; i++)
     194             :             {
     195      173860 :                 if (fcinfo->args[i].isnull)
     196       39906 :                     goto no_function_result;
     197             :             }
     198             :         }
     199             :     }
     200             :     else
     201             :     {
     202             :         /* Treat setexpr as a generic expression */
     203          90 :         InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
     204             :     }
     205             : 
     206             :     /*
     207             :      * Switch to short-lived context for calling the function or expression.
     208             :      */
     209       82006 :     MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
     210             : 
     211             :     /*
     212             :      * Loop to handle the ValuePerCall protocol (which is also the same
     213             :      * behavior needed in the generic ExecEvalExpr path).
     214             :      */
     215             :     for (;;)
     216    17235952 :     {
     217             :         Datum       result;
     218             : 
     219    17317958 :         CHECK_FOR_INTERRUPTS();
     220             : 
     221             :         /*
     222             :          * Reset per-tuple memory context before each call of the function or
     223             :          * expression. This cleans up any local memory the function may leak
     224             :          * when called.
     225             :          */
     226    17317956 :         ResetExprContext(econtext);
     227             : 
     228             :         /* Call the function or expression one time */
     229    17317956 :         if (!setexpr->elidedFuncState)
     230             :         {
     231    17317866 :             pgstat_init_function_usage(fcinfo, &fcusage);
     232             : 
     233    17317866 :             fcinfo->isnull = false;
     234    17317866 :             rsinfo.isDone = ExprSingleResult;
     235    17317866 :             result = FunctionCallInvoke(fcinfo);
     236             : 
     237    17312888 :             pgstat_end_function_usage(&fcusage,
     238    17312888 :                                       rsinfo.isDone != ExprMultipleResult);
     239             :         }
     240             :         else
     241             :         {
     242          90 :             result =
     243          90 :                 ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo->isnull);
     244          90 :             rsinfo.isDone = ExprSingleResult;
     245             :         }
     246             : 
     247             :         /* Which protocol does function want to use? */
     248    17312978 :         if (rsinfo.returnMode == SFRM_ValuePerCall)
     249             :         {
     250             :             /*
     251             :              * Check for end of result set.
     252             :              */
     253    17295792 :             if (rsinfo.isDone == ExprEndResult)
     254       77026 :                 break;
     255             : 
     256             :             /*
     257             :              * If first time through, build tuplestore for result.  For a
     258             :              * scalar function result type, also make a suitable tupdesc.
     259             :              */
     260    17270218 :             if (first_time)
     261             :             {
     262             :                 MemoryContext oldcontext =
     263       58828 :                     MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
     264             : 
     265       58828 :                 tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
     266       58828 :                 rsinfo.setResult = tupstore;
     267       58828 :                 if (!returnsTuple)
     268             :                 {
     269       28584 :                     tupdesc = CreateTemplateTupleDesc(1);
     270       28584 :                     TupleDescInitEntry(tupdesc,
     271             :                                        (AttrNumber) 1,
     272             :                                        "column",
     273             :                                        funcrettype,
     274             :                                        -1,
     275             :                                        0);
     276       28584 :                     rsinfo.setDesc = tupdesc;
     277             :                 }
     278       58828 :                 MemoryContextSwitchTo(oldcontext);
     279             :             }
     280             : 
     281             :             /*
     282             :              * Store current resultset item.
     283             :              */
     284    17270218 :             if (returnsTuple)
     285             :             {
     286     1518754 :                 if (!fcinfo->isnull)
     287             :                 {
     288     1518692 :                     HeapTupleHeader td = DatumGetHeapTupleHeader(result);
     289             : 
     290     1518692 :                     if (tupdesc == NULL)
     291             :                     {
     292             :                         MemoryContext oldcontext =
     293       30206 :                             MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
     294             : 
     295             :                         /*
     296             :                          * This is the first non-NULL result from the
     297             :                          * function.  Use the type info embedded in the
     298             :                          * rowtype Datum to look up the needed tupdesc.  Make
     299             :                          * a copy for the query.
     300             :                          */
     301       30206 :                         tupdesc = lookup_rowtype_tupdesc_copy(HeapTupleHeaderGetTypeId(td),
     302             :                                                               HeapTupleHeaderGetTypMod(td));
     303       30206 :                         rsinfo.setDesc = tupdesc;
     304       30206 :                         MemoryContextSwitchTo(oldcontext);
     305             :                     }
     306             :                     else
     307             :                     {
     308             :                         /*
     309             :                          * Verify all later returned rows have same subtype;
     310             :                          * necessary in case the type is RECORD.
     311             :                          */
     312     1488486 :                         if (HeapTupleHeaderGetTypeId(td) != tupdesc->tdtypeid ||
     313     1488486 :                             HeapTupleHeaderGetTypMod(td) != tupdesc->tdtypmod)
     314           0 :                             ereport(ERROR,
     315             :                                     (errcode(ERRCODE_DATATYPE_MISMATCH),
     316             :                                      errmsg("rows returned by function are not all of the same row type")));
     317             :                     }
     318             : 
     319             :                     /*
     320             :                      * tuplestore_puttuple needs a HeapTuple not a bare
     321             :                      * HeapTupleHeader, but it doesn't need all the fields.
     322             :                      */
     323     1518692 :                     tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
     324     1518692 :                     tmptup.t_data = td;
     325             : 
     326     1518692 :                     tuplestore_puttuple(tupstore, &tmptup);
     327             :                 }
     328             :                 else
     329             :                 {
     330             :                     /*
     331             :                      * NULL result from a tuple-returning function; expand it
     332             :                      * to a row of all nulls.  We rely on the expectedDesc to
     333             :                      * form such rows.  (Note: this would be problematic if
     334             :                      * tuplestore_putvalues saved the tdtypeid/tdtypmod from
     335             :                      * the provided descriptor, since that might not match
     336             :                      * what we get from the function itself.  But it doesn't.)
     337             :                      */
     338          62 :                     int         natts = expectedDesc->natts;
     339             :                     bool       *nullflags;
     340             : 
     341          62 :                     nullflags = (bool *) palloc(natts * sizeof(bool));
     342          62 :                     memset(nullflags, true, natts * sizeof(bool));
     343          62 :                     tuplestore_putvalues(tupstore, expectedDesc, NULL, nullflags);
     344             :                 }
     345             :             }
     346             :             else
     347             :             {
     348             :                 /* Scalar-type case: just store the function result */
     349    15751464 :                 tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo->isnull);
     350             :             }
     351             : 
     352             :             /*
     353             :              * Are we done?
     354             :              */
     355    17270218 :             if (rsinfo.isDone != ExprMultipleResult)
     356       34266 :                 break;
     357             : 
     358             :             /*
     359             :              * Check that set-returning functions were properly declared.
     360             :              * (Note: for historical reasons, we don't complain if a non-SRF
     361             :              * returns ExprEndResult; that's treated as returning NULL.)
     362             :              */
     363    17235952 :             if (!returnsSet)
     364           0 :                 ereport(ERROR,
     365             :                         (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
     366             :                          errmsg("table-function protocol for value-per-call mode was not followed")));
     367             :         }
     368       17186 :         else if (rsinfo.returnMode == SFRM_Materialize)
     369             :         {
     370             :             /* check we're on the same page as the function author */
     371       17186 :             if (!first_time || rsinfo.isDone != ExprSingleResult || !returnsSet)
     372           0 :                 ereport(ERROR,
     373             :                         (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
     374             :                          errmsg("table-function protocol for materialize mode was not followed")));
     375             :             /* Done evaluating the set result */
     376       17186 :             break;
     377             :         }
     378             :         else
     379           0 :             ereport(ERROR,
     380             :                     (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
     381             :                      errmsg("unrecognized table-function returnMode: %d",
     382             :                             (int) rsinfo.returnMode)));
     383             : 
     384    17235952 :         first_time = false;
     385             :     }
     386             : 
     387      116932 : no_function_result:
     388             : 
     389             :     /*
     390             :      * If we got nothing from the function (ie, an empty-set or NULL result),
     391             :      * we have to create the tuplestore to return, and if it's a
     392             :      * non-set-returning function then insert a single all-nulls row.  As
     393             :      * above, we depend on the expectedDesc to manufacture the dummy row.
     394             :      */
     395      116932 :     if (rsinfo.setResult == NULL)
     396             :     {
     397             :         MemoryContext oldcontext =
     398       40946 :             MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
     399             : 
     400       40946 :         tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
     401       40946 :         rsinfo.setResult = tupstore;
     402       40946 :         MemoryContextSwitchTo(oldcontext);
     403             : 
     404       40946 :         if (!returnsSet)
     405             :         {
     406          14 :             int         natts = expectedDesc->natts;
     407             :             bool       *nullflags;
     408             : 
     409          14 :             nullflags = (bool *) palloc(natts * sizeof(bool));
     410          14 :             memset(nullflags, true, natts * sizeof(bool));
     411          14 :             tuplestore_putvalues(tupstore, expectedDesc, NULL, nullflags);
     412             :         }
     413             :     }
     414             : 
     415             :     /*
     416             :      * If function provided a tupdesc, cross-check it.  We only really need to
     417             :      * do this for functions returning RECORD, but might as well do it always.
     418             :      */
     419      116932 :     if (rsinfo.setDesc)
     420             :     {
     421       75942 :         tupledesc_match(expectedDesc, rsinfo.setDesc);
     422             : 
     423             :         /*
     424             :          * If it is a dynamically-allocated TupleDesc, free it: it is
     425             :          * typically allocated in a per-query context, so we must avoid
     426             :          * leaking it across multiple usages.
     427             :          */
     428       75882 :         if (rsinfo.setDesc->tdrefcount == -1)
     429       75882 :             FreeTupleDesc(rsinfo.setDesc);
     430             :     }
     431             : 
     432      116872 :     MemoryContextSwitchTo(callerContext);
     433             : 
     434             :     /* All done, pass back the tuplestore */
     435      116872 :     return rsinfo.setResult;
     436             : }
     437             : 
     438             : 
     439             : /*
     440             :  * Prepare targetlist SRF function call for execution.
     441             :  *
     442             :  * This is used by nodeProjectSet.c.
     443             :  */
     444             : SetExprState *
     445        6736 : ExecInitFunctionResultSet(Expr *expr,
     446             :                           ExprContext *econtext, PlanState *parent)
     447             : {
     448        6736 :     SetExprState *state = makeNode(SetExprState);
     449             : 
     450        6736 :     state->funcReturnsSet = true;
     451        6736 :     state->expr = expr;
     452        6736 :     state->func.fn_oid = InvalidOid;
     453             : 
     454             :     /*
     455             :      * Initialize metadata.  The expression node could be either a FuncExpr or
     456             :      * an OpExpr.
     457             :      */
     458        6736 :     if (IsA(expr, FuncExpr))
     459             :     {
     460        6730 :         FuncExpr   *func = (FuncExpr *) expr;
     461             : 
     462        6730 :         state->args = ExecInitExprList(func->args, parent);
     463        6730 :         init_sexpr(func->funcid, func->inputcollid, expr, state, parent,
     464             :                    econtext->ecxt_per_query_memory, true, true);
     465             :     }
     466           6 :     else if (IsA(expr, OpExpr))
     467             :     {
     468           6 :         OpExpr     *op = (OpExpr *) expr;
     469             : 
     470           6 :         state->args = ExecInitExprList(op->args, parent);
     471           6 :         init_sexpr(op->opfuncid, op->inputcollid, expr, state, parent,
     472             :                    econtext->ecxt_per_query_memory, true, true);
     473             :     }
     474             :     else
     475           0 :         elog(ERROR, "unrecognized node type: %d",
     476             :              (int) nodeTag(expr));
     477             : 
     478             :     /* shouldn't get here unless the selected function returns set */
     479             :     Assert(state->func.fn_retset);
     480             : 
     481        6732 :     return state;
     482             : }
     483             : 
     484             : /*
     485             :  *      ExecMakeFunctionResultSet
     486             :  *
     487             :  * Evaluate the arguments to a set-returning function and then call the
     488             :  * function itself.  The argument expressions may not contain set-returning
     489             :  * functions (the planner is supposed to have separated evaluation for those).
     490             :  *
     491             :  * This should be called in a short-lived (per-tuple) context, argContext
     492             :  * needs to live until all rows have been returned (i.e. *isDone set to
     493             :  * ExprEndResult or ExprSingleResult).
     494             :  *
     495             :  * This is used by nodeProjectSet.c.
     496             :  */
     497             : Datum
     498     2170240 : ExecMakeFunctionResultSet(SetExprState *fcache,
     499             :                           ExprContext *econtext,
     500             :                           MemoryContext argContext,
     501             :                           bool *isNull,
     502             :                           ExprDoneCond *isDone)
     503             : {
     504             :     List       *arguments;
     505             :     Datum       result;
     506             :     FunctionCallInfo fcinfo;
     507             :     PgStat_FunctionCallUsage fcusage;
     508             :     ReturnSetInfo rsinfo;
     509             :     bool        callit;
     510             :     int         i;
     511             : 
     512     2170240 : restart:
     513             : 
     514             :     /* Guard against stack overflow due to overly complex expressions */
     515     2170240 :     check_stack_depth();
     516             : 
     517             :     /*
     518             :      * If a previous call of the function returned a set result in the form of
     519             :      * a tuplestore, continue reading rows from the tuplestore until it's
     520             :      * empty.
     521             :      */
     522     2170240 :     if (fcache->funcResultStore)
     523             :     {
     524       76090 :         TupleTableSlot *slot = fcache->funcResultSlot;
     525             :         MemoryContext oldContext;
     526             :         bool        foundTup;
     527             : 
     528             :         /*
     529             :          * Have to make sure tuple in slot lives long enough, otherwise
     530             :          * clearing the slot could end up trying to free something already
     531             :          * freed.
     532             :          */
     533       76090 :         oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
     534       76090 :         foundTup = tuplestore_gettupleslot(fcache->funcResultStore, true, false,
     535             :                                            fcache->funcResultSlot);
     536       76090 :         MemoryContextSwitchTo(oldContext);
     537             : 
     538       76090 :         if (foundTup)
     539             :         {
     540       63060 :             *isDone = ExprMultipleResult;
     541       63060 :             if (fcache->funcReturnsTuple)
     542             :             {
     543             :                 /* We must return the whole tuple as a Datum. */
     544       58918 :                 *isNull = false;
     545       58918 :                 return ExecFetchSlotHeapTupleDatum(fcache->funcResultSlot);
     546             :             }
     547             :             else
     548             :             {
     549             :                 /* Extract the first column and return it as a scalar. */
     550        4142 :                 return slot_getattr(fcache->funcResultSlot, 1, isNull);
     551             :             }
     552             :         }
     553             :         /* Exhausted the tuplestore, so clean up */
     554       13030 :         tuplestore_end(fcache->funcResultStore);
     555       13030 :         fcache->funcResultStore = NULL;
     556       13030 :         *isDone = ExprEndResult;
     557       13030 :         *isNull = true;
     558       13030 :         return (Datum) 0;
     559             :     }
     560             : 
     561             :     /*
     562             :      * arguments is a list of expressions to evaluate before passing to the
     563             :      * function manager.  We skip the evaluation if it was already done in the
     564             :      * previous call (ie, we are continuing the evaluation of a set-valued
     565             :      * function).  Otherwise, collect the current argument values into fcinfo.
     566             :      *
     567             :      * The arguments have to live in a context that lives at least until all
     568             :      * rows from this SRF have been returned, otherwise ValuePerCall SRFs
     569             :      * would reference freed memory after the first returned row.
     570             :      */
     571     2094150 :     fcinfo = fcache->fcinfo;
     572     2094150 :     arguments = fcache->args;
     573     2094150 :     if (!fcache->setArgsValid)
     574             :     {
     575      155094 :         MemoryContext oldContext = MemoryContextSwitchTo(argContext);
     576             : 
     577      155094 :         ExecEvalFuncArgs(fcinfo, arguments, econtext);
     578      155094 :         MemoryContextSwitchTo(oldContext);
     579             :     }
     580             :     else
     581             :     {
     582             :         /* Reset flag (we may set it again below) */
     583     1939056 :         fcache->setArgsValid = false;
     584             :     }
     585             : 
     586             :     /*
     587             :      * Now call the function, passing the evaluated parameter values.
     588             :      */
     589             : 
     590             :     /* Prepare a resultinfo node for communication. */
     591     2094150 :     fcinfo->resultinfo = (Node *) &rsinfo;
     592     2094150 :     rsinfo.type = T_ReturnSetInfo;
     593     2094150 :     rsinfo.econtext = econtext;
     594     2094150 :     rsinfo.expectedDesc = fcache->funcResultDesc;
     595     2094150 :     rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize);
     596             :     /* note we do not set SFRM_Materialize_Random or _Preferred */
     597     2094150 :     rsinfo.returnMode = SFRM_ValuePerCall;
     598             :     /* isDone is filled below */
     599     2094150 :     rsinfo.setResult = NULL;
     600     2094150 :     rsinfo.setDesc = NULL;
     601             : 
     602             :     /*
     603             :      * If function is strict, and there are any NULL arguments, skip calling
     604             :      * the function.
     605             :      */
     606     2094150 :     callit = true;
     607     2094150 :     if (fcache->func.fn_strict)
     608             :     {
     609     5694334 :         for (i = 0; i < fcinfo->nargs; i++)
     610             :         {
     611     3658512 :             if (fcinfo->args[i].isnull)
     612             :             {
     613       53950 :                 callit = false;
     614       53950 :                 break;
     615             :             }
     616             :         }
     617             :     }
     618             : 
     619     2094150 :     if (callit)
     620             :     {
     621     2040200 :         pgstat_init_function_usage(fcinfo, &fcusage);
     622             : 
     623     2040200 :         fcinfo->isnull = false;
     624     2040200 :         rsinfo.isDone = ExprSingleResult;
     625     2040200 :         result = FunctionCallInvoke(fcinfo);
     626     2039562 :         *isNull = fcinfo->isnull;
     627     2039562 :         *isDone = rsinfo.isDone;
     628             : 
     629     2039562 :         pgstat_end_function_usage(&fcusage,
     630     2039562 :                                   rsinfo.isDone != ExprMultipleResult);
     631             :     }
     632             :     else
     633             :     {
     634             :         /* for a strict SRF, result for NULL is an empty set */
     635       53950 :         result = (Datum) 0;
     636       53950 :         *isNull = true;
     637       53950 :         *isDone = ExprEndResult;
     638             :     }
     639             : 
     640             :     /* Which protocol does function want to use? */
     641     2093512 :     if (rsinfo.returnMode == SFRM_ValuePerCall)
     642             :     {
     643     2080422 :         if (*isDone != ExprEndResult)
     644             :         {
     645             :             /*
     646             :              * Save the current argument values to re-use on the next call.
     647             :              */
     648     1939122 :             if (*isDone == ExprMultipleResult)
     649             :             {
     650     1939116 :                 fcache->setArgsValid = true;
     651             :                 /* Register cleanup callback if we didn't already */
     652     1939116 :                 if (!fcache->shutdown_reg)
     653             :                 {
     654       26658 :                     RegisterExprContextCallback(econtext,
     655             :                                                 ShutdownSetExpr,
     656             :                                                 PointerGetDatum(fcache));
     657       26658 :                     fcache->shutdown_reg = true;
     658             :                 }
     659             :             }
     660             :         }
     661             :     }
     662       13090 :     else if (rsinfo.returnMode == SFRM_Materialize)
     663             :     {
     664             :         /* check we're on the same page as the function author */
     665       13090 :         if (rsinfo.isDone != ExprSingleResult)
     666           0 :             ereport(ERROR,
     667             :                     (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
     668             :                      errmsg("table-function protocol for materialize mode was not followed")));
     669       13090 :         if (rsinfo.setResult != NULL)
     670             :         {
     671             :             /* prepare to return values from the tuplestore */
     672       13066 :             ExecPrepareTuplestoreResult(fcache, econtext,
     673             :                                         rsinfo.setResult,
     674             :                                         rsinfo.setDesc);
     675             :             /* loop back to top to start returning from tuplestore */
     676       13066 :             goto restart;
     677             :         }
     678             :         /* if setResult was left null, treat it as empty set */
     679          24 :         *isDone = ExprEndResult;
     680          24 :         *isNull = true;
     681          24 :         result = (Datum) 0;
     682             :     }
     683             :     else
     684           0 :         ereport(ERROR,
     685             :                 (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
     686             :                  errmsg("unrecognized table-function returnMode: %d",
     687             :                         (int) rsinfo.returnMode)));
     688             : 
     689     2080446 :     return result;
     690             : }
     691             : 
     692             : 
     693             : /*
     694             :  * init_sexpr - initialize a SetExprState node during first use
     695             :  */
     696             : static void
     697       66372 : init_sexpr(Oid foid, Oid input_collation, Expr *node,
     698             :            SetExprState *sexpr, PlanState *parent,
     699             :            MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF)
     700             : {
     701             :     AclResult   aclresult;
     702       66372 :     size_t      numargs = list_length(sexpr->args);
     703             : 
     704             :     /* Check permission to call function */
     705       66372 :     aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
     706       66372 :     if (aclresult != ACLCHECK_OK)
     707          12 :         aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
     708       66360 :     InvokeFunctionExecuteHook(foid);
     709             : 
     710             :     /*
     711             :      * Safety check on nargs.  Under normal circumstances this should never
     712             :      * fail, as parser should check sooner.  But possibly it might fail if
     713             :      * server has been compiled with FUNC_MAX_ARGS smaller than some functions
     714             :      * declared in pg_proc?
     715             :      */
     716       66360 :     if (list_length(sexpr->args) > FUNC_MAX_ARGS)
     717           0 :         ereport(ERROR,
     718             :                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
     719             :                  errmsg_plural("cannot pass more than %d argument to a function",
     720             :                                "cannot pass more than %d arguments to a function",
     721             :                                FUNC_MAX_ARGS,
     722             :                                FUNC_MAX_ARGS)));
     723             : 
     724             :     /* Set up the primary fmgr lookup information */
     725       66360 :     fmgr_info_cxt(foid, &(sexpr->func), sexprCxt);
     726       66360 :     fmgr_info_set_expr((Node *) sexpr->expr, &(sexpr->func));
     727             : 
     728             :     /* Initialize the function call parameter struct as well */
     729       66360 :     sexpr->fcinfo =
     730       66360 :         (FunctionCallInfo) palloc(SizeForFunctionCallInfo(numargs));
     731       66360 :     InitFunctionCallInfoData(*sexpr->fcinfo, &(sexpr->func),
     732             :                              numargs,
     733             :                              input_collation, NULL, NULL);
     734             : 
     735             :     /* If function returns set, check if that's allowed by caller */
     736       66360 :     if (sexpr->func.fn_retset && !allowSRF)
     737           0 :         ereport(ERROR,
     738             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     739             :                  errmsg("set-valued function called in context that cannot accept a set"),
     740             :                  parent ? executor_errposition(parent->state,
     741             :                                                exprLocation((Node *) node)) : 0));
     742             : 
     743             :     /* Otherwise, caller should have marked the sexpr correctly */
     744             :     Assert(sexpr->func.fn_retset == sexpr->funcReturnsSet);
     745             : 
     746             :     /* If function returns set, prepare expected tuple descriptor */
     747       66360 :     if (sexpr->func.fn_retset && needDescForSRF)
     748        6732 :     {
     749             :         TypeFuncClass functypclass;
     750             :         Oid         funcrettype;
     751             :         TupleDesc   tupdesc;
     752             :         MemoryContext oldcontext;
     753             : 
     754        6732 :         functypclass = get_expr_result_type(sexpr->func.fn_expr,
     755             :                                             &funcrettype,
     756             :                                             &tupdesc);
     757             : 
     758             :         /* Must save tupdesc in sexpr's context */
     759        6732 :         oldcontext = MemoryContextSwitchTo(sexprCxt);
     760             : 
     761        6732 :         if (functypclass == TYPEFUNC_COMPOSITE ||
     762             :             functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
     763             :         {
     764             :             /* Composite data type, e.g. a table's row type */
     765             :             Assert(tupdesc);
     766             :             /* Must copy it out of typcache for safety */
     767         756 :             sexpr->funcResultDesc = CreateTupleDescCopy(tupdesc);
     768         756 :             sexpr->funcReturnsTuple = true;
     769             :         }
     770        5976 :         else if (functypclass == TYPEFUNC_SCALAR)
     771             :         {
     772             :             /* Base data type, i.e. scalar */
     773        5892 :             tupdesc = CreateTemplateTupleDesc(1);
     774        5892 :             TupleDescInitEntry(tupdesc,
     775             :                                (AttrNumber) 1,
     776             :                                NULL,
     777             :                                funcrettype,
     778             :                                -1,
     779             :                                0);
     780        5892 :             sexpr->funcResultDesc = tupdesc;
     781        5892 :             sexpr->funcReturnsTuple = false;
     782             :         }
     783          84 :         else if (functypclass == TYPEFUNC_RECORD)
     784             :         {
     785             :             /* This will work if function doesn't need an expectedDesc */
     786          84 :             sexpr->funcResultDesc = NULL;
     787          84 :             sexpr->funcReturnsTuple = true;
     788             :         }
     789             :         else
     790             :         {
     791             :             /* Else, we will fail if function needs an expectedDesc */
     792           0 :             sexpr->funcResultDesc = NULL;
     793             :         }
     794             : 
     795        6732 :         MemoryContextSwitchTo(oldcontext);
     796             :     }
     797             :     else
     798       59628 :         sexpr->funcResultDesc = NULL;
     799             : 
     800             :     /* Initialize additional state */
     801       66360 :     sexpr->funcResultStore = NULL;
     802       66360 :     sexpr->funcResultSlot = NULL;
     803       66360 :     sexpr->shutdown_reg = false;
     804       66360 : }
     805             : 
     806             : /*
     807             :  * callback function in case a SetExprState needs to be shut down before it
     808             :  * has been run to completion
     809             :  */
     810             : static void
     811       27562 : ShutdownSetExpr(Datum arg)
     812             : {
     813       27562 :     SetExprState *sexpr = castNode(SetExprState, DatumGetPointer(arg));
     814             : 
     815             :     /* If we have a slot, make sure it's let go of any tuplestore pointer */
     816       27562 :     if (sexpr->funcResultSlot)
     817         910 :         ExecClearTuple(sexpr->funcResultSlot);
     818             : 
     819             :     /* Release any open tuplestore */
     820       27562 :     if (sexpr->funcResultStore)
     821          36 :         tuplestore_end(sexpr->funcResultStore);
     822       27562 :     sexpr->funcResultStore = NULL;
     823             : 
     824             :     /* Clear any active set-argument state */
     825       27562 :     sexpr->setArgsValid = false;
     826             : 
     827             :     /* execUtils will deregister the callback... */
     828       27562 :     sexpr->shutdown_reg = false;
     829       27562 : }
     830             : 
     831             : /*
     832             :  * Evaluate arguments for a function.
     833             :  */
     834             : static void
     835      276932 : ExecEvalFuncArgs(FunctionCallInfo fcinfo,
     836             :                  List *argList,
     837             :                  ExprContext *econtext)
     838             : {
     839             :     int         i;
     840             :     ListCell   *arg;
     841             : 
     842      276932 :     i = 0;
     843      666796 :     foreach(arg, argList)
     844             :     {
     845      389880 :         ExprState  *argstate = (ExprState *) lfirst(arg);
     846             : 
     847      389880 :         fcinfo->args[i].value = ExecEvalExpr(argstate,
     848             :                                              econtext,
     849             :                                              &fcinfo->args[i].isnull);
     850      389864 :         i++;
     851             :     }
     852             : 
     853             :     Assert(i == fcinfo->nargs);
     854      276916 : }
     855             : 
     856             : /*
     857             :  *      ExecPrepareTuplestoreResult
     858             :  *
     859             :  * Subroutine for ExecMakeFunctionResultSet: prepare to extract rows from a
     860             :  * tuplestore function result.  We must set up a funcResultSlot (unless
     861             :  * already done in a previous call cycle) and verify that the function
     862             :  * returned the expected tuple descriptor.
     863             :  */
     864             : static void
     865       13066 : ExecPrepareTuplestoreResult(SetExprState *sexpr,
     866             :                             ExprContext *econtext,
     867             :                             Tuplestorestate *resultStore,
     868             :                             TupleDesc resultDesc)
     869             : {
     870       13066 :     sexpr->funcResultStore = resultStore;
     871             : 
     872       13066 :     if (sexpr->funcResultSlot == NULL)
     873             :     {
     874             :         /* Create a slot so we can read data out of the tuplestore */
     875             :         TupleDesc   slotDesc;
     876             :         MemoryContext oldcontext;
     877             : 
     878         910 :         oldcontext = MemoryContextSwitchTo(sexpr->func.fn_mcxt);
     879             : 
     880             :         /*
     881             :          * If we were not able to determine the result rowtype from context,
     882             :          * and the function didn't return a tupdesc, we have to fail.
     883             :          */
     884         910 :         if (sexpr->funcResultDesc)
     885         868 :             slotDesc = sexpr->funcResultDesc;
     886          42 :         else if (resultDesc)
     887             :         {
     888             :             /* don't assume resultDesc is long-lived */
     889          42 :             slotDesc = CreateTupleDescCopy(resultDesc);
     890             :         }
     891             :         else
     892             :         {
     893           0 :             ereport(ERROR,
     894             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     895             :                      errmsg("function returning setof record called in "
     896             :                             "context that cannot accept type record")));
     897             :             slotDesc = NULL;    /* keep compiler quiet */
     898             :         }
     899             : 
     900         910 :         sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc,
     901             :                                                          &TTSOpsMinimalTuple);
     902         910 :         MemoryContextSwitchTo(oldcontext);
     903             :     }
     904             : 
     905             :     /*
     906             :      * If function provided a tupdesc, cross-check it.  We only really need to
     907             :      * do this for functions returning RECORD, but might as well do it always.
     908             :      */
     909       13066 :     if (resultDesc)
     910             :     {
     911       13066 :         if (sexpr->funcResultDesc)
     912       13012 :             tupledesc_match(sexpr->funcResultDesc, resultDesc);
     913             : 
     914             :         /*
     915             :          * If it is a dynamically-allocated TupleDesc, free it: it is
     916             :          * typically allocated in a per-query context, so we must avoid
     917             :          * leaking it across multiple usages.
     918             :          */
     919       13066 :         if (resultDesc->tdrefcount == -1)
     920       13066 :             FreeTupleDesc(resultDesc);
     921             :     }
     922             : 
     923             :     /* Register cleanup callback if we didn't already */
     924       13066 :     if (!sexpr->shutdown_reg)
     925             :     {
     926         910 :         RegisterExprContextCallback(econtext,
     927             :                                     ShutdownSetExpr,
     928             :                                     PointerGetDatum(sexpr));
     929         910 :         sexpr->shutdown_reg = true;
     930             :     }
     931       13066 : }
     932             : 
     933             : /*
     934             :  * Check that function result tuple type (src_tupdesc) matches or can
     935             :  * be considered to match what the query expects (dst_tupdesc). If
     936             :  * they don't match, ereport.
     937             :  *
     938             :  * We really only care about number of attributes and data type.
     939             :  * Also, we can ignore type mismatch on columns that are dropped in the
     940             :  * destination type, so long as the physical storage matches.  This is
     941             :  * helpful in some cases involving out-of-date cached plans.
     942             :  */
     943             : static void
     944       88954 : tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
     945             : {
     946             :     int         i;
     947             : 
     948       88954 :     if (dst_tupdesc->natts != src_tupdesc->natts)
     949          30 :         ereport(ERROR,
     950             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     951             :                  errmsg("function return row and query-specified return row do not match"),
     952             :                  errdetail_plural("Returned row contains %d attribute, but query expects %d.",
     953             :                                   "Returned row contains %d attributes, but query expects %d.",
     954             :                                   src_tupdesc->natts,
     955             :                                   src_tupdesc->natts, dst_tupdesc->natts)));
     956             : 
     957      455382 :     for (i = 0; i < dst_tupdesc->natts; i++)
     958             :     {
     959      366488 :         Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
     960      366488 :         Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
     961             : 
     962      366488 :         if (IsBinaryCoercible(sattr->atttypid, dattr->atttypid))
     963      366458 :             continue;           /* no worries */
     964          30 :         if (!dattr->attisdropped)
     965          30 :             ereport(ERROR,
     966             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
     967             :                      errmsg("function return row and query-specified return row do not match"),
     968             :                      errdetail("Returned type %s at ordinal position %d, but query expects %s.",
     969             :                                format_type_be(sattr->atttypid),
     970             :                                i + 1,
     971             :                                format_type_be(dattr->atttypid))));
     972             : 
     973           0 :         if (dattr->attlen != sattr->attlen ||
     974           0 :             dattr->attalign != sattr->attalign)
     975           0 :             ereport(ERROR,
     976             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
     977             :                      errmsg("function return row and query-specified return row do not match"),
     978             :                      errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
     979             :                                i + 1)));
     980             :     }
     981       88894 : }

Generated by: LCOV version 1.14