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