Coverage Report

Created: 2026-11-12 07:20

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