diff options
Diffstat (limited to 'src/backend/executor/functions.c')
-rw-r--r-- | src/backend/executor/functions.c | 695 |
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; } |