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