aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/functions.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/functions.c')
-rw-r--r--src/backend/executor/functions.c695
1 files changed, 366 insertions, 329 deletions
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 79f8bede085..96b9b19dcb6 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* functions.c--
- * Routines to handle functions called from the executor
- * Putting this stuff in fmgr makes the postmaster a mess....
+ * Routines to handle functions called from the executor
+ * Putting this stuff in fmgr makes the postmaster a mess....
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.7 1997/08/29 09:02:50 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.8 1997/09/07 04:41:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -41,401 +41,438 @@
#undef new
-typedef enum {F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE} ExecStatus;
+typedef enum
+{
+ F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE
+} ExecStatus;
-typedef struct local_es {
- QueryDesc *qd;
- EState *estate;
- struct local_es *next;
- ExecStatus status;
-} execution_state;
+typedef struct local_es
+{
+ QueryDesc *qd;
+ EState *estate;
+ struct local_es *next;
+ ExecStatus status;
+} execution_state;
#define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *)NULL)
/* non-export function prototypes */
-static TupleDesc postquel_start(execution_state *es);
-static execution_state *init_execution_state(FunctionCachePtr fcache,
- char *args[]);
-static TupleTableSlot *postquel_getnext(execution_state *es);
-static void postquel_end(execution_state *es);
-static void postquel_sub_params(execution_state *es, int nargs,
- char *args[], bool *nullV);
-static Datum postquel_execute(execution_state *es, FunctionCachePtr fcache,
- List *fTlist, char **args, bool *isNull);
-
+static TupleDesc postquel_start(execution_state * es);
+static execution_state *
+init_execution_state(FunctionCachePtr fcache,
+ char *args[]);
+static TupleTableSlot *postquel_getnext(execution_state * es);
+static void postquel_end(execution_state * es);
+static void
+postquel_sub_params(execution_state * es, int nargs,
+ char *args[], bool * nullV);
+static Datum
+postquel_execute(execution_state * es, FunctionCachePtr fcache,
+ List * fTlist, char **args, bool * isNull);
+
Datum
ProjectAttribute(TupleDesc TD,
- TargetEntry *tlist,
- HeapTuple tup,
- bool *isnullP)
+ TargetEntry * tlist,
+ HeapTuple tup,
+ bool * isnullP)
{
- Datum val,valueP;
- Var *attrVar = (Var *)tlist->expr;
- AttrNumber attrno = attrVar->varattno;
-
-
- val = PointerGetDatum(heap_getattr(tup,
- InvalidBuffer,
- attrno,
- TD,
- isnullP));
- if (*isnullP)
- return (Datum) NULL;
-
- valueP = datumCopy(val,
- TD->attrs[attrno-1]->atttypid,
- TD->attrs[attrno-1]->attbyval,
- (Size) TD->attrs[attrno-1]->attlen);
- return valueP;
+ Datum val,
+ valueP;
+ Var *attrVar = (Var *) tlist->expr;
+ AttrNumber attrno = attrVar->varattno;
+
+
+ val = PointerGetDatum(heap_getattr(tup,
+ InvalidBuffer,
+ attrno,
+ TD,
+ isnullP));
+ if (*isnullP)
+ return (Datum) NULL;
+
+ valueP = datumCopy(val,
+ TD->attrs[attrno - 1]->atttypid,
+ TD->attrs[attrno - 1]->attbyval,
+ (Size) TD->attrs[attrno - 1]->attlen);
+ return valueP;
}
static execution_state *
init_execution_state(FunctionCachePtr fcache,
- char *args[])
+ char *args[])
{
- execution_state *newes;
- execution_state *nextes;
- execution_state *preves;
- QueryTreeList *queryTree_list;
- int i;
- List *planTree_list;
- int nargs;
-
- nargs = fcache->nargs;
-
- newes = (execution_state *) palloc(sizeof(execution_state));
- nextes = newes;
- preves = (execution_state *)NULL;
-
-
- planTree_list = (List *)
- pg_plan(fcache->src, fcache->argOidVect, nargs, &queryTree_list, None);
-
- for (i=0; i < queryTree_list->len; i++) {
- EState *estate;
- Query *queryTree = (Query*) (queryTree_list->qtrees[i]);
- Plan *planTree = lfirst(planTree_list);
-
- if (!nextes)
- nextes = (execution_state *) palloc(sizeof(execution_state));
- if (preves)
- preves->next = nextes;
-
- nextes->next = NULL;
- nextes->status = F_EXEC_START;
- nextes->qd = CreateQueryDesc(queryTree,
- planTree,
- None);
- estate = CreateExecutorState();
-
- if (nargs > 0) {
- int i;
- ParamListInfo paramLI;
-
- paramLI =
- (ParamListInfo)palloc((nargs+1)*sizeof(ParamListInfoData));
-
- memset(paramLI, 0, nargs*sizeof(ParamListInfoData));
-
- estate->es_param_list_info = paramLI;
-
- for (i=0; i<nargs; paramLI++, i++) {
- paramLI->kind = PARAM_NUM;
- paramLI->id = i+1;
- paramLI->isnull = false;
- paramLI->value = (Datum) NULL;
- }
- paramLI->kind = PARAM_INVALID;
+ execution_state *newes;
+ execution_state *nextes;
+ execution_state *preves;
+ QueryTreeList *queryTree_list;
+ int i;
+ List *planTree_list;
+ int nargs;
+
+ nargs = fcache->nargs;
+
+ newes = (execution_state *) palloc(sizeof(execution_state));
+ nextes = newes;
+ preves = (execution_state *) NULL;
+
+
+ planTree_list = (List *)
+ pg_plan(fcache->src, fcache->argOidVect, nargs, &queryTree_list, None);
+
+ for (i = 0; i < queryTree_list->len; i++)
+ {
+ EState *estate;
+ Query *queryTree = (Query *) (queryTree_list->qtrees[i]);
+ Plan *planTree = lfirst(planTree_list);
+
+ if (!nextes)
+ nextes = (execution_state *) palloc(sizeof(execution_state));
+ if (preves)
+ preves->next = nextes;
+
+ nextes->next = NULL;
+ nextes->status = F_EXEC_START;
+ nextes->qd = CreateQueryDesc(queryTree,
+ planTree,
+ None);
+ estate = CreateExecutorState();
+
+ if (nargs > 0)
+ {
+ int i;
+ ParamListInfo paramLI;
+
+ paramLI =
+ (ParamListInfo) palloc((nargs + 1) * sizeof(ParamListInfoData));
+
+ memset(paramLI, 0, nargs * sizeof(ParamListInfoData));
+
+ estate->es_param_list_info = paramLI;
+
+ for (i = 0; i < nargs; paramLI++, i++)
+ {
+ paramLI->kind = PARAM_NUM;
+ paramLI->id = i + 1;
+ paramLI->isnull = false;
+ paramLI->value = (Datum) NULL;
+ }
+ paramLI->kind = PARAM_INVALID;
+ }
+ else
+ estate->es_param_list_info = (ParamListInfo) NULL;
+ nextes->estate = estate;
+ preves = nextes;
+ nextes = (execution_state *) NULL;
+
+ planTree_list = lnext(planTree_list);
}
- else
- estate->es_param_list_info = (ParamListInfo)NULL;
- nextes->estate = estate;
- preves = nextes;
- nextes = (execution_state *)NULL;
-
- planTree_list = lnext(planTree_list);
- }
-
- return newes;
+
+ return newes;
}
-static TupleDesc
-postquel_start(execution_state *es)
+static TupleDesc
+postquel_start(execution_state * es)
{
#ifdef FUNC_UTIL_PATCH
- /*
- * Do nothing for utility commands. (create, destroy...) DZ - 30-8-1996
- */
- if (es->qd->operation == CMD_UTILITY) {
- return (TupleDesc) NULL;
- }
+
+ /*
+ * Do nothing for utility commands. (create, destroy...) DZ -
+ * 30-8-1996
+ */
+ if (es->qd->operation == CMD_UTILITY)
+ {
+ return (TupleDesc) NULL;
+ }
#endif
- return ExecutorStart(es->qd, es->estate);
+ return ExecutorStart(es->qd, es->estate);
}
static TupleTableSlot *
-postquel_getnext(execution_state *es)
+postquel_getnext(execution_state * es)
{
- int feature;
-
+ int feature;
+
#ifdef FUNC_UTIL_PATCH
- if (es->qd->operation == CMD_UTILITY) {
- /*
- * Process an utility command. (create, destroy...) DZ - 30-8-1996
- */
- ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);
- if (!LAST_POSTQUEL_COMMAND(es)) CommandCounterIncrement();
- return (TupleTableSlot*) NULL;
- }
+ if (es->qd->operation == CMD_UTILITY)
+ {
+
+ /*
+ * Process an utility command. (create, destroy...) DZ -
+ * 30-8-1996
+ */
+ ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);
+ if (!LAST_POSTQUEL_COMMAND(es))
+ CommandCounterIncrement();
+ return (TupleTableSlot *) NULL;
+ }
#endif
- feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
-
- return ExecutorRun(es->qd, es->estate, feature, 0);
+ feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
+
+ return ExecutorRun(es->qd, es->estate, feature, 0);
}
static void
-postquel_end(execution_state *es)
+postquel_end(execution_state * es)
{
#ifdef FUNC_UTIL_PATCH
- /*
- * Do nothing for utility commands. (create, destroy...) DZ - 30-8-1996
- */
- if (es->qd->operation == CMD_UTILITY) {
- return;
- }
+
+ /*
+ * Do nothing for utility commands. (create, destroy...) DZ -
+ * 30-8-1996
+ */
+ if (es->qd->operation == CMD_UTILITY)
+ {
+ return;
+ }
#endif
- ExecutorEnd(es->qd, es->estate);
+ ExecutorEnd(es->qd, es->estate);
}
static void
-postquel_sub_params(execution_state *es,
- int nargs,
- char *args[],
- bool *nullV)
+postquel_sub_params(execution_state * es,
+ int nargs,
+ char *args[],
+ bool * nullV)
{
- ParamListInfo paramLI;
- EState *estate;
-
- estate = es->estate;
- paramLI = estate->es_param_list_info;
-
- while (paramLI->kind != PARAM_INVALID) {
- if (paramLI->kind == PARAM_NUM) {
- Assert(paramLI->id <= nargs);
- paramLI->value = (Datum)args[(paramLI->id - 1)];
- paramLI->isnull = nullV[(paramLI->id - 1)];
+ ParamListInfo paramLI;
+ EState *estate;
+
+ estate = es->estate;
+ paramLI = estate->es_param_list_info;
+
+ while (paramLI->kind != PARAM_INVALID)
+ {
+ if (paramLI->kind == PARAM_NUM)
+ {
+ Assert(paramLI->id <= nargs);
+ paramLI->value = (Datum) args[(paramLI->id - 1)];
+ paramLI->isnull = nullV[(paramLI->id - 1)];
+ }
+ paramLI++;
}
- paramLI++;
- }
}
static TupleTableSlot *
copy_function_result(FunctionCachePtr fcache,
- TupleTableSlot *resultSlot)
+ TupleTableSlot * resultSlot)
{
- TupleTableSlot *funcSlot;
- TupleDesc resultTd;
- HeapTuple newTuple;
- HeapTuple oldTuple;
-
- Assert(! TupIsNull(resultSlot));
- oldTuple = resultSlot->val;
-
- funcSlot = (TupleTableSlot*)fcache->funcSlot;
-
- if (funcSlot == (TupleTableSlot*)NULL)
- return resultSlot;
-
- resultTd = resultSlot->ttc_tupleDescriptor;
- /*
- * When the funcSlot is NULL we have to initialize the funcSlot's
- * tuple descriptor.
- */
- if (TupIsNull(funcSlot)) {
- int i= 0;
- TupleDesc funcTd = funcSlot->ttc_tupleDescriptor;
-
- while (i < oldTuple->t_natts) {
- funcTd->attrs[i] =
- (AttributeTupleForm)palloc(ATTRIBUTE_TUPLE_SIZE);
- memmove(funcTd->attrs[i],
- resultTd->attrs[i],
- ATTRIBUTE_TUPLE_SIZE);
- i++;
+ TupleTableSlot *funcSlot;
+ TupleDesc resultTd;
+ HeapTuple newTuple;
+ HeapTuple oldTuple;
+
+ Assert(!TupIsNull(resultSlot));
+ oldTuple = resultSlot->val;
+
+ funcSlot = (TupleTableSlot *) fcache->funcSlot;
+
+ if (funcSlot == (TupleTableSlot *) NULL)
+ return resultSlot;
+
+ resultTd = resultSlot->ttc_tupleDescriptor;
+
+ /*
+ * When the funcSlot is NULL we have to initialize the funcSlot's
+ * tuple descriptor.
+ */
+ if (TupIsNull(funcSlot))
+ {
+ int i = 0;
+ TupleDesc funcTd = funcSlot->ttc_tupleDescriptor;
+
+ while (i < oldTuple->t_natts)
+ {
+ funcTd->attrs[i] =
+ (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
+ memmove(funcTd->attrs[i],
+ resultTd->attrs[i],
+ ATTRIBUTE_TUPLE_SIZE);
+ i++;
+ }
}
- }
-
- newTuple = heap_copytuple(oldTuple);
-
- return ExecStoreTuple(newTuple,funcSlot,InvalidBuffer,true);
+
+ newTuple = heap_copytuple(oldTuple);
+
+ return ExecStoreTuple(newTuple, funcSlot, InvalidBuffer, true);
}
-static Datum
-postquel_execute(execution_state *es,
- FunctionCachePtr fcache,
- List *fTlist,
- char **args,
- bool *isNull)
+static Datum
+postquel_execute(execution_state * es,
+ FunctionCachePtr fcache,
+ List * fTlist,
+ char **args,
+ bool * isNull)
{
- TupleTableSlot *slot;
- Datum value;
+ TupleTableSlot *slot;
+ Datum value;
#ifdef INDEXSCAN_PATCH
- /*
- * It's more right place to do it (before postquel_start->ExecutorStart).
- * Now ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok.
- * (But note: I HOPE we can do it here). - vadim 01/22/97
- */
- if (fcache->nargs > 0)
- postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
+
+ /*
+ * It's more right place to do it (before
+ * postquel_start->ExecutorStart). Now
+ * ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok. (But
+ * note: I HOPE we can do it here). - vadim 01/22/97
+ */
+ if (fcache->nargs > 0)
+ postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
#endif
-
- if (es->status == F_EXEC_START)
+
+ if (es->status == F_EXEC_START)
{
- postquel_start(es);
- es->status = F_EXEC_RUN;
+ postquel_start(es);
+ es->status = F_EXEC_RUN;
}
#ifndef INDEXSCAN_PATCH
- if (fcache->nargs > 0)
- postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
+ if (fcache->nargs > 0)
+ postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
#endif
-
- slot = postquel_getnext(es);
-
- if (TupIsNull(slot)) {
- postquel_end(es);
- es->status = F_EXEC_DONE;
- *isNull = true;
- /*
- * If this isn't the last command for the function
- * we have to increment the command
- * counter so that subsequent commands can see changes made
- * by previous ones.
- */
- if (!LAST_POSTQUEL_COMMAND(es)) CommandCounterIncrement();
- return (Datum)NULL;
- }
-
- if (LAST_POSTQUEL_COMMAND(es)) {
- TupleTableSlot *resSlot;
-
- /*
- * Copy the result. copy_function_result is smart enough
- * to do nothing when no action is called for. This helps
- * reduce the logic and code redundancy here.
- */
- resSlot = copy_function_result(fcache, slot);
- if (fTlist != NIL) {
- HeapTuple tup;
- TargetEntry *tle = lfirst(fTlist);
-
- tup = resSlot->val;
- value = ProjectAttribute(resSlot->ttc_tupleDescriptor,
- tle,
- tup,
- isNull);
- }else {
- value = (Datum)resSlot;
- *isNull = false;
+
+ slot = postquel_getnext(es);
+
+ if (TupIsNull(slot))
+ {
+ postquel_end(es);
+ es->status = F_EXEC_DONE;
+ *isNull = true;
+
+ /*
+ * If this isn't the last command for the function we have to
+ * increment the command counter so that subsequent commands can
+ * see changes made by previous ones.
+ */
+ if (!LAST_POSTQUEL_COMMAND(es))
+ CommandCounterIncrement();
+ return (Datum) NULL;
}
-
+
+ if (LAST_POSTQUEL_COMMAND(es))
+ {
+ TupleTableSlot *resSlot;
+
+ /*
+ * Copy the result. copy_function_result is smart enough to do
+ * nothing when no action is called for. This helps reduce the
+ * logic and code redundancy here.
+ */
+ resSlot = copy_function_result(fcache, slot);
+ if (fTlist != NIL)
+ {
+ HeapTuple tup;
+ TargetEntry *tle = lfirst(fTlist);
+
+ tup = resSlot->val;
+ value = ProjectAttribute(resSlot->ttc_tupleDescriptor,
+ tle,
+ tup,
+ isNull);
+ }
+ else
+ {
+ value = (Datum) resSlot;
+ *isNull = false;
+ }
+
+ /*
+ * If this is a single valued function we have to end the function
+ * execution now.
+ */
+ if (fcache->oneResult)
+ {
+ postquel_end(es);
+ es->status = F_EXEC_DONE;
+ }
+
+ return value;
+ }
+
/*
- * If this is a single valued function we have to end the
- * function execution now.
+ * If this isn't the last command for the function, we don't return
+ * any results, but we have to increment the command counter so that
+ * subsequent commands can see changes made by previous ones.
*/
- if (fcache->oneResult) {
- postquel_end(es);
- es->status = F_EXEC_DONE;
- }
-
- return value;
- }
- /*
- * If this isn't the last command for the function, we don't
- * return any results, but we have to increment the command
- * counter so that subsequent commands can see changes made
- * by previous ones.
- */
- CommandCounterIncrement();
- return (Datum)NULL;
+ CommandCounterIncrement();
+ return (Datum) NULL;
}
Datum
-postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone)
+postquel_function(Func * funcNode, char **args, bool * isNull, bool * isDone)
{
- execution_state *es;
- Datum result = 0;
- FunctionCachePtr fcache = funcNode->func_fcache;
- CommandId savedId;
-
- /*
- * Before we start do anything we must save CurrentScanCommandId
- * to restore it before return to upper Executor. Also, we have to
- * set CurrentScanCommandId equal to CurrentCommandId.
- * - vadim 08/29/97
- */
- savedId = GetScanCommandId ();
- SetScanCommandId (GetCurrentCommandId ());
-
- es = (execution_state *) fcache->func_state;
- if (es == NULL)
+ execution_state *es;
+ Datum result = 0;
+ FunctionCachePtr fcache = funcNode->func_fcache;
+ CommandId savedId;
+
+ /*
+ * Before we start do anything we must save CurrentScanCommandId to
+ * restore it before return to upper Executor. Also, we have to set
+ * CurrentScanCommandId equal to CurrentCommandId. - vadim 08/29/97
+ */
+ savedId = GetScanCommandId();
+ SetScanCommandId(GetCurrentCommandId());
+
+ es = (execution_state *) fcache->func_state;
+ if (es == NULL)
{
- es = init_execution_state(fcache, args);
- fcache->func_state = (char *) es;
+ es = init_execution_state(fcache, args);
+ fcache->func_state = (char *) es;
}
-
- while (es && es->status == F_EXEC_DONE)
- es = es->next;
-
- Assert(es);
- /*
- * Execute each command in the function one after another until we're
- * executing the final command and get a result or we run out of
- * commands.
- */
- while (es != (execution_state *)NULL)
+
+ while (es && es->status == F_EXEC_DONE)
+ es = es->next;
+
+ Assert(es);
+
+ /*
+ * Execute each command in the function one after another until we're
+ * executing the final command and get a result or we run out of
+ * commands.
+ */
+ while (es != (execution_state *) NULL)
{
- result = postquel_execute(es,
- fcache,
- funcNode->func_tlist,
- args,
- isNull);
- if (es->status != F_EXEC_DONE)
- break;
- es = es->next;
+ result = postquel_execute(es,
+ fcache,
+ funcNode->func_tlist,
+ args,
+ isNull);
+ if (es->status != F_EXEC_DONE)
+ break;
+ es = es->next;
}
-
- /*
- * If we've gone through every command in this function, we are done.
- */
- if (es == (execution_state *)NULL)
- {
+
/*
- * Reset the execution states to start over again
+ * If we've gone through every command in this function, we are done.
*/
- es = (execution_state *)fcache->func_state;
- while (es)
+ if (es == (execution_state *) NULL)
{
- es->status = F_EXEC_START;
- es = es->next;
+
+ /*
+ * Reset the execution states to start over again
+ */
+ es = (execution_state *) fcache->func_state;
+ while (es)
+ {
+ es->status = F_EXEC_START;
+ es = es->next;
+ }
+
+ /*
+ * Let caller know we're finished.
+ */
+ *isDone = true;
+ SetScanCommandId(savedId);
+ return (fcache->oneResult) ? result : (Datum) NULL;
}
+
/*
- * Let caller know we're finished.
+ * If we got a result from a command within the function it has to be
+ * the final command. All others shouldn't be returing anything.
*/
- *isDone = true;
- SetScanCommandId (savedId);
- return (fcache->oneResult) ? result : (Datum)NULL;
- }
- /*
- * If we got a result from a command within the function it has
- * to be the final command. All others shouldn't be returing
- * anything.
- */
- Assert ( LAST_POSTQUEL_COMMAND(es) );
- *isDone = false;
-
- SetScanCommandId (savedId);
- return result;
+ Assert(LAST_POSTQUEL_COMMAND(es));
+ *isDone = false;
+
+ SetScanCommandId(savedId);
+ return result;
}