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

Generated by: LCOV version 1.11