1 /*-------------------------------------------------------------------------
4 * Routines to handle functions called from the executor
5 * Putting this stuff in fmgr makes the postmaster a mess....
7 * Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.18 1998/08/24 01:37:48 momjian Exp $
13 *-------------------------------------------------------------------------
18 #include "nodes/primnodes.h"
19 #include "nodes/relation.h"
20 #include "nodes/execnodes.h"
21 #include "nodes/plannodes.h"
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"
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"
45 F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE
48 typedef struct local_es
52 struct local_es *next;
56 #define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *)NULL)
58 /* non-export function prototypes */
59 static TupleDesc postquel_start(execution_state *es);
60 static execution_state *
61 init_execution_state(FunctionCachePtr fcache,
63 static TupleTableSlot *postquel_getnext(execution_state *es);
64 static void postquel_end(execution_state *es);
66 postquel_sub_params(execution_state *es, int nargs,
67 char *args[], bool *nullV);
69 postquel_execute(execution_state *es, FunctionCachePtr fcache,
70 List *fTlist, char **args, bool *isNull);
74 ProjectAttribute(TupleDesc TD,
81 Var *attrVar = (Var *) tlist->expr;
82 AttrNumber attrno = attrVar->varattno;
85 val = heap_getattr(tup, attrno, TD, isnullP);
89 valueP = datumCopy(val,
90 TD->attrs[attrno - 1]->atttypid,
91 TD->attrs[attrno - 1]->attbyval,
92 (Size) TD->attrs[attrno - 1]->attlen);
96 static execution_state *
97 init_execution_state(FunctionCachePtr fcache,
100 execution_state *newes;
101 execution_state *nextes;
102 execution_state *preves;
103 QueryTreeList *queryTree_list;
108 nargs = fcache->nargs;
110 newes = (execution_state *) palloc(sizeof(execution_state));
112 preves = (execution_state *) NULL;
115 planTree_list = (List *)
116 pg_parse_and_plan(fcache->src, fcache->argOidVect, nargs, &queryTree_list, None, FALSE);
118 for (i = 0; i < queryTree_list->len; i++)
121 Query *queryTree = (Query *) (queryTree_list->qtrees[i]);
122 Plan *planTree = lfirst(planTree_list);
125 nextes = (execution_state *) palloc(sizeof(execution_state));
127 preves->next = nextes;
130 nextes->status = F_EXEC_START;
131 nextes->qd = CreateQueryDesc(queryTree,
134 estate = CreateExecutorState();
139 ParamListInfo paramLI;
142 (ParamListInfo) palloc((nargs + 1) * sizeof(ParamListInfoData));
144 MemSet(paramLI, 0, nargs * sizeof(ParamListInfoData));
146 estate->es_param_list_info = paramLI;
148 for (i = 0; i < nargs; paramLI++, i++)
150 paramLI->kind = PARAM_NUM;
152 paramLI->isnull = false;
153 paramLI->value = (Datum) NULL;
155 paramLI->kind = PARAM_INVALID;
158 estate->es_param_list_info = (ParamListInfo) NULL;
159 nextes->estate = estate;
161 nextes = (execution_state *) NULL;
163 planTree_list = lnext(planTree_list);
170 postquel_start(execution_state *es)
172 #ifdef FUNC_UTIL_PATCH
175 * Do nothing for utility commands. (create, destroy...) DZ -
178 if (es->qd->operation == CMD_UTILITY)
179 return (TupleDesc) NULL;
181 return ExecutorStart(es->qd, es->estate);
184 static TupleTableSlot *
185 postquel_getnext(execution_state *es)
189 #ifdef FUNC_UTIL_PATCH
190 if (es->qd->operation == CMD_UTILITY)
194 * Process an utility command. (create, destroy...) DZ -
197 ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);
198 if (!LAST_POSTQUEL_COMMAND(es))
199 CommandCounterIncrement();
200 return (TupleTableSlot *) NULL;
204 feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
206 return ExecutorRun(es->qd, es->estate, feature, 0);
210 postquel_end(execution_state *es)
212 #ifdef FUNC_UTIL_PATCH
215 * Do nothing for utility commands. (create, destroy...) DZ -
218 if (es->qd->operation == CMD_UTILITY)
221 ExecutorEnd(es->qd, es->estate);
225 postquel_sub_params(execution_state *es,
230 ParamListInfo paramLI;
234 paramLI = estate->es_param_list_info;
236 while (paramLI->kind != PARAM_INVALID)
238 if (paramLI->kind == PARAM_NUM)
240 Assert(paramLI->id <= nargs);
241 paramLI->value = (Datum) args[(paramLI->id - 1)];
242 paramLI->isnull = nullV[(paramLI->id - 1)];
248 static TupleTableSlot *
249 copy_function_result(FunctionCachePtr fcache,
250 TupleTableSlot *resultSlot)
252 TupleTableSlot *funcSlot;
257 Assert(!TupIsNull(resultSlot));
258 oldTuple = resultSlot->val;
260 funcSlot = (TupleTableSlot *) fcache->funcSlot;
262 if (funcSlot == (TupleTableSlot *) NULL)
265 resultTd = resultSlot->ttc_tupleDescriptor;
268 * When the funcSlot is NULL we have to initialize the funcSlot's
271 if (TupIsNull(funcSlot))
274 TupleDesc funcTd = funcSlot->ttc_tupleDescriptor;
276 while (i < oldTuple->t_natts)
279 (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
280 memmove(funcTd->attrs[i],
282 ATTRIBUTE_TUPLE_SIZE);
287 newTuple = heap_copytuple(oldTuple);
289 return ExecStoreTuple(newTuple, funcSlot, InvalidBuffer, true);
293 postquel_execute(execution_state *es,
294 FunctionCachePtr fcache,
299 TupleTableSlot *slot;
303 * It's more right place to do it (before
304 * postquel_start->ExecutorStart). Now
305 * ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok. (But
306 * note: I HOPE we can do it here). - vadim 01/22/97
308 if (fcache->nargs > 0)
309 postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
311 if (es->status == F_EXEC_START)
314 es->status = F_EXEC_RUN;
317 slot = postquel_getnext(es);
322 es->status = F_EXEC_DONE;
326 * If this isn't the last command for the function we have to
327 * increment the command counter so that subsequent commands can
328 * see changes made by previous ones.
330 if (!LAST_POSTQUEL_COMMAND(es))
331 CommandCounterIncrement();
335 if (LAST_POSTQUEL_COMMAND(es))
337 TupleTableSlot *resSlot;
340 * Copy the result. copy_function_result is smart enough to do
341 * nothing when no action is called for. This helps reduce the
342 * logic and code redundancy here.
344 resSlot = copy_function_result(fcache, slot);
348 TargetEntry *tle = lfirst(fTlist);
351 value = ProjectAttribute(resSlot->ttc_tupleDescriptor,
358 value = (Datum) resSlot;
363 * If this is a single valued function we have to end the function
366 if (fcache->oneResult)
369 es->status = F_EXEC_DONE;
376 * If this isn't the last command for the function, we don't return
377 * any results, but we have to increment the command counter so that
378 * subsequent commands can see changes made by previous ones.
380 CommandCounterIncrement();
385 postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone)
389 FunctionCachePtr fcache = funcNode->func_fcache;
393 * Before we start do anything we must save CurrentScanCommandId to
394 * restore it before return to upper Executor. Also, we have to set
395 * CurrentScanCommandId equal to CurrentCommandId. - vadim 08/29/97
397 savedId = GetScanCommandId();
398 SetScanCommandId(GetCurrentCommandId());
400 es = (execution_state *) fcache->func_state;
403 es = init_execution_state(fcache, args);
404 fcache->func_state = (char *) es;
407 while (es && es->status == F_EXEC_DONE)
413 * Execute each command in the function one after another until we're
414 * executing the final command and get a result or we run out of
417 while (es != (execution_state *) NULL)
419 result = postquel_execute(es,
421 funcNode->func_tlist,
424 if (es->status != F_EXEC_DONE)
430 * If we've gone through every command in this function, we are done.
432 if (es == (execution_state *) NULL)
436 * Reset the execution states to start over again
438 es = (execution_state *) fcache->func_state;
441 es->status = F_EXEC_START;
446 * Let caller know we're finished.
449 SetScanCommandId(savedId);
450 return (fcache->oneResult) ? result : (Datum) NULL;
454 * If we got a result from a command within the function it has to be
455 * the final command. All others shouldn't be returing anything.
457 Assert(LAST_POSTQUEL_COMMAND(es));
460 SetScanCommandId(savedId);