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