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

Generated by: LCOV version 1.13