PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
execSRF.c
Go to the documentation of this file.
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"
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 */
37static void init_sexpr(Oid foid, Oid input_collation, Expr *node,
38 SetExprState *sexpr, PlanState *parent,
39 MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF);
40static void ShutdownSetExpr(Datum arg);
41static void ExecEvalFuncArgs(FunctionCallInfo fcinfo,
42 List *argList, ExprContext *econtext);
44 ExprContext *econtext,
45 Tuplestorestate *resultStore,
46 TupleDesc resultDesc);
47static 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 */
57 ExprContext *econtext, PlanState *parent)
58{
60
61 state->funcReturnsSet = false;
62 state->expr = expr;
63 state->func.fn_oid = InvalidOid;
64
65 /*
66 * Normally the passed expression tree will be a FuncExpr, since the
67 * grammar only allows a function call at the top level of a table
68 * function reference. However, if the function doesn't return set then
69 * the planner might have replaced the function call via constant-folding
70 * or inlining. So if we see any other kind of expression node, execute
71 * it via the general ExecEvalExpr() code. That code path will not
72 * support set-returning functions buried in the expression, though.
73 */
74 if (IsA(expr, FuncExpr))
75 {
76 FuncExpr *func = (FuncExpr *) expr;
77
78 state->funcReturnsSet = func->funcretset;
79 state->args = ExecInitExprList(func->args, parent);
80
81 init_sexpr(func->funcid, func->inputcollid, expr, state, parent,
82 econtext->ecxt_per_query_memory, func->funcretset, false);
83 }
84 else
85 {
86 state->elidedFuncState = ExecInitExpr(expr, parent);
87 }
88
89 return state;
90}
91
92/*
93 * ExecMakeTableFunctionResult
94 *
95 * Evaluate a table function, producing a materialized result in a Tuplestore
96 * object.
97 *
98 * This is used by nodeFunctionscan.c.
99 */
102 ExprContext *econtext,
103 MemoryContext argContext,
104 TupleDesc expectedDesc,
105 bool randomAccess)
106{
107 Tuplestorestate *tupstore = NULL;
108 TupleDesc tupdesc = NULL;
109 Oid funcrettype;
110 bool returnsTuple;
111 bool returnsSet = false;
112 FunctionCallInfo fcinfo;
114 ReturnSetInfo rsinfo;
115 HeapTupleData tmptup;
116 MemoryContext callerContext;
117 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 MemoryContextReset(argContext);
133 callerContext = MemoryContextSwitchTo(argContext);
134
135 funcrettype = exprType((Node *) setexpr->expr);
136
137 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 rsinfo.type = T_ReturnSetInfo;
147 rsinfo.econtext = econtext;
148 rsinfo.expectedDesc = expectedDesc;
150 if (randomAccess)
153 /* isDone is filled below */
154 rsinfo.setResult = NULL;
155 rsinfo.setDesc = NULL;
156
157 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 if (!setexpr->elidedFuncState)
170 {
171 /*
172 * This path is similar to ExecMakeFunctionResultSet.
173 */
174 returnsSet = setexpr->funcReturnsSet;
175 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 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 if (setexpr->func.fn_strict)
189 {
190 int i;
191
192 for (i = 0; i < fcinfo->nargs; i++)
193 {
194 if (fcinfo->args[i].isnull)
195 goto no_function_result;
196 }
197 }
198 }
199 else
200 {
201 /* Treat setexpr as a generic expression */
202 InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
203 }
204
205 /*
206 * Switch to short-lived context for calling the function or expression.
207 */
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 {
216 Datum result;
217
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 ResetExprContext(econtext);
226
227 /* Call the function or expression one time */
228 if (!setexpr->elidedFuncState)
229 {
230 pgstat_init_function_usage(fcinfo, &fcusage);
231
232 fcinfo->isnull = false;
233 rsinfo.isDone = ExprSingleResult;
234 result = FunctionCallInvoke(fcinfo);
235
237 rsinfo.isDone != ExprMultipleResult);
238 }
239 else
240 {
241 result =
242 ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo->isnull);
243 rsinfo.isDone = ExprSingleResult;
244 }
245
246 /* Which protocol does function want to use? */
247 if (rsinfo.returnMode == SFRM_ValuePerCall)
248 {
249 /*
250 * Check for end of result set.
251 */
252 if (rsinfo.isDone == ExprEndResult)
253 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 if (first_time)
260 {
261 MemoryContext oldcontext =
263
264 tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
265 rsinfo.setResult = tupstore;
266 if (!returnsTuple)
267 {
268 tupdesc = CreateTemplateTupleDesc(1);
269 TupleDescInitEntry(tupdesc,
270 (AttrNumber) 1,
271 "column",
272 funcrettype,
273 -1,
274 0);
275 rsinfo.setDesc = tupdesc;
276 }
277 MemoryContextSwitchTo(oldcontext);
278 }
279
280 /*
281 * Store current resultset item.
282 */
283 if (returnsTuple)
284 {
285 if (!fcinfo->isnull)
286 {
288
289 if (tupdesc == NULL)
290 {
291 MemoryContext oldcontext =
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 */
302 rsinfo.setDesc = tupdesc;
303 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 if (HeapTupleHeaderGetTypeId(td) != tupdesc->tdtypeid ||
312 HeapTupleHeaderGetTypMod(td) != tupdesc->tdtypmod)
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 */
323 tmptup.t_data = td;
324
325 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 int natts = expectedDesc->natts;
338 bool *nullflags;
339
340 nullflags = (bool *) palloc(natts * sizeof(bool));
341 memset(nullflags, true, natts * sizeof(bool));
342 tuplestore_putvalues(tupstore, expectedDesc, NULL, nullflags);
343 }
344 }
345 else
346 {
347 /* Scalar-type case: just store the function result */
348 tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo->isnull);
349 }
350
351 /*
352 * Are we done?
353 */
354 if (rsinfo.isDone != ExprMultipleResult)
355 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 if (!returnsSet)
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 else if (rsinfo.returnMode == SFRM_Materialize)
368 {
369 /* check we're on the same page as the function author */
370 if (!first_time || rsinfo.isDone != ExprSingleResult || !returnsSet)
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 break;
376 }
377 else
379 (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
380 errmsg("unrecognized table-function returnMode: %d",
381 (int) rsinfo.returnMode)));
382
383 first_time = false;
384 }
385
386no_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 if (rsinfo.setResult == NULL)
395 {
396 MemoryContext oldcontext =
398
399 tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
400 rsinfo.setResult = tupstore;
401 MemoryContextSwitchTo(oldcontext);
402
403 if (!returnsSet)
404 {
405 int natts = expectedDesc->natts;
406 bool *nullflags;
407
408 nullflags = (bool *) palloc(natts * sizeof(bool));
409 memset(nullflags, true, natts * sizeof(bool));
410 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 if (rsinfo.setDesc)
419 {
420 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 if (rsinfo.setDesc->tdrefcount == -1)
428 FreeTupleDesc(rsinfo.setDesc);
429 }
430
431 MemoryContextSwitchTo(callerContext);
432
433 /* All done, pass back the tuplestore */
434 return rsinfo.setResult;
435}
436
437
438/*
439 * Prepare targetlist SRF function call for execution.
440 *
441 * This is used by nodeProjectSet.c.
442 */
445 ExprContext *econtext, PlanState *parent)
446{
448
449 state->funcReturnsSet = true;
450 state->expr = expr;
451 state->func.fn_oid = InvalidOid;
452
453 /*
454 * Initialize metadata. The expression node could be either a FuncExpr or
455 * an OpExpr.
456 */
457 if (IsA(expr, FuncExpr))
458 {
459 FuncExpr *func = (FuncExpr *) expr;
460
461 state->args = ExecInitExprList(func->args, parent);
462 init_sexpr(func->funcid, func->inputcollid, expr, state, parent,
463 econtext->ecxt_per_query_memory, true, true);
464 }
465 else if (IsA(expr, OpExpr))
466 {
467 OpExpr *op = (OpExpr *) expr;
468
469 state->args = ExecInitExprList(op->args, parent);
470 init_sexpr(op->opfuncid, op->inputcollid, expr, state, parent,
471 econtext->ecxt_per_query_memory, true, true);
472 }
473 else
474 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 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 */
496Datum
498 ExprContext *econtext,
499 MemoryContext argContext,
500 bool *isNull,
501 ExprDoneCond *isDone)
502{
504 Datum result;
505 FunctionCallInfo fcinfo;
507 ReturnSetInfo rsinfo;
508 bool callit;
509 int i;
510
511restart:
512
513 /* Guard against stack overflow due to overly complex expressions */
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 if (fcache->funcResultStore)
522 {
523 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 oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
533 foundTup = tuplestore_gettupleslot(fcache->funcResultStore, true, false,
534 fcache->funcResultSlot);
535 MemoryContextSwitchTo(oldContext);
536
537 if (foundTup)
538 {
539 *isDone = ExprMultipleResult;
540 if (fcache->funcReturnsTuple)
541 {
542 /* We must return the whole tuple as a Datum. */
543 *isNull = false;
545 }
546 else
547 {
548 /* Extract the first column and return it as a scalar. */
549 return slot_getattr(fcache->funcResultSlot, 1, isNull);
550 }
551 }
552 /* Exhausted the tuplestore, so clean up */
554 fcache->funcResultStore = NULL;
555 *isDone = ExprEndResult;
556 *isNull = true;
557 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 fcinfo = fcache->fcinfo;
571 arguments = fcache->args;
572 if (!fcache->setArgsValid)
573 {
574 MemoryContext oldContext = MemoryContextSwitchTo(argContext);
575
576 ExecEvalFuncArgs(fcinfo, arguments, econtext);
577 MemoryContextSwitchTo(oldContext);
578 }
579 else
580 {
581 /* Reset flag (we may set it again below) */
582 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 fcinfo->resultinfo = (Node *) &rsinfo;
591 rsinfo.type = T_ReturnSetInfo;
592 rsinfo.econtext = econtext;
593 rsinfo.expectedDesc = fcache->funcResultDesc;
595 /* note we do not set SFRM_Materialize_Random or _Preferred */
597 /* isDone is filled below */
598 rsinfo.setResult = NULL;
599 rsinfo.setDesc = NULL;
600
601 /*
602 * If function is strict, and there are any NULL arguments, skip calling
603 * the function.
604 */
605 callit = true;
606 if (fcache->func.fn_strict)
607 {
608 for (i = 0; i < fcinfo->nargs; i++)
609 {
610 if (fcinfo->args[i].isnull)
611 {
612 callit = false;
613 break;
614 }
615 }
616 }
617
618 if (callit)
619 {
620 pgstat_init_function_usage(fcinfo, &fcusage);
621
622 fcinfo->isnull = false;
623 rsinfo.isDone = ExprSingleResult;
624 result = FunctionCallInvoke(fcinfo);
625 *isNull = fcinfo->isnull;
626 *isDone = rsinfo.isDone;
627
629 rsinfo.isDone != ExprMultipleResult);
630 }
631 else
632 {
633 /* for a strict SRF, result for NULL is an empty set */
634 result = (Datum) 0;
635 *isNull = true;
636 *isDone = ExprEndResult;
637 }
638
639 /* Which protocol does function want to use? */
640 if (rsinfo.returnMode == SFRM_ValuePerCall)
641 {
642 if (*isDone != ExprEndResult)
643 {
644 /*
645 * Save the current argument values to re-use on the next call.
646 */
647 if (*isDone == ExprMultipleResult)
648 {
649 fcache->setArgsValid = true;
650 /* Register cleanup callback if we didn't already */
651 if (!fcache->shutdown_reg)
652 {
655 PointerGetDatum(fcache));
656 fcache->shutdown_reg = true;
657 }
658 }
659 }
660 }
661 else if (rsinfo.returnMode == SFRM_Materialize)
662 {
663 /* check we're on the same page as the function author */
664 if (rsinfo.isDone != ExprSingleResult)
666 (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
667 errmsg("table-function protocol for materialize mode was not followed")));
668 if (rsinfo.setResult != NULL)
669 {
670 /* prepare to return values from the tuplestore */
671 ExecPrepareTuplestoreResult(fcache, econtext,
672 rsinfo.setResult,
673 rsinfo.setDesc);
674 /* loop back to top to start returning from tuplestore */
675 goto restart;
676 }
677 /* if setResult was left null, treat it as empty set */
678 *isDone = ExprEndResult;
679 *isNull = true;
680 result = (Datum) 0;
681 }
682 else
684 (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
685 errmsg("unrecognized table-function returnMode: %d",
686 (int) rsinfo.returnMode)));
687
688 return result;
689}
690
691
692/*
693 * init_sexpr - initialize a SetExprState node during first use
694 */
695static void
696init_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 size_t numargs = list_length(sexpr->args);
702
703 /* Check permission to call function */
704 aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
705 if (aclresult != ACLCHECK_OK)
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 if (list_length(sexpr->args) > FUNC_MAX_ARGS)
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",
721 FUNC_MAX_ARGS)));
722
723 /* Set up the primary fmgr lookup information */
724 fmgr_info_cxt(foid, &(sexpr->func), sexprCxt);
725 fmgr_info_set_expr((Node *) sexpr->expr, &(sexpr->func));
726
727 /* Initialize the function call parameter struct as well */
728 sexpr->fcinfo =
730 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 if (sexpr->func.fn_retset && !allowSRF)
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 if (sexpr->func.fn_retset && needDescForSRF)
747 {
748 TypeFuncClass functypclass;
749 Oid funcrettype;
750 TupleDesc tupdesc;
751 MemoryContext oldcontext;
752
753 functypclass = get_expr_result_type(sexpr->func.fn_expr,
754 &funcrettype,
755 &tupdesc);
756
757 /* Must save tupdesc in sexpr's context */
758 oldcontext = MemoryContextSwitchTo(sexprCxt);
759
760 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 sexpr->funcResultDesc = CreateTupleDescCopy(tupdesc);
767 sexpr->funcReturnsTuple = true;
768 }
769 else if (functypclass == TYPEFUNC_SCALAR)
770 {
771 /* Base data type, i.e. scalar */
772 tupdesc = CreateTemplateTupleDesc(1);
773 TupleDescInitEntry(tupdesc,
774 (AttrNumber) 1,
775 NULL,
776 funcrettype,
777 -1,
778 0);
779 sexpr->funcResultDesc = tupdesc;
780 sexpr->funcReturnsTuple = false;
781 }
782 else if (functypclass == TYPEFUNC_RECORD)
783 {
784 /* This will work if function doesn't need an expectedDesc */
785 sexpr->funcResultDesc = NULL;
786 sexpr->funcReturnsTuple = true;
787 }
788 else
789 {
790 /* Else, we will fail if function needs an expectedDesc */
791 sexpr->funcResultDesc = NULL;
792 }
793
794 MemoryContextSwitchTo(oldcontext);
795 }
796 else
797 sexpr->funcResultDesc = NULL;
798
799 /* Initialize additional state */
800 sexpr->funcResultStore = NULL;
801 sexpr->funcResultSlot = NULL;
802 sexpr->shutdown_reg = false;
803}
804
805/*
806 * callback function in case a SetExprState needs to be shut down before it
807 * has been run to completion
808 */
809static void
811{
813
814 /* If we have a slot, make sure it's let go of any tuplestore pointer */
815 if (sexpr->funcResultSlot)
817
818 /* Release any open tuplestore */
819 if (sexpr->funcResultStore)
821 sexpr->funcResultStore = NULL;
822
823 /* Clear any active set-argument state */
824 sexpr->setArgsValid = false;
825
826 /* execUtils will deregister the callback... */
827 sexpr->shutdown_reg = false;
828}
829
830/*
831 * Evaluate arguments for a function.
832 */
833static void
835 List *argList,
836 ExprContext *econtext)
837{
838 int i;
839 ListCell *arg;
840
841 i = 0;
842 foreach(arg, argList)
843 {
844 ExprState *argstate = (ExprState *) lfirst(arg);
845
846 fcinfo->args[i].value = ExecEvalExpr(argstate,
847 econtext,
848 &fcinfo->args[i].isnull);
849 i++;
850 }
851
852 Assert(i == fcinfo->nargs);
853}
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 */
863static void
865 ExprContext *econtext,
866 Tuplestorestate *resultStore,
867 TupleDesc resultDesc)
868{
869 sexpr->funcResultStore = resultStore;
870
871 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 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 if (sexpr->funcResultDesc)
884 slotDesc = sexpr->funcResultDesc;
885 else if (resultDesc)
886 {
887 /* don't assume resultDesc is long-lived */
888 slotDesc = CreateTupleDescCopy(resultDesc);
889 }
890 else
891 {
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
901 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 if (resultDesc)
909 {
910 if (sexpr->funcResultDesc)
911 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 if (resultDesc->tdrefcount == -1)
919 FreeTupleDesc(resultDesc);
920 }
921
922 /* Register cleanup callback if we didn't already */
923 if (!sexpr->shutdown_reg)
924 {
927 PointerGetDatum(sexpr));
928 sexpr->shutdown_reg = true;
929 }
930}
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 */
942static void
943tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
944{
945 int i;
946
947 if (dst_tupdesc->natts != src_tupdesc->natts)
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 for (i = 0; i < dst_tupdesc->natts; i++)
957 {
958 Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
959 Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
960
961 if (IsBinaryCoercible(sattr->atttypid, dattr->atttypid))
962 continue; /* no worries */
963 if (!dattr->attisdropped)
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 if (dattr->attlen != sattr->attlen ||
973 dattr->attalign != sattr->attalign)
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}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3810
int16 AttrNumber
Definition: attnum.h:21
#define Assert(condition)
Definition: c.h:812
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1180
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1295
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:138
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:330
static void init_sexpr(Oid foid, Oid input_collation, Expr *node, SetExprState *sexpr, PlanState *parent, MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF)
Definition: execSRF.c:696
SetExprState * ExecInitFunctionResultSet(Expr *expr, ExprContext *econtext, PlanState *parent)
Definition: execSRF.c:444
Tuplestorestate * ExecMakeTableFunctionResult(SetExprState *setexpr, ExprContext *econtext, MemoryContext argContext, TupleDesc expectedDesc, bool randomAccess)
Definition: execSRF.c:101
Datum ExecMakeFunctionResultSet(SetExprState *fcache, ExprContext *econtext, MemoryContext argContext, bool *isNull, ExprDoneCond *isDone)
Definition: execSRF.c:497
SetExprState * ExecInitTableFunctionResult(Expr *expr, ExprContext *econtext, PlanState *parent)
Definition: execSRF.c:56
static void ExecEvalFuncArgs(FunctionCallInfo fcinfo, List *argList, ExprContext *econtext)
Definition: execSRF.c:834
static void ShutdownSetExpr(Datum arg)
Definition: execSRF.c:810
static void ExecPrepareTuplestoreResult(SetExprState *sexpr, ExprContext *econtext, Tuplestorestate *resultStore, TupleDesc resultDesc)
Definition: execSRF.c:864
static void tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
Definition: execSRF.c:943
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1425
Datum ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
Definition: execTuples.c:1910
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:86
int executor_errposition(EState *estate, int location)
Definition: execUtils.c:915
void RegisterExprContextCallback(ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
Definition: execUtils.c:942
ExprDoneCond
Definition: execnodes.h:305
@ ExprSingleResult
Definition: execnodes.h:306
@ ExprMultipleResult
Definition: execnodes.h:307
@ ExprEndResult
Definition: execnodes.h:308
@ SFRM_Materialize_Preferred
Definition: execnodes.h:322
@ SFRM_ValuePerCall
Definition: execnodes.h:319
@ SFRM_Materialize_Random
Definition: execnodes.h:321
@ SFRM_Materialize
Definition: execnodes.h:320
#define ResetExprContext(econtext)
Definition: executor.h:557
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:346
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:295
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
struct FunctionCallInfoBaseData * FunctionCallInfo
Definition: fmgr.h:38
#define FunctionCallInvoke(fcinfo)
Definition: fmgr.h:172
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
TypeFuncClass get_expr_result_type(Node *expr, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:299
TypeFuncClass
Definition: funcapi.h:147
@ TYPEFUNC_SCALAR
Definition: funcapi.h:148
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
@ TYPEFUNC_RECORD
Definition: funcapi.h:151
@ TYPEFUNC_COMPOSITE_DOMAIN
Definition: funcapi.h:150
int work_mem
Definition: globals.c:130
#define HeapTupleHeaderGetTypMod(tup)
Definition: htup_details.h:466
#define HeapTupleHeaderGetTypeId(tup)
Definition: htup_details.h:456
#define HeapTupleHeaderGetDatumLength(tup)
Definition: htup_details.h:450
int i
Definition: isn.c:72
bool type_is_rowtype(Oid typid)
Definition: lsyscache.c:2655
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1608
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
Oid GetUserId(void)
Definition: miscinit.c:517
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1380
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define makeNode(_type_)
Definition: nodes.h:155
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:213
bool IsBinaryCoercible(Oid srctype, Oid targettype)
@ OBJECT_FUNCTION
Definition: parsenodes.h:2287
#define ACL_EXECUTE
Definition: parsenodes.h:83
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
void * arg
#define FUNC_MAX_ARGS
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
void pgstat_init_function_usage(FunctionCallInfo fcinfo, PgStat_FunctionCallUsage *fcu)
void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContextSwitchTo(old_ctx)
void check_stack_depth(void)
Definition: stack_depth.c:95
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:266
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:265
fmNodePtr fn_expr
Definition: fmgr.h:66
MemoryContext fn_mcxt
Definition: fmgr.h:65
bool fn_retset
Definition: fmgr.h:62
bool fn_strict
Definition: fmgr.h:61
Oid funcid
Definition: primnodes.h:750
List * args
Definition: primnodes.h:768
fmNodePtr resultinfo
Definition: fmgr.h:89
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
uint32 t_len
Definition: htup.h:64
HeapTupleHeader t_data
Definition: htup.h:68
Definition: pg_list.h:54
Definition: nodes.h:129
Datum value
Definition: postgres.h:75
bool isnull
Definition: postgres.h:77
List * args
Definition: primnodes.h:836
EState * state
Definition: execnodes.h:1128
NodeTag type
Definition: execnodes.h:333
SetFunctionReturnMode returnMode
Definition: execnodes.h:339
ExprContext * econtext
Definition: execnodes.h:335
TupleDesc setDesc
Definition: execnodes.h:343
Tuplestorestate * setResult
Definition: execnodes.h:342
TupleDesc expectedDesc
Definition: execnodes.h:336
int allowedModes
Definition: execnodes.h:337
ExprDoneCond isDone
Definition: execnodes.h:340
Expr * expr
Definition: execnodes.h:902
FunctionCallInfo fcinfo
Definition: execnodes.h:962
TupleTableSlot * funcResultSlot
Definition: execnodes.h:925
Tuplestorestate * funcResultStore
Definition: execnodes.h:924
bool funcReturnsSet
Definition: execnodes.h:938
bool shutdown_reg
Definition: execnodes.h:955
bool funcReturnsTuple
Definition: execnodes.h:932
ExprState * elidedFuncState
Definition: execnodes.h:910
TupleDesc funcResultDesc
Definition: execnodes.h:931
FmgrInfo func
Definition: execnodes.h:917
List * args
Definition: execnodes.h:903
bool setArgsValid
Definition: execnodes.h:947
int tdrefcount
Definition: tupdesc.h:132
int32 tdtypmod
Definition: tupdesc.h:131
Oid tdtypeid
Definition: tupdesc.h:130
MemoryContext tts_mcxt
Definition: tuptable.h:128
Definition: regguts.h:323
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:478
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:165
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:235
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:797
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:152
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1130
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:330
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:492
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:764
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:395
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
TupleDesc lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod)
Definition: typcache.c:1954