]> granicus.if.org Git - postgresql/blob - src/backend/executor/functions.c
Improve snapshot manager by keeping explicit track of snapshots.
[postgresql] / src / backend / executor / functions.c
1 /*-------------------------------------------------------------------------
2  *
3  * functions.c
4  *        Execution of SQL-language functions
5  *
6  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.125 2008/05/12 20:02:00 alvherre Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/xact.h"
18 #include "catalog/pg_proc.h"
19 #include "catalog/pg_type.h"
20 #include "commands/trigger.h"
21 #include "executor/functions.h"
22 #include "funcapi.h"
23 #include "nodes/makefuncs.h"
24 #include "parser/parse_coerce.h"
25 #include "parser/parse_expr.h"
26 #include "tcop/tcopprot.h"
27 #include "tcop/utility.h"
28 #include "utils/builtins.h"
29 #include "utils/datum.h"
30 #include "utils/lsyscache.h"
31 #include "utils/snapmgr.h"
32 #include "utils/syscache.h"
33 #include "utils/typcache.h"
34
35
36 /*
37  * We have an execution_state record for each query in a function.      Each
38  * record contains a plantree for its query.  If the query is currently in
39  * F_EXEC_RUN state then there's a QueryDesc too.
40  */
41 typedef enum
42 {
43         F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE
44 } ExecStatus;
45
46 typedef struct local_es
47 {
48         struct local_es *next;
49         ExecStatus      status;
50         Node       *stmt;                       /* PlannedStmt or utility statement */
51         QueryDesc  *qd;                         /* null unless status == RUN */
52 } execution_state;
53
54 #define LAST_POSTQUEL_COMMAND(es) ((es)->next == NULL)
55
56
57 /*
58  * An SQLFunctionCache record is built during the first call,
59  * and linked to from the fn_extra field of the FmgrInfo struct.
60  */
61 typedef struct
62 {
63         char       *src;                        /* function body text (for error msgs) */
64
65         Oid                *argtypes;           /* resolved types of arguments */
66         Oid                     rettype;                /* actual return type */
67         int16           typlen;                 /* length of the return type */
68         bool            typbyval;               /* true if return type is pass by value */
69         bool            returnsTuple;   /* true if returning whole tuple result */
70         bool            shutdown_reg;   /* true if registered shutdown callback */
71         bool            readonly_func;  /* true to run in "read only" mode */
72
73         ParamListInfo paramLI;          /* Param list representing current args */
74
75         JunkFilter *junkFilter;         /* used only if returnsTuple */
76
77         /* head of linked list of execution_state records */
78         execution_state *func_state;
79 } SQLFunctionCache;
80
81 typedef SQLFunctionCache *SQLFunctionCachePtr;
82
83
84 /* non-export function prototypes */
85 static execution_state *init_execution_state(List *queryTree_list,
86                                          bool readonly_func);
87 static void init_sql_fcache(FmgrInfo *finfo);
88 static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
89 static TupleTableSlot *postquel_getnext(execution_state *es,
90                                  SQLFunctionCachePtr fcache);
91 static void postquel_end(execution_state *es);
92 static void postquel_sub_params(SQLFunctionCachePtr fcache,
93                                         FunctionCallInfo fcinfo);
94 static Datum postquel_execute(execution_state *es,
95                                  FunctionCallInfo fcinfo,
96                                  SQLFunctionCachePtr fcache,
97                                  MemoryContext resultcontext);
98 static void sql_exec_error_callback(void *arg);
99 static void ShutdownSQLFunction(Datum arg);
100
101
102 static execution_state *
103 init_execution_state(List *queryTree_list, bool readonly_func)
104 {
105         execution_state *firstes = NULL;
106         execution_state *preves = NULL;
107         ListCell   *qtl_item;
108
109         foreach(qtl_item, queryTree_list)
110         {
111                 Query      *queryTree = lfirst(qtl_item);
112                 Node       *stmt;
113                 execution_state *newes;
114
115                 Assert(IsA(queryTree, Query));
116
117                 if (queryTree->commandType == CMD_UTILITY)
118                         stmt = queryTree->utilityStmt;
119                 else
120                         stmt = (Node *) pg_plan_query(queryTree, 0, NULL);
121
122                 /* Precheck all commands for validity in a function */
123                 if (IsA(stmt, TransactionStmt))
124                         ereport(ERROR,
125                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
126                         /* translator: %s is a SQL statement name */
127                                          errmsg("%s is not allowed in a SQL function",
128                                                         CreateCommandTag(stmt))));
129
130                 if (readonly_func && !CommandIsReadOnly(stmt))
131                         ereport(ERROR,
132                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
133                         /* translator: %s is a SQL statement name */
134                                          errmsg("%s is not allowed in a non-volatile function",
135                                                         CreateCommandTag(stmt))));
136
137                 newes = (execution_state *) palloc(sizeof(execution_state));
138                 if (preves)
139                         preves->next = newes;
140                 else
141                         firstes = newes;
142
143                 newes->next = NULL;
144                 newes->status = F_EXEC_START;
145                 newes->stmt = stmt;
146                 newes->qd = NULL;
147
148                 preves = newes;
149         }
150
151         return firstes;
152 }
153
154
155 static void
156 init_sql_fcache(FmgrInfo *finfo)
157 {
158         Oid                     foid = finfo->fn_oid;
159         Oid                     rettype;
160         HeapTuple       procedureTuple;
161         Form_pg_proc procedureStruct;
162         SQLFunctionCachePtr fcache;
163         Oid                *argOidVect;
164         int                     nargs;
165         List       *queryTree_list;
166         Datum           tmp;
167         bool            isNull;
168
169         fcache = (SQLFunctionCachePtr) palloc0(sizeof(SQLFunctionCache));
170
171         /*
172          * get the procedure tuple corresponding to the given function Oid
173          */
174         procedureTuple = SearchSysCache(PROCOID,
175                                                                         ObjectIdGetDatum(foid),
176                                                                         0, 0, 0);
177         if (!HeapTupleIsValid(procedureTuple))
178                 elog(ERROR, "cache lookup failed for function %u", foid);
179         procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
180
181         /*
182          * get the result type from the procedure tuple, and check for polymorphic
183          * result type; if so, find out the actual result type.
184          */
185         rettype = procedureStruct->prorettype;
186
187         if (IsPolymorphicType(rettype))
188         {
189                 rettype = get_fn_expr_rettype(finfo);
190                 if (rettype == InvalidOid)              /* this probably should not happen */
191                         ereport(ERROR,
192                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
193                                          errmsg("could not determine actual result type for function declared to return type %s",
194                                                         format_type_be(procedureStruct->prorettype))));
195         }
196
197         fcache->rettype = rettype;
198
199         /* Fetch the typlen and byval info for the result type */
200         get_typlenbyval(rettype, &fcache->typlen, &fcache->typbyval);
201
202         /* Remember if function is STABLE/IMMUTABLE */
203         fcache->readonly_func =
204                 (procedureStruct->provolatile != PROVOLATILE_VOLATILE);
205
206         /*
207          * We need the actual argument types to pass to the parser.
208          */
209         nargs = procedureStruct->pronargs;
210         if (nargs > 0)
211         {
212                 int                     argnum;
213
214                 argOidVect = (Oid *) palloc(nargs * sizeof(Oid));
215                 memcpy(argOidVect,
216                            procedureStruct->proargtypes.values,
217                            nargs * sizeof(Oid));
218                 /* Resolve any polymorphic argument types */
219                 for (argnum = 0; argnum < nargs; argnum++)
220                 {
221                         Oid                     argtype = argOidVect[argnum];
222
223                         if (IsPolymorphicType(argtype))
224                         {
225                                 argtype = get_fn_expr_argtype(finfo, argnum);
226                                 if (argtype == InvalidOid)
227                                         ereport(ERROR,
228                                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
229                                                          errmsg("could not determine actual type of argument declared %s",
230                                                                         format_type_be(argOidVect[argnum]))));
231                                 argOidVect[argnum] = argtype;
232                         }
233                 }
234         }
235         else
236                 argOidVect = NULL;
237         fcache->argtypes = argOidVect;
238
239         /*
240          * And of course we need the function body text.
241          */
242         tmp = SysCacheGetAttr(PROCOID,
243                                                   procedureTuple,
244                                                   Anum_pg_proc_prosrc,
245                                                   &isNull);
246         if (isNull)
247                 elog(ERROR, "null prosrc for function %u", foid);
248         fcache->src = TextDatumGetCString(tmp);
249
250         /*
251          * Parse and rewrite the queries in the function text.
252          */
253         queryTree_list = pg_parse_and_rewrite(fcache->src, argOidVect, nargs);
254
255         /*
256          * Check that the function returns the type it claims to.  Although in
257          * simple cases this was already done when the function was defined, we
258          * have to recheck because database objects used in the function's queries
259          * might have changed type.  We'd have to do it anyway if the function had
260          * any polymorphic arguments.
261          *
262          * Note: we set fcache->returnsTuple according to whether we are returning
263          * the whole tuple result or just a single column.      In the latter case we
264          * clear returnsTuple because we need not act different from the scalar
265          * result case, even if it's a rowtype column.
266          *
267          * In the returnsTuple case, check_sql_fn_retval will also construct a
268          * JunkFilter we can use to coerce the returned rowtype to the desired
269          * form.
270          */
271         fcache->returnsTuple = check_sql_fn_retval(foid,
272                                                                                            rettype,
273                                                                                            queryTree_list,
274                                                                                            false,
275                                                                                            &fcache->junkFilter);
276
277         /* Finally, plan the queries */
278         fcache->func_state = init_execution_state(queryTree_list,
279                                                                                           fcache->readonly_func);
280
281         ReleaseSysCache(procedureTuple);
282
283         finfo->fn_extra = (void *) fcache;
284 }
285
286
287 static void
288 postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
289 {
290         Snapshot        snapshot;
291
292         Assert(es->qd == NULL);
293
294         /*
295          * In a read-only function, use the surrounding query's snapshot;
296          * otherwise take a new snapshot for each query.  The snapshot should
297          * include a fresh command ID so that all work to date in this transaction
298          * is visible.
299          */
300         if (fcache->readonly_func)
301                 snapshot = GetActiveSnapshot();
302         else
303         {
304                 CommandCounterIncrement();
305                 snapshot = GetTransactionSnapshot();
306         }
307
308         if (IsA(es->stmt, PlannedStmt))
309                 es->qd = CreateQueryDesc((PlannedStmt *) es->stmt,
310                                                                  snapshot, InvalidSnapshot,
311                                                                  None_Receiver,
312                                                                  fcache->paramLI, false);
313         else
314                 es->qd = CreateUtilityQueryDesc(es->stmt,
315                                                                                 snapshot,
316                                                                                 None_Receiver,
317                                                                                 fcache->paramLI);
318
319         /* We assume we don't need to set up ActiveSnapshot for ExecutorStart */
320
321         /* Utility commands don't need Executor. */
322         if (es->qd->utilitystmt == NULL)
323         {
324                 /*
325                  * Only set up to collect queued triggers if it's not a SELECT. This
326                  * isn't just an optimization, but is necessary in case a SELECT
327                  * returns multiple rows to caller --- we mustn't exit from the
328                  * function execution with a stacked AfterTrigger level still active.
329                  */
330                 if (es->qd->operation != CMD_SELECT)
331                         AfterTriggerBeginQuery();
332                 ExecutorStart(es->qd, 0);
333         }
334
335         es->status = F_EXEC_RUN;
336 }
337
338 static TupleTableSlot *
339 postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
340 {
341         TupleTableSlot *result;
342         long            count;
343
344         /* Make our snapshot the active one for any called functions */
345         PushActiveSnapshot(es->qd->snapshot);
346
347         if (es->qd->utilitystmt)
348         {
349                 /* ProcessUtility needs the PlannedStmt for DECLARE CURSOR */
350                 ProcessUtility((es->qd->plannedstmt ?
351                                                 (Node *) es->qd->plannedstmt :
352                                                 es->qd->utilitystmt),
353                                            fcache->src,
354                                            es->qd->params,
355                                            false,               /* not top level */
356                                            es->qd->dest,
357                                            NULL);
358                 result = NULL;
359         }
360         else
361         {
362                 /*
363                  * If it's the function's last command, and it's a SELECT, fetch
364                  * one row at a time so we can return the results. Otherwise just
365                  * run it to completion.  (If we run to completion then
366                  * ExecutorRun is guaranteed to return NULL.)
367                  */
368                 if (LAST_POSTQUEL_COMMAND(es) &&
369                         es->qd->operation == CMD_SELECT &&
370                         es->qd->plannedstmt->utilityStmt == NULL &&
371                         es->qd->plannedstmt->intoClause == NULL)
372                         count = 1L;
373                 else
374                         count = 0L;
375
376                 result = ExecutorRun(es->qd, ForwardScanDirection, count);
377         }
378
379         PopActiveSnapshot();
380
381         return result;
382 }
383
384 static void
385 postquel_end(execution_state *es)
386 {
387         /* mark status done to ensure we don't do ExecutorEnd twice */
388         es->status = F_EXEC_DONE;
389
390         /* Utility commands don't need Executor. */
391         if (es->qd->utilitystmt == NULL)
392         {
393                 /* Make our snapshot the active one for any called functions */
394                 PushActiveSnapshot(es->qd->snapshot);
395
396                 if (es->qd->operation != CMD_SELECT)
397                         AfterTriggerEndQuery(es->qd->estate);
398                 ExecutorEnd(es->qd);
399
400                 PopActiveSnapshot();
401         }
402
403         FreeQueryDesc(es->qd);
404         es->qd = NULL;
405 }
406
407 /* Build ParamListInfo array representing current arguments */
408 static void
409 postquel_sub_params(SQLFunctionCachePtr fcache,
410                                         FunctionCallInfo fcinfo)
411 {
412         ParamListInfo paramLI;
413         int                     nargs = fcinfo->nargs;
414
415         if (nargs > 0)
416         {
417                 int                     i;
418
419                 /* sizeof(ParamListInfoData) includes the first array element */
420                 paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
421                                                                            (nargs - 1) *sizeof(ParamExternData));
422                 paramLI->numParams = nargs;
423
424                 for (i = 0; i < nargs; i++)
425                 {
426                         ParamExternData *prm = &paramLI->params[i];
427
428                         prm->value = fcinfo->arg[i];
429                         prm->isnull = fcinfo->argnull[i];
430                         prm->pflags = 0;
431                         prm->ptype = fcache->argtypes[i];
432                 }
433         }
434         else
435                 paramLI = NULL;
436
437         if (fcache->paramLI)
438                 pfree(fcache->paramLI);
439
440         fcache->paramLI = paramLI;
441 }
442
443 static Datum
444 postquel_execute(execution_state *es,
445                                  FunctionCallInfo fcinfo,
446                                  SQLFunctionCachePtr fcache,
447                                  MemoryContext resultcontext)
448 {
449         TupleTableSlot *slot;
450         Datum           value;
451         MemoryContext oldcontext;
452
453         if (es->status == F_EXEC_START)
454                 postquel_start(es, fcache);
455
456         slot = postquel_getnext(es, fcache);
457
458         if (TupIsNull(slot))
459         {
460                 /*
461                  * We fall out here for all cases except where we have obtained a row
462                  * from a function's final SELECT.
463                  */
464                 postquel_end(es);
465                 fcinfo->isnull = true;
466                 return (Datum) NULL;
467         }
468
469         /*
470          * If we got a row from a command within the function it has to be the
471          * final command.  All others shouldn't be returning anything.
472          */
473         Assert(LAST_POSTQUEL_COMMAND(es));
474
475         /*
476          * Set up to return the function value.  For pass-by-reference datatypes,
477          * be sure to allocate the result in resultcontext, not the current memory
478          * context (which has query lifespan).
479          */
480         oldcontext = MemoryContextSwitchTo(resultcontext);
481
482         if (fcache->returnsTuple)
483         {
484                 /*
485                  * We are returning the whole tuple, so filter it and apply the proper
486                  * labeling to make it a valid Datum.  There are several reasons why
487                  * we do this:
488                  *
489                  * 1. To copy the tuple out of the child execution context and into
490                  * the desired result context.
491                  *
492                  * 2. To remove any junk attributes present in the raw subselect
493                  * result. (This is probably not absolutely necessary, but it seems
494                  * like good policy.)
495                  *
496                  * 3. To insert dummy null columns if the declared result type has any
497                  * attisdropped columns.
498                  */
499                 HeapTuple       newtup;
500                 HeapTupleHeader dtup;
501                 uint32          t_len;
502                 Oid                     dtuptype;
503                 int32           dtuptypmod;
504
505                 newtup = ExecRemoveJunk(fcache->junkFilter, slot);
506
507                 /*
508                  * Compress out the HeapTuple header data.      We assume that
509                  * heap_form_tuple made the tuple with header and body in one palloc'd
510                  * chunk.  We want to return a pointer to the chunk start so that it
511                  * will work if someone tries to free it.
512                  */
513                 t_len = newtup->t_len;
514                 dtup = (HeapTupleHeader) newtup;
515                 memmove((char *) dtup, (char *) newtup->t_data, t_len);
516
517                 /*
518                  * Use the declared return type if it's not RECORD; else take the type
519                  * from the computed result, making sure a typmod has been assigned.
520                  */
521                 if (fcache->rettype != RECORDOID)
522                 {
523                         /* function has a named composite return type */
524                         dtuptype = fcache->rettype;
525                         dtuptypmod = -1;
526                 }
527                 else
528                 {
529                         /* function is declared to return RECORD */
530                         TupleDesc       tupDesc = fcache->junkFilter->jf_cleanTupType;
531
532                         if (tupDesc->tdtypeid == RECORDOID &&
533                                 tupDesc->tdtypmod < 0)
534                                 assign_record_type_typmod(tupDesc);
535                         dtuptype = tupDesc->tdtypeid;
536                         dtuptypmod = tupDesc->tdtypmod;
537                 }
538
539                 HeapTupleHeaderSetDatumLength(dtup, t_len);
540                 HeapTupleHeaderSetTypeId(dtup, dtuptype);
541                 HeapTupleHeaderSetTypMod(dtup, dtuptypmod);
542
543                 value = PointerGetDatum(dtup);
544                 fcinfo->isnull = false;
545         }
546         else
547         {
548                 /*
549                  * Returning a scalar, which we have to extract from the first column
550                  * of the SELECT result, and then copy into result context if needed.
551                  */
552                 value = slot_getattr(slot, 1, &(fcinfo->isnull));
553
554                 if (!fcinfo->isnull)
555                         value = datumCopy(value, fcache->typbyval, fcache->typlen);
556         }
557
558         MemoryContextSwitchTo(oldcontext);
559
560         /*
561          * If this is a single valued function we have to end the function
562          * execution now.
563          */
564         if (!fcinfo->flinfo->fn_retset)
565                 postquel_end(es);
566
567         return value;
568 }
569
570 Datum
571 fmgr_sql(PG_FUNCTION_ARGS)
572 {
573         MemoryContext oldcontext;
574         SQLFunctionCachePtr fcache;
575         ErrorContextCallback sqlerrcontext;
576         execution_state *es;
577         Datum           result = 0;
578
579         /*
580          * Switch to context in which the fcache lives.  This ensures that
581          * parsetrees, plans, etc, will have sufficient lifetime.  The
582          * sub-executor is responsible for deleting per-tuple information.
583          */
584         oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
585
586         /*
587          * Setup error traceback support for ereport()
588          */
589         sqlerrcontext.callback = sql_exec_error_callback;
590         sqlerrcontext.arg = fcinfo->flinfo;
591         sqlerrcontext.previous = error_context_stack;
592         error_context_stack = &sqlerrcontext;
593
594         /*
595          * Initialize fcache (build plans) if first time through.
596          */
597         fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
598         if (fcache == NULL)
599         {
600                 init_sql_fcache(fcinfo->flinfo);
601                 fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
602         }
603         es = fcache->func_state;
604
605         /*
606          * Convert params to appropriate format if starting a fresh execution. (If
607          * continuing execution, we can re-use prior params.)
608          */
609         if (es && es->status == F_EXEC_START)
610                 postquel_sub_params(fcache, fcinfo);
611
612         /*
613          * Find first unfinished query in function.
614          */
615         while (es && es->status == F_EXEC_DONE)
616                 es = es->next;
617
618         /*
619          * Execute each command in the function one after another until we're
620          * executing the final command and get a result or we run out of commands.
621          */
622         while (es)
623         {
624                 result = postquel_execute(es, fcinfo, fcache, oldcontext);
625                 if (es->status != F_EXEC_DONE)
626                         break;
627                 es = es->next;
628         }
629
630         /*
631          * If we've gone through every command in this function, we are done.
632          */
633         if (es == NULL)
634         {
635                 /*
636                  * Reset the execution states to start over again on next call.
637                  */
638                 es = fcache->func_state;
639                 while (es)
640                 {
641                         es->status = F_EXEC_START;
642                         es = es->next;
643                 }
644
645                 /*
646                  * Let caller know we're finished.
647                  */
648                 if (fcinfo->flinfo->fn_retset)
649                 {
650                         ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
651
652                         if (rsi && IsA(rsi, ReturnSetInfo))
653                                 rsi->isDone = ExprEndResult;
654                         else
655                                 ereport(ERROR,
656                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
657                                                  errmsg("set-valued function called in context that cannot accept a set")));
658                         fcinfo->isnull = true;
659                         result = (Datum) 0;
660
661                         /* Deregister shutdown callback, if we made one */
662                         if (fcache->shutdown_reg)
663                         {
664                                 UnregisterExprContextCallback(rsi->econtext,
665                                                                                           ShutdownSQLFunction,
666                                                                                           PointerGetDatum(fcache));
667                                 fcache->shutdown_reg = false;
668                         }
669                 }
670
671                 error_context_stack = sqlerrcontext.previous;
672
673                 MemoryContextSwitchTo(oldcontext);
674
675                 return result;
676         }
677
678         /*
679          * If we got a result from a command within the function it has to be the
680          * final command.  All others shouldn't be returning anything.
681          */
682         Assert(LAST_POSTQUEL_COMMAND(es));
683
684         /*
685          * Let caller know we're not finished.
686          */
687         if (fcinfo->flinfo->fn_retset)
688         {
689                 ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
690
691                 if (rsi && IsA(rsi, ReturnSetInfo))
692                         rsi->isDone = ExprMultipleResult;
693                 else
694                         ereport(ERROR,
695                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
696                                          errmsg("set-valued function called in context that cannot accept a set")));
697
698                 /*
699                  * Ensure we will get shut down cleanly if the exprcontext is not run
700                  * to completion.
701                  */
702                 if (!fcache->shutdown_reg)
703                 {
704                         RegisterExprContextCallback(rsi->econtext,
705                                                                                 ShutdownSQLFunction,
706                                                                                 PointerGetDatum(fcache));
707                         fcache->shutdown_reg = true;
708                 }
709         }
710
711         error_context_stack = sqlerrcontext.previous;
712
713         MemoryContextSwitchTo(oldcontext);
714
715         return result;
716 }
717
718
719 /*
720  * error context callback to let us supply a call-stack traceback
721  */
722 static void
723 sql_exec_error_callback(void *arg)
724 {
725         FmgrInfo   *flinfo = (FmgrInfo *) arg;
726         SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) flinfo->fn_extra;
727         HeapTuple       func_tuple;
728         Form_pg_proc functup;
729         char       *fn_name;
730         int                     syntaxerrposition;
731
732         /* Need access to function's pg_proc tuple */
733         func_tuple = SearchSysCache(PROCOID,
734                                                                 ObjectIdGetDatum(flinfo->fn_oid),
735                                                                 0, 0, 0);
736         if (!HeapTupleIsValid(func_tuple))
737                 return;                                 /* shouldn't happen */
738         functup = (Form_pg_proc) GETSTRUCT(func_tuple);
739         fn_name = NameStr(functup->proname);
740
741         /*
742          * If there is a syntax error position, convert to internal syntax error
743          */
744         syntaxerrposition = geterrposition();
745         if (syntaxerrposition > 0)
746         {
747                 bool            isnull;
748                 Datum           tmp;
749                 char       *prosrc;
750
751                 tmp = SysCacheGetAttr(PROCOID, func_tuple, Anum_pg_proc_prosrc,
752                                                           &isnull);
753                 if (isnull)
754                         elog(ERROR, "null prosrc");
755                 prosrc = TextDatumGetCString(tmp);
756                 errposition(0);
757                 internalerrposition(syntaxerrposition);
758                 internalerrquery(prosrc);
759                 pfree(prosrc);
760         }
761
762         /*
763          * Try to determine where in the function we failed.  If there is a query
764          * with non-null QueryDesc, finger it.  (We check this rather than looking
765          * for F_EXEC_RUN state, so that errors during ExecutorStart or
766          * ExecutorEnd are blamed on the appropriate query; see postquel_start and
767          * postquel_end.)
768          */
769         if (fcache)
770         {
771                 execution_state *es;
772                 int                     query_num;
773
774                 es = fcache->func_state;
775                 query_num = 1;
776                 while (es)
777                 {
778                         if (es->qd)
779                         {
780                                 errcontext("SQL function \"%s\" statement %d",
781                                                    fn_name, query_num);
782                                 break;
783                         }
784                         es = es->next;
785                         query_num++;
786                 }
787                 if (es == NULL)
788                 {
789                         /*
790                          * couldn't identify a running query; might be function entry,
791                          * function exit, or between queries.
792                          */
793                         errcontext("SQL function \"%s\"", fn_name);
794                 }
795         }
796         else
797         {
798                 /* must have failed during init_sql_fcache() */
799                 errcontext("SQL function \"%s\" during startup", fn_name);
800         }
801
802         ReleaseSysCache(func_tuple);
803 }
804
805
806 /*
807  * callback function in case a function-returning-set needs to be shut down
808  * before it has been run to completion
809  */
810 static void
811 ShutdownSQLFunction(Datum arg)
812 {
813         SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) DatumGetPointer(arg);
814         execution_state *es = fcache->func_state;
815
816         while (es != NULL)
817         {
818                 /* Shut down anything still running */
819                 if (es->status == F_EXEC_RUN)
820                         postquel_end(es);
821                 /* Reset states to START in case we're called again */
822                 es->status = F_EXEC_START;
823                 es = es->next;
824         }
825
826         /* execUtils will deregister the callback... */
827         fcache->shutdown_reg = false;
828 }
829
830
831 /*
832  * check_sql_fn_retval() -- check return value of a list of sql parse trees.
833  *
834  * The return value of a sql function is the value returned by
835  * the final query in the function.  We do some ad-hoc type checking here
836  * to be sure that the user is returning the type he claims.  There are
837  * also a couple of strange-looking features to assist callers in dealing
838  * with allowed special cases, such as binary-compatible result types.
839  *
840  * For a polymorphic function the passed rettype must be the actual resolved
841  * output type of the function; we should never see a polymorphic pseudotype
842  * such as ANYELEMENT as rettype.  (This means we can't check the type during
843  * function definition of a polymorphic function.)
844  *
845  * This function returns true if the sql function returns the entire tuple
846  * result of its final SELECT, and false otherwise.  Note that because we
847  * allow "SELECT rowtype_expression", this may be false even when the declared
848  * function return type is a rowtype.
849  *
850  * If insertRelabels is true, then binary-compatible cases are dealt with
851  * by actually inserting RelabelType nodes into the final SELECT; obviously
852  * the caller must pass a parsetree that it's okay to modify in this case.
853  *
854  * If junkFilter isn't NULL, then *junkFilter is set to a JunkFilter defined
855  * to convert the function's tuple result to the correct output tuple type.
856  * Whenever the result value is false (ie, the function isn't returning a
857  * tuple result), *junkFilter is set to NULL.
858  */
859 bool
860 check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
861                                         bool insertRelabels,
862                                         JunkFilter **junkFilter)
863 {
864         Query      *parse;
865         List       *tlist;
866         ListCell   *tlistitem;
867         int                     tlistlen;
868         char            fn_typtype;
869         Oid                     restype;
870
871         AssertArg(!IsPolymorphicType(rettype));
872
873         if (junkFilter)
874                 *junkFilter = NULL;             /* default result */
875
876         /* guard against empty function body; OK only if void return type */
877         if (queryTreeList == NIL)
878         {
879                 if (rettype != VOIDOID)
880                         ereport(ERROR,
881                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
882                          errmsg("return type mismatch in function declared to return %s",
883                                         format_type_be(rettype)),
884                                  errdetail("Function's final statement must be a SELECT.")));
885                 return false;
886         }
887
888         /* find the final query */
889         parse = (Query *) lfirst(list_tail(queryTreeList));
890
891         /*
892          * If the last query isn't a SELECT, the return type must be VOID.
893          *
894          * Note: eventually replace this test with QueryReturnsTuples?  We'd need
895          * a more general method of determining the output type, though.
896          */
897         if (!(parse->commandType == CMD_SELECT &&
898                   parse->utilityStmt == NULL &&
899                   parse->intoClause == NULL))
900         {
901                 if (rettype != VOIDOID)
902                         ereport(ERROR,
903                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
904                          errmsg("return type mismatch in function declared to return %s",
905                                         format_type_be(rettype)),
906                                  errdetail("Function's final statement must be a SELECT.")));
907                 return false;
908         }
909
910         /*
911          * OK, it's a SELECT, so it must return something matching the declared
912          * type.  (We used to insist that the declared type not be VOID in this
913          * case, but that makes it hard to write a void function that exits after
914          * calling another void function.  Instead, we insist that the SELECT
915          * return void ... so void is treated as if it were a scalar type below.)
916          */
917
918         /*
919          * Count the non-junk entries in the result targetlist.
920          */
921         tlist = parse->targetList;
922         tlistlen = ExecCleanTargetListLength(tlist);
923
924         fn_typtype = get_typtype(rettype);
925
926         if (fn_typtype == TYPTYPE_BASE ||
927                 fn_typtype == TYPTYPE_DOMAIN ||
928                 fn_typtype == TYPTYPE_ENUM ||
929                 rettype == VOIDOID)
930         {
931                 /*
932                  * For scalar-type returns, the target list must have exactly one
933                  * non-junk entry, and its type must agree with what the user
934                  * declared; except we allow binary-compatible types too.
935                  */
936                 TargetEntry *tle;
937
938                 if (tlistlen != 1)
939                         ereport(ERROR,
940                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
941                          errmsg("return type mismatch in function declared to return %s",
942                                         format_type_be(rettype)),
943                                  errdetail("Final SELECT must return exactly one column.")));
944
945                 /* We assume here that non-junk TLEs must come first in tlists */
946                 tle = (TargetEntry *) linitial(tlist);
947                 Assert(!tle->resjunk);
948
949                 restype = exprType((Node *) tle->expr);
950                 if (!IsBinaryCoercible(restype, rettype))
951                         ereport(ERROR,
952                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
953                          errmsg("return type mismatch in function declared to return %s",
954                                         format_type_be(rettype)),
955                                          errdetail("Actual return type is %s.",
956                                                            format_type_be(restype))));
957                 if (insertRelabels && restype != rettype)
958                         tle->expr = (Expr *) makeRelabelType(tle->expr,
959                                                                                                  rettype,
960                                                                                                  -1,
961                                                                                                  COERCE_DONTCARE);
962         }
963         else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
964         {
965                 /* Returns a rowtype */
966                 TupleDesc       tupdesc;
967                 int                     tupnatts;       /* physical number of columns in tuple */
968                 int                     tuplogcols; /* # of nondeleted columns in tuple */
969                 int                     colindex;       /* physical column index */
970
971                 /*
972                  * If the target list is of length 1, and the type of the varnode in
973                  * the target list matches the declared return type, this is okay.
974                  * This can happen, for example, where the body of the function is
975                  * 'SELECT func2()', where func2 has the same composite return type
976                  * as the function that's calling it.
977                  */
978                 if (tlistlen == 1)
979                 {
980                         TargetEntry *tle = (TargetEntry *) linitial(tlist);
981
982                         Assert(!tle->resjunk);
983                         restype = exprType((Node *) tle->expr);
984                         if (IsBinaryCoercible(restype, rettype))
985                         {
986                                 if (insertRelabels && restype != rettype)
987                                         tle->expr = (Expr *) makeRelabelType(tle->expr,
988                                                                                                                  rettype,
989                                                                                                                  -1,
990                                                                                                                  COERCE_DONTCARE);
991                                 return false;   /* NOT returning whole tuple */
992                         }
993                 }
994
995                 /* Is the rowtype fixed, or determined only at runtime? */
996                 if (get_func_result_type(func_id, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
997                 {
998                         /*
999                          * Assume we are returning the whole tuple. Crosschecking against
1000                          * what the caller expects will happen at runtime.
1001                          */
1002                         if (junkFilter)
1003                                 *junkFilter = ExecInitJunkFilter(tlist, false, NULL);
1004                         return true;
1005                 }
1006                 Assert(tupdesc);
1007
1008                 /*
1009                  * Verify that the targetlist matches the return tuple type. We scan
1010                  * the non-deleted attributes to ensure that they match the datatypes
1011                  * of the non-resjunk columns.
1012                  */
1013                 tupnatts = tupdesc->natts;
1014                 tuplogcols = 0;                 /* we'll count nondeleted cols as we go */
1015                 colindex = 0;
1016
1017                 foreach(tlistitem, tlist)
1018                 {
1019                         TargetEntry *tle = (TargetEntry *) lfirst(tlistitem);
1020                         Form_pg_attribute attr;
1021                         Oid                     tletype;
1022                         Oid                     atttype;
1023
1024                         if (tle->resjunk)
1025                                 continue;
1026
1027                         do
1028                         {
1029                                 colindex++;
1030                                 if (colindex > tupnatts)
1031                                         ereport(ERROR,
1032                                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1033                                                          errmsg("return type mismatch in function declared to return %s",
1034                                                                         format_type_be(rettype)),
1035                                            errdetail("Final SELECT returns too many columns.")));
1036                                 attr = tupdesc->attrs[colindex - 1];
1037                         } while (attr->attisdropped);
1038                         tuplogcols++;
1039
1040                         tletype = exprType((Node *) tle->expr);
1041                         atttype = attr->atttypid;
1042                         if (!IsBinaryCoercible(tletype, atttype))
1043                                 ereport(ERROR,
1044                                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1045                                                  errmsg("return type mismatch in function declared to return %s",
1046                                                                 format_type_be(rettype)),
1047                                                  errdetail("Final SELECT returns %s instead of %s at column %d.",
1048                                                                    format_type_be(tletype),
1049                                                                    format_type_be(atttype),
1050                                                                    tuplogcols)));
1051                         if (insertRelabels && tletype != atttype)
1052                                 tle->expr = (Expr *) makeRelabelType(tle->expr,
1053                                                                                                          atttype,
1054                                                                                                          -1,
1055                                                                                                          COERCE_DONTCARE);
1056                 }
1057
1058                 for (;;)
1059                 {
1060                         colindex++;
1061                         if (colindex > tupnatts)
1062                                 break;
1063                         if (!tupdesc->attrs[colindex - 1]->attisdropped)
1064                                 tuplogcols++;
1065                 }
1066
1067                 if (tlistlen != tuplogcols)
1068                         ereport(ERROR,
1069                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1070                          errmsg("return type mismatch in function declared to return %s",
1071                                         format_type_be(rettype)),
1072                                          errdetail("Final SELECT returns too few columns.")));
1073
1074                 /* Set up junk filter if needed */
1075                 if (junkFilter)
1076                         *junkFilter = ExecInitJunkFilterConversion(tlist,
1077                                                                                                 CreateTupleDescCopy(tupdesc),
1078                                                                                                            NULL);
1079
1080                 /* Report that we are returning entire tuple result */
1081                 return true;
1082         }
1083         else
1084                 ereport(ERROR,
1085                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1086                                  errmsg("return type %s is not supported for SQL functions",
1087                                                 format_type_be(rettype))));
1088
1089         return false;
1090 }