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

Generated by: LCOV version 1.13