Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * execSRF.c
4 : * Routines implementing the API for set-returning functions
5 : *
6 : * This file serves nodeFunctionscan.c and nodeProjectSet.c, providing
7 : * common code for calling set-returning functions according to the
8 : * ReturnSetInfo API.
9 : *
10 : * Portions Copyright (c) 1996-2017, 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 *
56 1514 : ExecInitTableFunctionResult(Expr *expr,
57 : ExprContext *econtext, PlanState *parent)
58 : {
59 1514 : SetExprState *state = makeNode(SetExprState);
60 :
61 1514 : state->funcReturnsSet = false;
62 1514 : state->expr = expr;
63 1514 : 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 1514 : if (IsA(expr, FuncExpr))
75 : {
76 1486 : FuncExpr *func = (FuncExpr *) expr;
77 :
78 1486 : state->funcReturnsSet = func->funcretset;
79 1486 : state->args = ExecInitExprList(func->args, parent);
80 :
81 1486 : init_sexpr(func->funcid, func->inputcollid, expr, state, parent,
82 1486 : econtext->ecxt_per_query_memory, func->funcretset, false);
83 : }
84 : else
85 : {
86 28 : state->elidedFuncState = ExecInitExpr(expr, parent);
87 : }
88 :
89 1514 : return state;
90 : }
91 :
92 : /*
93 : * ExecMakeTableFunctionResult
94 : *
95 : * Evaluate a table function, producing a materialized result in a Tuplestore
96 : * object.
97 : *
98 : * This is used by nodeFunctionscan.c.
99 : */
100 : Tuplestorestate *
101 12583 : ExecMakeTableFunctionResult(SetExprState *setexpr,
102 : ExprContext *econtext,
103 : MemoryContext argContext,
104 : TupleDesc expectedDesc,
105 : bool randomAccess)
106 : {
107 12583 : Tuplestorestate *tupstore = NULL;
108 12583 : TupleDesc tupdesc = NULL;
109 : Oid funcrettype;
110 : bool returnsTuple;
111 12583 : bool returnsSet = false;
112 : FunctionCallInfoData fcinfo;
113 : PgStat_FunctionCallUsage fcusage;
114 : ReturnSetInfo rsinfo;
115 : HeapTupleData tmptup;
116 : MemoryContext callerContext;
117 : MemoryContext oldcontext;
118 12583 : bool first_time = true;
119 :
120 12583 : callerContext = CurrentMemoryContext;
121 :
122 12583 : funcrettype = exprType((Node *) setexpr->expr);
123 :
124 12583 : returnsTuple = type_is_rowtype(funcrettype);
125 :
126 : /*
127 : * Prepare a resultinfo node for communication. We always do this even if
128 : * not expecting a set result, so that we can pass expectedDesc. In the
129 : * generic-expression case, the expression doesn't actually get to see the
130 : * resultinfo, but set it up anyway because we use some of the fields as
131 : * our own state variables.
132 : */
133 12583 : rsinfo.type = T_ReturnSetInfo;
134 12583 : rsinfo.econtext = econtext;
135 12583 : rsinfo.expectedDesc = expectedDesc;
136 12583 : rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize | SFRM_Materialize_Preferred);
137 12583 : if (randomAccess)
138 40 : rsinfo.allowedModes |= (int) SFRM_Materialize_Random;
139 12583 : rsinfo.returnMode = SFRM_ValuePerCall;
140 : /* isDone is filled below */
141 12583 : rsinfo.setResult = NULL;
142 12583 : rsinfo.setDesc = NULL;
143 :
144 : /*
145 : * Normally the passed expression tree will be a SetExprState, since the
146 : * grammar only allows a function call at the top level of a table
147 : * function reference. However, if the function doesn't return set then
148 : * the planner might have replaced the function call via constant-folding
149 : * or inlining. So if we see any other kind of expression node, execute
150 : * it via the general ExecEvalExpr() code; the only difference is that we
151 : * don't get a chance to pass a special ReturnSetInfo to any functions
152 : * buried in the expression.
153 : */
154 12583 : if (!setexpr->elidedFuncState)
155 : {
156 : /*
157 : * This path is similar to ExecMakeFunctionResultSet.
158 : */
159 12556 : returnsSet = setexpr->funcReturnsSet;
160 12556 : InitFunctionCallInfoData(fcinfo, &(setexpr->func),
161 : list_length(setexpr->args),
162 : setexpr->fcinfo_data.fncollation,
163 : NULL, (Node *) &rsinfo);
164 :
165 : /*
166 : * Evaluate the function's argument list.
167 : *
168 : * We can't do this in the per-tuple context: the argument values
169 : * would disappear when we reset that context in the inner loop. And
170 : * the caller's CurrentMemoryContext is typically a query-lifespan
171 : * context, so we don't want to leak memory there. We require the
172 : * caller to pass a separate memory context that can be used for this,
173 : * and can be reset each time through to avoid bloat.
174 : */
175 12556 : MemoryContextReset(argContext);
176 12556 : oldcontext = MemoryContextSwitchTo(argContext);
177 12556 : ExecEvalFuncArgs(&fcinfo, setexpr->args, econtext);
178 12556 : MemoryContextSwitchTo(oldcontext);
179 :
180 : /*
181 : * If function is strict, and there are any NULL arguments, skip
182 : * calling the function and act like it returned NULL (or an empty
183 : * set, in the returns-set case).
184 : */
185 12556 : if (setexpr->func.fn_strict)
186 : {
187 : int i;
188 :
189 35697 : for (i = 0; i < fcinfo.nargs; i++)
190 : {
191 23750 : if (fcinfo.argnull[i])
192 148 : goto no_function_result;
193 : }
194 : }
195 : }
196 : else
197 : {
198 : /* Treat setexpr as a generic expression */
199 27 : InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
200 : }
201 :
202 : /*
203 : * Switch to short-lived context for calling the function or expression.
204 : */
205 12435 : MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
206 :
207 : /*
208 : * Loop to handle the ValuePerCall protocol (which is also the same
209 : * behavior needed in the generic ExecEvalExpr path).
210 : */
211 : for (;;)
212 : {
213 : Datum result;
214 :
215 670163 : CHECK_FOR_INTERRUPTS();
216 :
217 : /*
218 : * reset per-tuple memory context before each call of the function or
219 : * expression. This cleans up any local memory the function may leak
220 : * when called.
221 : */
222 670163 : ResetExprContext(econtext);
223 :
224 : /* Call the function or expression one time */
225 670163 : if (!setexpr->elidedFuncState)
226 : {
227 670136 : pgstat_init_function_usage(&fcinfo, &fcusage);
228 :
229 670136 : fcinfo.isnull = false;
230 670136 : rsinfo.isDone = ExprSingleResult;
231 670136 : result = FunctionCallInvoke(&fcinfo);
232 :
233 670064 : pgstat_end_function_usage(&fcusage,
234 670064 : rsinfo.isDone != ExprMultipleResult);
235 : }
236 : else
237 : {
238 27 : result =
239 27 : ExecEvalExpr(setexpr->elidedFuncState, econtext, &fcinfo.isnull);
240 27 : rsinfo.isDone = ExprSingleResult;
241 : }
242 :
243 : /* Which protocol does function want to use? */
244 670091 : if (rsinfo.returnMode == SFRM_ValuePerCall)
245 : {
246 : /*
247 : * Check for end of result set.
248 : */
249 669683 : if (rsinfo.isDone == ExprEndResult)
250 23093 : break;
251 :
252 : /*
253 : * If first time through, build tuplestore for result. For a
254 : * scalar function result type, also make a suitable tupdesc.
255 : */
256 658953 : if (first_time)
257 : {
258 6945 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
259 6945 : tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
260 6945 : rsinfo.setResult = tupstore;
261 6945 : if (!returnsTuple)
262 : {
263 6549 : tupdesc = CreateTemplateTupleDesc(1, false);
264 6549 : TupleDescInitEntry(tupdesc,
265 : (AttrNumber) 1,
266 : "column",
267 : funcrettype,
268 : -1,
269 : 0);
270 6549 : rsinfo.setDesc = tupdesc;
271 : }
272 6945 : MemoryContextSwitchTo(oldcontext);
273 : }
274 :
275 : /*
276 : * Store current resultset item.
277 : */
278 658953 : if (returnsTuple)
279 : {
280 4260 : if (!fcinfo.isnull)
281 : {
282 4255 : HeapTupleHeader td = DatumGetHeapTupleHeader(result);
283 :
284 4255 : if (tupdesc == NULL)
285 : {
286 : /*
287 : * This is the first non-NULL result from the
288 : * function. Use the type info embedded in the
289 : * rowtype Datum to look up the needed tupdesc. Make
290 : * a copy for the query.
291 : */
292 395 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
293 395 : tupdesc = lookup_rowtype_tupdesc_copy(HeapTupleHeaderGetTypeId(td),
294 : HeapTupleHeaderGetTypMod(td));
295 395 : rsinfo.setDesc = tupdesc;
296 395 : MemoryContextSwitchTo(oldcontext);
297 : }
298 : else
299 : {
300 : /*
301 : * Verify all later returned rows have same subtype;
302 : * necessary in case the type is RECORD.
303 : */
304 7720 : if (HeapTupleHeaderGetTypeId(td) != tupdesc->tdtypeid ||
305 3860 : HeapTupleHeaderGetTypMod(td) != tupdesc->tdtypmod)
306 0 : ereport(ERROR,
307 : (errcode(ERRCODE_DATATYPE_MISMATCH),
308 : errmsg("rows returned by function are not all of the same row type")));
309 : }
310 :
311 : /*
312 : * tuplestore_puttuple needs a HeapTuple not a bare
313 : * HeapTupleHeader, but it doesn't need all the fields.
314 : */
315 4255 : tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
316 4255 : tmptup.t_data = td;
317 :
318 4255 : tuplestore_puttuple(tupstore, &tmptup);
319 : }
320 : else
321 : {
322 : /*
323 : * NULL result from a tuple-returning function; expand it
324 : * to a row of all nulls. We rely on the expectedDesc to
325 : * form such rows. (Note: this would be problematic if
326 : * tuplestore_putvalues saved the tdtypeid/tdtypmod from
327 : * the provided descriptor, since that might not match
328 : * what we get from the function itself. But it doesn't.)
329 : */
330 5 : int natts = expectedDesc->natts;
331 : bool *nullflags;
332 :
333 5 : nullflags = (bool *) palloc(natts * sizeof(bool));
334 5 : memset(nullflags, true, natts * sizeof(bool));
335 5 : tuplestore_putvalues(tupstore, expectedDesc, NULL, nullflags);
336 : }
337 : }
338 : else
339 : {
340 : /* Scalar-type case: just store the function result */
341 654693 : tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo.isnull);
342 : }
343 :
344 : /*
345 : * Are we done?
346 : */
347 658953 : if (rsinfo.isDone != ExprMultipleResult)
348 1225 : break;
349 : }
350 408 : else if (rsinfo.returnMode == SFRM_Materialize)
351 : {
352 : /* check we're on the same page as the function author */
353 408 : if (!first_time || rsinfo.isDone != ExprSingleResult)
354 0 : ereport(ERROR,
355 : (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
356 : errmsg("table-function protocol for materialize mode was not followed")));
357 : /* Done evaluating the set result */
358 408 : break;
359 : }
360 : else
361 0 : ereport(ERROR,
362 : (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
363 : errmsg("unrecognized table-function returnMode: %d",
364 : (int) rsinfo.returnMode)));
365 :
366 657728 : first_time = false;
367 657728 : }
368 :
369 : no_function_result:
370 :
371 : /*
372 : * If we got nothing from the function (ie, an empty-set or NULL result),
373 : * we have to create the tuplestore to return, and if it's a
374 : * non-set-returning function then insert a single all-nulls row. As
375 : * above, we depend on the expectedDesc to manufacture the dummy row.
376 : */
377 12511 : if (rsinfo.setResult == NULL)
378 : {
379 5158 : MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
380 5158 : tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
381 5158 : rsinfo.setResult = tupstore;
382 5158 : if (!returnsSet)
383 : {
384 0 : int natts = expectedDesc->natts;
385 : bool *nullflags;
386 :
387 0 : MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
388 0 : nullflags = (bool *) palloc(natts * sizeof(bool));
389 0 : memset(nullflags, true, natts * sizeof(bool));
390 0 : tuplestore_putvalues(tupstore, expectedDesc, NULL, nullflags);
391 : }
392 : }
393 :
394 : /*
395 : * If function provided a tupdesc, cross-check it. We only really need to
396 : * do this for functions returning RECORD, but might as well do it always.
397 : */
398 12511 : if (rsinfo.setDesc)
399 : {
400 7352 : tupledesc_match(expectedDesc, rsinfo.setDesc);
401 :
402 : /*
403 : * If it is a dynamically-allocated TupleDesc, free it: it is
404 : * typically allocated in a per-query context, so we must avoid
405 : * leaking it across multiple usages.
406 : */
407 7350 : if (rsinfo.setDesc->tdrefcount == -1)
408 7350 : FreeTupleDesc(rsinfo.setDesc);
409 : }
410 :
411 12509 : MemoryContextSwitchTo(callerContext);
412 :
413 : /* All done, pass back the tuplestore */
414 12509 : return rsinfo.setResult;
415 : }
416 :
417 :
418 : /*
419 : * Prepare targetlist SRF function call for execution.
420 : *
421 : * This is used by nodeProjectSet.c.
422 : */
423 : SetExprState *
424 243 : ExecInitFunctionResultSet(Expr *expr,
425 : ExprContext *econtext, PlanState *parent)
426 : {
427 243 : SetExprState *state = makeNode(SetExprState);
428 :
429 243 : state->funcReturnsSet = true;
430 243 : state->expr = expr;
431 243 : state->func.fn_oid = InvalidOid;
432 :
433 : /*
434 : * Initialize metadata. The expression node could be either a FuncExpr or
435 : * an OpExpr.
436 : */
437 243 : if (IsA(expr, FuncExpr))
438 : {
439 242 : FuncExpr *func = (FuncExpr *) expr;
440 :
441 242 : state->args = ExecInitExprList(func->args, parent);
442 242 : init_sexpr(func->funcid, func->inputcollid, expr, state, parent,
443 : econtext->ecxt_per_query_memory, true, true);
444 : }
445 1 : else if (IsA(expr, OpExpr))
446 : {
447 1 : OpExpr *op = (OpExpr *) expr;
448 :
449 1 : state->args = ExecInitExprList(op->args, parent);
450 1 : init_sexpr(op->opfuncid, op->inputcollid, expr, state, parent,
451 : econtext->ecxt_per_query_memory, true, true);
452 : }
453 : else
454 0 : elog(ERROR, "unrecognized node type: %d",
455 : (int) nodeTag(expr));
456 :
457 : /* shouldn't get here unless the selected function returns set */
458 243 : Assert(state->func.fn_retset);
459 :
460 243 : return state;
461 : }
462 :
463 : /*
464 : * ExecMakeFunctionResultSet
465 : *
466 : * Evaluate the arguments to a set-returning function and then call the
467 : * function itself. The argument expressions may not contain set-returning
468 : * functions (the planner is supposed to have separated evaluation for those).
469 : *
470 : * This is used by nodeProjectSet.c.
471 : */
472 : Datum
473 27507 : ExecMakeFunctionResultSet(SetExprState *fcache,
474 : ExprContext *econtext,
475 : bool *isNull,
476 : ExprDoneCond *isDone)
477 : {
478 : List *arguments;
479 : Datum result;
480 : FunctionCallInfo fcinfo;
481 : PgStat_FunctionCallUsage fcusage;
482 : ReturnSetInfo rsinfo;
483 : bool callit;
484 : int i;
485 :
486 : restart:
487 :
488 : /* Guard against stack overflow due to overly complex expressions */
489 27507 : check_stack_depth();
490 :
491 : /*
492 : * If a previous call of the function returned a set result in the form of
493 : * a tuplestore, continue reading rows from the tuplestore until it's
494 : * empty.
495 : */
496 27507 : if (fcache->funcResultStore)
497 : {
498 11691 : if (tuplestore_gettupleslot(fcache->funcResultStore, true, false,
499 : fcache->funcResultSlot))
500 : {
501 9650 : *isDone = ExprMultipleResult;
502 9650 : if (fcache->funcReturnsTuple)
503 : {
504 : /* We must return the whole tuple as a Datum. */
505 9618 : *isNull = false;
506 9618 : return ExecFetchSlotTupleDatum(fcache->funcResultSlot);
507 : }
508 : else
509 : {
510 : /* Extract the first column and return it as a scalar. */
511 32 : return slot_getattr(fcache->funcResultSlot, 1, isNull);
512 : }
513 : }
514 : /* Exhausted the tuplestore, so clean up */
515 2041 : tuplestore_end(fcache->funcResultStore);
516 2041 : fcache->funcResultStore = NULL;
517 2041 : *isDone = ExprEndResult;
518 2041 : *isNull = true;
519 2041 : return (Datum) 0;
520 : }
521 :
522 : /*
523 : * arguments is a list of expressions to evaluate before passing to the
524 : * function manager. We skip the evaluation if it was already done in the
525 : * previous call (ie, we are continuing the evaluation of a set-valued
526 : * function). Otherwise, collect the current argument values into fcinfo.
527 : */
528 15816 : fcinfo = &fcache->fcinfo_data;
529 15816 : arguments = fcache->args;
530 15816 : if (!fcache->setArgsValid)
531 7390 : ExecEvalFuncArgs(fcinfo, arguments, econtext);
532 : else
533 : {
534 : /* Reset flag (we may set it again below) */
535 8426 : fcache->setArgsValid = false;
536 : }
537 :
538 : /*
539 : * Now call the function, passing the evaluated parameter values.
540 : */
541 :
542 : /* Prepare a resultinfo node for communication. */
543 15816 : fcinfo->resultinfo = (Node *) &rsinfo;
544 15816 : rsinfo.type = T_ReturnSetInfo;
545 15816 : rsinfo.econtext = econtext;
546 15816 : rsinfo.expectedDesc = fcache->funcResultDesc;
547 15816 : rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize);
548 : /* note we do not set SFRM_Materialize_Random or _Preferred */
549 15816 : rsinfo.returnMode = SFRM_ValuePerCall;
550 : /* isDone is filled below */
551 15816 : rsinfo.setResult = NULL;
552 15816 : rsinfo.setDesc = NULL;
553 :
554 : /*
555 : * If function is strict, and there are any NULL arguments, skip calling
556 : * the function.
557 : */
558 15816 : callit = true;
559 15816 : if (fcache->func.fn_strict)
560 : {
561 32035 : for (i = 0; i < fcinfo->nargs; i++)
562 : {
563 19688 : if (fcinfo->argnull[i])
564 : {
565 2859 : callit = false;
566 2859 : break;
567 : }
568 : }
569 : }
570 :
571 15816 : if (callit)
572 : {
573 12957 : pgstat_init_function_usage(fcinfo, &fcusage);
574 :
575 12957 : fcinfo->isnull = false;
576 12957 : rsinfo.isDone = ExprSingleResult;
577 12957 : result = FunctionCallInvoke(fcinfo);
578 12950 : *isNull = fcinfo->isnull;
579 12950 : *isDone = rsinfo.isDone;
580 :
581 12950 : pgstat_end_function_usage(&fcusage,
582 12950 : rsinfo.isDone != ExprMultipleResult);
583 : }
584 : else
585 : {
586 : /* for a strict SRF, result for NULL is an empty set */
587 2859 : result = (Datum) 0;
588 2859 : *isNull = true;
589 2859 : *isDone = ExprEndResult;
590 : }
591 :
592 : /* Which protocol does function want to use? */
593 15809 : if (rsinfo.returnMode == SFRM_ValuePerCall)
594 : {
595 13762 : if (*isDone != ExprEndResult)
596 : {
597 : /*
598 : * Save the current argument values to re-use on the next call.
599 : */
600 8434 : if (*isDone == ExprMultipleResult)
601 : {
602 8434 : fcache->setArgsValid = true;
603 : /* Register cleanup callback if we didn't already */
604 8434 : if (!fcache->shutdown_reg)
605 : {
606 351 : RegisterExprContextCallback(econtext,
607 : ShutdownSetExpr,
608 : PointerGetDatum(fcache));
609 351 : fcache->shutdown_reg = true;
610 : }
611 : }
612 : }
613 : }
614 2047 : else if (rsinfo.returnMode == SFRM_Materialize)
615 : {
616 : /* check we're on the same page as the function author */
617 2047 : if (rsinfo.isDone != ExprSingleResult)
618 0 : ereport(ERROR,
619 : (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
620 : errmsg("table-function protocol for materialize mode was not followed")));
621 2047 : if (rsinfo.setResult != NULL)
622 : {
623 : /* prepare to return values from the tuplestore */
624 2044 : ExecPrepareTuplestoreResult(fcache, econtext,
625 : rsinfo.setResult,
626 : rsinfo.setDesc);
627 : /* loop back to top to start returning from tuplestore */
628 2044 : goto restart;
629 : }
630 : /* if setResult was left null, treat it as empty set */
631 3 : *isDone = ExprEndResult;
632 3 : *isNull = true;
633 3 : result = (Datum) 0;
634 : }
635 : else
636 0 : ereport(ERROR,
637 : (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
638 : errmsg("unrecognized table-function returnMode: %d",
639 : (int) rsinfo.returnMode)));
640 :
641 13765 : return result;
642 : }
643 :
644 :
645 : /*
646 : * init_sexpr - initialize a SetExprState node during first use
647 : */
648 : static void
649 1729 : init_sexpr(Oid foid, Oid input_collation, Expr *node,
650 : SetExprState *sexpr, PlanState *parent,
651 : MemoryContext sexprCxt, bool allowSRF, bool needDescForSRF)
652 : {
653 : AclResult aclresult;
654 :
655 : /* Check permission to call function */
656 1729 : aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
657 1729 : if (aclresult != ACLCHECK_OK)
658 0 : aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid));
659 1729 : InvokeFunctionExecuteHook(foid);
660 :
661 : /*
662 : * Safety check on nargs. Under normal circumstances this should never
663 : * fail, as parser should check sooner. But possibly it might fail if
664 : * server has been compiled with FUNC_MAX_ARGS smaller than some functions
665 : * declared in pg_proc?
666 : */
667 1729 : if (list_length(sexpr->args) > FUNC_MAX_ARGS)
668 0 : ereport(ERROR,
669 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
670 : errmsg_plural("cannot pass more than %d argument to a function",
671 : "cannot pass more than %d arguments to a function",
672 : FUNC_MAX_ARGS,
673 : FUNC_MAX_ARGS)));
674 :
675 : /* Set up the primary fmgr lookup information */
676 1729 : fmgr_info_cxt(foid, &(sexpr->func), sexprCxt);
677 1729 : fmgr_info_set_expr((Node *) sexpr->expr, &(sexpr->func));
678 :
679 : /* Initialize the function call parameter struct as well */
680 1729 : InitFunctionCallInfoData(sexpr->fcinfo_data, &(sexpr->func),
681 : list_length(sexpr->args),
682 : input_collation, NULL, NULL);
683 :
684 : /* If function returns set, check if that's allowed by caller */
685 1729 : if (sexpr->func.fn_retset && !allowSRF)
686 0 : ereport(ERROR,
687 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
688 : errmsg("set-valued function called in context that cannot accept a set"),
689 : parent ? executor_errposition(parent->state,
690 : exprLocation((Node *) node)) : 0));
691 :
692 : /* Otherwise, caller should have marked the sexpr correctly */
693 1729 : Assert(sexpr->func.fn_retset == sexpr->funcReturnsSet);
694 :
695 : /* If function returns set, prepare expected tuple descriptor */
696 1729 : if (sexpr->func.fn_retset && needDescForSRF)
697 243 : {
698 : TypeFuncClass functypclass;
699 : Oid funcrettype;
700 : TupleDesc tupdesc;
701 : MemoryContext oldcontext;
702 :
703 243 : functypclass = get_expr_result_type(sexpr->func.fn_expr,
704 : &funcrettype,
705 : &tupdesc);
706 :
707 : /* Must save tupdesc in sexpr's context */
708 243 : oldcontext = MemoryContextSwitchTo(sexprCxt);
709 :
710 243 : if (functypclass == TYPEFUNC_COMPOSITE)
711 : {
712 : /* Composite data type, e.g. a table's row type */
713 62 : Assert(tupdesc);
714 : /* Must copy it out of typcache for safety */
715 62 : sexpr->funcResultDesc = CreateTupleDescCopy(tupdesc);
716 62 : sexpr->funcReturnsTuple = true;
717 : }
718 181 : else if (functypclass == TYPEFUNC_SCALAR)
719 : {
720 : /* Base data type, i.e. scalar */
721 179 : tupdesc = CreateTemplateTupleDesc(1, false);
722 179 : TupleDescInitEntry(tupdesc,
723 : (AttrNumber) 1,
724 : NULL,
725 : funcrettype,
726 : -1,
727 : 0);
728 179 : sexpr->funcResultDesc = tupdesc;
729 179 : sexpr->funcReturnsTuple = false;
730 : }
731 2 : else if (functypclass == TYPEFUNC_RECORD)
732 : {
733 : /* This will work if function doesn't need an expectedDesc */
734 2 : sexpr->funcResultDesc = NULL;
735 2 : sexpr->funcReturnsTuple = true;
736 : }
737 : else
738 : {
739 : /* Else, we will fail if function needs an expectedDesc */
740 0 : sexpr->funcResultDesc = NULL;
741 : }
742 :
743 243 : MemoryContextSwitchTo(oldcontext);
744 : }
745 : else
746 1486 : sexpr->funcResultDesc = NULL;
747 :
748 : /* Initialize additional state */
749 1729 : sexpr->funcResultStore = NULL;
750 1729 : sexpr->funcResultSlot = NULL;
751 1729 : sexpr->shutdown_reg = false;
752 1729 : }
753 :
754 : /*
755 : * callback function in case a SetExprState needs to be shut down before it
756 : * has been run to completion
757 : */
758 : static void
759 370 : ShutdownSetExpr(Datum arg)
760 : {
761 370 : SetExprState *sexpr = castNode(SetExprState, DatumGetPointer(arg));
762 :
763 : /* If we have a slot, make sure it's let go of any tuplestore pointer */
764 370 : if (sexpr->funcResultSlot)
765 20 : ExecClearTuple(sexpr->funcResultSlot);
766 :
767 : /* Release any open tuplestore */
768 370 : if (sexpr->funcResultStore)
769 3 : tuplestore_end(sexpr->funcResultStore);
770 370 : sexpr->funcResultStore = NULL;
771 :
772 : /* Clear any active set-argument state */
773 370 : sexpr->setArgsValid = false;
774 :
775 : /* execUtils will deregister the callback... */
776 370 : sexpr->shutdown_reg = false;
777 370 : }
778 :
779 : /*
780 : * Evaluate arguments for a function.
781 : */
782 : static void
783 19946 : ExecEvalFuncArgs(FunctionCallInfo fcinfo,
784 : List *argList,
785 : ExprContext *econtext)
786 : {
787 : int i;
788 : ListCell *arg;
789 :
790 19946 : i = 0;
791 52034 : foreach(arg, argList)
792 : {
793 32088 : ExprState *argstate = (ExprState *) lfirst(arg);
794 :
795 32088 : fcinfo->arg[i] = ExecEvalExpr(argstate,
796 : econtext,
797 : &fcinfo->argnull[i]);
798 32088 : i++;
799 : }
800 :
801 19946 : Assert(i == fcinfo->nargs);
802 19946 : }
803 :
804 : /*
805 : * ExecPrepareTuplestoreResult
806 : *
807 : * Subroutine for ExecMakeFunctionResultSet: prepare to extract rows from a
808 : * tuplestore function result. We must set up a funcResultSlot (unless
809 : * already done in a previous call cycle) and verify that the function
810 : * returned the expected tuple descriptor.
811 : */
812 : static void
813 2044 : ExecPrepareTuplestoreResult(SetExprState *sexpr,
814 : ExprContext *econtext,
815 : Tuplestorestate *resultStore,
816 : TupleDesc resultDesc)
817 : {
818 2044 : sexpr->funcResultStore = resultStore;
819 :
820 2044 : if (sexpr->funcResultSlot == NULL)
821 : {
822 : /* Create a slot so we can read data out of the tuplestore */
823 : TupleDesc slotDesc;
824 : MemoryContext oldcontext;
825 :
826 20 : oldcontext = MemoryContextSwitchTo(sexpr->func.fn_mcxt);
827 :
828 : /*
829 : * If we were not able to determine the result rowtype from context,
830 : * and the function didn't return a tupdesc, we have to fail.
831 : */
832 20 : if (sexpr->funcResultDesc)
833 19 : slotDesc = sexpr->funcResultDesc;
834 1 : else if (resultDesc)
835 : {
836 : /* don't assume resultDesc is long-lived */
837 1 : slotDesc = CreateTupleDescCopy(resultDesc);
838 : }
839 : else
840 : {
841 0 : ereport(ERROR,
842 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
843 : errmsg("function returning setof record called in "
844 : "context that cannot accept type record")));
845 : slotDesc = NULL; /* keep compiler quiet */
846 : }
847 :
848 20 : sexpr->funcResultSlot = MakeSingleTupleTableSlot(slotDesc);
849 20 : MemoryContextSwitchTo(oldcontext);
850 : }
851 :
852 : /*
853 : * If function provided a tupdesc, cross-check it. We only really need to
854 : * do this for functions returning RECORD, but might as well do it always.
855 : */
856 2044 : if (resultDesc)
857 : {
858 2044 : if (sexpr->funcResultDesc)
859 2043 : tupledesc_match(sexpr->funcResultDesc, resultDesc);
860 :
861 : /*
862 : * If it is a dynamically-allocated TupleDesc, free it: it is
863 : * typically allocated in a per-query context, so we must avoid
864 : * leaking it across multiple usages.
865 : */
866 2044 : if (resultDesc->tdrefcount == -1)
867 2044 : FreeTupleDesc(resultDesc);
868 : }
869 :
870 : /* Register cleanup callback if we didn't already */
871 2044 : if (!sexpr->shutdown_reg)
872 : {
873 20 : RegisterExprContextCallback(econtext,
874 : ShutdownSetExpr,
875 : PointerGetDatum(sexpr));
876 20 : sexpr->shutdown_reg = true;
877 : }
878 2044 : }
879 :
880 : /*
881 : * Check that function result tuple type (src_tupdesc) matches or can
882 : * be considered to match what the query expects (dst_tupdesc). If
883 : * they don't match, ereport.
884 : *
885 : * We really only care about number of attributes and data type.
886 : * Also, we can ignore type mismatch on columns that are dropped in the
887 : * destination type, so long as the physical storage matches. This is
888 : * helpful in some cases involving out-of-date cached plans.
889 : */
890 : static void
891 9395 : tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
892 : {
893 : int i;
894 :
895 9395 : if (dst_tupdesc->natts != src_tupdesc->natts)
896 1 : ereport(ERROR,
897 : (errcode(ERRCODE_DATATYPE_MISMATCH),
898 : errmsg("function return row and query-specified return row do not match"),
899 : errdetail_plural("Returned row contains %d attribute, but query expects %d.",
900 : "Returned row contains %d attributes, but query expects %d.",
901 : src_tupdesc->natts,
902 : src_tupdesc->natts, dst_tupdesc->natts)));
903 :
904 24403 : for (i = 0; i < dst_tupdesc->natts; i++)
905 : {
906 15010 : Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
907 15010 : Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
908 :
909 15010 : if (IsBinaryCoercible(sattr->atttypid, dattr->atttypid))
910 15009 : continue; /* no worries */
911 1 : if (!dattr->attisdropped)
912 1 : ereport(ERROR,
913 : (errcode(ERRCODE_DATATYPE_MISMATCH),
914 : errmsg("function return row and query-specified return row do not match"),
915 : errdetail("Returned type %s at ordinal position %d, but query expects %s.",
916 : format_type_be(sattr->atttypid),
917 : i + 1,
918 : format_type_be(dattr->atttypid))));
919 :
920 0 : if (dattr->attlen != sattr->attlen ||
921 0 : dattr->attalign != sattr->attalign)
922 0 : ereport(ERROR,
923 : (errcode(ERRCODE_DATATYPE_MISMATCH),
924 : errmsg("function return row and query-specified return row do not match"),
925 : errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
926 : i + 1)));
927 : }
928 9393 : }
|