diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execQual.c | 168 | ||||
-rw-r--r-- | src/backend/executor/execUtils.c | 6 | ||||
-rw-r--r-- | src/backend/executor/functions.c | 81 | ||||
-rw-r--r-- | src/backend/executor/nodeAgg.c | 95 |
4 files changed, 218 insertions, 132 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 58307e6a695..a53957c4f4a 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.69 2000/04/12 17:15:08 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.70 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -41,6 +41,7 @@ #include "executor/functions.h" #include "executor/nodeSubplan.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/fcache2.h" @@ -64,7 +65,8 @@ static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull); static Datum ExecEvalFunc(Expr *funcClause, ExprContext *econtext, bool *isNull, bool *isDone); static void ExecEvalFuncArgs(FunctionCachePtr fcache, ExprContext *econtext, - List *argList, Datum argV[], bool *argIsDone); + List *argList, FunctionCallInfo fcinfo, + bool *argIsDone); static Datum ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull); static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull); @@ -614,15 +616,12 @@ static void ExecEvalFuncArgs(FunctionCachePtr fcache, ExprContext *econtext, List *argList, - Datum argV[], + FunctionCallInfo fcinfo, bool *argIsDone) { int i; - bool *nullVect; List *arg; - nullVect = fcache->nullVect; - i = 0; foreach(arg, argList) { @@ -632,16 +631,16 @@ ExecEvalFuncArgs(FunctionCachePtr fcache, * as arguments but we make an exception in the case of nested dot * expressions. We have to watch out for this case here. */ - argV[i] = ExecEvalExpr((Node *) lfirst(arg), - econtext, - &nullVect[i], - argIsDone); + fcinfo->arg[i] = ExecEvalExpr((Node *) lfirst(arg), + econtext, + &fcinfo->argnull[i], + argIsDone); if (!(*argIsDone)) { if (i != 0) elog(ERROR, "functions can only take sets in their first argument"); - fcache->setArg = (char *) argV[0]; + fcache->setArg = fcinfo->arg[0]; fcache->hasSetArg = true; } i++; @@ -658,40 +657,45 @@ ExecMakeFunctionResult(Node *node, bool *isNull, bool *isDone) { - Datum argV[FUNC_MAX_ARGS]; - FunctionCachePtr fcache; - Func *funcNode = NULL; - Oper *operNode = NULL; - bool funcisset = false; + FunctionCallInfoData fcinfo; + FunctionCachePtr fcache; + List *ftlist; + bool funcisset; + Datum result; + bool argDone; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); /* * This is kind of ugly, Func nodes now have targetlists so that we * know when and what to project out from postquel function results. - * This means we have to pass the func node all the way down instead - * of using only the fcache struct as before. ExecMakeFunctionResult - * becomes a little bit more of a dual personality as a result. + * ExecMakeFunctionResult becomes a little bit more of a dual personality + * as a result. */ if (IsA(node, Func)) { - funcNode = (Func *) node; - fcache = funcNode->func_fcache; + fcache = ((Func *) node)->func_fcache; + ftlist = ((Func *) node)->func_tlist; + funcisset = (((Func *) node)->funcid == F_SETEVAL); } else { - operNode = (Oper *) node; - fcache = operNode->op_fcache; + fcache = ((Oper *) node)->op_fcache; + ftlist = NIL; + funcisset = false; } + fcinfo.flinfo = &fcache->func; + fcinfo.nargs = fcache->nargs; + /* * arguments is a list of expressions to evaluate before passing to - * the function manager. We collect the results of evaluating the - * expressions into a datum array (argV) and pass this array to - * arrayFmgr() + * the function manager. We collect the results of evaluating the + * expressions into the FunctionCallInfo struct. Note we assume that + * fcache->nargs is the correct length of the arguments list! */ - if (fcache->nargs != 0) + if (fcache->nargs > 0) { - bool argDone; - if (fcache->nargs > FUNC_MAX_ARGS) elog(ERROR, "ExecMakeFunctionResult: too many arguments"); @@ -700,21 +704,23 @@ ExecMakeFunctionResult(Node *node, * returning a set of tuples (i.e. a nested dot expression). We * don't want to evaluate the arguments again until the function * is done. hasSetArg will always be false until we eval the args - * for the first time. We should set this in the parser. + * for the first time. */ - if ((fcache->hasSetArg) && fcache->setArg != NULL) + if (fcache->hasSetArg && fcache->setArg != (Datum) 0) { - argV[0] = (Datum) fcache->setArg; + fcinfo.arg[0] = fcache->setArg; argDone = false; } else - ExecEvalFuncArgs(fcache, econtext, arguments, argV, &argDone); + ExecEvalFuncArgs(fcache, econtext, arguments, &fcinfo, &argDone); - if ((fcache->hasSetArg) && (argDone)) + if (fcache->hasSetArg && argDone) { + /* can only get here if input is an empty set. */ if (isDone) *isDone = true; - return (Datum) NULL; + *isNull = true; + return (Datum) 0; } } @@ -731,27 +737,23 @@ ExecMakeFunctionResult(Node *node, * which defines this set. So replace the existing funcid in the * funcnode with the set's OID. Also, we want a new fcache which * points to the right function, so get that, now that we have the - * right OID. Also zero out the argV, since the real set doesn't take + * right OID. Also zero out fcinfo.arg, since the real set doesn't take * any arguments. */ - if (((Func *) node)->funcid == F_SETEVAL) + if (funcisset) { - funcisset = true; if (fcache->setArg) { - argV[0] = 0; - - ((Func *) node)->funcid = (Oid) PointerGetDatum(fcache->setArg); - + ((Func *) node)->funcid = DatumGetObjectId(fcache->setArg); } else { - ((Func *) node)->funcid = (Oid) argV[0]; - setFcache(node, argV[0], NIL, econtext); + ((Func *) node)->funcid = DatumGetObjectId(fcinfo.arg[0]); + setFcache(node, DatumGetObjectId(fcinfo.arg[0]), NIL, econtext); fcache = ((Func *) node)->func_fcache; - fcache->setArg = (char *) argV[0]; - argV[0] = (Datum) 0; + fcache->setArg = fcinfo.arg[0]; } + fcinfo.arg[0] = (Datum) 0; } /* @@ -760,11 +762,6 @@ ExecMakeFunctionResult(Node *node, */ if (fcache->language == SQLlanguageId) { - Datum result; - bool argDone; - - Assert(funcNode); - /*-------------------- * This loop handles the situation where we are iterating through * all results in a nested dot function (whose argument function @@ -777,8 +774,37 @@ ExecMakeFunctionResult(Node *node, */ for (;;) { - result = postquel_function(funcNode, (char **) argV, - isNull, isDone); + /* + * If function is strict, and there are any NULL arguments, + * skip calling the function (at least for this set of args). + */ + bool callit = true; + + if (fcinfo.flinfo->fn_strict) + { + int i; + + for (i = 0; i < fcinfo.nargs; i++) + { + if (fcinfo.argnull[i]) + { + callit = false; + break; + } + } + } + + if (callit) + { + result = postquel_function(&fcinfo, fcache, ftlist, isDone); + *isNull = fcinfo.isnull; + } + else + { + result = (Datum) 0; + *isDone = true; + *isNull = true; + } if (!*isDone) break; /* got a result from current argument */ @@ -786,7 +812,7 @@ ExecMakeFunctionResult(Node *node, break; /* input not a set, so done */ /* OK, get the next argument... */ - ExecEvalFuncArgs(fcache, econtext, arguments, argV, &argDone); + ExecEvalFuncArgs(fcache, econtext, arguments, &fcinfo, &argDone); if (argDone) { @@ -795,10 +821,11 @@ ExecMakeFunctionResult(Node *node, * End of arguments, so reset the setArg flag and say * "Done" */ - fcache->setArg = (char *) NULL; + fcache->setArg = (Datum) 0; fcache->hasSetArg = false; *isDone = true; - result = (Datum) NULL; + *isNull = true; + result = (Datum) 0; break; } @@ -826,21 +853,34 @@ ExecMakeFunctionResult(Node *node, if (*isDone) ((Func *) node)->func_fcache = NULL; } - - return result; } else { - int i; - + /* A non-SQL function cannot return a set, at present. */ if (isDone) *isDone = true; - for (i = 0; i < fcache->nargs; i++) - if (fcache->nullVect[i] == true) - *isNull = true; + /* + * If function is strict, and there are any NULL arguments, + * skip calling the function and return NULL. + */ + if (fcinfo.flinfo->fn_strict) + { + int i; - return (Datum) fmgr_c(&fcache->func, (FmgrValues *) argV, isNull); + for (i = 0; i < fcinfo.nargs; i++) + { + if (fcinfo.argnull[i]) + { + *isNull = true; + return (Datum) 0; + } + } + } + result = FunctionCallInvoke(&fcinfo); + *isNull = fcinfo.isnull; } + + return result; } diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index e3783473f96..39b29138e19 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.55 2000/04/12 17:15:08 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.56 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -52,6 +52,8 @@ #include "executor/execdebug.h" #include "executor/executor.h" #include "miscadmin.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP, AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP); @@ -843,7 +845,7 @@ ExecOpenIndices(Oid resultRelationOid, */ if (VARSIZE(&indexStruct->indpred) != 0) { - predString = fmgr(F_TEXTOUT, &indexStruct->indpred); + predString = textout(&indexStruct->indpred); predicate = (PredInfo *) stringToNode(predString); pfree(predString); } diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index c8d119df482..ee5fabf1708 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -2,14 +2,13 @@ * * functions.c * Routines to handle functions called from the executor - * Putting this stuff in fmgr makes the postmaster a mess.... * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.33 2000/04/12 17:15:09 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.34 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,7 +23,6 @@ #include "tcop/utility.h" #include "utils/datum.h" -#undef new typedef enum { @@ -39,18 +37,18 @@ typedef struct local_es ExecStatus status; } execution_state; -#define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *)NULL) +#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 execution_state *init_execution_state(FunctionCachePtr fcache); 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 void postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo); +static Datum postquel_execute(execution_state *es, + FunctionCallInfo fcinfo, + FunctionCachePtr fcache, + List *func_tlist); Datum @@ -64,7 +62,6 @@ ProjectAttribute(TupleDesc TD, Var *attrVar = (Var *) tlist->expr; AttrNumber attrno = attrVar->varattno; - val = heap_getattr(tup, attrno, TD, isnullP); if (*isnullP) return (Datum) NULL; @@ -77,8 +74,7 @@ ProjectAttribute(TupleDesc TD, } static execution_state * -init_execution_state(FunctionCachePtr fcache, - char *args[]) +init_execution_state(FunctionCachePtr fcache) { execution_state *newes; execution_state *nextes; @@ -196,13 +192,10 @@ postquel_end(execution_state *es) } static void -postquel_sub_params(execution_state *es, - int nargs, - char *args[], - bool *nullV) +postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo) { - ParamListInfo paramLI; EState *estate; + ParamListInfo paramLI; estate = es->estate; paramLI = estate->es_param_list_info; @@ -211,9 +204,9 @@ postquel_sub_params(execution_state *es, { if (paramLI->kind == PARAM_NUM) { - Assert(paramLI->id <= nargs); - paramLI->value = (Datum) args[(paramLI->id - 1)]; - paramLI->isnull = nullV[(paramLI->id - 1)]; + Assert(paramLI->id <= fcinfo->nargs); + paramLI->value = fcinfo->arg[paramLI->id - 1]; + paramLI->isnull = fcinfo->argnull[paramLI->id - 1]; } paramLI++; } @@ -264,10 +257,9 @@ copy_function_result(FunctionCachePtr fcache, static Datum postquel_execute(execution_state *es, + FunctionCallInfo fcinfo, FunctionCachePtr fcache, - List *fTlist, - char **args, - bool *isNull) + List *func_tlist) { TupleTableSlot *slot; Datum value; @@ -278,8 +270,8 @@ postquel_execute(execution_state *es, * 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); + if (fcinfo->nargs > 0) + postquel_sub_params(es, fcinfo); if (es->status == F_EXEC_START) { @@ -293,7 +285,7 @@ postquel_execute(execution_state *es, { postquel_end(es); es->status = F_EXEC_DONE; - *isNull = true; + fcinfo->isnull = true; /* * If this isn't the last command for the function we have to @@ -315,19 +307,20 @@ postquel_execute(execution_state *es, * logic and code redundancy here. */ resSlot = copy_function_result(fcache, slot); - if (fTlist != NIL) + if (func_tlist != NIL) { - TargetEntry *tle = lfirst(fTlist); + TargetEntry *tle = lfirst(func_tlist); value = ProjectAttribute(resSlot->ttc_tupleDescriptor, tle, resSlot->val, - isNull); + &fcinfo->isnull); } else { - value = (Datum) resSlot; - *isNull = false; + /* XXX is this right? Return whole tuple slot?? */ + value = PointerGetDatum(resSlot); + fcinfo->isnull = false; } /* @@ -353,11 +346,13 @@ postquel_execute(execution_state *es, } Datum -postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone) +postquel_function(FunctionCallInfo fcinfo, + FunctionCachePtr fcache, + List *func_tlist, + bool *isDone) { execution_state *es; Datum result = 0; - FunctionCachePtr fcache = funcNode->func_fcache; CommandId savedId; /* @@ -371,7 +366,7 @@ postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone) es = (execution_state *) fcache->func_state; if (es == NULL) { - es = init_execution_state(fcache, args); + es = init_execution_state(fcache); fcache->func_state = (char *) es; } @@ -388,16 +383,20 @@ postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone) while (es != (execution_state *) NULL) { result = postquel_execute(es, + fcinfo, fcache, - funcNode->func_tlist, - args, - isNull); + func_tlist); if (es->status != F_EXEC_DONE) break; es = es->next; } /* + * Restore outer command ID. + */ + SetScanCommandId(savedId); + + /* * If we've gone through every command in this function, we are done. */ if (es == (execution_state *) NULL) @@ -417,17 +416,15 @@ postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone) * Let caller know we're finished. */ *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. + * the final command. All others shouldn't be returning anything. */ Assert(LAST_POSTQUEL_COMMAND(es)); - *isDone = false; - SetScanCommandId(savedId); + *isDone = false; return result; } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index e2db06f84d1..853fa96e2c3 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -32,7 +32,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.63 2000/04/12 17:15:09 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.64 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -218,8 +218,13 @@ static void advance_transition_functions(AggStatePerAgg peraggstate, Datum newVal, bool isNull) { - Datum args[2]; + FunctionCallInfoData fcinfo; + MemSet(&fcinfo, 0, sizeof(fcinfo)); + + /* + * XXX reconsider isNULL handling here + */ if (OidIsValid(peraggstate->xfn1_oid) && !isNull) { if (peraggstate->noInitValue) @@ -244,28 +249,48 @@ advance_transition_functions(AggStatePerAgg peraggstate, else { /* apply transition function 1 */ - args[0] = peraggstate->value1; - args[1] = newVal; - newVal = (Datum) fmgr_c(&peraggstate->xfn1, - (FmgrValues *) args, - &isNull); - if (!peraggstate->transtype1ByVal) + fcinfo.flinfo = &peraggstate->xfn1; + fcinfo.nargs = 2; + fcinfo.arg[0] = peraggstate->value1; + fcinfo.argnull[0] = peraggstate->value1IsNull; + fcinfo.arg[1] = newVal; + fcinfo.argnull[1] = isNull; + if (fcinfo.flinfo->fn_strict && + (peraggstate->value1IsNull || isNull)) + { + /* don't call a strict function with NULL inputs */ + newVal = (Datum) 0; + fcinfo.isnull = true; + } + else + newVal = FunctionCallInvoke(&fcinfo); + if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull) pfree(peraggstate->value1); peraggstate->value1 = newVal; + peraggstate->value1IsNull = fcinfo.isnull; } } if (OidIsValid(peraggstate->xfn2_oid)) { /* apply transition function 2 */ - args[0] = peraggstate->value2; - isNull = false; /* value2 cannot be null, currently */ - newVal = (Datum) fmgr_c(&peraggstate->xfn2, - (FmgrValues *) args, - &isNull); - if (!peraggstate->transtype2ByVal) + fcinfo.flinfo = &peraggstate->xfn2; + fcinfo.nargs = 1; + fcinfo.arg[0] = peraggstate->value2; + fcinfo.argnull[0] = peraggstate->value2IsNull; + fcinfo.isnull = false; /* must reset after use by xfn1 */ + if (fcinfo.flinfo->fn_strict && peraggstate->value2IsNull) + { + /* don't call a strict function with NULL inputs */ + newVal = (Datum) 0; + fcinfo.isnull = true; + } + else + newVal = FunctionCallInvoke(&fcinfo); + if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull) pfree(peraggstate->value2); peraggstate->value2 = newVal; + peraggstate->value2IsNull = fcinfo.isnull; } } @@ -276,8 +301,10 @@ static void finalize_aggregate(AggStatePerAgg peraggstate, Datum *resultVal, bool *resultIsNull) { - Aggref *aggref = peraggstate->aggref; - char *args[2]; + Aggref *aggref = peraggstate->aggref; + FunctionCallInfoData fcinfo; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); /* * If it's a DISTINCT aggregate, all we've done so far is to stuff the @@ -337,21 +364,41 @@ finalize_aggregate(AggStatePerAgg peraggstate, if (OidIsValid(peraggstate->finalfn_oid) && !peraggstate->noInitValue) { + fcinfo.flinfo = &peraggstate->finalfn; if (peraggstate->finalfn.fn_nargs > 1) { - args[0] = (char *) peraggstate->value1; - args[1] = (char *) peraggstate->value2; + fcinfo.nargs = 2; + fcinfo.arg[0] = peraggstate->value1; + fcinfo.argnull[0] = peraggstate->value1IsNull; + fcinfo.arg[1] = peraggstate->value2; + fcinfo.argnull[1] = peraggstate->value2IsNull; } else if (OidIsValid(peraggstate->xfn1_oid)) - args[0] = (char *) peraggstate->value1; + { + fcinfo.nargs = 1; + fcinfo.arg[0] = peraggstate->value1; + fcinfo.argnull[0] = peraggstate->value1IsNull; + } else if (OidIsValid(peraggstate->xfn2_oid)) - args[0] = (char *) peraggstate->value2; + { + fcinfo.nargs = 1; + fcinfo.arg[0] = peraggstate->value2; + fcinfo.argnull[0] = peraggstate->value2IsNull; + } else elog(ERROR, "ExecAgg: no valid transition functions??"); - *resultIsNull = false; - *resultVal = (Datum) fmgr_c(&peraggstate->finalfn, - (FmgrValues *) args, - resultIsNull); + if (fcinfo.flinfo->fn_strict && + (fcinfo.argnull[0] || fcinfo.argnull[1])) + { + /* don't call a strict function with NULL inputs */ + *resultVal = (Datum) 0; + *resultIsNull = true; + } + else + { + *resultVal = FunctionCallInvoke(&fcinfo); + *resultIsNull = fcinfo.isnull; + } } else if (OidIsValid(peraggstate->xfn1_oid)) { |