Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * functions.c
4 : * Execution of SQL-language functions
5 : *
6 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/executor/functions.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "access/htup_details.h"
18 : #include "access/xact.h"
19 : #include "catalog/pg_proc.h"
20 : #include "catalog/pg_type.h"
21 : #include "executor/functions.h"
22 : #include "funcapi.h"
23 : #include "miscadmin.h"
24 : #include "nodes/makefuncs.h"
25 : #include "nodes/nodeFuncs.h"
26 : #include "parser/parse_coerce.h"
27 : #include "parser/parse_collate.h"
28 : #include "parser/parse_func.h"
29 : #include "rewrite/rewriteHandler.h"
30 : #include "storage/proc.h"
31 : #include "tcop/utility.h"
32 : #include "utils/builtins.h"
33 : #include "utils/datum.h"
34 : #include "utils/funccache.h"
35 : #include "utils/lsyscache.h"
36 : #include "utils/memutils.h"
37 : #include "utils/snapmgr.h"
38 : #include "utils/syscache.h"
39 :
40 :
41 : /*
42 : * Specialized DestReceiver for collecting query output in a SQL function
43 : */
44 : typedef struct
45 : {
46 : DestReceiver pub; /* publicly-known function pointers */
47 : Tuplestorestate *tstore; /* where to put result tuples, or NULL */
48 : JunkFilter *filter; /* filter to convert tuple type */
49 : } DR_sqlfunction;
50 :
51 : /*
52 : * We have an execution_state record for each query in a function. Each
53 : * record references a plantree for its query. If the query is currently in
54 : * F_EXEC_RUN state then there's a QueryDesc too.
55 : *
56 : * The "next" fields chain together all the execution_state records generated
57 : * from a single original parsetree. (There will only be more than one in
58 : * case of rule expansion of the original parsetree.) The chain structure is
59 : * quite vestigial at this point, because we allocate the records in an array
60 : * for ease of memory management. But we'll get rid of it some other day.
61 : */
62 : typedef enum
63 : {
64 : F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE,
65 : } ExecStatus;
66 :
67 : typedef struct execution_state
68 : {
69 : struct execution_state *next;
70 : ExecStatus status;
71 : bool setsResult; /* true if this query produces func's result */
72 : bool lazyEval; /* true if should fetch one row at a time */
73 : PlannedStmt *stmt; /* plan for this query */
74 : QueryDesc *qd; /* null unless status == RUN */
75 : } execution_state;
76 :
77 :
78 : /*
79 : * Data associated with a SQL-language function is kept in two main
80 : * data structures:
81 : *
82 : * 1. SQLFunctionHashEntry is a long-lived (potentially session-lifespan)
83 : * struct that holds all the info we need out of the function's pg_proc row.
84 : * In addition it holds pointers to CachedPlanSource(s) that manage creation
85 : * of plans for the query(s) within the function. A SQLFunctionHashEntry is
86 : * potentially shared across multiple concurrent executions of the function,
87 : * so it must contain no execution-specific state; but its use_count must
88 : * reflect the number of SQLFunctionCache structs pointing at it.
89 : * If the function's pg_proc row is updated, we throw away and regenerate
90 : * the SQLFunctionHashEntry and subsidiary data. (Also note that if the
91 : * function is polymorphic or used as a trigger, there is a separate
92 : * SQLFunctionHashEntry for each usage, so that we need consider only one
93 : * set of relevant data types.) The struct itself is in memory managed by
94 : * funccache.c, and its subsidiary data is kept in one of two contexts:
95 : * * pcontext ("parse context") holds the raw parse trees or Query trees
96 : * that we read from the pg_proc row. These will be converted to
97 : * CachedPlanSources as they are needed. Once the last one is converted,
98 : * pcontext can be freed.
99 : * * hcontext ("hash context") holds everything else belonging to the
100 : * SQLFunctionHashEntry.
101 : *
102 : * 2. SQLFunctionCache is subsidiary data for a single FmgrInfo struct.
103 : * It is pointed to by the fn_extra field of the FmgrInfo struct, and is
104 : * always allocated in the FmgrInfo's fn_mcxt. It holds a reference to
105 : * the CachedPlan for the current query, and other execution-specific data.
106 : * A few subsidiary items such as the ParamListInfo object are also kept
107 : * directly in fn_mcxt (which is also called fcontext here). But most
108 : * subsidiary data is in jfcontext or subcontext.
109 : */
110 :
111 : typedef struct SQLFunctionHashEntry
112 : {
113 : CachedFunction cfunc; /* fields managed by funccache.c */
114 :
115 : char *fname; /* function name (for error msgs) */
116 : char *src; /* function body text (for error msgs) */
117 :
118 : SQLFunctionParseInfoPtr pinfo; /* data for parser callback hooks */
119 : int16 *argtyplen; /* lengths of the input argument types */
120 :
121 : Oid rettype; /* actual return type */
122 : int16 typlen; /* length of the return type */
123 : bool typbyval; /* true if return type is pass by value */
124 : bool returnsSet; /* true if returning multiple rows */
125 : bool returnsTuple; /* true if returning whole tuple result */
126 : bool readonly_func; /* true to run in "read only" mode */
127 : char prokind; /* prokind from pg_proc row */
128 :
129 : TupleDesc rettupdesc; /* result tuple descriptor */
130 :
131 : List *source_list; /* RawStmts or Queries read from pg_proc */
132 : int num_queries; /* original length of source_list */
133 : bool raw_source; /* true if source_list contains RawStmts */
134 :
135 : List *plansource_list; /* CachedPlanSources for fn's queries */
136 :
137 : MemoryContext pcontext; /* memory context holding source_list */
138 : MemoryContext hcontext; /* memory context holding all else */
139 : } SQLFunctionHashEntry;
140 :
141 : typedef struct SQLFunctionCache
142 : {
143 : SQLFunctionHashEntry *func; /* associated SQLFunctionHashEntry */
144 :
145 : bool lazyEvalOK; /* true if lazyEval is safe */
146 : bool shutdown_reg; /* true if registered shutdown callback */
147 : bool lazyEval; /* true if using lazyEval for result query */
148 : bool randomAccess; /* true if tstore needs random access */
149 : bool ownSubcontext; /* is subcontext really a separate context? */
150 :
151 : ParamListInfo paramLI; /* Param list representing current args */
152 :
153 : Tuplestorestate *tstore; /* where we accumulate result for a SRF */
154 : MemoryContext tscontext; /* memory context that tstore should be in */
155 :
156 : JunkFilter *junkFilter; /* will be NULL if function returns VOID */
157 : int jf_generation; /* tracks whether junkFilter is up-to-date */
158 :
159 : /*
160 : * While executing a particular query within the function, cplan is the
161 : * CachedPlan we've obtained for that query, and eslist is a chain of
162 : * execution_state records for the individual plans within the CachedPlan.
163 : * If eslist is not NULL at entry to fmgr_sql, then we are resuming
164 : * execution of a lazyEval-mode set-returning function.
165 : *
166 : * next_query_index is the 0-based index of the next CachedPlanSource to
167 : * get a CachedPlan from.
168 : */
169 : CachedPlan *cplan; /* Plan for current query, if any */
170 : ResourceOwner cowner; /* CachedPlan is registered with this owner */
171 : int next_query_index; /* index of next CachedPlanSource to run */
172 :
173 : execution_state *eslist; /* chain of execution_state records */
174 : execution_state *esarray; /* storage for eslist */
175 : int esarray_len; /* allocated length of esarray[] */
176 :
177 : /* if positive, this is the 1-based index of the query we're processing */
178 : int error_query_index;
179 :
180 : MemoryContext fcontext; /* memory context holding this struct and all
181 : * subsidiary data */
182 : MemoryContext jfcontext; /* subsidiary memory context holding
183 : * junkFilter, result slot, and related data */
184 : MemoryContext subcontext; /* subsidiary memory context for sub-executor */
185 :
186 : /* Callback to release our use-count on the SQLFunctionHashEntry */
187 : MemoryContextCallback mcb;
188 : } SQLFunctionCache;
189 :
190 : typedef SQLFunctionCache *SQLFunctionCachePtr;
191 :
192 :
193 : /* non-export function prototypes */
194 : static Node *sql_fn_param_ref(ParseState *pstate, ParamRef *pref);
195 : static Node *sql_fn_post_column_ref(ParseState *pstate,
196 : ColumnRef *cref, Node *var);
197 : static Node *sql_fn_make_param(SQLFunctionParseInfoPtr pinfo,
198 : int paramno, int location);
199 : static Node *sql_fn_resolve_param_name(SQLFunctionParseInfoPtr pinfo,
200 : const char *paramname, int location);
201 : static SQLFunctionCache *init_sql_fcache(FunctionCallInfo fcinfo,
202 : bool lazyEvalOK);
203 : static bool init_execution_state(SQLFunctionCachePtr fcache);
204 : static void prepare_next_query(SQLFunctionHashEntry *func);
205 : static void sql_compile_callback(FunctionCallInfo fcinfo,
206 : HeapTuple procedureTuple,
207 : const CachedFunctionHashKey *hashkey,
208 : CachedFunction *cfunc,
209 : bool forValidator);
210 : static void sql_delete_callback(CachedFunction *cfunc);
211 : static void sql_postrewrite_callback(List *querytree_list, void *arg);
212 : static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
213 : static bool postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache);
214 : static void postquel_end(execution_state *es, SQLFunctionCachePtr fcache);
215 : static void postquel_sub_params(SQLFunctionCachePtr fcache,
216 : FunctionCallInfo fcinfo);
217 : static Datum postquel_get_single_result(TupleTableSlot *slot,
218 : FunctionCallInfo fcinfo,
219 : SQLFunctionCachePtr fcache);
220 : static void sql_compile_error_callback(void *arg);
221 : static void sql_exec_error_callback(void *arg);
222 : static void ShutdownSQLFunction(Datum arg);
223 : static void RemoveSQLFunctionCache(void *arg);
224 : static void check_sql_fn_statement(List *queryTreeList);
225 : static bool check_sql_stmt_retval(List *queryTreeList,
226 : Oid rettype, TupleDesc rettupdesc,
227 : char prokind, bool insertDroppedCols);
228 : static bool coerce_fn_result_column(TargetEntry *src_tle,
229 : Oid res_type, int32 res_typmod,
230 : bool tlist_is_modifiable,
231 : List **upper_tlist,
232 : bool *upper_tlist_nontrivial);
233 : static List *get_sql_fn_result_tlist(List *queryTreeList);
234 : static void sqlfunction_startup(DestReceiver *self, int operation, TupleDesc typeinfo);
235 : static bool sqlfunction_receive(TupleTableSlot *slot, DestReceiver *self);
236 : static void sqlfunction_shutdown(DestReceiver *self);
237 : static void sqlfunction_destroy(DestReceiver *self);
238 :
239 :
240 : /*
241 : * Prepare the SQLFunctionParseInfo struct for parsing a SQL function body
242 : *
243 : * This includes resolving actual types of polymorphic arguments.
244 : *
245 : * call_expr can be passed as NULL, but then we will fail if there are any
246 : * polymorphic arguments.
247 : */
248 : SQLFunctionParseInfoPtr
249 7102 : prepare_sql_fn_parse_info(HeapTuple procedureTuple,
250 : Node *call_expr,
251 : Oid inputCollation)
252 : {
253 : SQLFunctionParseInfoPtr pinfo;
254 7102 : Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
255 : int nargs;
256 :
257 7102 : pinfo = (SQLFunctionParseInfoPtr) palloc0(sizeof(SQLFunctionParseInfo));
258 :
259 : /* Function's name (only) can be used to qualify argument names */
260 7102 : pinfo->fname = pstrdup(NameStr(procedureStruct->proname));
261 :
262 : /* Save the function's input collation */
263 7102 : pinfo->collation = inputCollation;
264 :
265 : /*
266 : * Copy input argument types from the pg_proc entry, then resolve any
267 : * polymorphic types.
268 : */
269 7102 : pinfo->nargs = nargs = procedureStruct->pronargs;
270 7102 : if (nargs > 0)
271 : {
272 : Oid *argOidVect;
273 : int argnum;
274 :
275 5862 : argOidVect = (Oid *) palloc(nargs * sizeof(Oid));
276 5862 : memcpy(argOidVect,
277 5862 : procedureStruct->proargtypes.values,
278 : nargs * sizeof(Oid));
279 :
280 15640 : for (argnum = 0; argnum < nargs; argnum++)
281 : {
282 9778 : Oid argtype = argOidVect[argnum];
283 :
284 9778 : if (IsPolymorphicType(argtype))
285 : {
286 2612 : argtype = get_call_expr_argtype(call_expr, argnum);
287 2612 : if (argtype == InvalidOid)
288 0 : ereport(ERROR,
289 : (errcode(ERRCODE_DATATYPE_MISMATCH),
290 : errmsg("could not determine actual type of argument declared %s",
291 : format_type_be(argOidVect[argnum]))));
292 2612 : argOidVect[argnum] = argtype;
293 : }
294 : }
295 :
296 5862 : pinfo->argtypes = argOidVect;
297 : }
298 :
299 : /*
300 : * Collect names of arguments, too, if any
301 : */
302 7102 : if (nargs > 0)
303 : {
304 : Datum proargnames;
305 : Datum proargmodes;
306 : int n_arg_names;
307 : bool isNull;
308 :
309 5862 : proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, procedureTuple,
310 : Anum_pg_proc_proargnames,
311 : &isNull);
312 5862 : if (isNull)
313 3970 : proargnames = PointerGetDatum(NULL); /* just to be sure */
314 :
315 5862 : proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, procedureTuple,
316 : Anum_pg_proc_proargmodes,
317 : &isNull);
318 5862 : if (isNull)
319 5228 : proargmodes = PointerGetDatum(NULL); /* just to be sure */
320 :
321 5862 : n_arg_names = get_func_input_arg_names(proargnames, proargmodes,
322 : &pinfo->argnames);
323 :
324 : /* Paranoia: ignore the result if too few array entries */
325 5862 : if (n_arg_names < nargs)
326 3970 : pinfo->argnames = NULL;
327 : }
328 : else
329 1240 : pinfo->argnames = NULL;
330 :
331 7102 : return pinfo;
332 : }
333 :
334 : /*
335 : * Parser setup hook for parsing a SQL function body.
336 : */
337 : void
338 12024 : sql_fn_parser_setup(struct ParseState *pstate, SQLFunctionParseInfoPtr pinfo)
339 : {
340 12024 : pstate->p_pre_columnref_hook = NULL;
341 12024 : pstate->p_post_columnref_hook = sql_fn_post_column_ref;
342 12024 : pstate->p_paramref_hook = sql_fn_param_ref;
343 : /* no need to use p_coerce_param_hook */
344 12024 : pstate->p_ref_hook_state = pinfo;
345 12024 : }
346 :
347 : /*
348 : * sql_fn_post_column_ref parser callback for ColumnRefs
349 : */
350 : static Node *
351 8898 : sql_fn_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var)
352 : {
353 8898 : SQLFunctionParseInfoPtr pinfo = (SQLFunctionParseInfoPtr) pstate->p_ref_hook_state;
354 : int nnames;
355 : Node *field1;
356 8898 : Node *subfield = NULL;
357 : const char *name1;
358 8898 : const char *name2 = NULL;
359 : Node *param;
360 :
361 : /*
362 : * Never override a table-column reference. This corresponds to
363 : * considering the parameter names to appear in a scope outside the
364 : * individual SQL commands, which is what we want.
365 : */
366 8898 : if (var != NULL)
367 7468 : return NULL;
368 :
369 : /*----------
370 : * The allowed syntaxes are:
371 : *
372 : * A A = parameter name
373 : * A.B A = function name, B = parameter name
374 : * OR: A = record-typed parameter name, B = field name
375 : * (the first possibility takes precedence)
376 : * A.B.C A = function name, B = record-typed parameter name,
377 : * C = field name
378 : * A.* Whole-row reference to composite parameter A.
379 : * A.B.* Same, with A = function name, B = parameter name
380 : *
381 : * Here, it's sufficient to ignore the "*" in the last two cases --- the
382 : * main parser will take care of expanding the whole-row reference.
383 : *----------
384 : */
385 1430 : nnames = list_length(cref->fields);
386 :
387 1430 : if (nnames > 3)
388 0 : return NULL;
389 :
390 1430 : if (IsA(llast(cref->fields), A_Star))
391 42 : nnames--;
392 :
393 1430 : field1 = (Node *) linitial(cref->fields);
394 1430 : name1 = strVal(field1);
395 1430 : if (nnames > 1)
396 : {
397 156 : subfield = (Node *) lsecond(cref->fields);
398 156 : name2 = strVal(subfield);
399 : }
400 :
401 1430 : if (nnames == 3)
402 : {
403 : /*
404 : * Three-part name: if the first part doesn't match the function name,
405 : * we can fail immediately. Otherwise, look up the second part, and
406 : * take the third part to be a field reference.
407 : */
408 24 : if (strcmp(name1, pinfo->fname) != 0)
409 0 : return NULL;
410 :
411 24 : param = sql_fn_resolve_param_name(pinfo, name2, cref->location);
412 :
413 24 : subfield = (Node *) lthird(cref->fields);
414 : Assert(IsA(subfield, String));
415 : }
416 1406 : else if (nnames == 2 && strcmp(name1, pinfo->fname) == 0)
417 : {
418 : /*
419 : * Two-part name with first part matching function name: first see if
420 : * second part matches any parameter name.
421 : */
422 24 : param = sql_fn_resolve_param_name(pinfo, name2, cref->location);
423 :
424 24 : if (param)
425 : {
426 : /* Yes, so this is a parameter reference, no subfield */
427 24 : subfield = NULL;
428 : }
429 : else
430 : {
431 : /* No, so try to match as parameter name and subfield */
432 0 : param = sql_fn_resolve_param_name(pinfo, name1, cref->location);
433 : }
434 : }
435 : else
436 : {
437 : /* Single name, or parameter name followed by subfield */
438 1382 : param = sql_fn_resolve_param_name(pinfo, name1, cref->location);
439 : }
440 :
441 1430 : if (!param)
442 0 : return NULL; /* No match */
443 :
444 1430 : if (subfield)
445 : {
446 : /*
447 : * Must be a reference to a field of a composite parameter; otherwise
448 : * ParseFuncOrColumn will return NULL, and we'll fail back at the
449 : * caller.
450 : */
451 132 : param = ParseFuncOrColumn(pstate,
452 132 : list_make1(subfield),
453 132 : list_make1(param),
454 : pstate->p_last_srf,
455 : NULL,
456 : false,
457 : cref->location);
458 : }
459 :
460 1430 : return param;
461 : }
462 :
463 : /*
464 : * sql_fn_param_ref parser callback for ParamRefs ($n symbols)
465 : */
466 : static Node *
467 21564 : sql_fn_param_ref(ParseState *pstate, ParamRef *pref)
468 : {
469 21564 : SQLFunctionParseInfoPtr pinfo = (SQLFunctionParseInfoPtr) pstate->p_ref_hook_state;
470 21564 : int paramno = pref->number;
471 :
472 : /* Check parameter number is valid */
473 21564 : if (paramno <= 0 || paramno > pinfo->nargs)
474 6 : return NULL; /* unknown parameter number */
475 :
476 21558 : return sql_fn_make_param(pinfo, paramno, pref->location);
477 : }
478 :
479 : /*
480 : * sql_fn_make_param construct a Param node for the given paramno
481 : */
482 : static Node *
483 22988 : sql_fn_make_param(SQLFunctionParseInfoPtr pinfo,
484 : int paramno, int location)
485 : {
486 : Param *param;
487 :
488 22988 : param = makeNode(Param);
489 22988 : param->paramkind = PARAM_EXTERN;
490 22988 : param->paramid = paramno;
491 22988 : param->paramtype = pinfo->argtypes[paramno - 1];
492 22988 : param->paramtypmod = -1;
493 22988 : param->paramcollid = get_typcollation(param->paramtype);
494 22988 : param->location = location;
495 :
496 : /*
497 : * If we have a function input collation, allow it to override the
498 : * type-derived collation for parameter symbols. (XXX perhaps this should
499 : * not happen if the type collation is not default?)
500 : */
501 22988 : if (OidIsValid(pinfo->collation) && OidIsValid(param->paramcollid))
502 2008 : param->paramcollid = pinfo->collation;
503 :
504 22988 : return (Node *) param;
505 : }
506 :
507 : /*
508 : * Search for a function parameter of the given name; if there is one,
509 : * construct and return a Param node for it. If not, return NULL.
510 : * Helper function for sql_fn_post_column_ref.
511 : */
512 : static Node *
513 1430 : sql_fn_resolve_param_name(SQLFunctionParseInfoPtr pinfo,
514 : const char *paramname, int location)
515 : {
516 : int i;
517 :
518 1430 : if (pinfo->argnames == NULL)
519 0 : return NULL;
520 :
521 1960 : for (i = 0; i < pinfo->nargs; i++)
522 : {
523 1960 : if (pinfo->argnames[i] && strcmp(pinfo->argnames[i], paramname) == 0)
524 1430 : return sql_fn_make_param(pinfo, i + 1, location);
525 : }
526 :
527 0 : return NULL;
528 : }
529 :
530 : /*
531 : * Initialize the SQLFunctionCache for a SQL function
532 : */
533 : static SQLFunctionCache *
534 86904 : init_sql_fcache(FunctionCallInfo fcinfo, bool lazyEvalOK)
535 : {
536 86904 : FmgrInfo *finfo = fcinfo->flinfo;
537 : SQLFunctionHashEntry *func;
538 : SQLFunctionCache *fcache;
539 :
540 : /*
541 : * If this is the first execution for this FmgrInfo, set up a cache struct
542 : * (initially containing null pointers). The cache must live as long as
543 : * the FmgrInfo, so it goes in fn_mcxt. Also set up a memory context
544 : * callback that will be invoked when fn_mcxt is deleted.
545 : */
546 86904 : fcache = finfo->fn_extra;
547 86904 : if (fcache == NULL)
548 : {
549 : fcache = (SQLFunctionCache *)
550 34006 : MemoryContextAllocZero(finfo->fn_mcxt, sizeof(SQLFunctionCache));
551 34006 : fcache->fcontext = finfo->fn_mcxt;
552 34006 : fcache->mcb.func = RemoveSQLFunctionCache;
553 34006 : fcache->mcb.arg = fcache;
554 34006 : MemoryContextRegisterResetCallback(finfo->fn_mcxt, &fcache->mcb);
555 34006 : finfo->fn_extra = fcache;
556 : }
557 :
558 : /*
559 : * If we are resuming execution of a set-returning function, just keep
560 : * using the same cache. We do not ask funccache.c to re-validate the
561 : * SQLFunctionHashEntry: we want to run to completion using the function's
562 : * initial definition.
563 : */
564 86904 : if (fcache->eslist != NULL)
565 : {
566 : Assert(fcache->func != NULL);
567 988 : return fcache;
568 : }
569 :
570 : /*
571 : * Look up, or re-validate, the long-lived hash entry. Make the hash key
572 : * depend on the result of get_call_result_type() when that's composite,
573 : * so that we can safely assume that we'll build a new hash entry if the
574 : * composite rowtype changes.
575 : */
576 : func = (SQLFunctionHashEntry *)
577 85916 : cached_function_compile(fcinfo,
578 85916 : (CachedFunction *) fcache->func,
579 : sql_compile_callback,
580 : sql_delete_callback,
581 : sizeof(SQLFunctionHashEntry),
582 : true,
583 : false);
584 :
585 : /*
586 : * Install the hash pointer in the SQLFunctionCache, and increment its use
587 : * count to reflect that. If cached_function_compile gave us back a
588 : * different hash entry than we were using before, we must decrement that
589 : * one's use count.
590 : */
591 85910 : if (func != fcache->func)
592 : {
593 34000 : if (fcache->func != NULL)
594 : {
595 : Assert(fcache->func->cfunc.use_count > 0);
596 0 : fcache->func->cfunc.use_count--;
597 : }
598 34000 : fcache->func = func;
599 34000 : func->cfunc.use_count++;
600 : /* Assume we need to rebuild the junkFilter */
601 34000 : fcache->junkFilter = NULL;
602 : }
603 :
604 : /*
605 : * We're beginning a new execution of the function, so convert params to
606 : * appropriate format.
607 : */
608 85910 : postquel_sub_params(fcache, fcinfo);
609 :
610 : /* Also reset lazyEval state for the new execution. */
611 85910 : fcache->lazyEvalOK = lazyEvalOK;
612 85910 : fcache->lazyEval = false;
613 :
614 : /* Also reset data about where we are in the function. */
615 85910 : fcache->eslist = NULL;
616 85910 : fcache->next_query_index = 0;
617 85910 : fcache->error_query_index = 0;
618 :
619 85910 : return fcache;
620 : }
621 :
622 : /*
623 : * Set up the per-query execution_state records for the next query within
624 : * the SQL function.
625 : *
626 : * Returns true if successful, false if there are no more queries.
627 : */
628 : static bool
629 164014 : init_execution_state(SQLFunctionCachePtr fcache)
630 : {
631 : CachedPlanSource *plansource;
632 164014 : execution_state *preves = NULL;
633 164014 : execution_state *lasttages = NULL;
634 : int nstmts;
635 : ListCell *lc;
636 :
637 : /*
638 : * Clean up after previous query, if there was one.
639 : */
640 164014 : if (fcache->cplan)
641 : {
642 78104 : ReleaseCachedPlan(fcache->cplan, fcache->cowner);
643 78104 : fcache->cplan = NULL;
644 : }
645 164014 : fcache->eslist = NULL;
646 :
647 : /*
648 : * Get the next CachedPlanSource, or stop if there are no more. We might
649 : * need to create the next CachedPlanSource; if so, advance
650 : * error_query_index first, so that errors detected in prepare_next_query
651 : * are blamed on the right statement.
652 : */
653 164014 : if (fcache->next_query_index >= list_length(fcache->func->plansource_list))
654 : {
655 80210 : if (fcache->next_query_index >= fcache->func->num_queries)
656 78014 : return false;
657 2196 : fcache->error_query_index++;
658 2196 : prepare_next_query(fcache->func);
659 : }
660 : else
661 83804 : fcache->error_query_index++;
662 :
663 85994 : plansource = (CachedPlanSource *) list_nth(fcache->func->plansource_list,
664 : fcache->next_query_index);
665 85994 : fcache->next_query_index++;
666 :
667 : /*
668 : * Generate plans for the query or queries within this CachedPlanSource.
669 : * Register the CachedPlan with the current resource owner. (Saving
670 : * cowner here is mostly paranoia, but this way we needn't assume that
671 : * CurrentResourceOwner will be the same when ShutdownSQLFunction runs.)
672 : */
673 85994 : fcache->cowner = CurrentResourceOwner;
674 85994 : fcache->cplan = GetCachedPlan(plansource,
675 : fcache->paramLI,
676 : fcache->cowner,
677 : NULL);
678 :
679 : /*
680 : * If necessary, make esarray[] bigger to hold the needed state.
681 : */
682 85944 : nstmts = list_length(fcache->cplan->stmt_list);
683 85944 : if (nstmts > fcache->esarray_len)
684 : {
685 33950 : if (fcache->esarray == NULL)
686 33950 : fcache->esarray = (execution_state *)
687 33950 : MemoryContextAlloc(fcache->fcontext,
688 : sizeof(execution_state) * nstmts);
689 : else
690 0 : fcache->esarray = repalloc_array(fcache->esarray,
691 : execution_state, nstmts);
692 33950 : fcache->esarray_len = nstmts;
693 : }
694 :
695 : /*
696 : * Build execution_state list to match the number of contained plans.
697 : */
698 171894 : foreach(lc, fcache->cplan->stmt_list)
699 : {
700 85950 : PlannedStmt *stmt = lfirst_node(PlannedStmt, lc);
701 : execution_state *newes;
702 :
703 : /*
704 : * Precheck all commands for validity in a function. This should
705 : * generally match the restrictions spi.c applies.
706 : */
707 85950 : if (stmt->commandType == CMD_UTILITY)
708 : {
709 180 : if (IsA(stmt->utilityStmt, CopyStmt) &&
710 0 : ((CopyStmt *) stmt->utilityStmt)->filename == NULL)
711 0 : ereport(ERROR,
712 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
713 : errmsg("cannot COPY to/from client in an SQL function")));
714 :
715 180 : if (IsA(stmt->utilityStmt, TransactionStmt))
716 0 : ereport(ERROR,
717 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
718 : /* translator: %s is a SQL statement name */
719 : errmsg("%s is not allowed in an SQL function",
720 : CreateCommandName(stmt->utilityStmt))));
721 : }
722 :
723 85950 : if (fcache->func->readonly_func && !CommandIsReadOnly(stmt))
724 0 : ereport(ERROR,
725 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
726 : /* translator: %s is a SQL statement name */
727 : errmsg("%s is not allowed in a non-volatile function",
728 : CreateCommandName((Node *) stmt))));
729 :
730 : /* OK, build the execution_state for this query */
731 85950 : newes = &fcache->esarray[foreach_current_index(lc)];
732 85950 : if (preves)
733 6 : preves->next = newes;
734 : else
735 85944 : fcache->eslist = newes;
736 :
737 85950 : newes->next = NULL;
738 85950 : newes->status = F_EXEC_START;
739 85950 : newes->setsResult = false; /* might change below */
740 85950 : newes->lazyEval = false; /* might change below */
741 85950 : newes->stmt = stmt;
742 85950 : newes->qd = NULL;
743 :
744 85950 : if (stmt->canSetTag)
745 85944 : lasttages = newes;
746 :
747 85950 : preves = newes;
748 : }
749 :
750 : /*
751 : * If this isn't the last CachedPlanSource, we're done here. Otherwise,
752 : * we need to prepare information about how to return the results.
753 : */
754 85944 : if (fcache->next_query_index < fcache->func->num_queries)
755 126 : return true;
756 :
757 : /*
758 : * Construct a JunkFilter we can use to coerce the returned rowtype to the
759 : * desired form, unless the result type is VOID, in which case there's
760 : * nothing to coerce to. (XXX Frequently, the JunkFilter isn't doing
761 : * anything very interesting, but much of this module expects it to be
762 : * there anyway.)
763 : *
764 : * Normally we can re-use the JunkFilter across executions, but if the
765 : * plan for the last CachedPlanSource changed, we'd better rebuild it.
766 : *
767 : * The JunkFilter, its result slot, and its tupledesc are kept in a
768 : * subsidiary memory context so that we can free them easily when needed.
769 : */
770 85818 : if (fcache->func->rettype != VOIDOID &&
771 85524 : (fcache->junkFilter == NULL ||
772 51898 : fcache->jf_generation != fcache->cplan->generation))
773 : {
774 : TupleTableSlot *slot;
775 : List *resulttlist;
776 : MemoryContext oldcontext;
777 :
778 : /* Create or reset the jfcontext */
779 35770 : if (fcache->jfcontext == NULL)
780 33626 : fcache->jfcontext = AllocSetContextCreate(fcache->fcontext,
781 : "SQL function junkfilter",
782 : ALLOCSET_SMALL_SIZES);
783 : else
784 2144 : MemoryContextReset(fcache->jfcontext);
785 35770 : oldcontext = MemoryContextSwitchTo(fcache->jfcontext);
786 :
787 35770 : slot = MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
788 :
789 : /*
790 : * Re-fetch the (possibly modified) output tlist of the final
791 : * statement. By this point, we should have thrown an error if there
792 : * is not one.
793 : */
794 35770 : resulttlist = get_sql_fn_result_tlist(plansource->query_list);
795 :
796 : /*
797 : * If the result is composite, *and* we are returning the whole tuple
798 : * result, we need to insert nulls for any dropped columns. In the
799 : * single-column-result case, there might be dropped columns within
800 : * the composite column value, but it's not our problem here. There
801 : * should be no resjunk entries in resulttlist, so in the second case
802 : * the JunkFilter is certainly a no-op.
803 : */
804 35770 : if (fcache->func->rettupdesc && fcache->func->returnsTuple)
805 1606 : fcache->junkFilter = ExecInitJunkFilterConversion(resulttlist,
806 1606 : fcache->func->rettupdesc,
807 : slot);
808 : else
809 34164 : fcache->junkFilter = ExecInitJunkFilter(resulttlist, slot);
810 :
811 : /*
812 : * The resulttlist tree belongs to the plancache and might disappear
813 : * underneath us due to plancache invalidation. While we could
814 : * forestall that by copying it, that'd just be a waste of cycles,
815 : * because the junkfilter doesn't need it anymore. (It'd only be used
816 : * by ExecFindJunkAttribute(), which we don't use here.) To ensure
817 : * there's not a dangling pointer laying about, clear the junkFilter's
818 : * pointer.
819 : */
820 35770 : fcache->junkFilter->jf_targetList = NIL;
821 :
822 : /* Make sure output rowtype is properly blessed */
823 35770 : if (fcache->func->returnsTuple)
824 1630 : BlessTupleDesc(fcache->junkFilter->jf_resultSlot->tts_tupleDescriptor);
825 :
826 : /* Mark the JunkFilter as up-to-date */
827 35770 : fcache->jf_generation = fcache->cplan->generation;
828 :
829 35770 : MemoryContextSwitchTo(oldcontext);
830 : }
831 :
832 85818 : if (fcache->func->returnsSet &&
833 4240 : !fcache->func->returnsTuple &&
834 194 : type_is_rowtype(fcache->func->rettype))
835 : {
836 : /*
837 : * Returning rowtype as if it were scalar --- materialize won't work.
838 : * Right now it's sufficient to override any caller preference for
839 : * materialize mode, but this might need more work in future.
840 : */
841 0 : fcache->lazyEvalOK = true;
842 : }
843 :
844 : /*
845 : * Mark the last canSetTag query as delivering the function result; then,
846 : * if it is a plain SELECT, mark it for lazy evaluation. If it's not a
847 : * SELECT we must always run it to completion.
848 : *
849 : * Note: at some point we might add additional criteria for whether to use
850 : * lazy eval. However, we should prefer to use it whenever the function
851 : * doesn't return set, since fetching more than one row is useless in that
852 : * case.
853 : *
854 : * Note: don't set setsResult if the function returns VOID, as evidenced
855 : * by not having made a junkfilter. This ensures we'll throw away any
856 : * output from the last statement in such a function.
857 : */
858 85818 : if (lasttages && fcache->junkFilter)
859 : {
860 85524 : lasttages->setsResult = true;
861 85524 : if (fcache->lazyEvalOK &&
862 84690 : lasttages->stmt->commandType == CMD_SELECT &&
863 84612 : !lasttages->stmt->hasModifyingCTE)
864 84612 : fcache->lazyEval = lasttages->lazyEval = true;
865 : }
866 :
867 85818 : return true;
868 : }
869 :
870 : /*
871 : * Convert the SQL function's next query from source form (RawStmt or Query)
872 : * into a CachedPlanSource. If it's the last query, also determine whether
873 : * the function returnsTuple.
874 : */
875 : static void
876 2196 : prepare_next_query(SQLFunctionHashEntry *func)
877 : {
878 : int qindex;
879 : bool islast;
880 : CachedPlanSource *plansource;
881 : List *queryTree_list;
882 : MemoryContext oldcontext;
883 :
884 : /* Which query should we process? */
885 2196 : qindex = list_length(func->plansource_list);
886 : Assert(qindex < func->num_queries); /* else caller error */
887 2196 : islast = (qindex + 1 >= func->num_queries);
888 :
889 : /*
890 : * Parse and/or rewrite the query, creating a CachedPlanSource that holds
891 : * a copy of the original parsetree. Note fine point: we make a copy of
892 : * each original parsetree to ensure that the source_list in pcontext
893 : * remains unmodified during parse analysis and rewrite. This is normally
894 : * unnecessary, but we have to do it in case an error is raised during
895 : * parse analysis. Otherwise, a fresh attempt to execute the function
896 : * will arrive back here and try to work from a corrupted source_list.
897 : */
898 2196 : if (!func->raw_source)
899 : {
900 : /* Source queries are already parse-analyzed */
901 886 : Query *parsetree = list_nth_node(Query, func->source_list, qindex);
902 :
903 886 : parsetree = copyObject(parsetree);
904 886 : plansource = CreateCachedPlanForQuery(parsetree,
905 886 : func->src,
906 : CreateCommandTag((Node *) parsetree));
907 886 : AcquireRewriteLocks(parsetree, true, false);
908 886 : queryTree_list = pg_rewrite_query(parsetree);
909 : }
910 : else
911 : {
912 : /* Source queries are raw parsetrees */
913 1310 : RawStmt *parsetree = list_nth_node(RawStmt, func->source_list, qindex);
914 :
915 1310 : parsetree = copyObject(parsetree);
916 1310 : plansource = CreateCachedPlan(parsetree,
917 1310 : func->src,
918 : CreateCommandTag(parsetree->stmt));
919 1310 : queryTree_list = pg_analyze_and_rewrite_withcb(parsetree,
920 1310 : func->src,
921 : (ParserSetupHook) sql_fn_parser_setup,
922 1310 : func->pinfo,
923 : NULL);
924 : }
925 :
926 : /*
927 : * Check that there are no statements we don't want to allow.
928 : */
929 2196 : check_sql_fn_statement(queryTree_list);
930 :
931 : /*
932 : * If this is the last query, check that the function returns the type it
933 : * claims to. Although in simple cases this was already done when the
934 : * function was defined, we have to recheck because database objects used
935 : * in the function's queries might have changed type. We'd have to
936 : * recheck anyway if the function had any polymorphic arguments. Moreover,
937 : * check_sql_stmt_retval takes care of injecting any required column type
938 : * coercions. (But we don't ask it to insert nulls for dropped columns;
939 : * the junkfilter handles that.)
940 : *
941 : * Note: we set func->returnsTuple according to whether we are returning
942 : * the whole tuple result or just a single column. In the latter case we
943 : * clear returnsTuple because we need not act different from the scalar
944 : * result case, even if it's a rowtype column. (However, we have to force
945 : * lazy eval mode in that case; otherwise we'd need extra code to expand
946 : * the rowtype column into multiple columns, since we have no way to
947 : * notify the caller that it should do that.)
948 : */
949 2196 : if (islast)
950 2120 : func->returnsTuple = check_sql_stmt_retval(queryTree_list,
951 : func->rettype,
952 : func->rettupdesc,
953 2126 : func->prokind,
954 : false);
955 :
956 : /*
957 : * Now that check_sql_stmt_retval has done its thing, we can complete plan
958 : * cache entry creation.
959 : */
960 2190 : CompleteCachedPlan(plansource,
961 : queryTree_list,
962 : NULL,
963 : NULL,
964 : 0,
965 : (ParserSetupHook) sql_fn_parser_setup,
966 2190 : func->pinfo,
967 : CURSOR_OPT_PARALLEL_OK | CURSOR_OPT_NO_SCROLL,
968 : false);
969 :
970 : /*
971 : * Install post-rewrite hook. Its arg is the hash entry if this is the
972 : * last statement, else NULL.
973 : */
974 2190 : SetPostRewriteHook(plansource,
975 : sql_postrewrite_callback,
976 : islast ? func : NULL);
977 :
978 : /*
979 : * While the CachedPlanSources can take care of themselves, our List
980 : * pointing to them had better be in the hcontext.
981 : */
982 2190 : oldcontext = MemoryContextSwitchTo(func->hcontext);
983 2190 : func->plansource_list = lappend(func->plansource_list, plansource);
984 2190 : MemoryContextSwitchTo(oldcontext);
985 :
986 : /*
987 : * As soon as we've linked the CachedPlanSource into the list, mark it as
988 : * "saved".
989 : */
990 2190 : SaveCachedPlan(plansource);
991 :
992 : /*
993 : * Finally, if this was the last statement, we can flush the pcontext with
994 : * the original query trees; they're all safely copied into
995 : * CachedPlanSources now.
996 : */
997 2190 : if (islast)
998 : {
999 2120 : func->source_list = NIL; /* avoid dangling pointer */
1000 2120 : MemoryContextDelete(func->pcontext);
1001 2120 : func->pcontext = NULL;
1002 : }
1003 2190 : }
1004 :
1005 : /*
1006 : * Fill a new SQLFunctionHashEntry.
1007 : *
1008 : * The passed-in "cfunc" struct is expected to be zeroes, except
1009 : * for the CachedFunction fields, which we don't touch here.
1010 : *
1011 : * We expect to be called in a short-lived memory context (typically a
1012 : * query's per-tuple context). Data that is to be part of the hash entry
1013 : * must be copied into the hcontext or pcontext as appropriate.
1014 : */
1015 : static void
1016 2162 : sql_compile_callback(FunctionCallInfo fcinfo,
1017 : HeapTuple procedureTuple,
1018 : const CachedFunctionHashKey *hashkey,
1019 : CachedFunction *cfunc,
1020 : bool forValidator)
1021 : {
1022 2162 : SQLFunctionHashEntry *func = (SQLFunctionHashEntry *) cfunc;
1023 2162 : Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
1024 : ErrorContextCallback comperrcontext;
1025 : MemoryContext hcontext;
1026 : MemoryContext pcontext;
1027 2162 : MemoryContext oldcontext = CurrentMemoryContext;
1028 : Oid rettype;
1029 : TupleDesc rettupdesc;
1030 : Datum tmp;
1031 : bool isNull;
1032 : List *source_list;
1033 :
1034 : /*
1035 : * Setup error traceback support for ereport() during compile. (This is
1036 : * mainly useful for reporting parse errors from pg_parse_query.)
1037 : */
1038 2162 : comperrcontext.callback = sql_compile_error_callback;
1039 2162 : comperrcontext.arg = func;
1040 2162 : comperrcontext.previous = error_context_stack;
1041 2162 : error_context_stack = &comperrcontext;
1042 :
1043 : /*
1044 : * Create the hash entry's memory context. For now it's a child of the
1045 : * caller's context, so that it will go away if we fail partway through.
1046 : */
1047 2162 : hcontext = AllocSetContextCreate(CurrentMemoryContext,
1048 : "SQL function",
1049 : ALLOCSET_SMALL_SIZES);
1050 :
1051 : /*
1052 : * Create the not-as-long-lived pcontext. We make this a child of
1053 : * hcontext so that it doesn't require separate deletion.
1054 : */
1055 2162 : pcontext = AllocSetContextCreate(hcontext,
1056 : "SQL function parse trees",
1057 : ALLOCSET_SMALL_SIZES);
1058 2162 : func->pcontext = pcontext;
1059 :
1060 : /*
1061 : * copy function name immediately for use by error reporting callback, and
1062 : * for use as memory context identifier
1063 : */
1064 4324 : func->fname = MemoryContextStrdup(hcontext,
1065 2162 : NameStr(procedureStruct->proname));
1066 2162 : MemoryContextSetIdentifier(hcontext, func->fname);
1067 :
1068 : /*
1069 : * Resolve any polymorphism, obtaining the actual result type, and the
1070 : * corresponding tupdesc if it's a rowtype.
1071 : */
1072 2162 : (void) get_call_result_type(fcinfo, &rettype, &rettupdesc);
1073 :
1074 2162 : func->rettype = rettype;
1075 2162 : if (rettupdesc)
1076 : {
1077 530 : MemoryContextSwitchTo(hcontext);
1078 530 : func->rettupdesc = CreateTupleDescCopy(rettupdesc);
1079 530 : MemoryContextSwitchTo(oldcontext);
1080 : }
1081 :
1082 : /* Fetch the typlen and byval info for the result type */
1083 2162 : get_typlenbyval(rettype, &func->typlen, &func->typbyval);
1084 :
1085 : /* Remember whether we're returning setof something */
1086 2162 : func->returnsSet = procedureStruct->proretset;
1087 :
1088 : /* Remember if function is STABLE/IMMUTABLE */
1089 2162 : func->readonly_func =
1090 2162 : (procedureStruct->provolatile != PROVOLATILE_VOLATILE);
1091 :
1092 : /* Remember routine kind */
1093 2162 : func->prokind = procedureStruct->prokind;
1094 :
1095 : /*
1096 : * We need the actual argument types to pass to the parser. Also make
1097 : * sure that parameter symbols are considered to have the function's
1098 : * resolved input collation.
1099 : */
1100 2162 : MemoryContextSwitchTo(hcontext);
1101 4324 : func->pinfo = prepare_sql_fn_parse_info(procedureTuple,
1102 2162 : fcinfo->flinfo->fn_expr,
1103 : PG_GET_COLLATION());
1104 2162 : MemoryContextSwitchTo(oldcontext);
1105 :
1106 : /*
1107 : * Now that we have the resolved argument types, collect their typlens for
1108 : * use in postquel_sub_params.
1109 : */
1110 2162 : func->argtyplen = (int16 *)
1111 2162 : MemoryContextAlloc(hcontext, func->pinfo->nargs * sizeof(int16));
1112 5284 : for (int i = 0; i < func->pinfo->nargs; i++)
1113 3122 : func->argtyplen[i] = get_typlen(func->pinfo->argtypes[i]);
1114 :
1115 : /*
1116 : * And of course we need the function body text.
1117 : */
1118 2162 : tmp = SysCacheGetAttrNotNull(PROCOID, procedureTuple, Anum_pg_proc_prosrc);
1119 2162 : func->src = MemoryContextStrdup(hcontext,
1120 2162 : TextDatumGetCString(tmp));
1121 :
1122 : /* If we have prosqlbody, pay attention to that not prosrc. */
1123 2162 : tmp = SysCacheGetAttr(PROCOID,
1124 : procedureTuple,
1125 : Anum_pg_proc_prosqlbody,
1126 : &isNull);
1127 2162 : if (!isNull)
1128 : {
1129 : /* Source queries are already parse-analyzed */
1130 : Node *n;
1131 :
1132 886 : n = stringToNode(TextDatumGetCString(tmp));
1133 886 : if (IsA(n, List))
1134 656 : source_list = linitial_node(List, castNode(List, n));
1135 : else
1136 230 : source_list = list_make1(n);
1137 886 : func->raw_source = false;
1138 : }
1139 : else
1140 : {
1141 : /* Source queries are raw parsetrees */
1142 1276 : source_list = pg_parse_query(func->src);
1143 1276 : func->raw_source = true;
1144 : }
1145 :
1146 : /*
1147 : * Note: we must save the number of queries so that we'll still remember
1148 : * how many there are after we discard source_list.
1149 : */
1150 2162 : func->num_queries = list_length(source_list);
1151 :
1152 : /*
1153 : * Edge case: empty function body is OK only if it returns VOID. Normally
1154 : * we validate that the last statement returns the right thing in
1155 : * check_sql_stmt_retval, but we'll never reach that if there's no last
1156 : * statement.
1157 : */
1158 2162 : if (func->num_queries == 0 && rettype != VOIDOID)
1159 6 : ereport(ERROR,
1160 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1161 : errmsg("return type mismatch in function declared to return %s",
1162 : format_type_be(rettype)),
1163 : errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.")));
1164 :
1165 : /* Save the source trees in pcontext for now. */
1166 2156 : MemoryContextSwitchTo(pcontext);
1167 2156 : func->source_list = copyObject(source_list);
1168 2156 : MemoryContextSwitchTo(oldcontext);
1169 :
1170 : /*
1171 : * We now have a fully valid hash entry, so reparent hcontext under
1172 : * CacheMemoryContext to make all the subsidiary data long-lived, and only
1173 : * then install the hcontext link so that sql_delete_callback will know to
1174 : * delete it.
1175 : */
1176 2156 : MemoryContextSetParent(hcontext, CacheMemoryContext);
1177 2156 : func->hcontext = hcontext;
1178 :
1179 2156 : error_context_stack = comperrcontext.previous;
1180 2156 : }
1181 :
1182 : /*
1183 : * Deletion callback used by funccache.c.
1184 : *
1185 : * Free any free-able subsidiary data of cfunc, but not the
1186 : * struct CachedFunction itself.
1187 : */
1188 : static void
1189 66 : sql_delete_callback(CachedFunction *cfunc)
1190 : {
1191 66 : SQLFunctionHashEntry *func = (SQLFunctionHashEntry *) cfunc;
1192 : ListCell *lc;
1193 :
1194 : /* Release the CachedPlanSources */
1195 132 : foreach(lc, func->plansource_list)
1196 : {
1197 66 : CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
1198 :
1199 66 : DropCachedPlan(plansource);
1200 : }
1201 66 : func->plansource_list = NIL;
1202 :
1203 : /*
1204 : * If we have an hcontext, free it, thereby getting rid of all subsidiary
1205 : * data. (If we still have a pcontext, this gets rid of that too.)
1206 : */
1207 66 : if (func->hcontext)
1208 66 : MemoryContextDelete(func->hcontext);
1209 66 : func->hcontext = NULL;
1210 66 : }
1211 :
1212 : /*
1213 : * Post-rewrite callback used by plancache.c.
1214 : *
1215 : * This must match the processing that prepare_next_query() does between
1216 : * rewriting and calling CompleteCachedPlan().
1217 : */
1218 : static void
1219 418 : sql_postrewrite_callback(List *querytree_list, void *arg)
1220 : {
1221 : /*
1222 : * Check that there are no statements we don't want to allow. (Presently,
1223 : * there's no real point in this because the result can't change from what
1224 : * we saw originally. But it's cheap and maybe someday it will matter.)
1225 : */
1226 418 : check_sql_fn_statement(querytree_list);
1227 :
1228 : /*
1229 : * If this is the last query, we must re-do what check_sql_stmt_retval did
1230 : * to its targetlist. Also check that returnsTuple didn't change (it
1231 : * probably cannot, but be cautious).
1232 : */
1233 418 : if (arg != NULL)
1234 : {
1235 418 : SQLFunctionHashEntry *func = (SQLFunctionHashEntry *) arg;
1236 : bool returnsTuple;
1237 :
1238 418 : returnsTuple = check_sql_stmt_retval(querytree_list,
1239 : func->rettype,
1240 : func->rettupdesc,
1241 418 : func->prokind,
1242 : false);
1243 418 : if (returnsTuple != func->returnsTuple)
1244 0 : ereport(ERROR,
1245 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1246 : errmsg("cached plan must not change result type")));
1247 : }
1248 418 : }
1249 :
1250 : /* Start up execution of one execution_state node */
1251 : static void
1252 85950 : postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
1253 : {
1254 : DestReceiver *dest;
1255 85950 : MemoryContext oldcontext = CurrentMemoryContext;
1256 :
1257 : Assert(es->qd == NULL);
1258 :
1259 : /* Caller should have ensured a suitable snapshot is active */
1260 : Assert(ActiveSnapshotSet());
1261 :
1262 : /*
1263 : * In lazyEval mode for a SRF, we must run the sub-executor in a child of
1264 : * fcontext, so that it can survive across multiple calls to fmgr_sql.
1265 : * (XXX in the case of a long-lived FmgrInfo, this policy potentially
1266 : * causes memory leakage, but it's not very clear where we could keep
1267 : * stuff instead. Fortunately, there are few if any cases where
1268 : * set-returning functions are invoked via FmgrInfos that would outlive
1269 : * the calling query.) Otherwise, we're going to run it to completion
1270 : * before exiting fmgr_sql, so it can perfectly well run in the caller's
1271 : * context.
1272 : */
1273 85950 : if (es->lazyEval && fcache->func->returnsSet)
1274 : {
1275 3176 : fcache->subcontext = AllocSetContextCreate(fcache->fcontext,
1276 : "SQL function execution",
1277 : ALLOCSET_DEFAULT_SIZES);
1278 3176 : fcache->ownSubcontext = true;
1279 : }
1280 82774 : else if (es->stmt->commandType == CMD_UTILITY)
1281 : {
1282 : /*
1283 : * The code path using a sub-executor is pretty good about cleaning up
1284 : * cruft, since the executor will make its own sub-context. We don't
1285 : * really need an additional layer of sub-context in that case.
1286 : * However, if this is a utility statement, it won't make its own
1287 : * sub-context, so it seems advisable to make one that we can free on
1288 : * completion.
1289 : */
1290 180 : fcache->subcontext = AllocSetContextCreate(CurrentMemoryContext,
1291 : "SQL function execution",
1292 : ALLOCSET_DEFAULT_SIZES);
1293 180 : fcache->ownSubcontext = true;
1294 : }
1295 : else
1296 : {
1297 82594 : fcache->subcontext = CurrentMemoryContext;
1298 82594 : fcache->ownSubcontext = false;
1299 : }
1300 :
1301 : /*
1302 : * Build a tuplestore if needed, that is if it's a set-returning function
1303 : * and we're producing the function result without using lazyEval mode.
1304 : */
1305 85950 : if (es->setsResult)
1306 : {
1307 : Assert(fcache->tstore == NULL);
1308 85524 : if (fcache->func->returnsSet && !es->lazyEval)
1309 : {
1310 864 : MemoryContextSwitchTo(fcache->tscontext);
1311 864 : fcache->tstore = tuplestore_begin_heap(fcache->randomAccess,
1312 : false, work_mem);
1313 : }
1314 : }
1315 :
1316 : /* Switch into the selected subcontext (might be a no-op) */
1317 85950 : MemoryContextSwitchTo(fcache->subcontext);
1318 :
1319 : /*
1320 : * If this query produces the function result, collect its output using
1321 : * our custom DestReceiver; else discard any output.
1322 : */
1323 85950 : if (es->setsResult)
1324 : {
1325 : DR_sqlfunction *myState;
1326 :
1327 85524 : dest = CreateDestReceiver(DestSQLFunction);
1328 : /* pass down the needed info to the dest receiver routines */
1329 85524 : myState = (DR_sqlfunction *) dest;
1330 : Assert(myState->pub.mydest == DestSQLFunction);
1331 85524 : myState->tstore = fcache->tstore; /* might be NULL */
1332 85524 : myState->filter = fcache->junkFilter;
1333 :
1334 : /* Make very sure the junkfilter's result slot is empty */
1335 85524 : ExecClearTuple(fcache->junkFilter->jf_resultSlot);
1336 : }
1337 : else
1338 426 : dest = None_Receiver;
1339 :
1340 85950 : es->qd = CreateQueryDesc(es->stmt,
1341 : NULL,
1342 85950 : fcache->func->src,
1343 : GetActiveSnapshot(),
1344 : InvalidSnapshot,
1345 : dest,
1346 : fcache->paramLI,
1347 85950 : es->qd ? es->qd->queryEnv : NULL,
1348 : 0);
1349 :
1350 : /* Utility commands don't need Executor. */
1351 85950 : if (es->qd->operation != CMD_UTILITY)
1352 : {
1353 : /*
1354 : * In lazyEval mode, do not let the executor set up an AfterTrigger
1355 : * context. This is necessary not just an optimization, because we
1356 : * mustn't exit from the function execution with a stacked
1357 : * AfterTrigger level still active. We are careful not to select
1358 : * lazyEval mode for any statement that could possibly queue triggers.
1359 : */
1360 : int eflags;
1361 :
1362 85770 : if (es->lazyEval)
1363 84612 : eflags = EXEC_FLAG_SKIP_TRIGGERS;
1364 : else
1365 1158 : eflags = 0; /* default run-to-completion flags */
1366 85770 : if (!ExecutorStart(es->qd, eflags))
1367 0 : elog(ERROR, "ExecutorStart() failed unexpectedly");
1368 : }
1369 :
1370 85944 : es->status = F_EXEC_RUN;
1371 :
1372 85944 : MemoryContextSwitchTo(oldcontext);
1373 85944 : }
1374 :
1375 : /* Run one execution_state; either to completion or to first result row */
1376 : /* Returns true if we ran to completion */
1377 : static bool
1378 86932 : postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
1379 : {
1380 : bool result;
1381 : MemoryContext oldcontext;
1382 :
1383 : /* Run the sub-executor in subcontext */
1384 86932 : oldcontext = MemoryContextSwitchTo(fcache->subcontext);
1385 :
1386 86932 : if (es->qd->operation == CMD_UTILITY)
1387 : {
1388 180 : ProcessUtility(es->qd->plannedstmt,
1389 180 : fcache->func->src,
1390 : true, /* protect function cache's parsetree */
1391 : PROCESS_UTILITY_QUERY,
1392 180 : es->qd->params,
1393 180 : es->qd->queryEnv,
1394 180 : es->qd->dest,
1395 : NULL);
1396 90 : result = true; /* never stops early */
1397 : }
1398 : else
1399 : {
1400 : /* Run regular commands to completion unless lazyEval */
1401 86752 : uint64 count = (es->lazyEval) ? 1 : 0;
1402 :
1403 86752 : ExecutorRun(es->qd, ForwardScanDirection, count);
1404 :
1405 : /*
1406 : * If we requested run to completion OR there was no tuple returned,
1407 : * command must be complete.
1408 : */
1409 79032 : result = (count == 0 || es->qd->estate->es_processed == 0);
1410 : }
1411 :
1412 79122 : MemoryContextSwitchTo(oldcontext);
1413 :
1414 79122 : return result;
1415 : }
1416 :
1417 : /* Shut down execution of one execution_state node */
1418 : static void
1419 78134 : postquel_end(execution_state *es, SQLFunctionCachePtr fcache)
1420 : {
1421 : MemoryContext oldcontext;
1422 :
1423 : /* Run the sub-executor in subcontext */
1424 78134 : oldcontext = MemoryContextSwitchTo(fcache->subcontext);
1425 :
1426 : /* mark status done to ensure we don't do ExecutorEnd twice */
1427 78134 : es->status = F_EXEC_DONE;
1428 :
1429 : /* Utility commands don't need Executor. */
1430 78134 : if (es->qd->operation != CMD_UTILITY)
1431 : {
1432 78044 : ExecutorFinish(es->qd);
1433 78026 : ExecutorEnd(es->qd);
1434 : }
1435 :
1436 78116 : es->qd->dest->rDestroy(es->qd->dest);
1437 :
1438 78116 : FreeQueryDesc(es->qd);
1439 78116 : es->qd = NULL;
1440 :
1441 78116 : MemoryContextSwitchTo(oldcontext);
1442 :
1443 : /* Delete the subcontext, if it's actually a separate context */
1444 78116 : if (fcache->ownSubcontext)
1445 3266 : MemoryContextDelete(fcache->subcontext);
1446 78116 : fcache->subcontext = NULL;
1447 78116 : }
1448 :
1449 : /* Build ParamListInfo array representing current arguments */
1450 : static void
1451 85910 : postquel_sub_params(SQLFunctionCachePtr fcache,
1452 : FunctionCallInfo fcinfo)
1453 : {
1454 85910 : int nargs = fcinfo->nargs;
1455 :
1456 85910 : if (nargs > 0)
1457 : {
1458 : ParamListInfo paramLI;
1459 77352 : Oid *argtypes = fcache->func->pinfo->argtypes;
1460 77352 : int16 *argtyplen = fcache->func->argtyplen;
1461 :
1462 77352 : if (fcache->paramLI == NULL)
1463 : {
1464 : /* First time through: build a persistent ParamListInfo struct */
1465 : MemoryContext oldcontext;
1466 :
1467 25478 : oldcontext = MemoryContextSwitchTo(fcache->fcontext);
1468 25478 : paramLI = makeParamList(nargs);
1469 25478 : fcache->paramLI = paramLI;
1470 25478 : MemoryContextSwitchTo(oldcontext);
1471 : }
1472 : else
1473 : {
1474 51874 : paramLI = fcache->paramLI;
1475 : Assert(paramLI->numParams == nargs);
1476 : }
1477 :
1478 227982 : for (int i = 0; i < nargs; i++)
1479 : {
1480 150630 : ParamExternData *prm = ¶mLI->params[i];
1481 :
1482 : /*
1483 : * If an incoming parameter value is a R/W expanded datum, we
1484 : * force it to R/O. We'd be perfectly entitled to scribble on it,
1485 : * but the problem is that if the parameter is referenced more
1486 : * than once in the function, earlier references might mutate the
1487 : * value seen by later references, which won't do at all. We
1488 : * could do better if we could be sure of the number of Param
1489 : * nodes in the function's plans; but we might not have planned
1490 : * all the statements yet, nor do we have plan tree walker
1491 : * infrastructure. (Examining the parse trees is not good enough,
1492 : * because of possible function inlining during planning.)
1493 : */
1494 150630 : prm->isnull = fcinfo->args[i].isnull;
1495 150630 : prm->value = MakeExpandedObjectReadOnly(fcinfo->args[i].value,
1496 : prm->isnull,
1497 : argtyplen[i]);
1498 : /* Allow the value to be substituted into custom plans */
1499 150630 : prm->pflags = PARAM_FLAG_CONST;
1500 150630 : prm->ptype = argtypes[i];
1501 : }
1502 : }
1503 : else
1504 8558 : fcache->paramLI = NULL;
1505 85910 : }
1506 :
1507 : /*
1508 : * Extract the SQL function's value from a single result row. This is used
1509 : * both for scalar (non-set) functions and for each row of a lazy-eval set
1510 : * result. We expect the current memory context to be that of the caller
1511 : * of fmgr_sql.
1512 : */
1513 : static Datum
1514 69932 : postquel_get_single_result(TupleTableSlot *slot,
1515 : FunctionCallInfo fcinfo,
1516 : SQLFunctionCachePtr fcache)
1517 : {
1518 : Datum value;
1519 :
1520 : /*
1521 : * Set up to return the function value. For pass-by-reference datatypes,
1522 : * be sure to copy the result into the current context. We can't leave
1523 : * the data in the TupleTableSlot because we must clear the slot before
1524 : * returning.
1525 : */
1526 69932 : if (fcache->func->returnsTuple)
1527 : {
1528 : /* We must return the whole tuple as a Datum. */
1529 1470 : fcinfo->isnull = false;
1530 1470 : value = ExecFetchSlotHeapTupleDatum(slot);
1531 : }
1532 : else
1533 : {
1534 : /*
1535 : * Returning a scalar, which we have to extract from the first column
1536 : * of the SELECT result, and then copy into current context if needed.
1537 : */
1538 68462 : value = slot_getattr(slot, 1, &(fcinfo->isnull));
1539 :
1540 68462 : if (!fcinfo->isnull)
1541 68128 : value = datumCopy(value, fcache->func->typbyval, fcache->func->typlen);
1542 : }
1543 :
1544 : /* Clear the slot for next time */
1545 69932 : ExecClearTuple(slot);
1546 :
1547 69932 : return value;
1548 : }
1549 :
1550 : /*
1551 : * fmgr_sql: function call manager for SQL functions
1552 : */
1553 : Datum
1554 86904 : fmgr_sql(PG_FUNCTION_ARGS)
1555 : {
1556 : SQLFunctionCachePtr fcache;
1557 : ErrorContextCallback sqlerrcontext;
1558 : MemoryContext tscontext;
1559 : bool randomAccess;
1560 : bool lazyEvalOK;
1561 : bool pushed_snapshot;
1562 : execution_state *es;
1563 : TupleTableSlot *slot;
1564 : Datum result;
1565 :
1566 : /* Check call context */
1567 86904 : if (fcinfo->flinfo->fn_retset)
1568 : {
1569 5040 : ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1570 :
1571 : /*
1572 : * For simplicity, we require callers to support both set eval modes.
1573 : * There are cases where we must use one or must use the other, and
1574 : * it's not really worthwhile to postpone the check till we know. But
1575 : * note we do not require caller to provide an expectedDesc.
1576 : */
1577 5040 : if (!rsi || !IsA(rsi, ReturnSetInfo) ||
1578 5040 : (rsi->allowedModes & SFRM_ValuePerCall) == 0 ||
1579 5040 : (rsi->allowedModes & SFRM_Materialize) == 0)
1580 0 : ereport(ERROR,
1581 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1582 : errmsg("set-valued function called in context that cannot accept a set")));
1583 5040 : randomAccess = rsi->allowedModes & SFRM_Materialize_Random;
1584 5040 : lazyEvalOK = !(rsi->allowedModes & SFRM_Materialize_Preferred);
1585 : /* tuplestore, if used, must have query lifespan */
1586 5040 : tscontext = rsi->econtext->ecxt_per_query_memory;
1587 : }
1588 : else
1589 : {
1590 81864 : randomAccess = false;
1591 81864 : lazyEvalOK = true;
1592 : /* we won't need a tuplestore */
1593 81864 : tscontext = NULL;
1594 : }
1595 :
1596 : /*
1597 : * Initialize fcache if starting a fresh execution.
1598 : */
1599 86904 : fcache = init_sql_fcache(fcinfo, lazyEvalOK);
1600 :
1601 : /* Remember info that we might need later to construct tuplestore */
1602 86898 : fcache->tscontext = tscontext;
1603 86898 : fcache->randomAccess = randomAccess;
1604 :
1605 : /*
1606 : * Now we can set up error traceback support for ereport()
1607 : */
1608 86898 : sqlerrcontext.callback = sql_exec_error_callback;
1609 86898 : sqlerrcontext.arg = fcache;
1610 86898 : sqlerrcontext.previous = error_context_stack;
1611 86898 : error_context_stack = &sqlerrcontext;
1612 :
1613 : /*
1614 : * Find first unfinished execution_state. If none, advance to the next
1615 : * query in function.
1616 : */
1617 : do
1618 : {
1619 172746 : es = fcache->eslist;
1620 172746 : while (es && es->status == F_EXEC_DONE)
1621 0 : es = es->next;
1622 172746 : if (es)
1623 86836 : break;
1624 85910 : } while (init_execution_state(fcache));
1625 :
1626 : /*
1627 : * Execute each command in the function one after another until we either
1628 : * run out of commands or get a result row from a lazily-evaluated SELECT.
1629 : *
1630 : * Notes about snapshot management:
1631 : *
1632 : * In a read-only function, we just use the surrounding query's snapshot.
1633 : *
1634 : * In a non-read-only function, we rely on the fact that we'll never
1635 : * suspend execution between queries of the function: the only reason to
1636 : * suspend execution before completion is if we are returning a row from a
1637 : * lazily-evaluated SELECT. So, when first entering this loop, we'll
1638 : * either start a new query (and push a fresh snapshot) or re-establish
1639 : * the active snapshot from the existing query descriptor. If we need to
1640 : * start a new query in a subsequent execution of the loop, either we need
1641 : * a fresh snapshot (and pushed_snapshot is false) or the existing
1642 : * snapshot is on the active stack and we can just bump its command ID.
1643 : */
1644 86842 : pushed_snapshot = false;
1645 164952 : while (es)
1646 : {
1647 : bool completed;
1648 :
1649 86938 : if (es->status == F_EXEC_START)
1650 : {
1651 : /*
1652 : * If not read-only, be sure to advance the command counter for
1653 : * each command, so that all work to date in this transaction is
1654 : * visible. Take a new snapshot if we don't have one yet,
1655 : * otherwise just bump the command ID in the existing snapshot.
1656 : */
1657 85950 : if (!fcache->func->readonly_func)
1658 : {
1659 73302 : CommandCounterIncrement();
1660 73302 : if (!pushed_snapshot)
1661 : {
1662 73296 : PushActiveSnapshot(GetTransactionSnapshot());
1663 73296 : pushed_snapshot = true;
1664 : }
1665 : else
1666 6 : UpdateActiveSnapshotCommandId();
1667 : }
1668 :
1669 85950 : postquel_start(es, fcache);
1670 : }
1671 988 : else if (!fcache->func->readonly_func && !pushed_snapshot)
1672 : {
1673 : /* Re-establish active snapshot when re-entering function */
1674 640 : PushActiveSnapshot(es->qd->snapshot);
1675 640 : pushed_snapshot = true;
1676 : }
1677 :
1678 86932 : completed = postquel_getnext(es, fcache);
1679 :
1680 : /*
1681 : * If we ran the command to completion, we can shut it down now. Any
1682 : * row(s) we need to return are safely stashed in the result slot or
1683 : * tuplestore, and we want to be sure that, for example, AFTER
1684 : * triggers get fired before we return anything. Also, if the
1685 : * function doesn't return set, we can shut it down anyway because it
1686 : * must be a SELECT and we don't care about fetching any more result
1687 : * rows.
1688 : */
1689 79122 : if (completed || !fcache->func->returnsSet)
1690 78128 : postquel_end(es, fcache);
1691 :
1692 : /*
1693 : * Break from loop if we didn't shut down (implying we got a
1694 : * lazily-evaluated row). Otherwise we'll press on till the whole
1695 : * function is done, relying on the tuplestore to keep hold of the
1696 : * data to eventually be returned. This is necessary since an
1697 : * INSERT/UPDATE/DELETE RETURNING that sets the result might be
1698 : * followed by additional rule-inserted commands, and we want to
1699 : * finish doing all those commands before we return anything.
1700 : */
1701 79104 : if (es->status != F_EXEC_DONE)
1702 994 : break;
1703 :
1704 : /*
1705 : * Advance to next execution_state, and perhaps next query.
1706 : */
1707 78110 : es = es->next;
1708 78206 : while (!es)
1709 : {
1710 : /*
1711 : * Flush the current snapshot so that we will take a new one for
1712 : * the new query list. This ensures that new snaps are taken at
1713 : * original-query boundaries, matching the behavior of interactive
1714 : * execution.
1715 : */
1716 78104 : if (pushed_snapshot)
1717 : {
1718 65494 : PopActiveSnapshot();
1719 65494 : pushed_snapshot = false;
1720 : }
1721 :
1722 78104 : if (!init_execution_state(fcache))
1723 78008 : break; /* end of function */
1724 :
1725 96 : es = fcache->eslist;
1726 : }
1727 : }
1728 :
1729 : /*
1730 : * The result slot or tuplestore now contains whatever row(s) we are
1731 : * supposed to return.
1732 : */
1733 79008 : if (fcache->func->returnsSet)
1734 : {
1735 5034 : ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1736 :
1737 5034 : if (es)
1738 : {
1739 : /*
1740 : * If we stopped short of being done, we must have a lazy-eval
1741 : * row.
1742 : */
1743 : Assert(es->lazyEval);
1744 : /* The junkfilter's result slot contains the query result tuple */
1745 : Assert(fcache->junkFilter);
1746 994 : slot = fcache->junkFilter->jf_resultSlot;
1747 : Assert(!TTS_EMPTY(slot));
1748 : /* Extract the result as a datum, and copy out from the slot */
1749 994 : result = postquel_get_single_result(slot, fcinfo, fcache);
1750 :
1751 : /*
1752 : * Let caller know we're not finished.
1753 : */
1754 994 : rsi->isDone = ExprMultipleResult;
1755 :
1756 : /*
1757 : * Ensure we will get shut down cleanly if the exprcontext is not
1758 : * run to completion.
1759 : */
1760 994 : if (!fcache->shutdown_reg)
1761 : {
1762 726 : RegisterExprContextCallback(rsi->econtext,
1763 : ShutdownSQLFunction,
1764 : PointerGetDatum(fcache));
1765 726 : fcache->shutdown_reg = true;
1766 : }
1767 : }
1768 4040 : else if (fcache->lazyEval)
1769 : {
1770 : /*
1771 : * We are done with a lazy evaluation. Let caller know we're
1772 : * finished.
1773 : */
1774 3170 : rsi->isDone = ExprEndResult;
1775 :
1776 3170 : fcinfo->isnull = true;
1777 3170 : result = (Datum) 0;
1778 :
1779 : /* Deregister shutdown callback, if we made one */
1780 3170 : if (fcache->shutdown_reg)
1781 : {
1782 720 : UnregisterExprContextCallback(rsi->econtext,
1783 : ShutdownSQLFunction,
1784 : PointerGetDatum(fcache));
1785 720 : fcache->shutdown_reg = false;
1786 : }
1787 : }
1788 : else
1789 : {
1790 : /*
1791 : * We are done with a non-lazy evaluation. Return whatever is in
1792 : * the tuplestore. (It is now caller's responsibility to free the
1793 : * tuplestore when done.)
1794 : *
1795 : * Note an edge case: we could get here without having made a
1796 : * tuplestore if the function is declared to return SETOF VOID.
1797 : * ExecMakeTableFunctionResult will cope with null setResult.
1798 : */
1799 : Assert(fcache->tstore || fcache->func->rettype == VOIDOID);
1800 870 : rsi->returnMode = SFRM_Materialize;
1801 870 : rsi->setResult = fcache->tstore;
1802 870 : fcache->tstore = NULL;
1803 : /* must copy desc because execSRF.c will free it */
1804 870 : if (fcache->junkFilter)
1805 864 : rsi->setDesc = CreateTupleDescCopy(fcache->junkFilter->jf_cleanTupType);
1806 :
1807 870 : fcinfo->isnull = true;
1808 870 : result = (Datum) 0;
1809 :
1810 : /* Deregister shutdown callback, if we made one */
1811 870 : if (fcache->shutdown_reg)
1812 : {
1813 0 : UnregisterExprContextCallback(rsi->econtext,
1814 : ShutdownSQLFunction,
1815 : PointerGetDatum(fcache));
1816 0 : fcache->shutdown_reg = false;
1817 : }
1818 : }
1819 : }
1820 : else
1821 : {
1822 : /*
1823 : * Non-set function. If we got a row, return it; else return NULL.
1824 : */
1825 73974 : if (fcache->junkFilter)
1826 : {
1827 : /* The junkfilter's result slot contains the query result tuple */
1828 73760 : slot = fcache->junkFilter->jf_resultSlot;
1829 73760 : if (!TTS_EMPTY(slot))
1830 68938 : result = postquel_get_single_result(slot, fcinfo, fcache);
1831 : else
1832 : {
1833 4822 : fcinfo->isnull = true;
1834 4822 : result = (Datum) 0;
1835 : }
1836 : }
1837 : else
1838 : {
1839 : /* Should only get here for VOID functions and procedures */
1840 : Assert(fcache->func->rettype == VOIDOID);
1841 214 : fcinfo->isnull = true;
1842 214 : result = (Datum) 0;
1843 : }
1844 : }
1845 :
1846 : /* Pop snapshot if we have pushed one */
1847 79008 : if (pushed_snapshot)
1848 646 : PopActiveSnapshot();
1849 :
1850 : /*
1851 : * If we've gone through every command in the function, we are done. Reset
1852 : * state to start over again on next call.
1853 : */
1854 79008 : if (es == NULL)
1855 78014 : fcache->eslist = NULL;
1856 :
1857 79008 : error_context_stack = sqlerrcontext.previous;
1858 :
1859 79008 : return result;
1860 : }
1861 :
1862 :
1863 : /*
1864 : * error context callback to let us supply a traceback during compile
1865 : */
1866 : static void
1867 6 : sql_compile_error_callback(void *arg)
1868 : {
1869 6 : SQLFunctionHashEntry *func = (SQLFunctionHashEntry *) arg;
1870 : int syntaxerrposition;
1871 :
1872 : /*
1873 : * We can do nothing useful if sql_compile_callback() didn't get as far as
1874 : * copying the function name
1875 : */
1876 6 : if (func->fname == NULL)
1877 0 : return;
1878 :
1879 : /*
1880 : * If there is a syntax error position, convert to internal syntax error
1881 : */
1882 6 : syntaxerrposition = geterrposition();
1883 6 : if (syntaxerrposition > 0 && func->src != NULL)
1884 : {
1885 0 : errposition(0);
1886 0 : internalerrposition(syntaxerrposition);
1887 0 : internalerrquery(func->src);
1888 : }
1889 :
1890 : /*
1891 : * sql_compile_callback() doesn't do any per-query processing, so just
1892 : * report the context as "during startup".
1893 : */
1894 6 : errcontext("SQL function \"%s\" during startup", func->fname);
1895 : }
1896 :
1897 : /*
1898 : * error context callback to let us supply a call-stack traceback at runtime
1899 : */
1900 : static void
1901 7928 : sql_exec_error_callback(void *arg)
1902 : {
1903 7928 : SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) arg;
1904 : int syntaxerrposition;
1905 :
1906 : /*
1907 : * If there is a syntax error position, convert to internal syntax error
1908 : */
1909 7928 : syntaxerrposition = geterrposition();
1910 7928 : if (syntaxerrposition > 0 && fcache->func->src != NULL)
1911 : {
1912 2 : errposition(0);
1913 2 : internalerrposition(syntaxerrposition);
1914 2 : internalerrquery(fcache->func->src);
1915 : }
1916 :
1917 : /*
1918 : * If we failed while executing an identifiable query within the function,
1919 : * report that. Otherwise say it was "during startup".
1920 : */
1921 7928 : if (fcache->error_query_index > 0)
1922 7928 : errcontext("SQL function \"%s\" statement %d",
1923 7928 : fcache->func->fname, fcache->error_query_index);
1924 : else
1925 0 : errcontext("SQL function \"%s\" during startup", fcache->func->fname);
1926 7928 : }
1927 :
1928 :
1929 : /*
1930 : * ExprContext callback function
1931 : *
1932 : * We register this in the active ExprContext while a set-returning SQL
1933 : * function is running, in case the function needs to be shut down before it
1934 : * has been run to completion. Note that this will not be called during an
1935 : * error abort, but we don't need it because transaction abort will take care
1936 : * of releasing executor resources.
1937 : */
1938 : static void
1939 6 : ShutdownSQLFunction(Datum arg)
1940 : {
1941 6 : SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) DatumGetPointer(arg);
1942 : execution_state *es;
1943 :
1944 6 : es = fcache->eslist;
1945 12 : while (es)
1946 : {
1947 : /* Shut down anything still running */
1948 6 : if (es->status == F_EXEC_RUN)
1949 : {
1950 : /* Re-establish active snapshot for any called functions */
1951 6 : if (!fcache->func->readonly_func)
1952 6 : PushActiveSnapshot(es->qd->snapshot);
1953 :
1954 6 : postquel_end(es, fcache);
1955 :
1956 6 : if (!fcache->func->readonly_func)
1957 6 : PopActiveSnapshot();
1958 : }
1959 6 : es = es->next;
1960 : }
1961 6 : fcache->eslist = NULL;
1962 :
1963 : /* Release tuplestore if we have one */
1964 6 : if (fcache->tstore)
1965 0 : tuplestore_end(fcache->tstore);
1966 6 : fcache->tstore = NULL;
1967 :
1968 : /* Release CachedPlan if we have one */
1969 6 : if (fcache->cplan)
1970 6 : ReleaseCachedPlan(fcache->cplan, fcache->cowner);
1971 6 : fcache->cplan = NULL;
1972 :
1973 : /* execUtils will deregister the callback... */
1974 6 : fcache->shutdown_reg = false;
1975 6 : }
1976 :
1977 : /*
1978 : * MemoryContext callback function
1979 : *
1980 : * We register this in the memory context that contains a SQLFunctionCache
1981 : * struct. When the memory context is reset or deleted, we release the
1982 : * reference count (if any) that the cache holds on the long-lived hash entry.
1983 : * Note that this will happen even during error aborts.
1984 : */
1985 : static void
1986 34006 : RemoveSQLFunctionCache(void *arg)
1987 : {
1988 34006 : SQLFunctionCache *fcache = (SQLFunctionCache *) arg;
1989 :
1990 : /* Release reference count on SQLFunctionHashEntry */
1991 34006 : if (fcache->func != NULL)
1992 : {
1993 : Assert(fcache->func->cfunc.use_count > 0);
1994 34000 : fcache->func->cfunc.use_count--;
1995 : /* This should be unnecessary, but let's just be sure: */
1996 34000 : fcache->func = NULL;
1997 : }
1998 34006 : }
1999 :
2000 : /*
2001 : * check_sql_fn_statements
2002 : *
2003 : * Check statements in an SQL function. Error out if there is anything that
2004 : * is not acceptable.
2005 : */
2006 : void
2007 7146 : check_sql_fn_statements(List *queryTreeLists)
2008 : {
2009 : ListCell *lc;
2010 :
2011 : /* We are given a list of sublists of Queries */
2012 14402 : foreach(lc, queryTreeLists)
2013 : {
2014 7262 : List *sublist = lfirst_node(List, lc);
2015 :
2016 7262 : check_sql_fn_statement(sublist);
2017 : }
2018 7140 : }
2019 :
2020 : /*
2021 : * As above, for a single sublist of Queries.
2022 : */
2023 : static void
2024 9876 : check_sql_fn_statement(List *queryTreeList)
2025 : {
2026 : ListCell *lc;
2027 :
2028 19752 : foreach(lc, queryTreeList)
2029 : {
2030 9882 : Query *query = lfirst_node(Query, lc);
2031 :
2032 : /*
2033 : * Disallow calling procedures with output arguments. The current
2034 : * implementation would just throw the output values away, unless the
2035 : * statement is the last one. Per SQL standard, we should assign the
2036 : * output values by name. By disallowing this here, we preserve an
2037 : * opportunity for future improvement.
2038 : */
2039 9882 : if (query->commandType == CMD_UTILITY &&
2040 154 : IsA(query->utilityStmt, CallStmt))
2041 : {
2042 30 : CallStmt *stmt = (CallStmt *) query->utilityStmt;
2043 :
2044 30 : if (stmt->outargs != NIL)
2045 6 : ereport(ERROR,
2046 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2047 : errmsg("calling procedures with output arguments is not supported in SQL functions")));
2048 : }
2049 : }
2050 9870 : }
2051 :
2052 : /*
2053 : * check_sql_fn_retval()
2054 : * Check return value of a list of lists of sql parse trees.
2055 : *
2056 : * The return value of a sql function is the value returned by the last
2057 : * canSetTag query in the function. We do some ad-hoc type checking and
2058 : * coercion here to ensure that the function returns what it's supposed to.
2059 : * Note that we may actually modify the last query to make it match!
2060 : *
2061 : * This function returns true if the sql function returns the entire tuple
2062 : * result of its final statement, or false if it returns just the first column
2063 : * result of that statement. It throws an error if the final statement doesn't
2064 : * return the right type at all.
2065 : *
2066 : * Note that because we allow "SELECT rowtype_expression", the result can be
2067 : * false even when the declared function return type is a rowtype.
2068 : *
2069 : * For a polymorphic function the passed rettype must be the actual resolved
2070 : * output type of the function. (This means we can't check the type during
2071 : * function definition of a polymorphic function.) If we do see a polymorphic
2072 : * rettype we'll throw an error, saying it is not a supported rettype.
2073 : *
2074 : * If the function returns composite, the passed rettupdesc should describe
2075 : * the expected output. If rettupdesc is NULL, we can't verify that the
2076 : * output matches; that should only happen in fmgr_sql_validator(), or when
2077 : * the function returns RECORD and the caller doesn't actually care which
2078 : * composite type it is.
2079 : *
2080 : * (Typically, rettype and rettupdesc are computed by get_call_result_type
2081 : * or a sibling function.)
2082 : *
2083 : * In addition to coercing individual output columns, we can modify the
2084 : * output to include dummy NULL columns for any dropped columns appearing
2085 : * in rettupdesc. This is done only if the caller asks for it.
2086 : */
2087 : bool
2088 10690 : check_sql_fn_retval(List *queryTreeLists,
2089 : Oid rettype, TupleDesc rettupdesc,
2090 : char prokind,
2091 : bool insertDroppedCols)
2092 : {
2093 : List *queryTreeList;
2094 :
2095 : /*
2096 : * We consider only the last sublist of Query nodes, so that only the last
2097 : * original statement is a candidate to produce the result. This is a
2098 : * change from pre-v18 versions, which would back up to the last statement
2099 : * that includes a canSetTag query, thus ignoring any ending statement(s)
2100 : * that rewrite to DO INSTEAD NOTHING. That behavior was undocumented and
2101 : * there seems no good reason for it, except that it was an artifact of
2102 : * the original coding.
2103 : *
2104 : * If the function body is completely empty, handle that the same as if
2105 : * the last query had rewritten to nothing.
2106 : */
2107 10690 : if (queryTreeLists != NIL)
2108 10666 : queryTreeList = llast_node(List, queryTreeLists);
2109 : else
2110 24 : queryTreeList = NIL;
2111 :
2112 10690 : return check_sql_stmt_retval(queryTreeList,
2113 : rettype, rettupdesc,
2114 : prokind, insertDroppedCols);
2115 : }
2116 :
2117 : /*
2118 : * As for check_sql_fn_retval, but we are given just the last query's
2119 : * rewritten-queries list.
2120 : */
2121 : static bool
2122 13234 : check_sql_stmt_retval(List *queryTreeList,
2123 : Oid rettype, TupleDesc rettupdesc,
2124 : char prokind, bool insertDroppedCols)
2125 : {
2126 13234 : bool is_tuple_result = false;
2127 : Query *parse;
2128 : ListCell *parse_cell;
2129 : List *tlist;
2130 : int tlistlen;
2131 : bool tlist_is_modifiable;
2132 : char fn_typtype;
2133 13234 : List *upper_tlist = NIL;
2134 13234 : bool upper_tlist_nontrivial = false;
2135 : ListCell *lc;
2136 :
2137 : /*
2138 : * If it's declared to return VOID, we don't care what's in the function.
2139 : * (This takes care of procedures with no output parameters, as well.)
2140 : */
2141 13234 : if (rettype == VOIDOID)
2142 622 : return false;
2143 :
2144 : /*
2145 : * Find the last canSetTag query in the list of Query nodes. This isn't
2146 : * necessarily the last parsetree, because rule rewriting can insert
2147 : * queries after what the user wrote.
2148 : */
2149 12612 : parse = NULL;
2150 12612 : parse_cell = NULL;
2151 25224 : foreach(lc, queryTreeList)
2152 : {
2153 12612 : Query *q = lfirst_node(Query, lc);
2154 :
2155 12612 : if (q->canSetTag)
2156 : {
2157 12606 : parse = q;
2158 12606 : parse_cell = lc;
2159 : }
2160 : }
2161 :
2162 : /*
2163 : * If it's a plain SELECT, it returns whatever the targetlist says.
2164 : * Otherwise, if it's INSERT/UPDATE/DELETE/MERGE with RETURNING, it
2165 : * returns that. Otherwise, the function return type must be VOID.
2166 : *
2167 : * Note: eventually replace this test with QueryReturnsTuples? We'd need
2168 : * a more general method of determining the output type, though. Also, it
2169 : * seems too dangerous to consider FETCH or EXECUTE as returning a
2170 : * determinable rowtype, since they depend on relatively short-lived
2171 : * entities.
2172 : */
2173 12612 : if (parse &&
2174 12606 : parse->commandType == CMD_SELECT)
2175 : {
2176 12492 : tlist = parse->targetList;
2177 : /* tlist is modifiable unless it's a dummy in a setop query */
2178 12492 : tlist_is_modifiable = (parse->setOperations == NULL);
2179 : }
2180 120 : else if (parse &&
2181 114 : (parse->commandType == CMD_INSERT ||
2182 30 : parse->commandType == CMD_UPDATE ||
2183 30 : parse->commandType == CMD_DELETE ||
2184 30 : parse->commandType == CMD_MERGE) &&
2185 114 : parse->returningList)
2186 : {
2187 114 : tlist = parse->returningList;
2188 : /* returningList can always be modified */
2189 114 : tlist_is_modifiable = true;
2190 : }
2191 : else
2192 : {
2193 : /* Last statement is a utility command, or it rewrote to nothing */
2194 6 : ereport(ERROR,
2195 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2196 : errmsg("return type mismatch in function declared to return %s",
2197 : format_type_be(rettype)),
2198 : errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.")));
2199 : return false; /* keep compiler quiet */
2200 : }
2201 :
2202 : /*
2203 : * OK, check that the targetlist returns something matching the declared
2204 : * type, and modify it if necessary. If possible, we insert any coercion
2205 : * steps right into the final statement's targetlist. However, that might
2206 : * risk changes in the statement's semantics --- we can't safely change
2207 : * the output type of a grouping column, for instance. In such cases we
2208 : * handle coercions by inserting an extra level of Query that effectively
2209 : * just does a projection.
2210 : */
2211 :
2212 : /*
2213 : * Count the non-junk entries in the result targetlist.
2214 : */
2215 12606 : tlistlen = ExecCleanTargetListLength(tlist);
2216 :
2217 12606 : fn_typtype = get_typtype(rettype);
2218 :
2219 12606 : if (fn_typtype == TYPTYPE_BASE ||
2220 1438 : fn_typtype == TYPTYPE_DOMAIN ||
2221 1432 : fn_typtype == TYPTYPE_ENUM ||
2222 1396 : fn_typtype == TYPTYPE_RANGE ||
2223 : fn_typtype == TYPTYPE_MULTIRANGE)
2224 11234 : {
2225 : /*
2226 : * For scalar-type returns, the target list must have exactly one
2227 : * non-junk entry, and its type must be coercible to rettype.
2228 : */
2229 : TargetEntry *tle;
2230 :
2231 11246 : if (tlistlen != 1)
2232 6 : ereport(ERROR,
2233 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2234 : errmsg("return type mismatch in function declared to return %s",
2235 : format_type_be(rettype)),
2236 : errdetail("Final statement must return exactly one column.")));
2237 :
2238 : /* We assume here that non-junk TLEs must come first in tlists */
2239 11240 : tle = (TargetEntry *) linitial(tlist);
2240 : Assert(!tle->resjunk);
2241 :
2242 11240 : if (!coerce_fn_result_column(tle, rettype, -1,
2243 : tlist_is_modifiable,
2244 : &upper_tlist,
2245 : &upper_tlist_nontrivial))
2246 6 : ereport(ERROR,
2247 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2248 : errmsg("return type mismatch in function declared to return %s",
2249 : format_type_be(rettype)),
2250 : errdetail("Actual return type is %s.",
2251 : format_type_be(exprType((Node *) tle->expr)))));
2252 : }
2253 1360 : else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
2254 1222 : {
2255 : /*
2256 : * Returns a rowtype.
2257 : *
2258 : * Note that we will not consider a domain over composite to be a
2259 : * "rowtype" return type; it goes through the scalar case above. This
2260 : * is because we only provide column-by-column implicit casting, and
2261 : * will not cast the complete record result. So the only way to
2262 : * produce a domain-over-composite result is to compute it as an
2263 : * explicit single-column result. The single-composite-column code
2264 : * path just below could handle such cases, but it won't be reached.
2265 : */
2266 : int tupnatts; /* physical number of columns in tuple */
2267 : int tuplogcols; /* # of nondeleted columns in tuple */
2268 : int colindex; /* physical column index */
2269 :
2270 : /*
2271 : * If the target list has one non-junk entry, and that expression has
2272 : * or can be coerced to the declared return type, take it as the
2273 : * result. This allows, for example, 'SELECT func2()', where func2
2274 : * has the same composite return type as the function that's calling
2275 : * it. This provision creates some ambiguity --- maybe the expression
2276 : * was meant to be the lone field of the composite result --- but it
2277 : * works well enough as long as we don't get too enthusiastic about
2278 : * inventing coercions from scalar to composite types.
2279 : *
2280 : * XXX Note that if rettype is RECORD and the expression is of a named
2281 : * composite type, or vice versa, this coercion will succeed, whether
2282 : * or not the record type really matches. For the moment we rely on
2283 : * runtime type checking to catch any discrepancy, but it'd be nice to
2284 : * do better at parse time.
2285 : *
2286 : * We must *not* do this for a procedure, however. Procedures with
2287 : * output parameter(s) have rettype RECORD, and the CALL code expects
2288 : * to get results corresponding to the list of output parameters, even
2289 : * when there's just one parameter that's composite.
2290 : */
2291 1354 : if (tlistlen == 1 && prokind != PROKIND_PROCEDURE)
2292 : {
2293 216 : TargetEntry *tle = (TargetEntry *) linitial(tlist);
2294 :
2295 : Assert(!tle->resjunk);
2296 216 : if (coerce_fn_result_column(tle, rettype, -1,
2297 : tlist_is_modifiable,
2298 : &upper_tlist,
2299 : &upper_tlist_nontrivial))
2300 : {
2301 : /* Note that we're NOT setting is_tuple_result */
2302 72 : goto tlist_coercion_finished;
2303 : }
2304 : }
2305 :
2306 : /*
2307 : * If the caller didn't provide an expected tupdesc, we can't do any
2308 : * further checking. Assume we're returning the whole tuple.
2309 : */
2310 1282 : if (rettupdesc == NULL)
2311 48 : return true;
2312 :
2313 : /*
2314 : * Verify that the targetlist matches the return tuple type. We scan
2315 : * the non-resjunk columns, and coerce them if necessary to match the
2316 : * datatypes of the non-deleted attributes. For deleted attributes,
2317 : * insert NULL result columns if the caller asked for that.
2318 : */
2319 1234 : tupnatts = rettupdesc->natts;
2320 1234 : tuplogcols = 0; /* we'll count nondeleted cols as we go */
2321 1234 : colindex = 0;
2322 :
2323 4736 : foreach(lc, tlist)
2324 : {
2325 3514 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
2326 : Form_pg_attribute attr;
2327 :
2328 : /* resjunk columns can simply be ignored */
2329 3514 : if (tle->resjunk)
2330 0 : continue;
2331 :
2332 : do
2333 : {
2334 3568 : colindex++;
2335 3568 : if (colindex > tupnatts)
2336 0 : ereport(ERROR,
2337 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2338 : errmsg("return type mismatch in function declared to return %s",
2339 : format_type_be(rettype)),
2340 : errdetail("Final statement returns too many columns.")));
2341 3568 : attr = TupleDescAttr(rettupdesc, colindex - 1);
2342 3568 : if (attr->attisdropped && insertDroppedCols)
2343 : {
2344 : Expr *null_expr;
2345 :
2346 : /* The type of the null we insert isn't important */
2347 6 : null_expr = (Expr *) makeConst(INT4OID,
2348 : -1,
2349 : InvalidOid,
2350 : sizeof(int32),
2351 : (Datum) 0,
2352 : true, /* isnull */
2353 : true /* byval */ );
2354 6 : upper_tlist = lappend(upper_tlist,
2355 6 : makeTargetEntry(null_expr,
2356 6 : list_length(upper_tlist) + 1,
2357 : NULL,
2358 : false));
2359 6 : upper_tlist_nontrivial = true;
2360 : }
2361 3568 : } while (attr->attisdropped);
2362 3514 : tuplogcols++;
2363 :
2364 3514 : if (!coerce_fn_result_column(tle,
2365 : attr->atttypid, attr->atttypmod,
2366 : tlist_is_modifiable,
2367 : &upper_tlist,
2368 : &upper_tlist_nontrivial))
2369 12 : ereport(ERROR,
2370 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2371 : errmsg("return type mismatch in function declared to return %s",
2372 : format_type_be(rettype)),
2373 : errdetail("Final statement returns %s instead of %s at column %d.",
2374 : format_type_be(exprType((Node *) tle->expr)),
2375 : format_type_be(attr->atttypid),
2376 : tuplogcols)));
2377 : }
2378 :
2379 : /* remaining columns in rettupdesc had better all be dropped */
2380 1222 : for (colindex++; colindex <= tupnatts; colindex++)
2381 : {
2382 0 : if (!TupleDescCompactAttr(rettupdesc, colindex - 1)->attisdropped)
2383 0 : ereport(ERROR,
2384 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2385 : errmsg("return type mismatch in function declared to return %s",
2386 : format_type_be(rettype)),
2387 : errdetail("Final statement returns too few columns.")));
2388 0 : if (insertDroppedCols)
2389 : {
2390 : Expr *null_expr;
2391 :
2392 : /* The type of the null we insert isn't important */
2393 0 : null_expr = (Expr *) makeConst(INT4OID,
2394 : -1,
2395 : InvalidOid,
2396 : sizeof(int32),
2397 : (Datum) 0,
2398 : true, /* isnull */
2399 : true /* byval */ );
2400 0 : upper_tlist = lappend(upper_tlist,
2401 0 : makeTargetEntry(null_expr,
2402 0 : list_length(upper_tlist) + 1,
2403 : NULL,
2404 : false));
2405 0 : upper_tlist_nontrivial = true;
2406 : }
2407 : }
2408 :
2409 : /* Report that we are returning entire tuple result */
2410 1222 : is_tuple_result = true;
2411 : }
2412 : else
2413 6 : ereport(ERROR,
2414 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
2415 : errmsg("return type %s is not supported for SQL functions",
2416 : format_type_be(rettype))));
2417 :
2418 12528 : tlist_coercion_finished:
2419 :
2420 : /*
2421 : * If necessary, modify the final Query by injecting an extra Query level
2422 : * that just performs a projection. (It'd be dubious to do this to a
2423 : * non-SELECT query, but we never have to; RETURNING lists can always be
2424 : * modified in-place.)
2425 : */
2426 12528 : if (upper_tlist_nontrivial)
2427 : {
2428 : Query *newquery;
2429 : List *colnames;
2430 : RangeTblEntry *rte;
2431 : RangeTblRef *rtr;
2432 :
2433 : Assert(parse->commandType == CMD_SELECT);
2434 :
2435 : /* Most of the upper Query struct can be left as zeroes/nulls */
2436 84 : newquery = makeNode(Query);
2437 84 : newquery->commandType = CMD_SELECT;
2438 84 : newquery->querySource = parse->querySource;
2439 84 : newquery->canSetTag = true;
2440 84 : newquery->targetList = upper_tlist;
2441 :
2442 : /* We need a moderately realistic colnames list for the subquery RTE */
2443 84 : colnames = NIL;
2444 216 : foreach(lc, parse->targetList)
2445 : {
2446 132 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
2447 :
2448 132 : if (tle->resjunk)
2449 0 : continue;
2450 132 : colnames = lappend(colnames,
2451 132 : makeString(tle->resname ? tle->resname : ""));
2452 : }
2453 :
2454 : /* Build a suitable RTE for the subquery */
2455 84 : rte = makeNode(RangeTblEntry);
2456 84 : rte->rtekind = RTE_SUBQUERY;
2457 84 : rte->subquery = parse;
2458 84 : rte->eref = rte->alias = makeAlias("*SELECT*", colnames);
2459 84 : rte->lateral = false;
2460 84 : rte->inh = false;
2461 84 : rte->inFromCl = true;
2462 84 : newquery->rtable = list_make1(rte);
2463 :
2464 84 : rtr = makeNode(RangeTblRef);
2465 84 : rtr->rtindex = 1;
2466 84 : newquery->jointree = makeFromExpr(list_make1(rtr), NULL);
2467 :
2468 : /*
2469 : * Make sure the new query is marked as having row security if the
2470 : * original one does.
2471 : */
2472 84 : newquery->hasRowSecurity = parse->hasRowSecurity;
2473 :
2474 : /* Replace original query in the correct element of the query list */
2475 84 : lfirst(parse_cell) = newquery;
2476 : }
2477 :
2478 12528 : return is_tuple_result;
2479 : }
2480 :
2481 : /*
2482 : * Process one function result column for check_sql_fn_retval
2483 : *
2484 : * Coerce the output value to the required type/typmod, and add a column
2485 : * to *upper_tlist for it. Set *upper_tlist_nontrivial to true if we
2486 : * add an upper tlist item that's not just a Var.
2487 : *
2488 : * Returns true if OK, false if could not coerce to required type
2489 : * (in which case, no changes have been made)
2490 : */
2491 : static bool
2492 14970 : coerce_fn_result_column(TargetEntry *src_tle,
2493 : Oid res_type,
2494 : int32 res_typmod,
2495 : bool tlist_is_modifiable,
2496 : List **upper_tlist,
2497 : bool *upper_tlist_nontrivial)
2498 : {
2499 : TargetEntry *new_tle;
2500 : Expr *new_tle_expr;
2501 : Node *cast_result;
2502 :
2503 : /*
2504 : * If the TLE has a sortgroupref marking, don't change it, as it probably
2505 : * is referenced by ORDER BY, DISTINCT, etc, and changing its type would
2506 : * break query semantics. Otherwise, it's safe to modify in-place unless
2507 : * the query as a whole has issues with that.
2508 : */
2509 14970 : if (tlist_is_modifiable && src_tle->ressortgroupref == 0)
2510 : {
2511 : /* OK to modify src_tle in place, if necessary */
2512 29504 : cast_result = coerce_to_target_type(NULL,
2513 14752 : (Node *) src_tle->expr,
2514 14752 : exprType((Node *) src_tle->expr),
2515 : res_type, res_typmod,
2516 : COERCION_ASSIGNMENT,
2517 : COERCE_IMPLICIT_CAST,
2518 : -1);
2519 14752 : if (cast_result == NULL)
2520 144 : return false;
2521 14608 : assign_expr_collations(NULL, cast_result);
2522 14608 : src_tle->expr = (Expr *) cast_result;
2523 : /* Make a Var referencing the possibly-modified TLE */
2524 14608 : new_tle_expr = (Expr *) makeVarFromTargetEntry(1, src_tle);
2525 : }
2526 : else
2527 : {
2528 : /* Any casting must happen in the upper tlist */
2529 218 : Var *var = makeVarFromTargetEntry(1, src_tle);
2530 :
2531 218 : cast_result = coerce_to_target_type(NULL,
2532 : (Node *) var,
2533 : var->vartype,
2534 : res_type, res_typmod,
2535 : COERCION_ASSIGNMENT,
2536 : COERCE_IMPLICIT_CAST,
2537 : -1);
2538 218 : if (cast_result == NULL)
2539 18 : return false;
2540 200 : assign_expr_collations(NULL, cast_result);
2541 : /* Did the coercion actually do anything? */
2542 200 : if (cast_result != (Node *) var)
2543 102 : *upper_tlist_nontrivial = true;
2544 200 : new_tle_expr = (Expr *) cast_result;
2545 : }
2546 29616 : new_tle = makeTargetEntry(new_tle_expr,
2547 14808 : list_length(*upper_tlist) + 1,
2548 : src_tle->resname, false);
2549 14808 : *upper_tlist = lappend(*upper_tlist, new_tle);
2550 14808 : return true;
2551 : }
2552 :
2553 : /*
2554 : * Extract the targetlist of the last canSetTag query in the given list
2555 : * of parsed-and-rewritten Queries. Returns NIL if there is none.
2556 : */
2557 : static List *
2558 35770 : get_sql_fn_result_tlist(List *queryTreeList)
2559 : {
2560 35770 : Query *parse = NULL;
2561 : ListCell *lc;
2562 :
2563 71546 : foreach(lc, queryTreeList)
2564 : {
2565 35776 : Query *q = lfirst_node(Query, lc);
2566 :
2567 35776 : if (q->canSetTag)
2568 35770 : parse = q;
2569 : }
2570 35770 : if (parse &&
2571 35770 : parse->commandType == CMD_SELECT)
2572 35674 : return parse->targetList;
2573 96 : else if (parse &&
2574 96 : (parse->commandType == CMD_INSERT ||
2575 24 : parse->commandType == CMD_UPDATE ||
2576 24 : parse->commandType == CMD_DELETE ||
2577 24 : parse->commandType == CMD_MERGE) &&
2578 96 : parse->returningList)
2579 96 : return parse->returningList;
2580 : else
2581 0 : return NIL;
2582 : }
2583 :
2584 :
2585 : /*
2586 : * CreateSQLFunctionDestReceiver -- create a suitable DestReceiver object
2587 : */
2588 : DestReceiver *
2589 85524 : CreateSQLFunctionDestReceiver(void)
2590 : {
2591 85524 : DR_sqlfunction *self = (DR_sqlfunction *) palloc0(sizeof(DR_sqlfunction));
2592 :
2593 85524 : self->pub.receiveSlot = sqlfunction_receive;
2594 85524 : self->pub.rStartup = sqlfunction_startup;
2595 85524 : self->pub.rShutdown = sqlfunction_shutdown;
2596 85524 : self->pub.rDestroy = sqlfunction_destroy;
2597 85524 : self->pub.mydest = DestSQLFunction;
2598 :
2599 : /* private fields will be set by postquel_start */
2600 :
2601 85524 : return (DestReceiver *) self;
2602 : }
2603 :
2604 : /*
2605 : * sqlfunction_startup --- executor startup
2606 : */
2607 : static void
2608 86506 : sqlfunction_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
2609 : {
2610 : /* no-op */
2611 86506 : }
2612 :
2613 : /*
2614 : * sqlfunction_receive --- receive one tuple
2615 : */
2616 : static bool
2617 192282 : sqlfunction_receive(TupleTableSlot *slot, DestReceiver *self)
2618 : {
2619 192282 : DR_sqlfunction *myState = (DR_sqlfunction *) self;
2620 :
2621 192282 : if (myState->tstore)
2622 : {
2623 : /* We are collecting all of a set result into the tuplestore */
2624 :
2625 : /* Filter tuple as needed */
2626 122344 : slot = ExecFilterJunk(myState->filter, slot);
2627 :
2628 : /* Store the filtered tuple into the tuplestore */
2629 122344 : tuplestore_puttupleslot(myState->tstore, slot);
2630 : }
2631 : else
2632 : {
2633 : /*
2634 : * We only want the first tuple, which we'll save in the junkfilter's
2635 : * result slot. Ignore any additional tuples passed.
2636 : */
2637 69938 : if (TTS_EMPTY(myState->filter->jf_resultSlot))
2638 : {
2639 : /* Filter tuple as needed */
2640 69932 : slot = ExecFilterJunk(myState->filter, slot);
2641 : Assert(slot == myState->filter->jf_resultSlot);
2642 :
2643 : /* Materialize the slot so it preserves pass-by-ref values */
2644 69932 : ExecMaterializeSlot(slot);
2645 : }
2646 : }
2647 :
2648 192282 : return true;
2649 : }
2650 :
2651 : /*
2652 : * sqlfunction_shutdown --- executor end
2653 : */
2654 : static void
2655 78788 : sqlfunction_shutdown(DestReceiver *self)
2656 : {
2657 : /* no-op */
2658 78788 : }
2659 :
2660 : /*
2661 : * sqlfunction_destroy --- release DestReceiver object
2662 : */
2663 : static void
2664 77800 : sqlfunction_destroy(DestReceiver *self)
2665 : {
2666 77800 : pfree(self);
2667 77800 : }
|