Coverage Report

Created: 2025-10-09 06:07

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