aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execQual.c168
-rw-r--r--src/backend/executor/execUtils.c6
-rw-r--r--src/backend/executor/functions.c81
-rw-r--r--src/backend/executor/nodeAgg.c95
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))
{