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