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