1 /*-------------------------------------------------------------------------
4 * Routines implementing the API for set-returning functions
6 * This file serves nodeFunctionscan.c and nodeProjectSet.c, providing
7 * common code for calling set-returning functions according to the
10 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
15 * src/backend/executor/execSRF.c
17 *-------------------------------------------------------------------------
21 #include "access/htup_details.h"
22 #include "catalog/objectaccess.h"
23 #include "catalog/pg_proc.h"
25 #include "miscadmin.h"
26 #include "nodes/nodeFuncs.h"
27 #include "parser/parse_coerce.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"
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
);
51 * Prepare function call in FROM (ROWS FROM) for execution.
53 * This is used by nodeFunctionscan.c.
56 ExecInitTableFunctionResult(Expr
*expr
,
57 ExprContext
*econtext
, PlanState
*parent
)
59 SetExprState
*state
= makeNode(SetExprState
);
61 state
->funcReturnsSet
= false;
63 state
->func
.fn_oid
= InvalidOid
;
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.
74 if (IsA(expr
, FuncExpr
))
76 FuncExpr
*func
= (FuncExpr
*) expr
;
78 state
->funcReturnsSet
= func
->funcretset
;
79 state
->args
= ExecInitExprList(func
->args
, parent
);
81 init_sexpr(func
->funcid
, func
->inputcollid
, expr
, state
, parent
,
82 econtext
->ecxt_per_query_memory
, func
->funcretset
, false);
86 state
->elidedFuncState
= ExecInitExpr(expr
, parent
);
93 * ExecMakeTableFunctionResult
95 * Evaluate a table function, producing a materialized result in a Tuplestore
98 * This is used by nodeFunctionscan.c.
101 ExecMakeTableFunctionResult(SetExprState
*setexpr
,
102 ExprContext
*econtext
,
103 MemoryContext argContext
,
104 TupleDesc expectedDesc
,
107 Tuplestorestate
*tupstore
= NULL
;
108 TupleDesc tupdesc
= NULL
;
111 bool returnsSet
= false;
112 FunctionCallInfo fcinfo
;
113 PgStat_FunctionCallUsage fcusage
;
114 ReturnSetInfo rsinfo
;
115 HeapTupleData tmptup
;
116 MemoryContext callerContext
;
117 bool first_time
= true;
120 * Execute per-tablefunc actions in appropriate context.
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.
132 MemoryContextReset(argContext
);
133 callerContext
= MemoryContextSwitchTo(argContext
);
135 funcrettype
= exprType((Node
*) setexpr
->expr
);
137 returnsTuple
= type_is_rowtype(funcrettype
);
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.
146 rsinfo
.type
= T_ReturnSetInfo
;
147 rsinfo
.econtext
= econtext
;
148 rsinfo
.expectedDesc
= expectedDesc
;
149 rsinfo
.allowedModes
= (int) (SFRM_ValuePerCall
| SFRM_Materialize
| SFRM_Materialize_Preferred
);
151 rsinfo
.allowedModes
|= (int) SFRM_Materialize_Random
;
152 rsinfo
.returnMode
= SFRM_ValuePerCall
;
153 /* isDone is filled below */
154 rsinfo
.setResult
= NULL
;
155 rsinfo
.setDesc
= NULL
;
157 fcinfo
= palloc(SizeForFunctionCallInfo(list_length(setexpr
->args
)));
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.
169 if (!setexpr
->elidedFuncState
)
172 * This path is similar to ExecMakeFunctionResultSet.
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
);
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).
188 if (setexpr
->func
.fn_strict
)
192 for (i
= 0; i
< fcinfo
->nargs
; i
++)
194 if (fcinfo
->args
[i
].isnull
)
195 goto no_function_result
;
201 /* Treat setexpr as a generic expression */
202 InitFunctionCallInfoData(*fcinfo
, NULL
, 0, InvalidOid
, NULL
, NULL
);
206 * Switch to short-lived context for calling the function or expression.
208 MemoryContextSwitchTo(econtext
->ecxt_per_tuple_memory
);
211 * Loop to handle the ValuePerCall protocol (which is also the same
212 * behavior needed in the generic ExecEvalExpr path).
218 CHECK_FOR_INTERRUPTS();
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
225 ResetExprContext(econtext
);
227 /* Call the function or expression one time */
228 if (!setexpr
->elidedFuncState
)
230 pgstat_init_function_usage(fcinfo
, &fcusage
);
232 fcinfo
->isnull
= false;
233 rsinfo
.isDone
= ExprSingleResult
;
234 result
= FunctionCallInvoke(fcinfo
);
236 pgstat_end_function_usage(&fcusage
,
237 rsinfo
.isDone
!= ExprMultipleResult
);
242 ExecEvalExpr(setexpr
->elidedFuncState
, econtext
, &fcinfo
->isnull
);
243 rsinfo
.isDone
= ExprSingleResult
;
246 /* Which protocol does function want to use? */
247 if (rsinfo
.returnMode
== SFRM_ValuePerCall
)
250 * Check for end of result set.
252 if (rsinfo
.isDone
== ExprEndResult
)
256 * If first time through, build tuplestore for result. For a
257 * scalar function result type, also make a suitable tupdesc.
261 MemoryContext oldcontext
=
262 MemoryContextSwitchTo(econtext
->ecxt_per_query_memory
);
264 tupstore
= tuplestore_begin_heap(randomAccess
, false, work_mem
);
265 rsinfo
.setResult
= tupstore
;
268 tupdesc
= CreateTemplateTupleDesc(1);
269 TupleDescInitEntry(tupdesc
,
275 rsinfo
.setDesc
= tupdesc
;
277 MemoryContextSwitchTo(oldcontext
);
281 * Store current resultset item.
287 HeapTupleHeader td
= DatumGetHeapTupleHeader(result
);
291 MemoryContext oldcontext
=
292 MemoryContextSwitchTo(econtext
->ecxt_per_query_memory
);
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.
300 tupdesc
= lookup_rowtype_tupdesc_copy(HeapTupleHeaderGetTypeId(td
),
301 HeapTupleHeaderGetTypMod(td
));
302 rsinfo
.setDesc
= tupdesc
;
303 MemoryContextSwitchTo(oldcontext
);
308 * Verify all later returned rows have same subtype;
309 * necessary in case the type is RECORD.
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")));
319 * tuplestore_puttuple needs a HeapTuple not a bare
320 * HeapTupleHeader, but it doesn't need all the fields.
322 tmptup
.t_len
= HeapTupleHeaderGetDatumLength(td
);
325 tuplestore_puttuple(tupstore
, &tmptup
);
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.)
337 int natts
= expectedDesc
->natts
;
340 nullflags
= (bool *) palloc(natts
* sizeof(bool));
341 memset(nullflags
, true, natts
* sizeof(bool));
342 tuplestore_putvalues(tupstore
, expectedDesc
, NULL
, nullflags
);
347 /* Scalar-type case: just store the function result */
348 tuplestore_putvalues(tupstore
, tupdesc
, &result
, &fcinfo
->isnull
);
354 if (rsinfo
.isDone
!= ExprMultipleResult
)
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.)
364 (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED
),
365 errmsg("table-function protocol for value-per-call mode was not followed")));
367 else if (rsinfo
.returnMode
== SFRM_Materialize
)
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 */
379 (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED
),
380 errmsg("unrecognized table-function returnMode: %d",
381 (int) rsinfo
.returnMode
)));
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.
394 if (rsinfo
.setResult
== NULL
)
396 MemoryContext oldcontext
=
397 MemoryContextSwitchTo(econtext
->ecxt_per_query_memory
);
399 tupstore
= tuplestore_begin_heap(randomAccess
, false, work_mem
);
400 rsinfo
.setResult
= tupstore
;
401 MemoryContextSwitchTo(oldcontext
);
405 int natts
= expectedDesc
->natts
;
408 nullflags
= (bool *) palloc(natts
* sizeof(bool));
409 memset(nullflags
, true, natts
* sizeof(bool));
410 tuplestore_putvalues(tupstore
, expectedDesc
, NULL
, nullflags
);
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.
420 tupledesc_match(expectedDesc
, rsinfo
.setDesc
);
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.
427 if (rsinfo
.setDesc
->tdrefcount
== -1)
428 FreeTupleDesc(rsinfo
.setDesc
);
431 MemoryContextSwitchTo(callerContext
);
433 /* All done, pass back the tuplestore */
434 return rsinfo
.setResult
;
439 * Prepare targetlist SRF function call for execution.
441 * This is used by nodeProjectSet.c.
444 ExecInitFunctionResultSet(Expr
*expr
,
445 ExprContext
*econtext
, PlanState
*parent
)
447 SetExprState
*state
= makeNode(SetExprState
);
449 state
->funcReturnsSet
= true;
451 state
->func
.fn_oid
= InvalidOid
;
454 * Initialize metadata. The expression node could be either a FuncExpr or
457 if (IsA(expr
, FuncExpr
))
459 FuncExpr
*func
= (FuncExpr
*) expr
;
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);
465 else if (IsA(expr
, OpExpr
))
467 OpExpr
*op
= (OpExpr
*) expr
;
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);
474 elog(ERROR
, "unrecognized node type: %d",
475 (int) nodeTag(expr
));
477 /* shouldn't get here unless the selected function returns set */
478 Assert(state
->func
.fn_retset
);
484 * ExecMakeFunctionResultSet
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).
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).
494 * This is used by nodeProjectSet.c.
497 ExecMakeFunctionResultSet(SetExprState
*fcache
,
498 ExprContext
*econtext
,
499 MemoryContext argContext
,
501 ExprDoneCond
*isDone
)
505 FunctionCallInfo fcinfo
;
506 PgStat_FunctionCallUsage fcusage
;
507 ReturnSetInfo rsinfo
;
513 /* Guard against stack overflow due to overly complex expressions */
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
521 if (fcache
->funcResultStore
)
523 TupleTableSlot
*slot
= fcache
->funcResultSlot
;
524 MemoryContext oldContext
;
528 * Have to make sure tuple in slot lives long enough, otherwise
529 * clearing the slot could end up trying to free something already
532 oldContext
= MemoryContextSwitchTo(slot
->tts_mcxt
);
533 foundTup
= tuplestore_gettupleslot(fcache
->funcResultStore
, true, false,
534 fcache
->funcResultSlot
);
535 MemoryContextSwitchTo(oldContext
);
539 *isDone
= ExprMultipleResult
;
540 if (fcache
->funcReturnsTuple
)
542 /* We must return the whole tuple as a Datum. */
544 return ExecFetchSlotHeapTupleDatum(fcache
->funcResultSlot
);
548 /* Extract the first column and return it as a scalar. */
549 return slot_getattr(fcache
->funcResultSlot
, 1, isNull
);
552 /* Exhausted the tuplestore, so clean up */
553 tuplestore_end(fcache
->funcResultStore
);
554 fcache
->funcResultStore
= NULL
;
555 *isDone
= ExprEndResult
;
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.
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.
570 fcinfo
= fcache
->fcinfo
;
571 arguments
= fcache
->args
;
572 if (!fcache
->setArgsValid
)
574 MemoryContext oldContext
= MemoryContextSwitchTo(argContext
);
576 ExecEvalFuncArgs(fcinfo
, arguments
, econtext
);
577 MemoryContextSwitchTo(oldContext
);
581 /* Reset flag (we may set it again below) */
582 fcache
->setArgsValid
= false;
586 * Now call the function, passing the evaluated parameter values.
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
;
594 rsinfo
.allowedModes
= (int) (SFRM_ValuePerCall
| SFRM_Materialize
);
595 /* note we do not set SFRM_Materialize_Random or _Preferred */
596 rsinfo
.returnMode
= SFRM_ValuePerCall
;
597 /* isDone is filled below */
598 rsinfo
.setResult
= NULL
;
599 rsinfo
.setDesc
= NULL
;
602 * If function is strict, and there are any NULL arguments, skip calling
606 if (fcache
->func
.fn_strict
)
608 for (i
= 0; i
< fcinfo
->nargs
; i
++)
610 if (fcinfo
->args
[i
].isnull
)
620 pgstat_init_function_usage(fcinfo
, &fcusage
);
622 fcinfo
->isnull
= false;
623 rsinfo
.isDone
= ExprSingleResult
;
624 result
= FunctionCallInvoke(fcinfo
);
625 *isNull
= fcinfo
->isnull
;
626 *isDone
= rsinfo
.isDone
;
628 pgstat_end_function_usage(&fcusage
,
629 rsinfo
.isDone
!= ExprMultipleResult
);
633 /* for a strict SRF, result for NULL is an empty set */
636 *isDone
= ExprEndResult
;
639 /* Which protocol does function want to use? */
640 if (rsinfo
.returnMode
== SFRM_ValuePerCall
)
642 if (*isDone
!= ExprEndResult
)
645 * Save the current argument values to re-use on the next call.
647 if (*isDone
== ExprMultipleResult
)
649 fcache
->setArgsValid
= true;
650 /* Register cleanup callback if we didn't already */
651 if (!fcache
->shutdown_reg
)
653 RegisterExprContextCallback(econtext
,
655 PointerGetDatum(fcache
));
656 fcache
->shutdown_reg
= true;
661 else if (rsinfo
.returnMode
== SFRM_Materialize
)
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
)
670 /* prepare to return values from the tuplestore */
671 ExecPrepareTuplestoreResult(fcache
, econtext
,
674 /* loop back to top to start returning from tuplestore */
677 /* if setResult was left null, treat it as empty set */
678 *isDone
= ExprEndResult
;
684 (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED
),
685 errmsg("unrecognized table-function returnMode: %d",
686 (int) rsinfo
.returnMode
)));
693 * init_sexpr - initialize a SetExprState node during first use
696 init_sexpr(Oid foid
, Oid input_collation
, Expr
*node
,
697 SetExprState
*sexpr
, PlanState
*parent
,
698 MemoryContext sexprCxt
, bool allowSRF
, bool needDescForSRF
)
701 size_t numargs
= list_length(sexpr
->args
);
703 /* Check permission to call function */
704 aclresult
= object_aclcheck(ProcedureRelationId
, foid
, GetUserId(), ACL_EXECUTE
);
705 if (aclresult
!= ACLCHECK_OK
)
706 aclcheck_error(aclresult
, OBJECT_FUNCTION
, get_func_name(foid
));
707 InvokeFunctionExecuteHook(foid
);
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?
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",
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
));
727 /* Initialize the function call parameter struct as well */
729 (FunctionCallInfo
) palloc(SizeForFunctionCallInfo(numargs
));
730 InitFunctionCallInfoData(*sexpr
->fcinfo
, &(sexpr
->func
),
732 input_collation
, NULL
, NULL
);
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));
742 /* Otherwise, caller should have marked the sexpr correctly */
743 Assert(sexpr
->func
.fn_retset
== sexpr
->funcReturnsSet
);
745 /* If function returns set, prepare expected tuple descriptor */
746 if (sexpr
->func
.fn_retset
&& needDescForSRF
)
748 TypeFuncClass functypclass
;
751 MemoryContext oldcontext
;
753 functypclass
= get_expr_result_type(sexpr
->func
.fn_expr
,
757 /* Must save tupdesc in sexpr's context */
758 oldcontext
= MemoryContextSwitchTo(sexprCxt
);
760 if (functypclass
== TYPEFUNC_COMPOSITE
||
761 functypclass
== TYPEFUNC_COMPOSITE_DOMAIN
)
763 /* Composite data type, e.g. a table's row type */
765 /* Must copy it out of typcache for safety */
766 sexpr
->funcResultDesc
= CreateTupleDescCopy(tupdesc
);
767 sexpr
->funcReturnsTuple
= true;
769 else if (functypclass
== TYPEFUNC_SCALAR
)
771 /* Base data type, i.e. scalar */
772 tupdesc
= CreateTemplateTupleDesc(1);
773 TupleDescInitEntry(tupdesc
,
779 sexpr
->funcResultDesc
= tupdesc
;
780 sexpr
->funcReturnsTuple
= false;
782 else if (functypclass
== TYPEFUNC_RECORD
)
784 /* This will work if function doesn't need an expectedDesc */
785 sexpr
->funcResultDesc
= NULL
;
786 sexpr
->funcReturnsTuple
= true;
790 /* Else, we will fail if function needs an expectedDesc */
791 sexpr
->funcResultDesc
= NULL
;
794 MemoryContextSwitchTo(oldcontext
);
797 sexpr
->funcResultDesc
= NULL
;
799 /* Initialize additional state */
800 sexpr
->funcResultStore
= NULL
;
801 sexpr
->funcResultSlot
= NULL
;
802 sexpr
->shutdown_reg
= false;
806 * callback function in case a SetExprState needs to be shut down before it
807 * has been run to completion
810 ShutdownSetExpr(Datum arg
)
812 SetExprState
*sexpr
= castNode(SetExprState
, DatumGetPointer(arg
));
814 /* If we have a slot, make sure it's let go of any tuplestore pointer */
815 if (sexpr
->funcResultSlot
)
816 ExecClearTuple(sexpr
->funcResultSlot
);
818 /* Release any open tuplestore */
819 if (sexpr
->funcResultStore
)
820 tuplestore_end(sexpr
->funcResultStore
);
821 sexpr
->funcResultStore
= NULL
;
823 /* Clear any active set-argument state */
824 sexpr
->setArgsValid
= false;
826 /* execUtils will deregister the callback... */
827 sexpr
->shutdown_reg
= false;
831 * Evaluate arguments for a function.
834 ExecEvalFuncArgs(FunctionCallInfo fcinfo
,
836 ExprContext
*econtext
)
842 foreach(arg
, argList
)
844 ExprState
*argstate
= (ExprState
*) lfirst(arg
);
846 fcinfo
->args
[i
].value
= ExecEvalExpr(argstate
,
848 &fcinfo
->args
[i
].isnull
);
852 Assert(i
== fcinfo
->nargs
);
856 * ExecPrepareTuplestoreResult
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.
864 ExecPrepareTuplestoreResult(SetExprState
*sexpr
,
865 ExprContext
*econtext
,
866 Tuplestorestate
*resultStore
,
867 TupleDesc resultDesc
)
869 sexpr
->funcResultStore
= resultStore
;
871 if (sexpr
->funcResultSlot
== NULL
)
873 /* Create a slot so we can read data out of the tuplestore */
875 MemoryContext oldcontext
;
877 oldcontext
= MemoryContextSwitchTo(sexpr
->func
.fn_mcxt
);
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.
883 if (sexpr
->funcResultDesc
)
884 slotDesc
= sexpr
->funcResultDesc
;
887 /* don't assume resultDesc is long-lived */
888 slotDesc
= CreateTupleDescCopy(resultDesc
);
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 */
899 sexpr
->funcResultSlot
= MakeSingleTupleTableSlot(slotDesc
,
900 &TTSOpsMinimalTuple
);
901 MemoryContextSwitchTo(oldcontext
);
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.
910 if (sexpr
->funcResultDesc
)
911 tupledesc_match(sexpr
->funcResultDesc
, resultDesc
);
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.
918 if (resultDesc
->tdrefcount
== -1)
919 FreeTupleDesc(resultDesc
);
922 /* Register cleanup callback if we didn't already */
923 if (!sexpr
->shutdown_reg
)
925 RegisterExprContextCallback(econtext
,
927 PointerGetDatum(sexpr
));
928 sexpr
->shutdown_reg
= true;
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.
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.
943 tupledesc_match(TupleDesc dst_tupdesc
, TupleDesc src_tupdesc
)
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.",
954 src_tupdesc
->natts
, dst_tupdesc
->natts
)));
956 for (i
= 0; i
< dst_tupdesc
->natts
; i
++)
958 Form_pg_attribute dattr
= TupleDescAttr(dst_tupdesc
, i
);
959 Form_pg_attribute sattr
= TupleDescAttr(src_tupdesc
, i
);
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
),
970 format_type_be(dattr
->atttypid
))));
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.",