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