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-2023, 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 "executor/execdebug.h"
25 : #include "funcapi.h"
26 : #include "miscadmin.h"
27 : #include "nodes/nodeFuncs.h"
28 : #include "parser/parse_coerce.h"
29 : #include "pgstat.h"
30 : #include "utils/acl.h"
31 : #include "utils/builtins.h"
32 : #include "utils/lsyscache.h"
33 : #include "utils/memutils.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 59726 : ExecInitTableFunctionResult(Expr *expr,
58 : ExprContext *econtext, PlanState *parent)
59 : {
60 59726 : SetExprState *state = makeNode(SetExprState);
61 :
62 59726 : state->funcReturnsSet = false;
63 59726 : state->expr = expr;
64 59726 : 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 59726 : if (IsA(expr, FuncExpr))
76 : {
77 59636 : FuncExpr *func = (FuncExpr *) expr;
78 :
79 59636 : state->funcReturnsSet = func->funcretset;
80 59636 : state->args = ExecInitExprList(func->args, parent);
81 :
82 59636 : init_sexpr(func->funcid, func->inputcollid, expr, state, parent,
83 59636 : econtext->ecxt_per_query_memory, func->funcretset, false);
84 : }
85 : else
86 : {
87 90 : state->elidedFuncState = ExecInitExpr(expr, parent);
88 : }
89 :
90 59718 : 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 121928 : ExecMakeTableFunctionResult(SetExprState *setexpr,
103 : ExprContext *econtext,
104 : MemoryContext argContext,
105 : TupleDesc expectedDesc,
106 : bool randomAccess)
107 : {
108 121928 : Tuplestorestate *tupstore = NULL;
109 121928 : TupleDesc tupdesc = NULL;
110 : Oid funcrettype;
111 : bool returnsTuple;
112 121928 : bool returnsSet = false;
113 : FunctionCallInfo fcinfo;
114 : PgStat_FunctionCallUsage fcusage;
115 : ReturnSetInfo rsinfo;
116 : HeapTupleData tmptup;
117 : MemoryContext callerContext;
118 121928 : 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 121928 : MemoryContextReset(argContext);
134 121928 : callerContext = MemoryContextSwitchTo(argContext);
135 :
136 121928 : funcrettype = exprType((Node *) setexpr->expr);
137 :
138 121928 : 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 121928 : rsinfo.type = T_ReturnSetInfo;
148 121928 : rsinfo.econtext = econtext;
149 121928 : rsinfo.expectedDesc = expectedDesc;
150 121928 : rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize | SFRM_Materialize_Preferred);
151 121928 : if (randomAccess)
152 78 : rsinfo.allowedModes |= (int) SFRM_Materialize_Random;
153 121928 : rsinfo.returnMode = SFRM_ValuePerCall;
154 : /* isDone is filled below */
155 121928 : rsinfo.setResult = NULL;
156 121928 : rsinfo.setDesc = NULL;
157 :
158 121928 : 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 121928 : if (!setexpr->elidedFuncState)
171 : {
172 : /*
173 : * This path is similar to ExecMakeFunctionResultSet.
174 : */
175 121838 : returnsSet = setexpr->funcReturnsSet;
176 121838 : 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 121838 : 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 121822 : if (setexpr->func.fn_strict)
190 : {
191 : int i;
192 :
193 239336 : for (i = 0; i < fcinfo->nargs; i++)
194 : {
195 173860 : if (fcinfo->args[i].isnull)
196 39906 : goto no_function_result;
197 : }
198 : }
199 : }
200 : else
201 : {
202 : /* Treat setexpr as a generic expression */
203 90 : InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
204 : }
205 :
206 : /*
207 : * Switch to short-lived context for calling the function or expression.
208 : */
209 82006 : 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 17235952 : {
217 : Datum result;
218 :
219 17317958 : 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 17317956 : ResetExprContext(econtext);
227 :
228 : /* Call the function or expression one time */
229 17317956 : if (!setexpr->elidedFuncState)
230 : {
231 17317866 : pgstat_init_function_usage(fcinfo, &fcusage);
232 :
233 17317866 : fcinfo->isnull = false;
234 17317866 : rsinfo.isDone = ExprSingleResult;
235 17317866 : result = FunctionCallInvoke(fcinfo);
236 :
237 17312888 : pgstat_end_function_usage(&fcusage,
238 17312888 : rsinfo.isDone != ExprMultipleResult);
239 : }
240 : else
241 : {
242 90 : result =
243 90 : ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo->isnull);
244 90 : rsinfo.isDone = ExprSingleResult;
245 : }
246 :
247 : /* Which protocol does function want to use? */
248 17312978 : if (rsinfo.returnMode == SFRM_ValuePerCall)
249 : {
250 : /*
251 : * Check for end of result set.
252 : */
253 17295792 : if (rsinfo.isDone == ExprEndResult)
254 77026 : 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 17270218 : if (first_time)
261 : {
262 : MemoryContext oldcontext =
263 58828 : MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
264 :
265 58828 : tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
266 58828 : rsinfo.setResult = tupstore;
267 58828 : if (!returnsTuple)
268 : {
269 28584 : tupdesc = CreateTemplateTupleDesc(1);
270 28584 : TupleDescInitEntry(tupdesc,
271 : (AttrNumber) 1,
272 : "column",
273 : funcrettype,
274 : -1,
275 : 0);
276 28584 : rsinfo.setDesc = tupdesc;
277 : }
278 58828 : MemoryContextSwitchTo(oldcontext);
279 : }
280 :
281 : /*
282 : * Store current resultset item.
283 : */
284 17270218 : if (returnsTuple)
285 : {
286 1518754 : if (!fcinfo->isnull)
287 : {
288 1518692 : HeapTupleHeader td = DatumGetHeapTupleHeader(result);
289 :
290 1518692 : if (tupdesc == NULL)
291 : {
292 : MemoryContext oldcontext =
293 30206 : 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 30206 : tupdesc = lookup_rowtype_tupdesc_copy(HeapTupleHeaderGetTypeId(td),
302 : HeapTupleHeaderGetTypMod(td));
303 30206 : rsinfo.setDesc = tupdesc;
304 30206 : 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 1488486 : if (HeapTupleHeaderGetTypeId(td) != tupdesc->tdtypeid ||
313 1488486 : 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 1518692 : tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
324 1518692 : tmptup.t_data = td;
325 :
326 1518692 : 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 62 : int natts = expectedDesc->natts;
339 : bool *nullflags;
340 :
341 62 : nullflags = (bool *) palloc(natts * sizeof(bool));
342 62 : memset(nullflags, true, natts * sizeof(bool));
343 62 : tuplestore_putvalues(tupstore, expectedDesc, NULL, nullflags);
344 : }
345 : }
346 : else
347 : {
348 : /* Scalar-type case: just store the function result */
349 15751464 : tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo->isnull);
350 : }
351 :
352 : /*
353 : * Are we done?
354 : */
355 17270218 : if (rsinfo.isDone != ExprMultipleResult)
356 34266 : 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 17235952 : 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 17186 : else if (rsinfo.returnMode == SFRM_Materialize)
369 : {
370 : /* check we're on the same page as the function author */
371 17186 : 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 17186 : 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 17235952 : first_time = false;
385 : }
386 :
387 116932 : 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 116932 : if (rsinfo.setResult == NULL)
396 : {
397 : MemoryContext oldcontext =
398 40946 : MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
399 :
400 40946 : tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
401 40946 : rsinfo.setResult = tupstore;
402 40946 : MemoryContextSwitchTo(oldcontext);
403 :
404 40946 : if (!returnsSet)
405 : {
406 14 : int natts = expectedDesc->natts;
407 : bool *nullflags;
408 :
409 14 : nullflags = (bool *) palloc(natts * sizeof(bool));
410 14 : memset(nullflags, true, natts * sizeof(bool));
411 14 : 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 116932 : if (rsinfo.setDesc)
420 : {
421 75942 : 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 75882 : if (rsinfo.setDesc->tdrefcount == -1)
429 75882 : FreeTupleDesc(rsinfo.setDesc);
430 : }
431 :
432 116872 : MemoryContextSwitchTo(callerContext);
433 :
434 : /* All done, pass back the tuplestore */
435 116872 : 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 6736 : ExecInitFunctionResultSet(Expr *expr,
446 : ExprContext *econtext, PlanState *parent)
447 : {
448 6736 : SetExprState *state = makeNode(SetExprState);
449 :
450 6736 : state->funcReturnsSet = true;
451 6736 : state->expr = expr;
452 6736 : state->func.fn_oid = InvalidOid;
453 :
454 : /*
455 : * Initialize metadata. The expression node could be either a FuncExpr or
456 : * an OpExpr.
457 : */
458 6736 : if (IsA(expr, FuncExpr))
459 : {
460 6730 : FuncExpr *func = (FuncExpr *) expr;
461 :
462 6730 : state->args = ExecInitExprList(func->args, parent);
463 6730 : init_sexpr(func->funcid, func->inputcollid, expr, state, parent,
464 : econtext->ecxt_per_query_memory, true, true);
465 : }
466 6 : else if (IsA(expr, OpExpr))
467 : {
468 6 : OpExpr *op = (OpExpr *) expr;
469 :
470 6 : state->args = ExecInitExprList(op->args, parent);
471 6 : 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 6732 : 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 2170240 : 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 2170240 : restart:
513 :
514 : /* Guard against stack overflow due to overly complex expressions */
515 2170240 : 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 2170240 : if (fcache->funcResultStore)
523 : {
524 76090 : 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 76090 : oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
534 76090 : foundTup = tuplestore_gettupleslot(fcache->funcResultStore, true, false,
535 : fcache->funcResultSlot);
536 76090 : MemoryContextSwitchTo(oldContext);
537 :
538 76090 : if (foundTup)
539 : {
540 63060 : *isDone = ExprMultipleResult;
541 63060 : if (fcache->funcReturnsTuple)
542 : {
543 : /* We must return the whole tuple as a Datum. */
544 58918 : *isNull = false;
545 58918 : return ExecFetchSlotHeapTupleDatum(fcache->funcResultSlot);
546 : }
547 : else
548 : {
549 : /* Extract the first column and return it as a scalar. */
550 4142 : return slot_getattr(fcache->funcResultSlot, 1, isNull);
551 : }
552 : }
553 : /* Exhausted the tuplestore, so clean up */
554 13030 : tuplestore_end(fcache->funcResultStore);
555 13030 : fcache->funcResultStore = NULL;
556 13030 : *isDone = ExprEndResult;
557 13030 : *isNull = true;
558 13030 : 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 2094150 : fcinfo = fcache->fcinfo;
572 2094150 : arguments = fcache->args;
573 2094150 : if (!fcache->setArgsValid)
574 : {
575 155094 : MemoryContext oldContext = MemoryContextSwitchTo(argContext);
576 :
577 155094 : ExecEvalFuncArgs(fcinfo, arguments, econtext);
578 155094 : MemoryContextSwitchTo(oldContext);
579 : }
580 : else
581 : {
582 : /* Reset flag (we may set it again below) */
583 1939056 : 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 2094150 : fcinfo->resultinfo = (Node *) &rsinfo;
592 2094150 : rsinfo.type = T_ReturnSetInfo;
593 2094150 : rsinfo.econtext = econtext;
594 2094150 : rsinfo.expectedDesc = fcache->funcResultDesc;
595 2094150 : rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize);
596 : /* note we do not set SFRM_Materialize_Random or _Preferred */
597 2094150 : rsinfo.returnMode = SFRM_ValuePerCall;
598 : /* isDone is filled below */
599 2094150 : rsinfo.setResult = NULL;
600 2094150 : rsinfo.setDesc = NULL;
601 :
602 : /*
603 : * If function is strict, and there are any NULL arguments, skip calling
604 : * the function.
605 : */
606 2094150 : callit = true;
607 2094150 : if (fcache->func.fn_strict)
608 : {
609 5694334 : for (i = 0; i < fcinfo->nargs; i++)
610 : {
611 3658512 : if (fcinfo->args[i].isnull)
612 : {
613 53950 : callit = false;
614 53950 : break;
615 : }
616 : }
617 : }
618 :
619 2094150 : if (callit)
620 : {
621 2040200 : pgstat_init_function_usage(fcinfo, &fcusage);
622 :
623 2040200 : fcinfo->isnull = false;
624 2040200 : rsinfo.isDone = ExprSingleResult;
625 2040200 : result = FunctionCallInvoke(fcinfo);
626 2039562 : *isNull = fcinfo->isnull;
627 2039562 : *isDone = rsinfo.isDone;
628 :
629 2039562 : pgstat_end_function_usage(&fcusage,
630 2039562 : rsinfo.isDone != ExprMultipleResult);
631 : }
632 : else
633 : {
634 : /* for a strict SRF, result for NULL is an empty set */
635 53950 : result = (Datum) 0;
636 53950 : *isNull = true;
637 53950 : *isDone = ExprEndResult;
638 : }
639 :
640 : /* Which protocol does function want to use? */
641 2093512 : if (rsinfo.returnMode == SFRM_ValuePerCall)
642 : {
643 2080422 : if (*isDone != ExprEndResult)
644 : {
645 : /*
646 : * Save the current argument values to re-use on the next call.
647 : */
648 1939122 : if (*isDone == ExprMultipleResult)
649 : {
650 1939116 : fcache->setArgsValid = true;
651 : /* Register cleanup callback if we didn't already */
652 1939116 : if (!fcache->shutdown_reg)
653 : {
654 26658 : RegisterExprContextCallback(econtext,
655 : ShutdownSetExpr,
656 : PointerGetDatum(fcache));
657 26658 : fcache->shutdown_reg = true;
658 : }
659 : }
660 : }
661 : }
662 13090 : else if (rsinfo.returnMode == SFRM_Materialize)
663 : {
664 : /* check we're on the same page as the function author */
665 13090 : 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 13090 : if (rsinfo.setResult != NULL)
670 : {
671 : /* prepare to return values from the tuplestore */
672 13066 : ExecPrepareTuplestoreResult(fcache, econtext,
673 : rsinfo.setResult,
674 : rsinfo.setDesc);
675 : /* loop back to top to start returning from tuplestore */
676 13066 : goto restart;
677 : }
678 : /* if setResult was left null, treat it as empty set */
679 24 : *isDone = ExprEndResult;
680 24 : *isNull = true;
681 24 : 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 2080446 : return result;
690 : }
691 :
692 :
693 : /*
694 : * init_sexpr - initialize a SetExprState node during first use
695 : */
696 : static void
697 66372 : 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 66372 : size_t numargs = list_length(sexpr->args);
703 :
704 : /* Check permission to call function */
705 66372 : aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
706 66372 : if (aclresult != ACLCHECK_OK)
707 12 : aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
708 66360 : 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 66360 : 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 66360 : fmgr_info_cxt(foid, &(sexpr->func), sexprCxt);
726 66360 : fmgr_info_set_expr((Node *) sexpr->expr, &(sexpr->func));
727 :
728 : /* Initialize the function call parameter struct as well */
729 66360 : sexpr->fcinfo =
730 66360 : (FunctionCallInfo) palloc(SizeForFunctionCallInfo(numargs));
731 66360 : 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 66360 : 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 66360 : if (sexpr->func.fn_retset && needDescForSRF)
748 6732 : {
749 : TypeFuncClass functypclass;
750 : Oid funcrettype;
751 : TupleDesc tupdesc;
752 : MemoryContext oldcontext;
753 :
754 6732 : functypclass = get_expr_result_type(sexpr->func.fn_expr,
755 : &funcrettype,
756 : &tupdesc);
757 :
758 : /* Must save tupdesc in sexpr's context */
759 6732 : oldcontext = MemoryContextSwitchTo(sexprCxt);
760 :
761 6732 : 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 756 : sexpr->funcResultDesc = CreateTupleDescCopy(tupdesc);
768 756 : sexpr->funcReturnsTuple = true;
769 : }
770 5976 : else if (functypclass == TYPEFUNC_SCALAR)
771 : {
772 : /* Base data type, i.e. scalar */
773 5892 : tupdesc = CreateTemplateTupleDesc(1);
774 5892 : TupleDescInitEntry(tupdesc,
775 : (AttrNumber) 1,
776 : NULL,
777 : funcrettype,
778 : -1,
779 : 0);
780 5892 : sexpr->funcResultDesc = tupdesc;
781 5892 : sexpr->funcReturnsTuple = false;
782 : }
783 84 : else if (functypclass == TYPEFUNC_RECORD)
784 : {
785 : /* This will work if function doesn't need an expectedDesc */
786 84 : sexpr->funcResultDesc = NULL;
787 84 : sexpr->funcReturnsTuple = true;
788 : }
789 : else
790 : {
791 : /* Else, we will fail if function needs an expectedDesc */
792 0 : sexpr->funcResultDesc = NULL;
793 : }
794 :
795 6732 : MemoryContextSwitchTo(oldcontext);
796 : }
797 : else
798 59628 : sexpr->funcResultDesc = NULL;
799 :
800 : /* Initialize additional state */
801 66360 : sexpr->funcResultStore = NULL;
802 66360 : sexpr->funcResultSlot = NULL;
803 66360 : sexpr->shutdown_reg = false;
804 66360 : }
805 :
806 : /*
807 : * callback function in case a SetExprState needs to be shut down before it
808 : * has been run to completion
809 : */
810 : static void
811 27562 : ShutdownSetExpr(Datum arg)
812 : {
813 27562 : SetExprState *sexpr = castNode(SetExprState, DatumGetPointer(arg));
814 :
815 : /* If we have a slot, make sure it's let go of any tuplestore pointer */
816 27562 : if (sexpr->funcResultSlot)
817 910 : ExecClearTuple(sexpr->funcResultSlot);
818 :
819 : /* Release any open tuplestore */
820 27562 : if (sexpr->funcResultStore)
821 36 : tuplestore_end(sexpr->funcResultStore);
822 27562 : sexpr->funcResultStore = NULL;
823 :
824 : /* Clear any active set-argument state */
825 27562 : sexpr->setArgsValid = false;
826 :
827 : /* execUtils will deregister the callback... */
828 27562 : sexpr->shutdown_reg = false;
829 27562 : }
830 :
831 : /*
832 : * Evaluate arguments for a function.
833 : */
834 : static void
835 276932 : ExecEvalFuncArgs(FunctionCallInfo fcinfo,
836 : List *argList,
837 : ExprContext *econtext)
838 : {
839 : int i;
840 : ListCell *arg;
841 :
842 276932 : i = 0;
843 666796 : foreach(arg, argList)
844 : {
845 389880 : ExprState *argstate = (ExprState *) lfirst(arg);
846 :
847 389880 : fcinfo->args[i].value = ExecEvalExpr(argstate,
848 : econtext,
849 : &fcinfo->args[i].isnull);
850 389864 : i++;
851 : }
852 :
853 : Assert(i == fcinfo->nargs);
854 276916 : }
855 :
856 : /*
857 : * ExecPrepareTuplestoreResult
858 : *
859 : * Subroutine for ExecMakeFunctionResultSet: prepare to extract rows from a
860 : * tuplestore function result. We must set up a funcResultSlot (unless
861 : * already done in a previous call cycle) and verify that the function
862 : * returned the expected tuple descriptor.
863 : */
864 : static void
865 13066 : ExecPrepareTuplestoreResult(SetExprState *sexpr,
866 : ExprContext *econtext,
867 : Tuplestorestate *resultStore,
868 : TupleDesc resultDesc)
869 : {
870 13066 : sexpr->funcResultStore = resultStore;
871 :
872 13066 : if (sexpr->funcResultSlot == NULL)
873 : {
874 : /* Create a slot so we can read data out of the tuplestore */
875 : TupleDesc slotDesc;
876 : MemoryContext oldcontext;
877 :
878 910 : oldcontext = MemoryContextSwitchTo(sexpr->func.fn_mcxt);
879 :
880 : /*
881 : * If we were not able to determine the result rowtype from context,
882 : * and the function didn't return a tupdesc, we have to fail.
883 : */
884 910 : if (sexpr->funcResultDesc)
885 868 : slotDesc = sexpr->funcResultDesc;
886 42 : else if (resultDesc)
887 : {
888 : /* don't assume resultDesc is long-lived */
889 42 : slotDesc = CreateTupleDescCopy(resultDesc);
890 : }
891 : else
892 : {
893 0 : ereport(ERROR,
894 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
895 : errmsg("function returning setof record called in "
896 : "context that cannot accept type record")));
897 : slotDesc = NULL; /* keep compiler quiet */
898 : }
899 :
900 910 : sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc,
901 : &TTSOpsMinimalTuple);
902 910 : MemoryContextSwitchTo(oldcontext);
903 : }
904 :
905 : /*
906 : * If function provided a tupdesc, cross-check it. We only really need to
907 : * do this for functions returning RECORD, but might as well do it always.
908 : */
909 13066 : if (resultDesc)
910 : {
911 13066 : if (sexpr->funcResultDesc)
912 13012 : tupledesc_match(sexpr->funcResultDesc, resultDesc);
913 :
914 : /*
915 : * If it is a dynamically-allocated TupleDesc, free it: it is
916 : * typically allocated in a per-query context, so we must avoid
917 : * leaking it across multiple usages.
918 : */
919 13066 : if (resultDesc->tdrefcount == -1)
920 13066 : FreeTupleDesc(resultDesc);
921 : }
922 :
923 : /* Register cleanup callback if we didn't already */
924 13066 : if (!sexpr->shutdown_reg)
925 : {
926 910 : RegisterExprContextCallback(econtext,
927 : ShutdownSetExpr,
928 : PointerGetDatum(sexpr));
929 910 : sexpr->shutdown_reg = true;
930 : }
931 13066 : }
932 :
933 : /*
934 : * Check that function result tuple type (src_tupdesc) matches or can
935 : * be considered to match what the query expects (dst_tupdesc). If
936 : * they don't match, ereport.
937 : *
938 : * We really only care about number of attributes and data type.
939 : * Also, we can ignore type mismatch on columns that are dropped in the
940 : * destination type, so long as the physical storage matches. This is
941 : * helpful in some cases involving out-of-date cached plans.
942 : */
943 : static void
944 88954 : tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
945 : {
946 : int i;
947 :
948 88954 : if (dst_tupdesc->natts != src_tupdesc->natts)
949 30 : ereport(ERROR,
950 : (errcode(ERRCODE_DATATYPE_MISMATCH),
951 : errmsg("function return row and query-specified return row do not match"),
952 : errdetail_plural("Returned row contains %d attribute, but query expects %d.",
953 : "Returned row contains %d attributes, but query expects %d.",
954 : src_tupdesc->natts,
955 : src_tupdesc->natts, dst_tupdesc->natts)));
956 :
957 455382 : for (i = 0; i < dst_tupdesc->natts; i++)
958 : {
959 366488 : Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
960 366488 : Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
961 :
962 366488 : if (IsBinaryCoercible(sattr->atttypid, dattr->atttypid))
963 366458 : continue; /* no worries */
964 30 : if (!dattr->attisdropped)
965 30 : ereport(ERROR,
966 : (errcode(ERRCODE_DATATYPE_MISMATCH),
967 : errmsg("function return row and query-specified return row do not match"),
968 : errdetail("Returned type %s at ordinal position %d, but query expects %s.",
969 : format_type_be(sattr->atttypid),
970 : i + 1,
971 : format_type_be(dattr->atttypid))));
972 :
973 0 : if (dattr->attlen != sattr->attlen ||
974 0 : dattr->attalign != sattr->attalign)
975 0 : ereport(ERROR,
976 : (errcode(ERRCODE_DATATYPE_MISMATCH),
977 : errmsg("function return row and query-specified return row do not match"),
978 : errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
979 : i + 1)));
980 : }
981 88894 : }
|