Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * functions.c
4 : * Execution of SQL-language functions
5 : *
6 : * Portions Copyright (c) 1996-2017, 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_func.h"
28 : #include "storage/proc.h"
29 : #include "tcop/utility.h"
30 : #include "utils/builtins.h"
31 : #include "utils/datum.h"
32 : #include "utils/lsyscache.h"
33 : #include "utils/memutils.h"
34 : #include "utils/snapmgr.h"
35 : #include "utils/syscache.h"
36 :
37 :
38 : /*
39 : * Specialized DestReceiver for collecting query output in a SQL function
40 : */
41 : typedef struct
42 : {
43 : DestReceiver pub; /* publicly-known function pointers */
44 : Tuplestorestate *tstore; /* where to put result tuples */
45 : MemoryContext cxt; /* context containing tstore */
46 : JunkFilter *filter; /* filter to convert tuple type */
47 : } DR_sqlfunction;
48 :
49 : /*
50 : * We have an execution_state record for each query in a function. Each
51 : * record contains a plantree for its query. If the query is currently in
52 : * F_EXEC_RUN state then there's a QueryDesc too.
53 : *
54 : * The "next" fields chain together all the execution_state records generated
55 : * from a single original parsetree. (There will only be more than one in
56 : * case of rule expansion of the original parsetree.)
57 : */
58 : typedef enum
59 : {
60 : F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE
61 : } ExecStatus;
62 :
63 : typedef struct execution_state
64 : {
65 : struct execution_state *next;
66 : ExecStatus status;
67 : bool setsResult; /* true if this query produces func's result */
68 : bool lazyEval; /* true if should fetch one row at a time */
69 : PlannedStmt *stmt; /* plan for this query */
70 : QueryDesc *qd; /* null unless status == RUN */
71 : } execution_state;
72 :
73 :
74 : /*
75 : * An SQLFunctionCache record is built during the first call,
76 : * and linked to from the fn_extra field of the FmgrInfo struct.
77 : *
78 : * Note that currently this has only the lifespan of the calling query.
79 : * Someday we should rewrite this code to use plancache.c to save parse/plan
80 : * results for longer than that.
81 : *
82 : * Physically, though, the data has the lifespan of the FmgrInfo that's used
83 : * to call the function, and there are cases (particularly with indexes)
84 : * where the FmgrInfo might survive across transactions. We cannot assume
85 : * that the parse/plan trees are good for longer than the (sub)transaction in
86 : * which parsing was done, so we must mark the record with the LXID/subxid of
87 : * its creation time, and regenerate everything if that's obsolete. To avoid
88 : * memory leakage when we do have to regenerate things, all the data is kept
89 : * in a sub-context of the FmgrInfo's fn_mcxt.
90 : */
91 : typedef struct
92 : {
93 : char *fname; /* function name (for error msgs) */
94 : char *src; /* function body text (for error msgs) */
95 :
96 : SQLFunctionParseInfoPtr pinfo; /* data for parser callback hooks */
97 :
98 : Oid rettype; /* actual return type */
99 : int16 typlen; /* length of the return type */
100 : bool typbyval; /* true if return type is pass by value */
101 : bool returnsSet; /* true if returning multiple rows */
102 : bool returnsTuple; /* true if returning whole tuple result */
103 : bool shutdown_reg; /* true if registered shutdown callback */
104 : bool readonly_func; /* true to run in "read only" mode */
105 : bool lazyEval; /* true if using lazyEval for result query */
106 :
107 : ParamListInfo paramLI; /* Param list representing current args */
108 :
109 : Tuplestorestate *tstore; /* where we accumulate result tuples */
110 :
111 : JunkFilter *junkFilter; /* will be NULL if function returns VOID */
112 :
113 : /*
114 : * func_state is a List of execution_state records, each of which is the
115 : * first for its original parsetree, with any additional records chained
116 : * to it via the "next" fields. This sublist structure is needed to keep
117 : * track of where the original query boundaries are.
118 : */
119 : List *func_state;
120 :
121 : MemoryContext fcontext; /* memory context holding this struct and all
122 : * subsidiary data */
123 :
124 : LocalTransactionId lxid; /* lxid in which cache was made */
125 : SubTransactionId subxid; /* subxid in which cache was made */
126 : } SQLFunctionCache;
127 :
128 : typedef SQLFunctionCache *SQLFunctionCachePtr;
129 :
130 : /*
131 : * Data structure needed by the parser callback hooks to resolve parameter
132 : * references during parsing of a SQL function's body. This is separate from
133 : * SQLFunctionCache since we sometimes do parsing separately from execution.
134 : */
135 : typedef struct SQLFunctionParseInfo
136 : {
137 : char *fname; /* function's name */
138 : int nargs; /* number of input arguments */
139 : Oid *argtypes; /* resolved types of input arguments */
140 : char **argnames; /* names of input arguments; NULL if none */
141 : /* Note that argnames[i] can be NULL, if some args are unnamed */
142 : Oid collation; /* function's input collation, if known */
143 : } SQLFunctionParseInfo;
144 :
145 :
146 : /* non-export function prototypes */
147 : static Node *sql_fn_param_ref(ParseState *pstate, ParamRef *pref);
148 : static Node *sql_fn_post_column_ref(ParseState *pstate,
149 : ColumnRef *cref, Node *var);
150 : static Node *sql_fn_make_param(SQLFunctionParseInfoPtr pinfo,
151 : int paramno, int location);
152 : static Node *sql_fn_resolve_param_name(SQLFunctionParseInfoPtr pinfo,
153 : const char *paramname, int location);
154 : static List *init_execution_state(List *queryTree_list,
155 : SQLFunctionCachePtr fcache,
156 : bool lazyEvalOK);
157 : static void init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK);
158 : static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
159 : static bool postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache);
160 : static void postquel_end(execution_state *es);
161 : static void postquel_sub_params(SQLFunctionCachePtr fcache,
162 : FunctionCallInfo fcinfo);
163 : static Datum postquel_get_single_result(TupleTableSlot *slot,
164 : FunctionCallInfo fcinfo,
165 : SQLFunctionCachePtr fcache,
166 : MemoryContext resultcontext);
167 : static void sql_exec_error_callback(void *arg);
168 : static void ShutdownSQLFunction(Datum arg);
169 : static void sqlfunction_startup(DestReceiver *self, int operation, TupleDesc typeinfo);
170 : static bool sqlfunction_receive(TupleTableSlot *slot, DestReceiver *self);
171 : static void sqlfunction_shutdown(DestReceiver *self);
172 : static void sqlfunction_destroy(DestReceiver *self);
173 :
174 :
175 : /*
176 : * Prepare the SQLFunctionParseInfo struct for parsing a SQL function body
177 : *
178 : * This includes resolving actual types of polymorphic arguments.
179 : *
180 : * call_expr can be passed as NULL, but then we will fail if there are any
181 : * polymorphic arguments.
182 : */
183 : SQLFunctionParseInfoPtr
184 5749 : prepare_sql_fn_parse_info(HeapTuple procedureTuple,
185 : Node *call_expr,
186 : Oid inputCollation)
187 : {
188 : SQLFunctionParseInfoPtr pinfo;
189 5749 : Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
190 : int nargs;
191 :
192 5749 : pinfo = (SQLFunctionParseInfoPtr) palloc0(sizeof(SQLFunctionParseInfo));
193 :
194 : /* Function's name (only) can be used to qualify argument names */
195 5749 : pinfo->fname = pstrdup(NameStr(procedureStruct->proname));
196 :
197 : /* Save the function's input collation */
198 5749 : pinfo->collation = inputCollation;
199 :
200 : /*
201 : * Copy input argument types from the pg_proc entry, then resolve any
202 : * polymorphic types.
203 : */
204 5749 : pinfo->nargs = nargs = procedureStruct->pronargs;
205 5749 : if (nargs > 0)
206 : {
207 : Oid *argOidVect;
208 : int argnum;
209 :
210 1040 : argOidVect = (Oid *) palloc(nargs * sizeof(Oid));
211 2080 : memcpy(argOidVect,
212 1040 : procedureStruct->proargtypes.values,
213 : nargs * sizeof(Oid));
214 :
215 2874 : for (argnum = 0; argnum < nargs; argnum++)
216 : {
217 1834 : Oid argtype = argOidVect[argnum];
218 :
219 1834 : if (IsPolymorphicType(argtype))
220 : {
221 213 : argtype = get_call_expr_argtype(call_expr, argnum);
222 213 : if (argtype == InvalidOid)
223 0 : ereport(ERROR,
224 : (errcode(ERRCODE_DATATYPE_MISMATCH),
225 : errmsg("could not determine actual type of argument declared %s",
226 : format_type_be(argOidVect[argnum]))));
227 213 : argOidVect[argnum] = argtype;
228 : }
229 : }
230 :
231 1040 : pinfo->argtypes = argOidVect;
232 : }
233 :
234 : /*
235 : * Collect names of arguments, too, if any
236 : */
237 5749 : if (nargs > 0)
238 : {
239 : Datum proargnames;
240 : Datum proargmodes;
241 : int n_arg_names;
242 : bool isNull;
243 :
244 1040 : proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, procedureTuple,
245 : Anum_pg_proc_proargnames,
246 : &isNull);
247 1040 : if (isNull)
248 845 : proargnames = PointerGetDatum(NULL); /* just to be sure */
249 :
250 1040 : proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, procedureTuple,
251 : Anum_pg_proc_proargmodes,
252 : &isNull);
253 1040 : if (isNull)
254 946 : proargmodes = PointerGetDatum(NULL); /* just to be sure */
255 :
256 1040 : n_arg_names = get_func_input_arg_names(proargnames, proargmodes,
257 : &pinfo->argnames);
258 :
259 : /* Paranoia: ignore the result if too few array entries */
260 1040 : if (n_arg_names < nargs)
261 845 : pinfo->argnames = NULL;
262 : }
263 : else
264 4709 : pinfo->argnames = NULL;
265 :
266 5749 : return pinfo;
267 : }
268 :
269 : /*
270 : * Parser setup hook for parsing a SQL function body.
271 : */
272 : void
273 5749 : sql_fn_parser_setup(struct ParseState *pstate, SQLFunctionParseInfoPtr pinfo)
274 : {
275 5749 : pstate->p_pre_columnref_hook = NULL;
276 5749 : pstate->p_post_columnref_hook = sql_fn_post_column_ref;
277 5749 : pstate->p_paramref_hook = sql_fn_param_ref;
278 : /* no need to use p_coerce_param_hook */
279 5749 : pstate->p_ref_hook_state = (void *) pinfo;
280 5749 : }
281 :
282 : /*
283 : * sql_fn_post_column_ref parser callback for ColumnRefs
284 : */
285 : static Node *
286 2054 : sql_fn_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var)
287 : {
288 2054 : SQLFunctionParseInfoPtr pinfo = (SQLFunctionParseInfoPtr) pstate->p_ref_hook_state;
289 : int nnames;
290 : Node *field1;
291 2054 : Node *subfield = NULL;
292 : const char *name1;
293 2054 : const char *name2 = NULL;
294 : Node *param;
295 :
296 : /*
297 : * Never override a table-column reference. This corresponds to
298 : * considering the parameter names to appear in a scope outside the
299 : * individual SQL commands, which is what we want.
300 : */
301 2054 : if (var != NULL)
302 1985 : return NULL;
303 :
304 : /*----------
305 : * The allowed syntaxes are:
306 : *
307 : * A A = parameter name
308 : * A.B A = function name, B = parameter name
309 : * OR: A = record-typed parameter name, B = field name
310 : * (the first possibility takes precedence)
311 : * A.B.C A = function name, B = record-typed parameter name,
312 : * C = field name
313 : * A.* Whole-row reference to composite parameter A.
314 : * A.B.* Same, with A = function name, B = parameter name
315 : *
316 : * Here, it's sufficient to ignore the "*" in the last two cases --- the
317 : * main parser will take care of expanding the whole-row reference.
318 : *----------
319 : */
320 69 : nnames = list_length(cref->fields);
321 :
322 69 : if (nnames > 3)
323 0 : return NULL;
324 :
325 69 : if (IsA(llast(cref->fields), A_Star))
326 9 : nnames--;
327 :
328 69 : field1 = (Node *) linitial(cref->fields);
329 69 : Assert(IsA(field1, String));
330 69 : name1 = strVal(field1);
331 69 : if (nnames > 1)
332 : {
333 24 : subfield = (Node *) lsecond(cref->fields);
334 24 : Assert(IsA(subfield, String));
335 24 : name2 = strVal(subfield);
336 : }
337 :
338 69 : if (nnames == 3)
339 : {
340 : /*
341 : * Three-part name: if the first part doesn't match the function name,
342 : * we can fail immediately. Otherwise, look up the second part, and
343 : * take the third part to be a field reference.
344 : */
345 4 : if (strcmp(name1, pinfo->fname) != 0)
346 0 : return NULL;
347 :
348 4 : param = sql_fn_resolve_param_name(pinfo, name2, cref->location);
349 :
350 4 : subfield = (Node *) lthird(cref->fields);
351 4 : Assert(IsA(subfield, String));
352 : }
353 65 : else if (nnames == 2 && strcmp(name1, pinfo->fname) == 0)
354 : {
355 : /*
356 : * Two-part name with first part matching function name: first see if
357 : * second part matches any parameter name.
358 : */
359 4 : param = sql_fn_resolve_param_name(pinfo, name2, cref->location);
360 :
361 8 : if (param)
362 : {
363 : /* Yes, so this is a parameter reference, no subfield */
364 4 : subfield = NULL;
365 : }
366 : else
367 : {
368 : /* No, so try to match as parameter name and subfield */
369 0 : param = sql_fn_resolve_param_name(pinfo, name1, cref->location);
370 : }
371 : }
372 : else
373 : {
374 : /* Single name, or parameter name followed by subfield */
375 61 : param = sql_fn_resolve_param_name(pinfo, name1, cref->location);
376 : }
377 :
378 69 : if (!param)
379 0 : return NULL; /* No match */
380 :
381 69 : if (subfield)
382 : {
383 : /*
384 : * Must be a reference to a field of a composite parameter; otherwise
385 : * ParseFuncOrColumn will return NULL, and we'll fail back at the
386 : * caller.
387 : */
388 20 : param = ParseFuncOrColumn(pstate,
389 : list_make1(subfield),
390 : list_make1(param),
391 : pstate->p_last_srf,
392 : NULL,
393 : cref->location);
394 : }
395 :
396 69 : return param;
397 : }
398 :
399 : /*
400 : * sql_fn_param_ref parser callback for ParamRefs ($n symbols)
401 : */
402 : static Node *
403 1817 : sql_fn_param_ref(ParseState *pstate, ParamRef *pref)
404 : {
405 1817 : SQLFunctionParseInfoPtr pinfo = (SQLFunctionParseInfoPtr) pstate->p_ref_hook_state;
406 1817 : int paramno = pref->number;
407 :
408 : /* Check parameter number is valid */
409 1817 : if (paramno <= 0 || paramno > pinfo->nargs)
410 1 : return NULL; /* unknown parameter number */
411 :
412 1816 : return sql_fn_make_param(pinfo, paramno, pref->location);
413 : }
414 :
415 : /*
416 : * sql_fn_make_param construct a Param node for the given paramno
417 : */
418 : static Node *
419 1885 : sql_fn_make_param(SQLFunctionParseInfoPtr pinfo,
420 : int paramno, int location)
421 : {
422 : Param *param;
423 :
424 1885 : param = makeNode(Param);
425 1885 : param->paramkind = PARAM_EXTERN;
426 1885 : param->paramid = paramno;
427 1885 : param->paramtype = pinfo->argtypes[paramno - 1];
428 1885 : param->paramtypmod = -1;
429 1885 : param->paramcollid = get_typcollation(param->paramtype);
430 1885 : param->location = location;
431 :
432 : /*
433 : * If we have a function input collation, allow it to override the
434 : * type-derived collation for parameter symbols. (XXX perhaps this should
435 : * not happen if the type collation is not default?)
436 : */
437 1885 : if (OidIsValid(pinfo->collation) && OidIsValid(param->paramcollid))
438 325 : param->paramcollid = pinfo->collation;
439 :
440 1885 : return (Node *) param;
441 : }
442 :
443 : /*
444 : * Search for a function parameter of the given name; if there is one,
445 : * construct and return a Param node for it. If not, return NULL.
446 : * Helper function for sql_fn_post_column_ref.
447 : */
448 : static Node *
449 69 : sql_fn_resolve_param_name(SQLFunctionParseInfoPtr pinfo,
450 : const char *paramname, int location)
451 : {
452 : int i;
453 :
454 69 : if (pinfo->argnames == NULL)
455 0 : return NULL;
456 :
457 80 : for (i = 0; i < pinfo->nargs; i++)
458 : {
459 80 : if (pinfo->argnames[i] && strcmp(pinfo->argnames[i], paramname) == 0)
460 69 : return sql_fn_make_param(pinfo, i + 1, location);
461 : }
462 :
463 0 : return NULL;
464 : }
465 :
466 : /*
467 : * Set up the per-query execution_state records for a SQL function.
468 : *
469 : * The input is a List of Lists of parsed and rewritten, but not planned,
470 : * querytrees. The sublist structure denotes the original query boundaries.
471 : */
472 : static List *
473 2886 : init_execution_state(List *queryTree_list,
474 : SQLFunctionCachePtr fcache,
475 : bool lazyEvalOK)
476 : {
477 2886 : List *eslist = NIL;
478 2886 : execution_state *lasttages = NULL;
479 : ListCell *lc1;
480 :
481 5771 : foreach(lc1, queryTree_list)
482 : {
483 2886 : List *qtlist = lfirst_node(List, lc1);
484 2886 : execution_state *firstes = NULL;
485 2886 : execution_state *preves = NULL;
486 : ListCell *lc2;
487 :
488 5772 : foreach(lc2, qtlist)
489 : {
490 2887 : Query *queryTree = lfirst_node(Query, lc2);
491 : PlannedStmt *stmt;
492 : execution_state *newes;
493 :
494 : /* Plan the query if needed */
495 2887 : if (queryTree->commandType == CMD_UTILITY)
496 : {
497 : /* Utility commands require no planning. */
498 8 : stmt = makeNode(PlannedStmt);
499 8 : stmt->commandType = CMD_UTILITY;
500 8 : stmt->canSetTag = queryTree->canSetTag;
501 8 : stmt->utilityStmt = queryTree->utilityStmt;
502 8 : stmt->stmt_location = queryTree->stmt_location;
503 8 : stmt->stmt_len = queryTree->stmt_len;
504 : }
505 : else
506 2879 : stmt = pg_plan_query(queryTree,
507 : CURSOR_OPT_PARALLEL_OK,
508 : NULL);
509 :
510 : /*
511 : * Precheck all commands for validity in a function. This should
512 : * generally match the restrictions spi.c applies.
513 : */
514 2886 : if (stmt->commandType == CMD_UTILITY)
515 : {
516 8 : if (IsA(stmt->utilityStmt, CopyStmt) &&
517 0 : ((CopyStmt *) stmt->utilityStmt)->filename == NULL)
518 0 : ereport(ERROR,
519 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
520 : errmsg("cannot COPY to/from client in a SQL function")));
521 :
522 8 : if (IsA(stmt->utilityStmt, TransactionStmt))
523 0 : ereport(ERROR,
524 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
525 : /* translator: %s is a SQL statement name */
526 : errmsg("%s is not allowed in a SQL function",
527 : CreateCommandTag(stmt->utilityStmt))));
528 : }
529 :
530 2886 : if (fcache->readonly_func && !CommandIsReadOnly(stmt))
531 0 : ereport(ERROR,
532 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
533 : /* translator: %s is a SQL statement name */
534 : errmsg("%s is not allowed in a non-volatile function",
535 : CreateCommandTag((Node *) stmt))));
536 :
537 2886 : if (IsInParallelMode() && !CommandIsReadOnly(stmt))
538 0 : PreventCommandIfParallelMode(CreateCommandTag((Node *) stmt));
539 :
540 : /* OK, build the execution_state for this query */
541 2886 : newes = (execution_state *) palloc(sizeof(execution_state));
542 2886 : if (preves)
543 1 : preves->next = newes;
544 : else
545 2885 : firstes = newes;
546 :
547 2886 : newes->next = NULL;
548 2886 : newes->status = F_EXEC_START;
549 2886 : newes->setsResult = false; /* might change below */
550 2886 : newes->lazyEval = false; /* might change below */
551 2886 : newes->stmt = stmt;
552 2886 : newes->qd = NULL;
553 :
554 2886 : if (queryTree->canSetTag)
555 2885 : lasttages = newes;
556 :
557 2886 : preves = newes;
558 : }
559 :
560 2885 : eslist = lappend(eslist, firstes);
561 : }
562 :
563 : /*
564 : * Mark the last canSetTag query as delivering the function result; then,
565 : * if it is a plain SELECT, mark it for lazy evaluation. If it's not a
566 : * SELECT we must always run it to completion.
567 : *
568 : * Note: at some point we might add additional criteria for whether to use
569 : * lazy eval. However, we should prefer to use it whenever the function
570 : * doesn't return set, since fetching more than one row is useless in that
571 : * case.
572 : *
573 : * Note: don't set setsResult if the function returns VOID, as evidenced
574 : * by not having made a junkfilter. This ensures we'll throw away any
575 : * output from a utility statement that check_sql_fn_retval deemed to not
576 : * have output.
577 : */
578 2885 : if (lasttages && fcache->junkFilter)
579 : {
580 2874 : lasttages->setsResult = true;
581 5628 : if (lazyEvalOK &&
582 5498 : lasttages->stmt->commandType == CMD_SELECT &&
583 2744 : !lasttages->stmt->hasModifyingCTE)
584 2744 : fcache->lazyEval = lasttages->lazyEval = true;
585 : }
586 :
587 2885 : return eslist;
588 : }
589 :
590 : /*
591 : * Initialize the SQLFunctionCache for a SQL function
592 : */
593 : static void
594 2886 : init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK)
595 : {
596 2886 : Oid foid = finfo->fn_oid;
597 : MemoryContext fcontext;
598 : MemoryContext oldcontext;
599 : Oid rettype;
600 : HeapTuple procedureTuple;
601 : Form_pg_proc procedureStruct;
602 : SQLFunctionCachePtr fcache;
603 : List *raw_parsetree_list;
604 : List *queryTree_list;
605 : List *flat_query_list;
606 : ListCell *lc;
607 : Datum tmp;
608 : bool isNull;
609 :
610 : /*
611 : * Create memory context that holds all the SQLFunctionCache data. It
612 : * must be a child of whatever context holds the FmgrInfo.
613 : */
614 2886 : fcontext = AllocSetContextCreate(finfo->fn_mcxt,
615 : "SQL function data",
616 : ALLOCSET_DEFAULT_SIZES);
617 :
618 2886 : oldcontext = MemoryContextSwitchTo(fcontext);
619 :
620 : /*
621 : * Create the struct proper, link it to fcontext and fn_extra. Once this
622 : * is done, we'll be able to recover the memory after failure, even if the
623 : * FmgrInfo is long-lived.
624 : */
625 2886 : fcache = (SQLFunctionCachePtr) palloc0(sizeof(SQLFunctionCache));
626 2886 : fcache->fcontext = fcontext;
627 2886 : finfo->fn_extra = (void *) fcache;
628 :
629 : /*
630 : * get the procedure tuple corresponding to the given function Oid
631 : */
632 2886 : procedureTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(foid));
633 2886 : if (!HeapTupleIsValid(procedureTuple))
634 0 : elog(ERROR, "cache lookup failed for function %u", foid);
635 2886 : procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
636 :
637 : /*
638 : * copy function name immediately for use by error reporting callback
639 : */
640 2886 : fcache->fname = pstrdup(NameStr(procedureStruct->proname));
641 :
642 : /*
643 : * get the result type from the procedure tuple, and check for polymorphic
644 : * result type; if so, find out the actual result type.
645 : */
646 2886 : rettype = procedureStruct->prorettype;
647 :
648 2886 : if (IsPolymorphicType(rettype))
649 : {
650 35 : rettype = get_fn_expr_rettype(finfo);
651 35 : if (rettype == InvalidOid) /* this probably should not happen */
652 0 : ereport(ERROR,
653 : (errcode(ERRCODE_DATATYPE_MISMATCH),
654 : errmsg("could not determine actual result type for function declared to return type %s",
655 : format_type_be(procedureStruct->prorettype))));
656 : }
657 :
658 2886 : fcache->rettype = rettype;
659 :
660 : /* Fetch the typlen and byval info for the result type */
661 2886 : get_typlenbyval(rettype, &fcache->typlen, &fcache->typbyval);
662 :
663 : /* Remember whether we're returning setof something */
664 2886 : fcache->returnsSet = procedureStruct->proretset;
665 :
666 : /* Remember if function is STABLE/IMMUTABLE */
667 2886 : fcache->readonly_func =
668 2886 : (procedureStruct->provolatile != PROVOLATILE_VOLATILE);
669 :
670 : /*
671 : * We need the actual argument types to pass to the parser. Also make
672 : * sure that parameter symbols are considered to have the function's
673 : * resolved input collation.
674 : */
675 2886 : fcache->pinfo = prepare_sql_fn_parse_info(procedureTuple,
676 2886 : finfo->fn_expr,
677 : collation);
678 :
679 : /*
680 : * And of course we need the function body text.
681 : */
682 2886 : tmp = SysCacheGetAttr(PROCOID,
683 : procedureTuple,
684 : Anum_pg_proc_prosrc,
685 : &isNull);
686 2886 : if (isNull)
687 0 : elog(ERROR, "null prosrc for function %u", foid);
688 2886 : fcache->src = TextDatumGetCString(tmp);
689 :
690 : /*
691 : * Parse and rewrite the queries in the function text. Use sublists to
692 : * keep track of the original query boundaries. But we also build a
693 : * "flat" list of the rewritten queries to pass to check_sql_fn_retval.
694 : * This is because the last canSetTag query determines the result type
695 : * independently of query boundaries --- and it might not be in the last
696 : * sublist, for example if the last query rewrites to DO INSTEAD NOTHING.
697 : * (It might not be unreasonable to throw an error in such a case, but
698 : * this is the historical behavior and it doesn't seem worth changing.)
699 : *
700 : * Note: since parsing and planning is done in fcontext, we will generate
701 : * a lot of cruft that lives as long as the fcache does. This is annoying
702 : * but we'll not worry about it until the module is rewritten to use
703 : * plancache.c.
704 : */
705 2886 : raw_parsetree_list = pg_parse_query(fcache->src);
706 :
707 2886 : queryTree_list = NIL;
708 2886 : flat_query_list = NIL;
709 5772 : foreach(lc, raw_parsetree_list)
710 : {
711 2886 : RawStmt *parsetree = lfirst_node(RawStmt, lc);
712 : List *queryTree_sublist;
713 :
714 2886 : queryTree_sublist = pg_analyze_and_rewrite_params(parsetree,
715 2886 : fcache->src,
716 : (ParserSetupHook) sql_fn_parser_setup,
717 2886 : fcache->pinfo,
718 : NULL);
719 2886 : queryTree_list = lappend(queryTree_list, queryTree_sublist);
720 2886 : flat_query_list = list_concat(flat_query_list,
721 : list_copy(queryTree_sublist));
722 : }
723 :
724 : /*
725 : * Check that the function returns the type it claims to. Although in
726 : * simple cases this was already done when the function was defined, we
727 : * have to recheck because database objects used in the function's queries
728 : * might have changed type. We'd have to do it anyway if the function had
729 : * any polymorphic arguments.
730 : *
731 : * Note: we set fcache->returnsTuple according to whether we are returning
732 : * the whole tuple result or just a single column. In the latter case we
733 : * clear returnsTuple because we need not act different from the scalar
734 : * result case, even if it's a rowtype column. (However, we have to force
735 : * lazy eval mode in that case; otherwise we'd need extra code to expand
736 : * the rowtype column into multiple columns, since we have no way to
737 : * notify the caller that it should do that.)
738 : *
739 : * check_sql_fn_retval will also construct a JunkFilter we can use to
740 : * coerce the returned rowtype to the desired form (unless the result type
741 : * is VOID, in which case there's nothing to coerce to).
742 : */
743 2886 : fcache->returnsTuple = check_sql_fn_retval(foid,
744 : rettype,
745 : flat_query_list,
746 : NULL,
747 : &fcache->junkFilter);
748 :
749 2886 : if (fcache->returnsTuple)
750 : {
751 : /* Make sure output rowtype is properly blessed */
752 183 : BlessTupleDesc(fcache->junkFilter->jf_resultSlot->tts_tupleDescriptor);
753 : }
754 2703 : else if (fcache->returnsSet && type_is_rowtype(fcache->rettype))
755 : {
756 : /*
757 : * Returning rowtype as if it were scalar --- materialize won't work.
758 : * Right now it's sufficient to override any caller preference for
759 : * materialize mode, but to add more smarts in init_execution_state
760 : * about this, we'd probably need a three-way flag instead of bool.
761 : */
762 0 : lazyEvalOK = true;
763 : }
764 :
765 : /* Finally, plan the queries */
766 2886 : fcache->func_state = init_execution_state(queryTree_list,
767 : fcache,
768 : lazyEvalOK);
769 :
770 : /* Mark fcache with time of creation to show it's valid */
771 2885 : fcache->lxid = MyProc->lxid;
772 2885 : fcache->subxid = GetCurrentSubTransactionId();
773 :
774 2885 : ReleaseSysCache(procedureTuple);
775 :
776 2885 : MemoryContextSwitchTo(oldcontext);
777 2885 : }
778 :
779 : /* Start up execution of one execution_state node */
780 : static void
781 5211 : postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
782 : {
783 : DestReceiver *dest;
784 :
785 5211 : Assert(es->qd == NULL);
786 :
787 : /* Caller should have ensured a suitable snapshot is active */
788 5211 : Assert(ActiveSnapshotSet());
789 :
790 : /*
791 : * If this query produces the function result, send its output to the
792 : * tuplestore; else discard any output.
793 : */
794 5211 : if (es->setsResult)
795 : {
796 : DR_sqlfunction *myState;
797 :
798 5199 : dest = CreateDestReceiver(DestSQLFunction);
799 : /* pass down the needed info to the dest receiver routines */
800 5199 : myState = (DR_sqlfunction *) dest;
801 5199 : Assert(myState->pub.mydest == DestSQLFunction);
802 5199 : myState->tstore = fcache->tstore;
803 5199 : myState->cxt = CurrentMemoryContext;
804 5199 : myState->filter = fcache->junkFilter;
805 : }
806 : else
807 12 : dest = None_Receiver;
808 :
809 10422 : es->qd = CreateQueryDesc(es->stmt,
810 5211 : fcache->src,
811 : GetActiveSnapshot(),
812 : InvalidSnapshot,
813 : dest,
814 : fcache->paramLI,
815 5211 : es->qd ? es->qd->queryEnv : NULL,
816 : 0);
817 :
818 : /* Utility commands don't need Executor. */
819 5211 : if (es->qd->operation != CMD_UTILITY)
820 : {
821 : /*
822 : * In lazyEval mode, do not let the executor set up an AfterTrigger
823 : * context. This is necessary not just an optimization, because we
824 : * mustn't exit from the function execution with a stacked
825 : * AfterTrigger level still active. We are careful not to select
826 : * lazyEval mode for any statement that could possibly queue triggers.
827 : */
828 : int eflags;
829 :
830 5203 : if (es->lazyEval)
831 5041 : eflags = EXEC_FLAG_SKIP_TRIGGERS;
832 : else
833 162 : eflags = 0; /* default run-to-completion flags */
834 5203 : ExecutorStart(es->qd, eflags);
835 : }
836 :
837 5211 : es->status = F_EXEC_RUN;
838 5211 : }
839 :
840 : /* Run one execution_state; either to completion or to first result row */
841 : /* Returns true if we ran to completion */
842 : static bool
843 5349 : postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
844 : {
845 : bool result;
846 :
847 5349 : if (es->qd->operation == CMD_UTILITY)
848 : {
849 32 : ProcessUtility(es->qd->plannedstmt,
850 8 : fcache->src,
851 : PROCESS_UTILITY_QUERY,
852 8 : es->qd->params,
853 8 : es->qd->queryEnv,
854 8 : es->qd->dest,
855 : NULL);
856 5 : result = true; /* never stops early */
857 : }
858 : else
859 : {
860 : /* Run regular commands to completion unless lazyEval */
861 5341 : uint64 count = (es->lazyEval) ? 1 : 0;
862 :
863 5341 : ExecutorRun(es->qd, ForwardScanDirection, count, !fcache->returnsSet || !es->lazyEval);
864 :
865 : /*
866 : * If we requested run to completion OR there was no tuple returned,
867 : * command must be complete.
868 : */
869 3040 : result = (count == 0 || es->qd->estate->es_processed == 0);
870 : }
871 :
872 3045 : return result;
873 : }
874 :
875 : /* Shut down execution of one execution_state node */
876 : static void
877 2907 : postquel_end(execution_state *es)
878 : {
879 : /* mark status done to ensure we don't do ExecutorEnd twice */
880 2907 : es->status = F_EXEC_DONE;
881 :
882 : /* Utility commands don't need Executor. */
883 2907 : if (es->qd->operation != CMD_UTILITY)
884 : {
885 2902 : ExecutorFinish(es->qd);
886 2902 : ExecutorEnd(es->qd);
887 : }
888 :
889 2907 : (*es->qd->dest->rDestroy) (es->qd->dest);
890 :
891 2907 : FreeQueryDesc(es->qd);
892 2907 : es->qd = NULL;
893 2907 : }
894 :
895 : /* Build ParamListInfo array representing current arguments */
896 : static void
897 5210 : postquel_sub_params(SQLFunctionCachePtr fcache,
898 : FunctionCallInfo fcinfo)
899 : {
900 5210 : int nargs = fcinfo->nargs;
901 :
902 5210 : if (nargs > 0)
903 : {
904 : ParamListInfo paramLI;
905 : int i;
906 :
907 2841 : if (fcache->paramLI == NULL)
908 : {
909 522 : paramLI = (ParamListInfo)
910 522 : palloc(offsetof(ParamListInfoData, params) +
911 522 : nargs * sizeof(ParamExternData));
912 : /* we have static list of params, so no hooks needed */
913 522 : paramLI->paramFetch = NULL;
914 522 : paramLI->paramFetchArg = NULL;
915 522 : paramLI->parserSetup = NULL;
916 522 : paramLI->parserSetupArg = NULL;
917 522 : paramLI->numParams = nargs;
918 522 : paramLI->paramMask = NULL;
919 522 : fcache->paramLI = paramLI;
920 : }
921 : else
922 : {
923 2319 : paramLI = fcache->paramLI;
924 2319 : Assert(paramLI->numParams == nargs);
925 : }
926 :
927 7928 : for (i = 0; i < nargs; i++)
928 : {
929 5087 : ParamExternData *prm = ¶mLI->params[i];
930 :
931 5087 : prm->value = fcinfo->arg[i];
932 5087 : prm->isnull = fcinfo->argnull[i];
933 5087 : prm->pflags = 0;
934 5087 : prm->ptype = fcache->pinfo->argtypes[i];
935 : }
936 : }
937 : else
938 2369 : fcache->paramLI = NULL;
939 5210 : }
940 :
941 : /*
942 : * Extract the SQL function's value from a single result row. This is used
943 : * both for scalar (non-set) functions and for each row of a lazy-eval set
944 : * result.
945 : */
946 : static Datum
947 1975 : postquel_get_single_result(TupleTableSlot *slot,
948 : FunctionCallInfo fcinfo,
949 : SQLFunctionCachePtr fcache,
950 : MemoryContext resultcontext)
951 : {
952 : Datum value;
953 : MemoryContext oldcontext;
954 :
955 : /*
956 : * Set up to return the function value. For pass-by-reference datatypes,
957 : * be sure to allocate the result in resultcontext, not the current memory
958 : * context (which has query lifespan). We can't leave the data in the
959 : * TupleTableSlot because we intend to clear the slot before returning.
960 : */
961 1975 : oldcontext = MemoryContextSwitchTo(resultcontext);
962 :
963 1975 : if (fcache->returnsTuple)
964 : {
965 : /* We must return the whole tuple as a Datum. */
966 191 : fcinfo->isnull = false;
967 191 : value = ExecFetchSlotTupleDatum(slot);
968 : }
969 : else
970 : {
971 : /*
972 : * Returning a scalar, which we have to extract from the first column
973 : * of the SELECT result, and then copy into result context if needed.
974 : */
975 1784 : value = slot_getattr(slot, 1, &(fcinfo->isnull));
976 :
977 1784 : if (!fcinfo->isnull)
978 1727 : value = datumCopy(value, fcache->typbyval, fcache->typlen);
979 : }
980 :
981 1975 : MemoryContextSwitchTo(oldcontext);
982 :
983 1975 : return value;
984 : }
985 :
986 : /*
987 : * fmgr_sql: function call manager for SQL functions
988 : */
989 : Datum
990 5349 : fmgr_sql(PG_FUNCTION_ARGS)
991 : {
992 : SQLFunctionCachePtr fcache;
993 : ErrorContextCallback sqlerrcontext;
994 : MemoryContext oldcontext;
995 : bool randomAccess;
996 : bool lazyEvalOK;
997 : bool is_first;
998 : bool pushed_snapshot;
999 : execution_state *es;
1000 : TupleTableSlot *slot;
1001 : Datum result;
1002 : List *eslist;
1003 : ListCell *eslc;
1004 :
1005 : /*
1006 : * Setup error traceback support for ereport()
1007 : */
1008 5349 : sqlerrcontext.callback = sql_exec_error_callback;
1009 5349 : sqlerrcontext.arg = fcinfo->flinfo;
1010 5349 : sqlerrcontext.previous = error_context_stack;
1011 5349 : error_context_stack = &sqlerrcontext;
1012 :
1013 : /* Check call context */
1014 5349 : if (fcinfo->flinfo->fn_retset)
1015 : {
1016 800 : ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1017 :
1018 : /*
1019 : * For simplicity, we require callers to support both set eval modes.
1020 : * There are cases where we must use one or must use the other, and
1021 : * it's not really worthwhile to postpone the check till we know. But
1022 : * note we do not require caller to provide an expectedDesc.
1023 : */
1024 1600 : if (!rsi || !IsA(rsi, ReturnSetInfo) ||
1025 1600 : (rsi->allowedModes & SFRM_ValuePerCall) == 0 ||
1026 800 : (rsi->allowedModes & SFRM_Materialize) == 0)
1027 0 : ereport(ERROR,
1028 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1029 : errmsg("set-valued function called in context that cannot accept a set")));
1030 800 : randomAccess = rsi->allowedModes & SFRM_Materialize_Random;
1031 800 : lazyEvalOK = !(rsi->allowedModes & SFRM_Materialize_Preferred);
1032 : }
1033 : else
1034 : {
1035 4549 : randomAccess = false;
1036 4549 : lazyEvalOK = true;
1037 : }
1038 :
1039 : /*
1040 : * Initialize fcache (build plans) if first time through; or re-initialize
1041 : * if the cache is stale.
1042 : */
1043 5349 : fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
1044 :
1045 5349 : if (fcache != NULL)
1046 : {
1047 4926 : if (fcache->lxid != MyProc->lxid ||
1048 2463 : !SubTransactionIsActive(fcache->subxid))
1049 : {
1050 : /* It's stale; unlink and delete */
1051 0 : fcinfo->flinfo->fn_extra = NULL;
1052 0 : MemoryContextDelete(fcache->fcontext);
1053 0 : fcache = NULL;
1054 : }
1055 : }
1056 :
1057 5349 : if (fcache == NULL)
1058 : {
1059 2886 : init_sql_fcache(fcinfo->flinfo, PG_GET_COLLATION(), lazyEvalOK);
1060 2885 : fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
1061 : }
1062 :
1063 : /*
1064 : * Switch to context in which the fcache lives. This ensures that our
1065 : * tuplestore etc will have sufficient lifetime. The sub-executor is
1066 : * responsible for deleting per-tuple information. (XXX in the case of a
1067 : * long-lived FmgrInfo, this policy represents more memory leakage, but
1068 : * it's not entirely clear where to keep stuff instead.)
1069 : */
1070 5348 : oldcontext = MemoryContextSwitchTo(fcache->fcontext);
1071 :
1072 : /*
1073 : * Find first unfinished query in function, and note whether it's the
1074 : * first query.
1075 : */
1076 5348 : eslist = fcache->func_state;
1077 5348 : es = NULL;
1078 5348 : is_first = true;
1079 5348 : foreach(eslc, eslist)
1080 : {
1081 5348 : es = (execution_state *) lfirst(eslc);
1082 :
1083 10696 : while (es && es->status == F_EXEC_DONE)
1084 : {
1085 0 : is_first = false;
1086 0 : es = es->next;
1087 : }
1088 :
1089 5348 : if (es)
1090 5348 : break;
1091 : }
1092 :
1093 : /*
1094 : * Convert params to appropriate format if starting a fresh execution. (If
1095 : * continuing execution, we can re-use prior params.)
1096 : */
1097 5348 : if (is_first && es && es->status == F_EXEC_START)
1098 5210 : postquel_sub_params(fcache, fcinfo);
1099 :
1100 : /*
1101 : * Build tuplestore to hold results, if we don't have one already. Note
1102 : * it's in the query-lifespan context.
1103 : */
1104 5348 : if (!fcache->tstore)
1105 2913 : fcache->tstore = tuplestore_begin_heap(randomAccess, false, work_mem);
1106 :
1107 : /*
1108 : * Execute each command in the function one after another until we either
1109 : * run out of commands or get a result row from a lazily-evaluated SELECT.
1110 : *
1111 : * Notes about snapshot management:
1112 : *
1113 : * In a read-only function, we just use the surrounding query's snapshot.
1114 : *
1115 : * In a non-read-only function, we rely on the fact that we'll never
1116 : * suspend execution between queries of the function: the only reason to
1117 : * suspend execution before completion is if we are returning a row from a
1118 : * lazily-evaluated SELECT. So, when first entering this loop, we'll
1119 : * either start a new query (and push a fresh snapshot) or re-establish
1120 : * the active snapshot from the existing query descriptor. If we need to
1121 : * start a new query in a subsequent execution of the loop, either we need
1122 : * a fresh snapshot (and pushed_snapshot is false) or the existing
1123 : * snapshot is on the active stack and we can just bump its command ID.
1124 : */
1125 5348 : pushed_snapshot = false;
1126 13603 : while (es)
1127 : {
1128 : bool completed;
1129 :
1130 5349 : if (es->status == F_EXEC_START)
1131 : {
1132 : /*
1133 : * If not read-only, be sure to advance the command counter for
1134 : * each command, so that all work to date in this transaction is
1135 : * visible. Take a new snapshot if we don't have one yet,
1136 : * otherwise just bump the command ID in the existing snapshot.
1137 : */
1138 5211 : if (!fcache->readonly_func)
1139 : {
1140 3483 : CommandCounterIncrement();
1141 3483 : if (!pushed_snapshot)
1142 : {
1143 3482 : PushActiveSnapshot(GetTransactionSnapshot());
1144 3482 : pushed_snapshot = true;
1145 : }
1146 : else
1147 1 : UpdateActiveSnapshotCommandId();
1148 : }
1149 :
1150 5211 : postquel_start(es, fcache);
1151 : }
1152 138 : else if (!fcache->readonly_func && !pushed_snapshot)
1153 : {
1154 : /* Re-establish active snapshot when re-entering function */
1155 101 : PushActiveSnapshot(es->qd->snapshot);
1156 101 : pushed_snapshot = true;
1157 : }
1158 :
1159 5349 : completed = postquel_getnext(es, fcache);
1160 :
1161 : /*
1162 : * If we ran the command to completion, we can shut it down now. Any
1163 : * row(s) we need to return are safely stashed in the tuplestore, and
1164 : * we want to be sure that, for example, AFTER triggers get fired
1165 : * before we return anything. Also, if the function doesn't return
1166 : * set, we can shut it down anyway because it must be a SELECT and we
1167 : * don't care about fetching any more result rows.
1168 : */
1169 3045 : if (completed || !fcache->returnsSet)
1170 2907 : postquel_end(es);
1171 :
1172 : /*
1173 : * Break from loop if we didn't shut down (implying we got a
1174 : * lazily-evaluated row). Otherwise we'll press on till the whole
1175 : * function is done, relying on the tuplestore to keep hold of the
1176 : * data to eventually be returned. This is necessary since an
1177 : * INSERT/UPDATE/DELETE RETURNING that sets the result might be
1178 : * followed by additional rule-inserted commands, and we want to
1179 : * finish doing all those commands before we return anything.
1180 : */
1181 3045 : if (es->status != F_EXEC_DONE)
1182 138 : break;
1183 :
1184 : /*
1185 : * Advance to next execution_state, which might be in the next list.
1186 : */
1187 2907 : es = es->next;
1188 5814 : while (!es)
1189 : {
1190 2906 : eslc = lnext(eslc);
1191 2906 : if (!eslc)
1192 2906 : break; /* end of function */
1193 :
1194 0 : es = (execution_state *) lfirst(eslc);
1195 :
1196 : /*
1197 : * Flush the current snapshot so that we will take a new one for
1198 : * the new query list. This ensures that new snaps are taken at
1199 : * original-query boundaries, matching the behavior of interactive
1200 : * execution.
1201 : */
1202 0 : if (pushed_snapshot)
1203 : {
1204 0 : PopActiveSnapshot();
1205 0 : pushed_snapshot = false;
1206 : }
1207 : }
1208 : }
1209 :
1210 : /*
1211 : * The tuplestore now contains whatever row(s) we are supposed to return.
1212 : */
1213 3044 : if (fcache->returnsSet)
1214 : {
1215 800 : ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
1216 :
1217 800 : if (es)
1218 : {
1219 : /*
1220 : * If we stopped short of being done, we must have a lazy-eval
1221 : * row.
1222 : */
1223 138 : Assert(es->lazyEval);
1224 : /* Re-use the junkfilter's output slot to fetch back the tuple */
1225 138 : Assert(fcache->junkFilter);
1226 138 : slot = fcache->junkFilter->jf_resultSlot;
1227 138 : if (!tuplestore_gettupleslot(fcache->tstore, true, false, slot))
1228 0 : elog(ERROR, "failed to fetch lazy-eval tuple");
1229 : /* Extract the result as a datum, and copy out from the slot */
1230 138 : result = postquel_get_single_result(slot, fcinfo,
1231 : fcache, oldcontext);
1232 : /* Clear the tuplestore, but keep it for next time */
1233 : /* NB: this might delete the slot's content, but we don't care */
1234 138 : tuplestore_clear(fcache->tstore);
1235 :
1236 : /*
1237 : * Let caller know we're not finished.
1238 : */
1239 138 : rsi->isDone = ExprMultipleResult;
1240 :
1241 : /*
1242 : * Ensure we will get shut down cleanly if the exprcontext is not
1243 : * run to completion.
1244 : */
1245 138 : if (!fcache->shutdown_reg)
1246 : {
1247 104 : RegisterExprContextCallback(rsi->econtext,
1248 : ShutdownSQLFunction,
1249 : PointerGetDatum(fcache));
1250 104 : fcache->shutdown_reg = true;
1251 : }
1252 : }
1253 662 : else if (fcache->lazyEval)
1254 : {
1255 : /*
1256 : * We are done with a lazy evaluation. Clean up.
1257 : */
1258 509 : tuplestore_clear(fcache->tstore);
1259 :
1260 : /*
1261 : * Let caller know we're finished.
1262 : */
1263 509 : rsi->isDone = ExprEndResult;
1264 :
1265 509 : fcinfo->isnull = true;
1266 509 : result = (Datum) 0;
1267 :
1268 : /* Deregister shutdown callback, if we made one */
1269 509 : if (fcache->shutdown_reg)
1270 : {
1271 104 : UnregisterExprContextCallback(rsi->econtext,
1272 : ShutdownSQLFunction,
1273 : PointerGetDatum(fcache));
1274 104 : fcache->shutdown_reg = false;
1275 : }
1276 : }
1277 : else
1278 : {
1279 : /*
1280 : * We are done with a non-lazy evaluation. Return whatever is in
1281 : * the tuplestore. (It is now caller's responsibility to free the
1282 : * tuplestore when done.)
1283 : */
1284 153 : rsi->returnMode = SFRM_Materialize;
1285 153 : rsi->setResult = fcache->tstore;
1286 153 : fcache->tstore = NULL;
1287 : /* must copy desc because execSRF.c will free it */
1288 153 : if (fcache->junkFilter)
1289 153 : rsi->setDesc = CreateTupleDescCopy(fcache->junkFilter->jf_cleanTupType);
1290 :
1291 153 : fcinfo->isnull = true;
1292 153 : result = (Datum) 0;
1293 :
1294 : /* Deregister shutdown callback, if we made one */
1295 153 : if (fcache->shutdown_reg)
1296 : {
1297 0 : UnregisterExprContextCallback(rsi->econtext,
1298 : ShutdownSQLFunction,
1299 : PointerGetDatum(fcache));
1300 0 : fcache->shutdown_reg = false;
1301 : }
1302 : }
1303 : }
1304 : else
1305 : {
1306 : /*
1307 : * Non-set function. If we got a row, return it; else return NULL.
1308 : */
1309 2244 : if (fcache->junkFilter)
1310 : {
1311 : /* Re-use the junkfilter's output slot to fetch back the tuple */
1312 2236 : slot = fcache->junkFilter->jf_resultSlot;
1313 2236 : if (tuplestore_gettupleslot(fcache->tstore, true, false, slot))
1314 1837 : result = postquel_get_single_result(slot, fcinfo,
1315 : fcache, oldcontext);
1316 : else
1317 : {
1318 399 : fcinfo->isnull = true;
1319 399 : result = (Datum) 0;
1320 : }
1321 : }
1322 : else
1323 : {
1324 : /* Should only get here for VOID functions */
1325 8 : Assert(fcache->rettype == VOIDOID);
1326 8 : fcinfo->isnull = true;
1327 8 : result = (Datum) 0;
1328 : }
1329 :
1330 : /* Clear the tuplestore, but keep it for next time */
1331 2244 : tuplestore_clear(fcache->tstore);
1332 : }
1333 :
1334 : /* Pop snapshot if we have pushed one */
1335 3044 : if (pushed_snapshot)
1336 1286 : PopActiveSnapshot();
1337 :
1338 : /*
1339 : * If we've gone through every command in the function, we are done. Reset
1340 : * the execution states to start over again on next call.
1341 : */
1342 3044 : if (es == NULL)
1343 : {
1344 5812 : foreach(eslc, fcache->func_state)
1345 : {
1346 2906 : es = (execution_state *) lfirst(eslc);
1347 8719 : while (es)
1348 : {
1349 2907 : es->status = F_EXEC_START;
1350 2907 : es = es->next;
1351 : }
1352 : }
1353 : }
1354 :
1355 3044 : error_context_stack = sqlerrcontext.previous;
1356 :
1357 3044 : MemoryContextSwitchTo(oldcontext);
1358 :
1359 3044 : return result;
1360 : }
1361 :
1362 :
1363 : /*
1364 : * error context callback to let us supply a call-stack traceback
1365 : */
1366 : static void
1367 2311 : sql_exec_error_callback(void *arg)
1368 : {
1369 2311 : FmgrInfo *flinfo = (FmgrInfo *) arg;
1370 2311 : SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) flinfo->fn_extra;
1371 : int syntaxerrposition;
1372 :
1373 : /*
1374 : * We can do nothing useful if init_sql_fcache() didn't get as far as
1375 : * saving the function name
1376 : */
1377 2311 : if (fcache == NULL || fcache->fname == NULL)
1378 2311 : return;
1379 :
1380 : /*
1381 : * If there is a syntax error position, convert to internal syntax error
1382 : */
1383 2311 : syntaxerrposition = geterrposition();
1384 2311 : if (syntaxerrposition > 0 && fcache->src != NULL)
1385 : {
1386 0 : errposition(0);
1387 0 : internalerrposition(syntaxerrposition);
1388 0 : internalerrquery(fcache->src);
1389 : }
1390 :
1391 : /*
1392 : * Try to determine where in the function we failed. If there is a query
1393 : * with non-null QueryDesc, finger it. (We check this rather than looking
1394 : * for F_EXEC_RUN state, so that errors during ExecutorStart or
1395 : * ExecutorEnd are blamed on the appropriate query; see postquel_start and
1396 : * postquel_end.)
1397 : */
1398 2311 : if (fcache->func_state)
1399 : {
1400 : execution_state *es;
1401 : int query_num;
1402 : ListCell *lc;
1403 :
1404 2310 : es = NULL;
1405 2310 : query_num = 1;
1406 2310 : foreach(lc, fcache->func_state)
1407 : {
1408 2310 : es = (execution_state *) lfirst(lc);
1409 4620 : while (es)
1410 : {
1411 2310 : if (es->qd)
1412 : {
1413 2310 : errcontext("SQL function \"%s\" statement %d",
1414 : fcache->fname, query_num);
1415 2310 : break;
1416 : }
1417 0 : es = es->next;
1418 : }
1419 2310 : if (es)
1420 2310 : break;
1421 0 : query_num++;
1422 : }
1423 2310 : if (es == NULL)
1424 : {
1425 : /*
1426 : * couldn't identify a running query; might be function entry,
1427 : * function exit, or between queries.
1428 : */
1429 0 : errcontext("SQL function \"%s\"", fcache->fname);
1430 : }
1431 : }
1432 : else
1433 : {
1434 : /*
1435 : * Assume we failed during init_sql_fcache(). (It's possible that the
1436 : * function actually has an empty body, but in that case we may as
1437 : * well report all errors as being "during startup".)
1438 : */
1439 1 : errcontext("SQL function \"%s\" during startup", fcache->fname);
1440 : }
1441 : }
1442 :
1443 :
1444 : /*
1445 : * callback function in case a function-returning-set needs to be shut down
1446 : * before it has been run to completion
1447 : */
1448 : static void
1449 0 : ShutdownSQLFunction(Datum arg)
1450 : {
1451 0 : SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) DatumGetPointer(arg);
1452 : execution_state *es;
1453 : ListCell *lc;
1454 :
1455 0 : foreach(lc, fcache->func_state)
1456 : {
1457 0 : es = (execution_state *) lfirst(lc);
1458 0 : while (es)
1459 : {
1460 : /* Shut down anything still running */
1461 0 : if (es->status == F_EXEC_RUN)
1462 : {
1463 : /* Re-establish active snapshot for any called functions */
1464 0 : if (!fcache->readonly_func)
1465 0 : PushActiveSnapshot(es->qd->snapshot);
1466 :
1467 0 : postquel_end(es);
1468 :
1469 0 : if (!fcache->readonly_func)
1470 0 : PopActiveSnapshot();
1471 : }
1472 :
1473 : /* Reset states to START in case we're called again */
1474 0 : es->status = F_EXEC_START;
1475 0 : es = es->next;
1476 : }
1477 : }
1478 :
1479 : /* Release tuplestore if we have one */
1480 0 : if (fcache->tstore)
1481 0 : tuplestore_end(fcache->tstore);
1482 0 : fcache->tstore = NULL;
1483 :
1484 : /* execUtils will deregister the callback... */
1485 0 : fcache->shutdown_reg = false;
1486 0 : }
1487 :
1488 :
1489 : /*
1490 : * check_sql_fn_retval() -- check return value of a list of sql parse trees.
1491 : *
1492 : * The return value of a sql function is the value returned by the last
1493 : * canSetTag query in the function. We do some ad-hoc type checking here
1494 : * to be sure that the user is returning the type he claims. There are
1495 : * also a couple of strange-looking features to assist callers in dealing
1496 : * with allowed special cases, such as binary-compatible result types.
1497 : *
1498 : * For a polymorphic function the passed rettype must be the actual resolved
1499 : * output type of the function; we should never see a polymorphic pseudotype
1500 : * such as ANYELEMENT as rettype. (This means we can't check the type during
1501 : * function definition of a polymorphic function.)
1502 : *
1503 : * This function returns true if the sql function returns the entire tuple
1504 : * result of its final statement, or false if it returns just the first column
1505 : * result of that statement. It throws an error if the final statement doesn't
1506 : * return the right type at all.
1507 : *
1508 : * Note that because we allow "SELECT rowtype_expression", the result can be
1509 : * false even when the declared function return type is a rowtype.
1510 : *
1511 : * If modifyTargetList isn't NULL, the function will modify the final
1512 : * statement's targetlist in two cases:
1513 : * (1) if the tlist returns values that are binary-coercible to the expected
1514 : * type rather than being exactly the expected type. RelabelType nodes will
1515 : * be inserted to make the result types match exactly.
1516 : * (2) if there are dropped columns in the declared result rowtype. NULL
1517 : * output columns will be inserted in the tlist to match them.
1518 : * (Obviously the caller must pass a parsetree that is okay to modify when
1519 : * using this flag.) Note that this flag does not affect whether the tlist is
1520 : * considered to be a legal match to the result type, only how we react to
1521 : * allowed not-exact-match cases. *modifyTargetList will be set true iff
1522 : * we had to make any "dangerous" changes that could modify the semantics of
1523 : * the statement. If it is set true, the caller should not use the modified
1524 : * statement, but for simplicity we apply the changes anyway.
1525 : *
1526 : * If junkFilter isn't NULL, then *junkFilter is set to a JunkFilter defined
1527 : * to convert the function's tuple result to the correct output tuple type.
1528 : * Exception: if the function is defined to return VOID then *junkFilter is
1529 : * set to NULL.
1530 : */
1531 : bool
1532 5538 : check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
1533 : bool *modifyTargetList,
1534 : JunkFilter **junkFilter)
1535 : {
1536 : Query *parse;
1537 : List **tlist_ptr;
1538 : List *tlist;
1539 : int tlistlen;
1540 : char fn_typtype;
1541 : Oid restype;
1542 : ListCell *lc;
1543 :
1544 5538 : AssertArg(!IsPolymorphicType(rettype));
1545 :
1546 5538 : if (modifyTargetList)
1547 2481 : *modifyTargetList = false; /* initialize for no change */
1548 5538 : if (junkFilter)
1549 2886 : *junkFilter = NULL; /* initialize in case of VOID result */
1550 :
1551 : /*
1552 : * Find the last canSetTag query in the list. This isn't necessarily the
1553 : * last parsetree, because rule rewriting can insert queries after what
1554 : * the user wrote.
1555 : */
1556 5538 : parse = NULL;
1557 11077 : foreach(lc, queryTreeList)
1558 : {
1559 5539 : Query *q = lfirst_node(Query, lc);
1560 :
1561 5539 : if (q->canSetTag)
1562 5538 : parse = q;
1563 : }
1564 :
1565 : /*
1566 : * If it's a plain SELECT, it returns whatever the targetlist says.
1567 : * Otherwise, if it's INSERT/UPDATE/DELETE with RETURNING, it returns
1568 : * that. Otherwise, the function return type must be VOID.
1569 : *
1570 : * Note: eventually replace this test with QueryReturnsTuples? We'd need
1571 : * a more general method of determining the output type, though. Also, it
1572 : * seems too dangerous to consider FETCH or EXECUTE as returning a
1573 : * determinable rowtype, since they depend on relatively short-lived
1574 : * entities.
1575 : */
1576 11076 : if (parse &&
1577 5538 : parse->commandType == CMD_SELECT)
1578 : {
1579 5504 : tlist_ptr = &parse->targetList;
1580 5504 : tlist = parse->targetList;
1581 : }
1582 68 : else if (parse &&
1583 47 : (parse->commandType == CMD_INSERT ||
1584 26 : parse->commandType == CMD_UPDATE ||
1585 34 : parse->commandType == CMD_DELETE) &&
1586 21 : parse->returningList)
1587 : {
1588 17 : tlist_ptr = &parse->returningList;
1589 17 : tlist = parse->returningList;
1590 : }
1591 : else
1592 : {
1593 : /* Empty function body, or last statement is a utility command */
1594 17 : if (rettype != VOIDOID)
1595 0 : ereport(ERROR,
1596 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1597 : errmsg("return type mismatch in function declared to return %s",
1598 : format_type_be(rettype)),
1599 : errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE RETURNING.")));
1600 17 : return false;
1601 : }
1602 :
1603 : /*
1604 : * OK, check that the targetlist returns something matching the declared
1605 : * type. (We used to insist that the declared type not be VOID in this
1606 : * case, but that makes it hard to write a void function that exits after
1607 : * calling another void function. Instead, we insist that the tlist
1608 : * return void ... so void is treated as if it were a scalar type below.)
1609 : */
1610 :
1611 : /*
1612 : * Count the non-junk entries in the result targetlist.
1613 : */
1614 5521 : tlistlen = ExecCleanTargetListLength(tlist);
1615 :
1616 5521 : fn_typtype = get_typtype(rettype);
1617 :
1618 5521 : if (fn_typtype == TYPTYPE_BASE ||
1619 234 : fn_typtype == TYPTYPE_DOMAIN ||
1620 233 : fn_typtype == TYPTYPE_ENUM ||
1621 233 : fn_typtype == TYPTYPE_RANGE ||
1622 : rettype == VOIDOID)
1623 5291 : {
1624 : /*
1625 : * For scalar-type returns, the target list must have exactly one
1626 : * non-junk entry, and its type must agree with what the user
1627 : * declared; except we allow binary-compatible types too.
1628 : */
1629 : TargetEntry *tle;
1630 :
1631 5293 : if (tlistlen != 1)
1632 1 : ereport(ERROR,
1633 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1634 : errmsg("return type mismatch in function declared to return %s",
1635 : format_type_be(rettype)),
1636 : errdetail("Final statement must return exactly one column.")));
1637 :
1638 : /* We assume here that non-junk TLEs must come first in tlists */
1639 5292 : tle = (TargetEntry *) linitial(tlist);
1640 5292 : Assert(!tle->resjunk);
1641 :
1642 5292 : restype = exprType((Node *) tle->expr);
1643 5292 : if (!IsBinaryCoercible(restype, rettype))
1644 1 : ereport(ERROR,
1645 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1646 : errmsg("return type mismatch in function declared to return %s",
1647 : format_type_be(rettype)),
1648 : errdetail("Actual return type is %s.",
1649 : format_type_be(restype))));
1650 5291 : if (modifyTargetList && restype != rettype)
1651 : {
1652 1 : tle->expr = (Expr *) makeRelabelType(tle->expr,
1653 : rettype,
1654 : -1,
1655 : get_typcollation(rettype),
1656 : COERCE_IMPLICIT_CAST);
1657 : /* Relabel is dangerous if TLE is a sort/group or setop column */
1658 1 : if (tle->ressortgroupref != 0 || parse->setOperations)
1659 1 : *modifyTargetList = true;
1660 : }
1661 :
1662 : /* Set up junk filter if needed */
1663 5291 : if (junkFilter)
1664 2689 : *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
1665 : }
1666 228 : else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
1667 : {
1668 : /* Returns a rowtype */
1669 : TupleDesc tupdesc;
1670 : int tupnatts; /* physical number of columns in tuple */
1671 : int tuplogcols; /* # of nondeleted columns in tuple */
1672 : int colindex; /* physical column index */
1673 : List *newtlist; /* new non-junk tlist entries */
1674 : List *junkattrs; /* new junk tlist entries */
1675 :
1676 : /*
1677 : * If the target list is of length 1, and the type of the varnode in
1678 : * the target list matches the declared return type, this is okay.
1679 : * This can happen, for example, where the body of the function is
1680 : * 'SELECT func2()', where func2 has the same composite return type as
1681 : * the function that's calling it.
1682 : *
1683 : * XXX Note that if rettype is RECORD, the IsBinaryCoercible check
1684 : * will succeed for any composite restype. For the moment we rely on
1685 : * runtime type checking to catch any discrepancy, but it'd be nice to
1686 : * do better at parse time.
1687 : */
1688 228 : if (tlistlen == 1)
1689 : {
1690 12 : TargetEntry *tle = (TargetEntry *) linitial(tlist);
1691 :
1692 12 : Assert(!tle->resjunk);
1693 12 : restype = exprType((Node *) tle->expr);
1694 12 : if (IsBinaryCoercible(restype, rettype))
1695 : {
1696 6 : if (modifyTargetList && restype != rettype)
1697 : {
1698 0 : tle->expr = (Expr *) makeRelabelType(tle->expr,
1699 : rettype,
1700 : -1,
1701 : get_typcollation(rettype),
1702 : COERCE_IMPLICIT_CAST);
1703 : /* Relabel is dangerous if sort/group or setop column */
1704 0 : if (tle->ressortgroupref != 0 || parse->setOperations)
1705 0 : *modifyTargetList = true;
1706 : }
1707 : /* Set up junk filter if needed */
1708 6 : if (junkFilter)
1709 3 : *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
1710 6 : return false; /* NOT returning whole tuple */
1711 : }
1712 : }
1713 :
1714 : /* Is the rowtype fixed, or determined only at runtime? */
1715 222 : if (get_func_result_type(func_id, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1716 : {
1717 : /*
1718 : * Assume we are returning the whole tuple. Crosschecking against
1719 : * what the caller expects will happen at runtime.
1720 : */
1721 31 : if (junkFilter)
1722 27 : *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
1723 31 : return true;
1724 : }
1725 191 : Assert(tupdesc);
1726 :
1727 : /*
1728 : * Verify that the targetlist matches the return tuple type. We scan
1729 : * the non-deleted attributes to ensure that they match the datatypes
1730 : * of the non-resjunk columns. For deleted attributes, insert NULL
1731 : * result columns if the caller asked for that.
1732 : */
1733 191 : tupnatts = tupdesc->natts;
1734 191 : tuplogcols = 0; /* we'll count nondeleted cols as we go */
1735 191 : colindex = 0;
1736 191 : newtlist = NIL; /* these are only used if modifyTargetList */
1737 191 : junkattrs = NIL;
1738 :
1739 733 : foreach(lc, tlist)
1740 : {
1741 542 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
1742 : Form_pg_attribute attr;
1743 : Oid tletype;
1744 : Oid atttype;
1745 :
1746 542 : if (tle->resjunk)
1747 : {
1748 0 : if (modifyTargetList)
1749 0 : junkattrs = lappend(junkattrs, tle);
1750 0 : continue;
1751 : }
1752 :
1753 : do
1754 : {
1755 556 : colindex++;
1756 556 : if (colindex > tupnatts)
1757 0 : ereport(ERROR,
1758 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1759 : errmsg("return type mismatch in function declared to return %s",
1760 : format_type_be(rettype)),
1761 : errdetail("Final statement returns too many columns.")));
1762 556 : attr = TupleDescAttr(tupdesc, colindex - 1);
1763 556 : if (attr->attisdropped && modifyTargetList)
1764 : {
1765 : Expr *null_expr;
1766 :
1767 : /* The type of the null we insert isn't important */
1768 1 : null_expr = (Expr *) makeConst(INT4OID,
1769 : -1,
1770 : InvalidOid,
1771 : sizeof(int32),
1772 : (Datum) 0,
1773 : true, /* isnull */
1774 : true /* byval */ );
1775 1 : newtlist = lappend(newtlist,
1776 1 : makeTargetEntry(null_expr,
1777 : colindex,
1778 : NULL,
1779 : false));
1780 : /* NULL insertion is dangerous in a setop */
1781 1 : if (parse->setOperations)
1782 0 : *modifyTargetList = true;
1783 : }
1784 556 : } while (attr->attisdropped);
1785 542 : tuplogcols++;
1786 :
1787 542 : tletype = exprType((Node *) tle->expr);
1788 542 : atttype = attr->atttypid;
1789 542 : if (!IsBinaryCoercible(tletype, atttype))
1790 0 : ereport(ERROR,
1791 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1792 : errmsg("return type mismatch in function declared to return %s",
1793 : format_type_be(rettype)),
1794 : errdetail("Final statement returns %s instead of %s at column %d.",
1795 : format_type_be(tletype),
1796 : format_type_be(atttype),
1797 : tuplogcols)));
1798 542 : if (modifyTargetList)
1799 : {
1800 7 : if (tletype != atttype)
1801 : {
1802 0 : tle->expr = (Expr *) makeRelabelType(tle->expr,
1803 : atttype,
1804 : -1,
1805 : get_typcollation(atttype),
1806 : COERCE_IMPLICIT_CAST);
1807 : /* Relabel is dangerous if sort/group or setop column */
1808 0 : if (tle->ressortgroupref != 0 || parse->setOperations)
1809 0 : *modifyTargetList = true;
1810 : }
1811 7 : tle->resno = colindex;
1812 7 : newtlist = lappend(newtlist, tle);
1813 : }
1814 : }
1815 :
1816 : /* remaining columns in tupdesc had better all be dropped */
1817 191 : for (colindex++; colindex <= tupnatts; colindex++)
1818 : {
1819 0 : if (!TupleDescAttr(tupdesc, colindex - 1)->attisdropped)
1820 0 : ereport(ERROR,
1821 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1822 : errmsg("return type mismatch in function declared to return %s",
1823 : format_type_be(rettype)),
1824 : errdetail("Final statement returns too few columns.")));
1825 0 : if (modifyTargetList)
1826 : {
1827 : Expr *null_expr;
1828 :
1829 : /* The type of the null we insert isn't important */
1830 0 : null_expr = (Expr *) makeConst(INT4OID,
1831 : -1,
1832 : InvalidOid,
1833 : sizeof(int32),
1834 : (Datum) 0,
1835 : true, /* isnull */
1836 : true /* byval */ );
1837 0 : newtlist = lappend(newtlist,
1838 0 : makeTargetEntry(null_expr,
1839 : colindex,
1840 : NULL,
1841 : false));
1842 : /* NULL insertion is dangerous in a setop */
1843 0 : if (parse->setOperations)
1844 0 : *modifyTargetList = true;
1845 : }
1846 : }
1847 :
1848 191 : if (modifyTargetList)
1849 : {
1850 : /* ensure resjunk columns are numbered correctly */
1851 3 : foreach(lc, junkattrs)
1852 : {
1853 0 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
1854 :
1855 0 : tle->resno = colindex++;
1856 : }
1857 : /* replace the tlist with the modified one */
1858 3 : *tlist_ptr = list_concat(newtlist, junkattrs);
1859 : }
1860 :
1861 : /* Set up junk filter if needed */
1862 191 : if (junkFilter)
1863 156 : *junkFilter = ExecInitJunkFilterConversion(tlist,
1864 : CreateTupleDescCopy(tupdesc),
1865 : NULL);
1866 :
1867 : /* Report that we are returning entire tuple result */
1868 191 : return true;
1869 : }
1870 : else
1871 0 : ereport(ERROR,
1872 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1873 : errmsg("return type %s is not supported for SQL functions",
1874 : format_type_be(rettype))));
1875 :
1876 5291 : return false;
1877 : }
1878 :
1879 :
1880 : /*
1881 : * CreateSQLFunctionDestReceiver -- create a suitable DestReceiver object
1882 : */
1883 : DestReceiver *
1884 5199 : CreateSQLFunctionDestReceiver(void)
1885 : {
1886 5199 : DR_sqlfunction *self = (DR_sqlfunction *) palloc0(sizeof(DR_sqlfunction));
1887 :
1888 5199 : self->pub.receiveSlot = sqlfunction_receive;
1889 5199 : self->pub.rStartup = sqlfunction_startup;
1890 5199 : self->pub.rShutdown = sqlfunction_shutdown;
1891 5199 : self->pub.rDestroy = sqlfunction_destroy;
1892 5199 : self->pub.mydest = DestSQLFunction;
1893 :
1894 : /* private fields will be set by postquel_start */
1895 :
1896 5199 : return (DestReceiver *) self;
1897 : }
1898 :
1899 : /*
1900 : * sqlfunction_startup --- executor startup
1901 : */
1902 : static void
1903 5337 : sqlfunction_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
1904 : {
1905 : /* no-op */
1906 5337 : }
1907 :
1908 : /*
1909 : * sqlfunction_receive --- receive one tuple
1910 : */
1911 : static bool
1912 22380 : sqlfunction_receive(TupleTableSlot *slot, DestReceiver *self)
1913 : {
1914 22380 : DR_sqlfunction *myState = (DR_sqlfunction *) self;
1915 :
1916 : /* Filter tuple as needed */
1917 22380 : slot = ExecFilterJunk(myState->filter, slot);
1918 :
1919 : /* Store the filtered tuple into the tuplestore */
1920 22380 : tuplestore_puttupleslot(myState->tstore, slot);
1921 :
1922 22380 : return true;
1923 : }
1924 :
1925 : /*
1926 : * sqlfunction_shutdown --- executor end
1927 : */
1928 : static void
1929 3036 : sqlfunction_shutdown(DestReceiver *self)
1930 : {
1931 : /* no-op */
1932 3036 : }
1933 :
1934 : /*
1935 : * sqlfunction_destroy --- release DestReceiver object
1936 : */
1937 : static void
1938 2898 : sqlfunction_destroy(DestReceiver *self)
1939 : {
1940 2898 : pfree(self);
1941 2898 : }
|