Coverage Report

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