mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
First round of changes for new fmgr interface. fmgr itself and the
key call sites are changed, but most called functions are still oldstyle. An exception is that the PL managers are updated (so, for example, NULL handling now behaves as expected in plperl and plpgsql functions). NOTE initdb is forced due to added column in pg_proc.
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,15 +383,19 @@ 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.
|
||||
*/
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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))
|
||||
{
|
||||
|
Reference in New Issue
Block a user