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-2021, 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 "executor/execdebug.h"
24 #include "funcapi.h"
25 #include "miscadmin.h"
26 #include "nodes/nodeFuncs.h"
27 #include "parser/parse_coerce.h"
28 #include "pgstat.h"
29 #include "utils/acl.h"
30 #include "utils/builtins.h"
31 #include "utils/lsyscache.h"
32 #include "utils/memutils.h"
33 #include "utils/typcache.h"
34 
35 
36 /* static function decls */
37 static void init_sexpr(Oid foid, Oid input_collation, Expr *node,
38 					   SetExprState *sexpr, PlanState *parent,
39 					   MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF);
40 static void ShutdownSetExpr(Datum arg);
41 static void ExecEvalFuncArgs(FunctionCallInfo fcinfo,
42 							 List *argList, ExprContext *econtext);
43 static void ExecPrepareTuplestoreResult(SetExprState *sexpr,
44 										ExprContext *econtext,
45 										Tuplestorestate *resultStore,
46 										TupleDesc resultDesc);
47 static void tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc);
48 
49 
50 /*
51  * Prepare function call in FROM (ROWS FROM) for execution.
52  *
53  * This is used by nodeFunctionscan.c.
54  */
55 SetExprState *
ExecInitTableFunctionResult(Expr * expr,ExprContext * econtext,PlanState * parent)56 ExecInitTableFunctionResult(Expr *expr,
57 							ExprContext *econtext, PlanState *parent)
58 {
59 	SetExprState *state = makeNode(SetExprState);
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  */
100 Tuplestorestate *
ExecMakeTableFunctionResult(SetExprState * setexpr,ExprContext * econtext,MemoryContext argContext,TupleDesc expectedDesc,bool randomAccess)101 ExecMakeTableFunctionResult(SetExprState *setexpr,
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;
113 	PgStat_FunctionCallUsage fcusage;
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;
149 	rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize | SFRM_Materialize_Preferred);
150 	if (randomAccess)
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;
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 	 */
208 	MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
209 
210 	/*
211 	 * Loop to handle the ValuePerCall protocol (which is also the same
212 	 * behavior needed in the generic ExecEvalExpr path).
213 	 */
214 	for (;;)
215 	{
216 		Datum		result;
217 
218 		CHECK_FOR_INTERRUPTS();
219 
220 		/*
221 		 * Reset per-tuple memory context before each call of the function or
222 		 * expression. This cleans up any local memory the function may leak
223 		 * when called.
224 		 */
225 		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 
236 			pgstat_end_function_usage(&fcusage,
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 =
262 				MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
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 				{
287 					HeapTupleHeader td = DatumGetHeapTupleHeader(result);
288 
289 					if (tupdesc == NULL)
290 					{
291 						MemoryContext oldcontext =
292 						MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
293 
294 						/*
295 						 * This is the first non-NULL result from the
296 						 * function.  Use the type info embedded in the
297 						 * rowtype Datum to look up the needed tupdesc.  Make
298 						 * a copy for the query.
299 						 */
300 						tupdesc = lookup_rowtype_tupdesc_copy(HeapTupleHeaderGetTypeId(td),
301 															  HeapTupleHeaderGetTypMod(td));
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)
313 							ereport(ERROR,
314 									(errcode(ERRCODE_DATATYPE_MISMATCH),
315 									 errmsg("rows returned by function are not all of the same row type")));
316 					}
317 
318 					/*
319 					 * tuplestore_puttuple needs a HeapTuple not a bare
320 					 * HeapTupleHeader, but it doesn't need all the fields.
321 					 */
322 					tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
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)
363 				ereport(ERROR,
364 						(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
365 						 errmsg("table-function protocol for value-per-call mode was not followed")));
366 		}
367 		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)
371 				ereport(ERROR,
372 						(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
373 						 errmsg("table-function protocol for materialize mode was not followed")));
374 			/* Done evaluating the set result */
375 			break;
376 		}
377 		else
378 			ereport(ERROR,
379 					(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
380 					 errmsg("unrecognized table-function returnMode: %d",
381 							(int) rsinfo.returnMode)));
382 
383 		first_time = false;
384 	}
385 
386 no_function_result:
387 
388 	/*
389 	 * If we got nothing from the function (ie, an empty-set or NULL result),
390 	 * we have to create the tuplestore to return, and if it's a
391 	 * non-set-returning function then insert a single all-nulls row.  As
392 	 * above, we depend on the expectedDesc to manufacture the dummy row.
393 	 */
394 	if (rsinfo.setResult == NULL)
395 	{
396 		MemoryContext oldcontext =
397 		MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
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  */
443 SetExprState *
ExecInitFunctionResultSet(Expr * expr,ExprContext * econtext,PlanState * parent)444 ExecInitFunctionResultSet(Expr *expr,
445 						  ExprContext *econtext, PlanState *parent)
446 {
447 	SetExprState *state = makeNode(SetExprState);
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  */
496 Datum
ExecMakeFunctionResultSet(SetExprState * fcache,ExprContext * econtext,MemoryContext argContext,bool * isNull,ExprDoneCond * isDone)497 ExecMakeFunctionResultSet(SetExprState *fcache,
498 						  ExprContext *econtext,
499 						  MemoryContext argContext,
500 						  bool *isNull,
501 						  ExprDoneCond *isDone)
502 {
503 	List	   *arguments;
504 	Datum		result;
505 	FunctionCallInfo fcinfo;
506 	PgStat_FunctionCallUsage fcusage;
507 	ReturnSetInfo rsinfo;
508 	bool		callit;
509 	int			i;
510 
511 restart:
512 
513 	/* Guard against stack overflow due to overly complex expressions */
514 	check_stack_depth();
515 
516 	/*
517 	 * If a previous call of the function returned a set result in the form of
518 	 * a tuplestore, continue reading rows from the tuplestore until it's
519 	 * empty.
520 	 */
521 	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;
544 				return ExecFetchSlotHeapTupleDatum(fcache->funcResultSlot);
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 */
553 		tuplestore_end(fcache->funcResultStore);
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;
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;
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 
628 		pgstat_end_function_usage(&fcusage,
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 				{
653 					RegisterExprContextCallback(econtext,
654 												ShutdownSetExpr,
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)
665 			ereport(ERROR,
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
683 		ereport(ERROR,
684 				(errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
685 				 errmsg("unrecognized table-function returnMode: %d",
686 						(int) rsinfo.returnMode)));
687 
688 	return result;
689 }
690 
691 
692 /*
693  * init_sexpr - initialize a SetExprState node during first use
694  */
695 static void
init_sexpr(Oid foid,Oid input_collation,Expr * node,SetExprState * sexpr,PlanState * parent,MemoryContext sexprCxt,bool allowSRF,bool needDescForSRF)696 init_sexpr(Oid foid, Oid input_collation, Expr *node,
697 		   SetExprState *sexpr, PlanState *parent,
698 		   MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF)
699 {
700 	AclResult	aclresult;
701 	size_t		numargs = list_length(sexpr->args);
702 
703 	/* Check permission to call function */
704 	aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
705 	if (aclresult != ACLCHECK_OK)
706 		aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
707 	InvokeFunctionExecuteHook(foid);
708 
709 	/*
710 	 * Safety check on nargs.  Under normal circumstances this should never
711 	 * fail, as parser should check sooner.  But possibly it might fail if
712 	 * server has been compiled with FUNC_MAX_ARGS smaller than some functions
713 	 * declared in pg_proc?
714 	 */
715 	if (list_length(sexpr->args) > FUNC_MAX_ARGS)
716 		ereport(ERROR,
717 				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
718 				 errmsg_plural("cannot pass more than %d argument to a function",
719 							   "cannot pass more than %d arguments to a function",
720 							   FUNC_MAX_ARGS,
721 							   FUNC_MAX_ARGS)));
722 
723 	/* Set up the primary fmgr lookup information */
724 	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 =
729 		(FunctionCallInfo) palloc(SizeForFunctionCallInfo(numargs));
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)
736 		ereport(ERROR,
737 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
738 				 errmsg("set-valued function called in context that cannot accept a set"),
739 				 parent ? executor_errposition(parent->state,
740 											   exprLocation((Node *) node)) : 0));
741 
742 	/* Otherwise, caller should have marked the sexpr correctly */
743 	Assert(sexpr->func.fn_retset == sexpr->funcReturnsSet);
744 
745 	/* If function returns set, prepare expected tuple descriptor */
746 	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  */
809 static void
ShutdownSetExpr(Datum arg)810 ShutdownSetExpr(Datum arg)
811 {
812 	SetExprState *sexpr = castNode(SetExprState, DatumGetPointer(arg));
813 
814 	/* If we have a slot, make sure it's let go of any tuplestore pointer */
815 	if (sexpr->funcResultSlot)
816 		ExecClearTuple(sexpr->funcResultSlot);
817 
818 	/* Release any open tuplestore */
819 	if (sexpr->funcResultStore)
820 		tuplestore_end(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  */
833 static void
ExecEvalFuncArgs(FunctionCallInfo fcinfo,List * argList,ExprContext * econtext)834 ExecEvalFuncArgs(FunctionCallInfo fcinfo,
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  */
863 static void
ExecPrepareTuplestoreResult(SetExprState * sexpr,ExprContext * econtext,Tuplestorestate * resultStore,TupleDesc resultDesc)864 ExecPrepareTuplestoreResult(SetExprState *sexpr,
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 		{
892 			ereport(ERROR,
893 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
894 					 errmsg("function returning setof record called in "
895 							"context that cannot accept type record")));
896 			slotDesc = NULL;	/* keep compiler quiet */
897 		}
898 
899 		sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc,
900 														 &TTSOpsMinimalTuple);
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 	{
925 		RegisterExprContextCallback(econtext,
926 									ShutdownSetExpr,
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  */
942 static void
tupledesc_match(TupleDesc dst_tupdesc,TupleDesc src_tupdesc)943 tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
944 {
945 	int			i;
946 
947 	if (dst_tupdesc->natts != src_tupdesc->natts)
948 		ereport(ERROR,
949 				(errcode(ERRCODE_DATATYPE_MISMATCH),
950 				 errmsg("function return row and query-specified return row do not match"),
951 				 errdetail_plural("Returned row contains %d attribute, but query expects %d.",
952 								  "Returned row contains %d attributes, but query expects %d.",
953 								  src_tupdesc->natts,
954 								  src_tupdesc->natts, dst_tupdesc->natts)));
955 
956 	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)
964 			ereport(ERROR,
965 					(errcode(ERRCODE_DATATYPE_MISMATCH),
966 					 errmsg("function return row and query-specified return row do not match"),
967 					 errdetail("Returned type %s at ordinal position %d, but query expects %s.",
968 							   format_type_be(sattr->atttypid),
969 							   i + 1,
970 							   format_type_be(dattr->atttypid))));
971 
972 		if (dattr->attlen != sattr->attlen ||
973 			dattr->attalign != sattr->attalign)
974 			ereport(ERROR,
975 					(errcode(ERRCODE_DATATYPE_MISMATCH),
976 					 errmsg("function return row and query-specified return row do not match"),
977 					 errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
978 							   i + 1)));
979 	}
980 }
981