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