]> granicus.if.org Git - postgresql/blob - src/backend/executor/functions.c
Cleanup of source files where 'return' or 'var =' is alone on a line.
[postgresql] / src / backend / executor / functions.c
1 /*-------------------------------------------------------------------------
2  *
3  * functions.c--
4  *        Routines to handle functions called from the executor
5  *        Putting this stuff in fmgr makes the postmaster a mess....
6  *
7  * Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.22 1999/02/03 21:16:12 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include <string.h>
16 #include "postgres.h"
17
18 #include "nodes/primnodes.h"
19 #include "nodes/relation.h"
20 #include "nodes/execnodes.h"
21 #include "nodes/plannodes.h"
22
23 #include "catalog/pg_proc.h"
24 #include "tcop/pquery.h"
25 #include "tcop/tcopprot.h"
26 #include "tcop/utility.h"
27 #include "nodes/params.h"
28 #include "fmgr.h"
29 #include "utils/fcache.h"
30 #include "utils/datum.h"
31 #include "utils/elog.h"
32 #include "utils/palloc.h"
33 #include "utils/syscache.h"
34 #include "catalog/pg_language.h"
35 #include "access/heapam.h"
36 #include "access/xact.h"
37 #include "executor/executor.h"
38 #include "executor/execdefs.h"
39 #include "executor/functions.h"
40
41 #undef new
42
43 typedef enum
44 {
45         F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE
46 } ExecStatus;
47
48 typedef struct local_es
49 {
50         QueryDesc  *qd;
51         EState     *estate;
52         struct local_es *next;
53         ExecStatus      status;
54 } execution_state;
55
56 #define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *)NULL)
57
58 /* non-export function prototypes */
59 static TupleDesc postquel_start(execution_state *es);
60 static execution_state *init_execution_state(FunctionCachePtr fcache,
61                                          char *args[]);
62 static TupleTableSlot *postquel_getnext(execution_state *es);
63 static void postquel_end(execution_state *es);
64 static void postquel_sub_params(execution_state *es, int nargs,
65                                         char *args[], bool *nullV);
66 static Datum postquel_execute(execution_state *es, FunctionCachePtr fcache,
67                                  List *fTlist, char **args, bool *isNull);
68
69
70 Datum
71 ProjectAttribute(TupleDesc TD,
72                                  TargetEntry *tlist,
73                                  HeapTuple tup,
74                                  bool *isnullP)
75 {
76         Datum           val,
77                                 valueP;
78         Var                *attrVar = (Var *) tlist->expr;
79         AttrNumber      attrno = attrVar->varattno;
80
81
82         val = heap_getattr(tup, attrno, TD, isnullP);
83         if (*isnullP)
84                 return (Datum) NULL;
85
86         valueP = datumCopy(val,
87                                            TD->attrs[attrno - 1]->atttypid,
88                                            TD->attrs[attrno - 1]->attbyval,
89                                            (Size) TD->attrs[attrno - 1]->attlen);
90         return valueP;
91 }
92
93 static execution_state *
94 init_execution_state(FunctionCachePtr fcache,
95                                          char *args[])
96 {
97         execution_state *newes;
98         execution_state *nextes;
99         execution_state *preves;
100         QueryTreeList *queryTree_list;
101         int                     i;
102         List       *planTree_list;
103         int                     nargs;
104
105         nargs = fcache->nargs;
106
107         newes = (execution_state *) palloc(sizeof(execution_state));
108         nextes = newes;
109         preves = (execution_state *) NULL;
110
111
112         planTree_list = (List *)
113                 pg_parse_and_plan(fcache->src, fcache->argOidVect, nargs, &queryTree_list, None, FALSE);
114
115         for (i = 0; i < queryTree_list->len; i++)
116         {
117                 EState     *estate;
118                 Query      *queryTree = (Query *) (queryTree_list->qtrees[i]);
119                 Plan       *planTree = lfirst(planTree_list);
120
121                 if (!nextes)
122                         nextes = (execution_state *) palloc(sizeof(execution_state));
123                 if (preves)
124                         preves->next = nextes;
125
126                 nextes->next = NULL;
127                 nextes->status = F_EXEC_START;
128                 nextes->qd = CreateQueryDesc(queryTree,
129                                                                          planTree,
130                                                                          None);
131                 estate = CreateExecutorState();
132
133                 if (nargs > 0)
134                 {
135                         int                     i;
136                         ParamListInfo paramLI;
137
138                         paramLI = (ParamListInfo) palloc((nargs + 1) * sizeof(ParamListInfoData));
139
140                         MemSet(paramLI, 0, nargs * sizeof(ParamListInfoData));
141
142                         estate->es_param_list_info = paramLI;
143
144                         for (i = 0; i < nargs; paramLI++, i++)
145                         {
146                                 paramLI->kind = PARAM_NUM;
147                                 paramLI->id = i + 1;
148                                 paramLI->isnull = false;
149                                 paramLI->value = (Datum) NULL;
150                         }
151                         paramLI->kind = PARAM_INVALID;
152                 }
153                 else
154                         estate->es_param_list_info = (ParamListInfo) NULL;
155                 nextes->estate = estate;
156                 preves = nextes;
157                 nextes = (execution_state *) NULL;
158
159                 planTree_list = lnext(planTree_list);
160         }
161
162         return newes;
163 }
164
165 static TupleDesc
166 postquel_start(execution_state *es)
167 {
168 #ifdef FUNC_UTIL_PATCH
169
170         /*
171          * Do nothing for utility commands. (create, destroy...)  DZ -
172          * 30-8-1996
173          */
174         if (es->qd->operation == CMD_UTILITY)
175                 return (TupleDesc) NULL;
176 #endif
177         return ExecutorStart(es->qd, es->estate);
178 }
179
180 static TupleTableSlot *
181 postquel_getnext(execution_state *es)
182 {
183         int                     feature;
184
185 #ifdef FUNC_UTIL_PATCH
186         if (es->qd->operation == CMD_UTILITY)
187         {
188
189                 /*
190                  * Process an utility command. (create, destroy...)  DZ -
191                  * 30-8-1996
192                  */
193                 ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);
194                 if (!LAST_POSTQUEL_COMMAND(es))
195                         CommandCounterIncrement();
196                 return (TupleTableSlot *) NULL;
197         }
198 #endif
199
200         feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
201
202         return ExecutorRun(es->qd, es->estate, feature, 0);
203 }
204
205 static void
206 postquel_end(execution_state *es)
207 {
208 #ifdef FUNC_UTIL_PATCH
209
210         /*
211          * Do nothing for utility commands. (create, destroy...)  DZ -
212          * 30-8-1996
213          */
214         if (es->qd->operation == CMD_UTILITY)
215                 return;
216 #endif
217         ExecutorEnd(es->qd, es->estate);
218 }
219
220 static void
221 postquel_sub_params(execution_state *es,
222                                         int nargs,
223                                         char *args[],
224                                         bool *nullV)
225 {
226         ParamListInfo paramLI;
227         EState     *estate;
228
229         estate = es->estate;
230         paramLI = estate->es_param_list_info;
231
232         while (paramLI->kind != PARAM_INVALID)
233         {
234                 if (paramLI->kind == PARAM_NUM)
235                 {
236                         Assert(paramLI->id <= nargs);
237                         paramLI->value = (Datum) args[(paramLI->id - 1)];
238                         paramLI->isnull = nullV[(paramLI->id - 1)];
239                 }
240                 paramLI++;
241         }
242 }
243
244 static TupleTableSlot *
245 copy_function_result(FunctionCachePtr fcache,
246                                          TupleTableSlot *resultSlot)
247 {
248         TupleTableSlot *funcSlot;
249         TupleDesc       resultTd;
250         HeapTuple       newTuple;
251         HeapTuple       oldTuple;
252
253         Assert(!TupIsNull(resultSlot));
254         oldTuple = resultSlot->val;
255
256         funcSlot = (TupleTableSlot *) fcache->funcSlot;
257
258         if (funcSlot == (TupleTableSlot *) NULL)
259                 return resultSlot;
260
261         resultTd = resultSlot->ttc_tupleDescriptor;
262
263         /*
264          * When the funcSlot is NULL we have to initialize the funcSlot's
265          * tuple descriptor.
266          */
267         if (TupIsNull(funcSlot))
268         {
269                 int                     i = 0;
270                 TupleDesc       funcTd = funcSlot->ttc_tupleDescriptor;
271
272                 while (i < oldTuple->t_data->t_natts)
273                 {
274                         funcTd->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
275                         memmove(funcTd->attrs[i],
276                                         resultTd->attrs[i],
277                                         ATTRIBUTE_TUPLE_SIZE);
278                         i++;
279                 }
280         }
281
282         newTuple = heap_copytuple(oldTuple);
283
284         return ExecStoreTuple(newTuple, funcSlot, InvalidBuffer, true);
285 }
286
287 static Datum
288 postquel_execute(execution_state *es,
289                                  FunctionCachePtr fcache,
290                                  List *fTlist,
291                                  char **args,
292                                  bool *isNull)
293 {
294         TupleTableSlot *slot;
295         Datum           value;
296
297         /*
298          * It's more right place to do it (before
299          * postquel_start->ExecutorStart). Now
300          * ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok. (But
301          * note: I HOPE we can do it here). - vadim 01/22/97
302          */
303         if (fcache->nargs > 0)
304                 postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
305
306         if (es->status == F_EXEC_START)
307         {
308                 postquel_start(es);
309                 es->status = F_EXEC_RUN;
310         }
311
312         slot = postquel_getnext(es);
313
314         if (TupIsNull(slot))
315         {
316                 postquel_end(es);
317                 es->status = F_EXEC_DONE;
318                 *isNull = true;
319
320                 /*
321                  * If this isn't the last command for the function we have to
322                  * increment the command counter so that subsequent commands can
323                  * see changes made by previous ones.
324                  */
325                 if (!LAST_POSTQUEL_COMMAND(es))
326                         CommandCounterIncrement();
327                 return (Datum) NULL;
328         }
329
330         if (LAST_POSTQUEL_COMMAND(es))
331         {
332                 TupleTableSlot *resSlot;
333
334                 /*
335                  * Copy the result.  copy_function_result is smart enough to do
336                  * nothing when no action is called for.  This helps reduce the
337                  * logic and code redundancy here.
338                  */
339                 resSlot = copy_function_result(fcache, slot);
340                 if (fTlist != NIL)
341                 {
342                         TargetEntry *tle = lfirst(fTlist);
343
344                         value = ProjectAttribute(resSlot->ttc_tupleDescriptor,
345                                                                          tle,
346                                                                          resSlot->val,
347                                                                          isNull);
348                 }
349                 else
350                 {
351                         value = (Datum) resSlot;
352                         *isNull = false;
353                 }
354
355                 /*
356                  * If this is a single valued function we have to end the function
357                  * execution now.
358                  */
359                 if (fcache->oneResult)
360                 {
361                         postquel_end(es);
362                         es->status = F_EXEC_DONE;
363                 }
364
365                 return value;
366         }
367
368         /*
369          * If this isn't the last command for the function, we don't return
370          * any results, but we have to increment the command counter so that
371          * subsequent commands can see changes made by previous ones.
372          */
373         CommandCounterIncrement();
374         return (Datum) NULL;
375 }
376
377 Datum
378 postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone)
379 {
380         execution_state *es;
381         Datum           result = 0;
382         FunctionCachePtr fcache = funcNode->func_fcache;
383         CommandId       savedId;
384
385         /*
386          * Before we start do anything we must save CurrentScanCommandId to
387          * restore it before return to upper Executor. Also, we have to set
388          * CurrentScanCommandId equal to CurrentCommandId. - vadim 08/29/97
389          */
390         savedId = GetScanCommandId();
391         SetScanCommandId(GetCurrentCommandId());
392
393         es = (execution_state *) fcache->func_state;
394         if (es == NULL)
395         {
396                 es = init_execution_state(fcache, args);
397                 fcache->func_state = (char *) es;
398         }
399
400         while (es && es->status == F_EXEC_DONE)
401                 es = es->next;
402
403         Assert(es);
404
405         /*
406          * Execute each command in the function one after another until we're
407          * executing the final command and get a result or we run out of
408          * commands.
409          */
410         while (es != (execution_state *) NULL)
411         {
412                 result = postquel_execute(es,
413                                                                   fcache,
414                                                                   funcNode->func_tlist,
415                                                                   args,
416                                                                   isNull);
417                 if (es->status != F_EXEC_DONE)
418                         break;
419                 es = es->next;
420         }
421
422         /*
423          * If we've gone through every command in this function, we are done.
424          */
425         if (es == (execution_state *) NULL)
426         {
427
428                 /*
429                  * Reset the execution states to start over again
430                  */
431                 es = (execution_state *) fcache->func_state;
432                 while (es)
433                 {
434                         es->status = F_EXEC_START;
435                         es = es->next;
436                 }
437
438                 /*
439                  * Let caller know we're finished.
440                  */
441                 *isDone = true;
442                 SetScanCommandId(savedId);
443                 return (fcache->oneResult) ? result : (Datum) NULL;
444         }
445
446         /*
447          * If we got a result from a command within the function it has to be
448          * the final command.  All others shouldn't be returing anything.
449          */
450         Assert(LAST_POSTQUEL_COMMAND(es));
451         *isDone = false;
452
453         SetScanCommandId(savedId);
454         return result;
455 }