Commit c1352052 authored by Tom Lane's avatar Tom Lane

Replace the switching function ExecEvalExpr() with a macro that jumps

directly to the appropriate per-node execution function, using a function
pointer stored by ExecInitExpr.  This speeds things up by eliminating one
level of function call.  The function-pointer technique also enables further
small improvements such as only making one-time tests once (and then
changing the function pointer).  Overall this seems to gain about 10%
on evaluation of simple expressions, which isn't earthshaking but seems
a worthwhile gain for a relatively small hack.  Per recent discussion
on pghackers.
parent 2c7e4734
......@@ -8,28 +8,25 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.154 2004/02/03 17:34:02 tgl Exp $
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.155 2004/03/17 01:02:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecEvalExpr - evaluate an expression and return a datum
* ExecEvalExpr - (now a macro) evaluate an expression, return a datum
* ExecEvalExprSwitchContext - same, but switch into eval memory context
* ExecQual - return true/false if qualification is satisfied
* ExecProject - form a new tuple by projecting the given tuple
*
* NOTES
* ExecEvalExpr() and ExecEvalVar() are hotspots. making these faster
* will speed up the entire system. Unfortunately they are currently
* implemented recursively. Eliminating the recursion is bound to
* improve the speed of the executor.
* The more heavily used ExecEvalExpr routines, such as ExecEvalVar(),
* are hotspots. Making these faster will speed up the entire system.
*
* ExecProject() is used to make tuple projections. Rather then
* trying to speed it up, the execution plan should be pre-processed
* to facilitate attribute sharing between nodes wherever possible,
* instead of doing needless copying. -cim 5/31/91
*
*/
#include "postgres.h"
......@@ -50,41 +47,49 @@
/* static function decls */
static Datum ExecEvalArrayRef(ArrayRefExprState *astate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalAggref(AggrefExprState *aggref,
ExprContext *econtext,
bool *isNull);
static Datum ExecEvalArrayRef(ArrayRefExprState *astate,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo,
List *argList, ExprContext *econtext);
static Datum ExecMakeFunctionResultNoSets(FuncExprState *fcache,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);
static Datum ExecEvalParam(Param *expression, ExprContext *econtext,
bool *isNull);
static Datum ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext,
bool *isNull);
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
ExprContext *econtext, bool *isNull);
static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo,
List *argList, ExprContext *econtext);
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
bool *isNull);
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
bool *isNull);
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
bool *isNull);
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalArray(ArrayExprState *astate,
ExprContext *econtext,
bool *isNull);
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
ExprContext *econtext,
bool *isNull);
static Datum ExecEvalNullIf(FuncExprState *nullIfExpr, ExprContext *econtext,
bool *isNull);
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalNullIf(FuncExprState *nullIfExpr,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalNullTest(GenericExprState *nstate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
......@@ -94,11 +99,74 @@ static Datum ExecEvalBooleanTest(GenericExprState *bstate,
static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalCoerceToDomainValue(CoerceToDomainValue *conVal,
ExprContext *econtext, bool *isNull);
static Datum ExecEvalCoerceToDomainValue(ExprState *exprstate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalFieldSelect(GenericExprState *fstate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalRelabelType(GenericExprState *exprstate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
/* ----------------------------------------------------------------
* ExecEvalExpr routines
*
* Recursively evaluate a targetlist or qualification expression.
*
* Each of the following routines having the signature
* Datum ExecEvalFoo(ExprState *expression,
* ExprContext *econtext,
* bool *isNull,
* ExprDoneCond *isDone);
* is responsible for evaluating one type or subtype of ExprState node.
* They are normally called via the ExecEvalExpr macro, which makes use of
* the function pointer set up when the ExprState node was built by
* ExecInitExpr. (In some cases, we change this pointer later to avoid
* re-executing one-time overhead.)
*
* Note: for notational simplicity we declare these functions as taking the
* specific type of ExprState that they work on. This requires casting when
* assigning the function pointer in ExecInitExpr. Be careful that the
* function signature is declared correctly, because the cast suppresses
* automatic checking!
*
*
* All these functions share this calling convention:
*
* Inputs:
* expression: the expression state tree to evaluate
* econtext: evaluation context information
*
* Outputs:
* return value: Datum value of result
* *isNull: set to TRUE if result is NULL (actual return value is
* meaningless if so); set to FALSE if non-null result
* *isDone: set to indicator of set-result status
*
* A caller that can only accept a singleton (non-set) result should pass
* NULL for isDone; if the expression computes a set result then an error
* will be reported via ereport. If the caller does pass an isDone pointer
* then *isDone is set to one of these three states:
* ExprSingleResult singleton result (not a set)
* ExprMultipleResult return value is one element of a set
* ExprEndResult there are no more elements in the set
* When ExprMultipleResult is returned, the caller should invoke
* ExecEvalExpr() repeatedly until ExprEndResult is returned. ExprEndResult
* is returned after the last real set element. For convenience isNull will
* always be set TRUE when ExprEndResult is returned, but this should not be
* taken as indicating a NULL element of the set. Note that these return
* conventions allow us to distinguish among a singleton NULL, a NULL element
* of a set, and an empty set.
*
* The caller should already have switched into the temporary memory
* context econtext->ecxt_per_tuple_memory. The convenience entry point
* ExecEvalExprSwitchContext() is provided for callers who don't prefer to
* do the switch in an outer loop. We do not do the switch in these routines
* because it'd be a waste of cycles during nested expression evaluation.
* ----------------------------------------------------------------
*/
/*----------
......@@ -143,6 +211,11 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
lower;
int *lIndex;
/* Set default values for result flags: non-null, not a set result */
*isNull = false;
if (isDone)
*isDone = ExprSingleResult;
if (arrayRef->refexpr != NULL)
{
array_source = (ArrayType *)
......@@ -174,13 +247,15 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
foreach(elt, astate->refupperindexpr)
{
ExprState *eltstate = (ExprState *) lfirst(elt);
if (i >= MAXDIM)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
i, MAXDIM)));
upper.indx[i++] = DatumGetInt32(ExecEvalExpr((ExprState *) lfirst(elt),
upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate,
econtext,
isNull,
NULL));
......@@ -198,13 +273,15 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
{
foreach(elt, astate->reflowerindexpr)
{
ExprState *eltstate = (ExprState *) lfirst(elt);
if (j >= MAXDIM)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
i, MAXDIM)));
lower.indx[j++] = DatumGetInt32(ExecEvalExpr((ExprState *) lfirst(elt),
lower.indx[j++] = DatumGetInt32(ExecEvalExpr(eltstate,
econtext,
isNull,
NULL));
......@@ -301,8 +378,12 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
* ----------------------------------------------------------------
*/
static Datum
ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, bool *isNull)
ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
if (isDone)
*isDone = ExprSingleResult;
if (econtext->ecxt_aggvalues == NULL) /* safety check */
elog(ERROR, "no aggregates in this expression context");
......@@ -317,14 +398,19 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, bool *isNull)
* variable with respect to given expression context.
* ---------------------------------------------------------------- */
static Datum
ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
Var *variable = (Var *) exprstate->expr;
Datum result;
TupleTableSlot *slot;
AttrNumber attnum;
HeapTuple heapTuple;
TupleDesc tuple_type;
if (isDone)
*isDone = ExprSingleResult;
/*
* get the slot we want
*/
......@@ -415,6 +501,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);
ExecSetSlotDescriptor(tempSlot, tuple_type, false);
MemoryContextSwitchTo(oldContext);
*isNull = false;
return PointerGetDatum(tempSlot);
}
......@@ -427,6 +514,29 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
return result;
}
/* ----------------------------------------------------------------
* ExecEvalConst
*
* Returns the value of a constant.
*
* Note that for pass-by-ref datatypes, we return a pointer to the
* actual constant node. This is one of the reasons why functions
* must treat their input arguments as read-only.
* ----------------------------------------------------------------
*/
static Datum
ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
Const *con = (Const *) exprstate->expr;
if (isDone)
*isDone = ExprSingleResult;
*isNull = con->constisnull;
return con->constvalue;
}
/* ----------------------------------------------------------------
* ExecEvalParam
*
......@@ -442,11 +552,16 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
* ----------------------------------------------------------------
*/
static Datum
ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
Param *expression = (Param *) exprstate->expr;
int thisParamKind = expression->paramkind;
AttrNumber thisParamId = expression->paramid;
if (isDone)
*isDone = ExprSingleResult;
if (thisParamKind == PARAM_EXEC)
{
/*
......@@ -673,9 +788,10 @@ ExecEvalFuncArgs(FunctionCallInfo fcinfo,
i = 0;
foreach(arg, argList)
{
ExprState *argstate = (ExprState *) lfirst(arg);
ExprDoneCond thisArgIsDone;
fcinfo->arg[i] = ExecEvalExpr((ExprState *) lfirst(arg),
fcinfo->arg[i] = ExecEvalExpr(argstate,
econtext,
&fcinfo->argnull[i],
&thisArgIsDone);
......@@ -889,6 +1005,17 @@ ExecMakeFunctionResult(FuncExprState *fcache,
/*
* Non-set case: much easier.
*
* We change the ExprState function pointer to use the simpler
* ExecMakeFunctionResultNoSets on subsequent calls. This amounts
* to assuming that no argument can return a set if it didn't do so
* the first time.
*/
fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResultNoSets;
if (isDone)
*isDone = ExprSingleResult;
/*
* If function is strict, and there are any NULL arguments, skip
* calling the function and return NULL.
*/
......@@ -911,6 +1038,71 @@ ExecMakeFunctionResult(FuncExprState *fcache,
return result;
}
/*
* ExecMakeFunctionResultNoSets
*
* Simplified version of ExecMakeFunctionResult that can only handle
* non-set cases. Hand-tuned for speed.
*/
static Datum
ExecMakeFunctionResultNoSets(FuncExprState *fcache,
ExprContext *econtext,
bool *isNull,
ExprDoneCond *isDone)
{
List *arg;
Datum result;
FunctionCallInfoData fcinfo;
int i;
if (isDone)
*isDone = ExprSingleResult;
MemSet(&fcinfo, 0, sizeof(fcinfo));
fcinfo.flinfo = &(fcache->func);
/* inlined, simplified version of ExecEvalFuncArgs */
i = 0;
foreach(arg, fcache->args)
{
ExprState *argstate = (ExprState *) lfirst(arg);
ExprDoneCond thisArgIsDone;
fcinfo.arg[i] = ExecEvalExpr(argstate,
econtext,
&fcinfo.argnull[i],
&thisArgIsDone);
if (thisArgIsDone != ExprSingleResult)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
i++;
}
fcinfo.nargs = i;
/*
* If function is strict, and there are any NULL arguments, skip
* calling the function and return NULL.
*/
if (fcache->func.fn_strict)
{
while (--i >= 0)
{
if (fcinfo.argnull[i])
{
*isNull = true;
return (Datum) 0;
}
}
}
/* fcinfo.isnull = false; */ /* handled by MemSet */
result = FunctionCallInvoke(&fcinfo);
*isNull = fcinfo.isnull;
return result;
}
/*
* ExecMakeTableFunctionResult
......@@ -1201,15 +1393,14 @@ ExecEvalFunc(FuncExprState *fcache,
bool *isNull,
ExprDoneCond *isDone)
{
/*
* Initialize function cache if first time through
*/
if (fcache->func.fn_oid == InvalidOid)
{
/* This is called only the first time through */
FuncExpr *func = (FuncExpr *) fcache->xprstate.expr;
/* Initialize function lookup info */
init_fcache(func->funcid, fcache, econtext->ecxt_per_query_memory);
}
/* Go directly to ExecMakeFunctionResult on subsequent uses */
fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult;
return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);
}
......@@ -1224,15 +1415,14 @@ ExecEvalOper(FuncExprState *fcache,
bool *isNull,
ExprDoneCond *isDone)
{
/*
* Initialize function cache if first time through
*/
if (fcache->func.fn_oid == InvalidOid)
{
/* This is called only the first time through */
OpExpr *op = (OpExpr *) fcache->xprstate.expr;
/* Initialize function lookup info */
init_fcache(op->opfuncid, fcache, econtext->ecxt_per_query_memory);
}
/* Go directly to ExecMakeFunctionResult on subsequent uses */
fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult;
return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);
}
......@@ -1251,13 +1441,19 @@ ExecEvalOper(FuncExprState *fcache,
static Datum
ExecEvalDistinct(FuncExprState *fcache,
ExprContext *econtext,
bool *isNull)
bool *isNull,
ExprDoneCond *isDone)
{
Datum result;
FunctionCallInfoData fcinfo;
ExprDoneCond argDone;
List *argList;
/* Set default values for result flags: non-null, not a set result */
*isNull = false;
if (isDone)
*isDone = ExprSingleResult;
/*
* Initialize function cache if first time through
*/
......@@ -1316,7 +1512,8 @@ ExecEvalDistinct(FuncExprState *fcache,
*/
static Datum
ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
ExprContext *econtext, bool *isNull)
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) sstate->fxprstate.xprstate.expr;
bool useOr = opexpr->useOr;
......@@ -1332,6 +1529,11 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
char typalign;
char *s;
/* Set default values for result flags: non-null, not a set result */
*isNull = false;
if (isDone)
*isDone = ExprSingleResult;
/*
* Initialize function cache if first time through
*/
......@@ -1468,12 +1670,14 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
* ----------------------------------------------------------------
*/
static Datum
ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, bool *isNull)
ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
ExprState *clause;
ExprState *clause = lfirst(notclause->args);
Datum expr_value;
clause = lfirst(notclause->args);
if (isDone)
*isDone = ExprSingleResult;
expr_value = ExecEvalExpr(clause, econtext, isNull, NULL);
......@@ -1496,14 +1700,16 @@ ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, bool *isNull)
* ----------------------------------------------------------------
*/
static Datum
ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, bool *isNull)
ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
List *clauses;
List *clauses = orExpr->args;
List *clause;
bool AnyNull;
Datum clause_value;
clauses = orExpr->args;
if (isDone)
*isDone = ExprSingleResult;
AnyNull = false;
/*
......@@ -1522,8 +1728,10 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, bool *isNull)
*/
foreach(clause, clauses)
{
clause_value = ExecEvalExpr((ExprState *) lfirst(clause),
econtext, isNull, NULL);
ExprState *clausestate = (ExprState *) lfirst(clause);
Datum clause_value;
clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL);
/*
* if we have a non-null true result, then return it.
......@@ -1544,14 +1752,16 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, bool *isNull)
* ----------------------------------------------------------------
*/
static Datum
ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, bool *isNull)
ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
List *clauses;
List *clauses = andExpr->args;
List *clause;
bool AnyNull;
Datum clause_value;
clauses = andExpr->args;
if (isDone)
*isDone = ExprSingleResult;
AnyNull = false;
/*
......@@ -1564,8 +1774,10 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, bool *isNull)
*/
foreach(clause, clauses)
{
clause_value = ExecEvalExpr((ExprState *) lfirst(clause),
econtext, isNull, NULL);
ExprState *clausestate = (ExprState *) lfirst(clause);
Datum clause_value;
clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL);
/*
* if we have a non-null false result, then return it.
......@@ -1595,11 +1807,11 @@ static Datum
ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
List *clauses;
List *clauses = caseExpr->args;
List *clause;
Datum clause_value;
clauses = caseExpr->args;
if (isDone)
*isDone = ExprSingleResult;
/*
* we evaluate each of the WHEN clauses in turn, as soon as one is
......@@ -1609,6 +1821,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
foreach(clause, clauses)
{
CaseWhenState *wclause = lfirst(clause);
Datum clause_value;
clause_value = ExecEvalExpr(wclause->expr,
econtext,
......@@ -1651,7 +1864,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
*/
static Datum
ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
bool *isNull)
bool *isNull, ExprDoneCond *isDone)
{
ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr;
ArrayType *result;
......@@ -1661,6 +1874,11 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
int dims[MAXDIM];
int lbs[MAXDIM];
/* Set default values for result flags: non-null, not a set result */
*isNull = false;
if (isDone)
*isDone = ExprSingleResult;
if (!arrayExpr->multidims)
{
/* Elements are presumably of scalar type */
......@@ -1823,10 +2041,13 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
*/
static Datum
ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext,
bool *isNull)
bool *isNull, ExprDoneCond *isDone)
{
List *arg;
if (isDone)
*isDone = ExprSingleResult;
/* Simply loop through until something NOT NULL is found */
foreach(arg, coalesceExpr->args)
{
......@@ -1852,33 +2073,37 @@ ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext,
* ----------------------------------------------------------------
*/
static Datum
ExecEvalNullIf(FuncExprState *fcache, ExprContext *econtext,
bool *isNull)
ExecEvalNullIf(FuncExprState *nullIfExpr,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
Datum result;
FunctionCallInfoData fcinfo;
ExprDoneCond argDone;
List *argList;
if (isDone)
*isDone = ExprSingleResult;
/*
* Initialize function cache if first time through
*/
if (fcache->func.fn_oid == InvalidOid)
if (nullIfExpr->func.fn_oid == InvalidOid)
{
NullIfExpr *op = (NullIfExpr *) fcache->xprstate.expr;
NullIfExpr *op = (NullIfExpr *) nullIfExpr->xprstate.expr;
init_fcache(op->opfuncid, fcache, econtext->ecxt_per_query_memory);
Assert(!fcache->func.fn_retset);
init_fcache(op->opfuncid, nullIfExpr, econtext->ecxt_per_query_memory);
Assert(!nullIfExpr->func.fn_retset);
}
/*
* extract info from fcache
* extract info from nullIfExpr
*/
argList = fcache->args;
argList = nullIfExpr->args;
/* Need to prep callinfo structure */
MemSet(&fcinfo, 0, sizeof(fcinfo));
fcinfo.flinfo = &(fcache->func);
fcinfo.flinfo = &(nullIfExpr->func);
argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext);
if (argDone != ExprSingleResult)
ereport(ERROR,
......@@ -2119,9 +2344,12 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
* Return the value stored by CoerceToDomain.
*/
static Datum
ExecEvalCoerceToDomainValue(CoerceToDomainValue *conVal,
ExprContext *econtext, bool *isNull)
ExecEvalCoerceToDomainValue(ExprState *exprstate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
if (isDone)
*isDone = ExprSingleResult;
*isNull = econtext->domainValue_isNull;
return econtext->domainValue_datum;
}
......@@ -2158,210 +2386,24 @@ ExecEvalFieldSelect(GenericExprState *fstate,
}
/* ----------------------------------------------------------------
* ExecEvalExpr
*
* Recursively evaluate a targetlist or qualification expression.
*
* Inputs:
* expression: the expression state tree to evaluate
* econtext: evaluation context information
*
* Outputs:
* return value: Datum value of result
* *isNull: set to TRUE if result is NULL (actual return value is
* meaningless if so); set to FALSE if non-null result
* *isDone: set to indicator of set-result status
* ExecEvalRelabelType
*
* A caller that can only accept a singleton (non-set) result should pass
* NULL for isDone; if the expression computes a set result then an error
* will be reported via ereport. If the caller does pass an isDone pointer
* then *isDone is set to one of these three states:
* ExprSingleResult singleton result (not a set)
* ExprMultipleResult return value is one element of a set
* ExprEndResult there are no more elements in the set
* When ExprMultipleResult is returned, the caller should invoke
* ExecEvalExpr() repeatedly until ExprEndResult is returned. ExprEndResult
* is returned after the last real set element. For convenience isNull will
* always be set TRUE when ExprEndResult is returned, but this should not be
* taken as indicating a NULL element of the set. Note that these return
* conventions allow us to distinguish among a singleton NULL, a NULL element
* of a set, and an empty set.
*
* The caller should already have switched into the temporary memory
* context econtext->ecxt_per_tuple_memory. The convenience entry point
* ExecEvalExprSwitchContext() is provided for callers who don't prefer to
* do the switch in an outer loop. We do not do the switch here because
* it'd be a waste of cycles during recursive entries to ExecEvalExpr().
*
* This routine is an inner loop routine and must be as fast as possible.
* Evaluate a RelabelType node.
* ----------------------------------------------------------------
*/
Datum
ExecEvalExpr(ExprState *expression,
static Datum
ExecEvalRelabelType(GenericExprState *exprstate,
ExprContext *econtext,
bool *isNull,
ExprDoneCond *isDone)
bool *isNull, ExprDoneCond *isDone)
{
Datum retDatum;
Expr *expr;
/* Set default values for result flags: non-null, not a set result */
*isNull = false;
if (isDone)
*isDone = ExprSingleResult;
/* Is this still necessary? Doubtful... */
if (expression == NULL)
{
*isNull = true;
return (Datum) 0;
}
/*
* here we dispatch the work to the appropriate type of function given
* the type of our expression.
*/
expr = expression->expr;
switch (nodeTag(expr))
{
case T_Var:
retDatum = ExecEvalVar((Var *) expr, econtext, isNull);
break;
case T_Const:
{
Const *con = (Const *) expr;
retDatum = con->constvalue;
*isNull = con->constisnull;
break;
}
case T_Param:
retDatum = ExecEvalParam((Param *) expr, econtext, isNull);
break;
case T_Aggref:
retDatum = ExecEvalAggref((AggrefExprState *) expression,
econtext,
isNull);
break;
case T_ArrayRef:
retDatum = ExecEvalArrayRef((ArrayRefExprState *) expression,
econtext,
isNull,
isDone);
break;
case T_FuncExpr:
retDatum = ExecEvalFunc((FuncExprState *) expression, econtext,
isNull, isDone);
break;
case T_OpExpr:
retDatum = ExecEvalOper((FuncExprState *) expression, econtext,
isNull, isDone);
break;
case T_DistinctExpr:
retDatum = ExecEvalDistinct((FuncExprState *) expression, econtext,
isNull);
break;
case T_ScalarArrayOpExpr:
retDatum = ExecEvalScalarArrayOp((ScalarArrayOpExprState *) expression,
econtext, isNull);
break;
case T_BoolExpr:
{
BoolExprState *state = (BoolExprState *) expression;
switch (((BoolExpr *) expr)->boolop)
{
case AND_EXPR:
retDatum = ExecEvalAnd(state, econtext, isNull);
break;
case OR_EXPR:
retDatum = ExecEvalOr(state, econtext, isNull);
break;
case NOT_EXPR:
retDatum = ExecEvalNot(state, econtext, isNull);
break;
default:
elog(ERROR, "unrecognized boolop: %d",
(int) ((BoolExpr *) expr)->boolop);
retDatum = 0; /* keep compiler quiet */
break;
}
break;
}
case T_SubPlan:
retDatum = ExecSubPlan((SubPlanState *) expression,
econtext,
isNull);
break;
case T_FieldSelect:
retDatum = ExecEvalFieldSelect((GenericExprState *) expression,
econtext,
isNull,
isDone);
break;
case T_RelabelType:
retDatum = ExecEvalExpr(((GenericExprState *) expression)->arg,
econtext,
isNull,
isDone);
break;
case T_CaseExpr:
retDatum = ExecEvalCase((CaseExprState *) expression,
econtext,
isNull,
isDone);
break;
case T_ArrayExpr:
retDatum = ExecEvalArray((ArrayExprState *) expression,
econtext,
isNull);
break;
case T_CoalesceExpr:
retDatum = ExecEvalCoalesce((CoalesceExprState *) expression,
econtext,
isNull);
break;
case T_NullIfExpr:
retDatum = ExecEvalNullIf((FuncExprState *) expression,
econtext,
isNull);
break;
case T_NullTest:
retDatum = ExecEvalNullTest((GenericExprState *) expression,
econtext,
isNull,
isDone);
break;
case T_BooleanTest:
retDatum = ExecEvalBooleanTest((GenericExprState *) expression,
econtext,
isNull,
isDone);
break;
case T_CoerceToDomain:
retDatum = ExecEvalCoerceToDomain((CoerceToDomainState *) expression,
econtext,
isNull,
isDone);
break;
case T_CoerceToDomainValue:
retDatum = ExecEvalCoerceToDomainValue((CoerceToDomainValue *) expr,
econtext,
isNull);
break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(expression));
retDatum = 0; /* keep compiler quiet */
break;
}
return retDatum;
} /* ExecEvalExpr() */
return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone);
}
/*
* Same as above, but get into the right allocation context explicitly.
* ExecEvalExprSwitchContext
*
* Same as ExecEvalExpr, but get into the right allocation context explicitly.
*/
Datum
ExecEvalExprSwitchContext(ExprState *expression,
......@@ -2421,17 +2463,27 @@ ExecInitExpr(Expr *node, PlanState *parent)
switch (nodeTag(node))
{
case T_Var:
state = (ExprState *) makeNode(ExprState);
state->evalfunc = ExecEvalVar;
break;
case T_Const:
state = (ExprState *) makeNode(ExprState);
state->evalfunc = ExecEvalConst;
break;
case T_Param:
state = (ExprState *) makeNode(ExprState);
state->evalfunc = ExecEvalParam;
break;
case T_CoerceToDomainValue:
/* No special setup needed for these node types */
state = (ExprState *) makeNode(ExprState);
state->evalfunc = ExecEvalCoerceToDomainValue;
break;
case T_Aggref:
{
Aggref *aggref = (Aggref *) node;
AggrefExprState *astate = makeNode(AggrefExprState);
astate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalAggref;
if (parent && IsA(parent, AggState))
{
AggState *aggstate = (AggState *) parent;
......@@ -2466,6 +2518,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
ArrayRef *aref = (ArrayRef *) node;
ArrayRefExprState *astate = makeNode(ArrayRefExprState);
astate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalArrayRef;
astate->refupperindexpr = (List *)
ExecInitExpr((Expr *) aref->refupperindexpr, parent);
astate->reflowerindexpr = (List *)
......@@ -2487,6 +2540,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
FuncExpr *funcexpr = (FuncExpr *) node;
FuncExprState *fstate = makeNode(FuncExprState);
fstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalFunc;
fstate->args = (List *)
ExecInitExpr((Expr *) funcexpr->args, parent);
fstate->func.fn_oid = InvalidOid; /* not initialized */
......@@ -2498,6 +2552,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
OpExpr *opexpr = (OpExpr *) node;
FuncExprState *fstate = makeNode(FuncExprState);
fstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalOper;
fstate->args = (List *)
ExecInitExpr((Expr *) opexpr->args, parent);
fstate->func.fn_oid = InvalidOid; /* not initialized */
......@@ -2509,6 +2564,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
DistinctExpr *distinctexpr = (DistinctExpr *) node;
FuncExprState *fstate = makeNode(FuncExprState);
fstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalDistinct;
fstate->args = (List *)
ExecInitExpr((Expr *) distinctexpr->args, parent);
fstate->func.fn_oid = InvalidOid; /* not initialized */
......@@ -2520,6 +2576,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
ScalarArrayOpExprState *sstate = makeNode(ScalarArrayOpExprState);
sstate->fxprstate.xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalScalarArrayOp;
sstate->fxprstate.args = (List *)
ExecInitExpr((Expr *) opexpr->args, parent);
sstate->fxprstate.func.fn_oid = InvalidOid; /* not initialized */
......@@ -2532,6 +2589,22 @@ ExecInitExpr(Expr *node, PlanState *parent)
BoolExpr *boolexpr = (BoolExpr *) node;
BoolExprState *bstate = makeNode(BoolExprState);
switch (boolexpr->boolop)
{
case AND_EXPR:
bstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalAnd;
break;
case OR_EXPR:
bstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalOr;
break;
case NOT_EXPR:
bstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalNot;
break;
default:
elog(ERROR, "unrecognized boolop: %d",
(int) boolexpr->boolop);
break;
}
bstate->args = (List *)
ExecInitExpr((Expr *) boolexpr->args, parent);
state = (ExprState *) bstate;
......@@ -2543,6 +2616,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
SubPlan *subplan = (SubPlan *) node;
SubPlanState *sstate = makeNode(SubPlanState);
sstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecSubPlan;
if (!parent)
elog(ERROR, "SubPlan found with no parent plan");
......@@ -2568,6 +2643,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
FieldSelect *fselect = (FieldSelect *) node;
GenericExprState *gstate = makeNode(GenericExprState);
gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalFieldSelect;
gstate->arg = ExecInitExpr(fselect->arg, parent);
state = (ExprState *) gstate;
}
......@@ -2577,6 +2653,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
RelabelType *relabel = (RelabelType *) node;
GenericExprState *gstate = makeNode(GenericExprState);
gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalRelabelType;
gstate->arg = ExecInitExpr(relabel->arg, parent);
state = (ExprState *) gstate;
}
......@@ -2588,6 +2665,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
FastList outlist;
List *inlist;
cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCase;
FastListInit(&outlist);
foreach(inlist, caseexpr->args)
{
......@@ -2595,6 +2673,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
CaseWhenState *wstate = makeNode(CaseWhenState);
Assert(IsA(when, CaseWhen));
wstate->xprstate.evalfunc = NULL; /* not used */
wstate->xprstate.expr = (Expr *) when;
wstate->expr = ExecInitExpr(when->expr, parent);
wstate->result = ExecInitExpr(when->result, parent);
......@@ -2614,6 +2693,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
FastList outlist;
List *inlist;
astate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalArray;
FastListInit(&outlist);
foreach(inlist, arrayexpr->elements)
{
......@@ -2639,6 +2719,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
FastList outlist;
List *inlist;
cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCoalesce;
FastListInit(&outlist);
foreach(inlist, coalesceexpr->args)
{
......@@ -2657,6 +2738,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
NullIfExpr *nullifexpr = (NullIfExpr *) node;
FuncExprState *fstate = makeNode(FuncExprState);
fstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalNullIf;
fstate->args = (List *)
ExecInitExpr((Expr *) nullifexpr->args, parent);
fstate->func.fn_oid = InvalidOid; /* not initialized */
......@@ -2668,6 +2750,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
NullTest *ntest = (NullTest *) node;
GenericExprState *gstate = makeNode(GenericExprState);
gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalNullTest;
gstate->arg = ExecInitExpr(ntest->arg, parent);
state = (ExprState *) gstate;
}
......@@ -2677,6 +2760,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
BooleanTest *btest = (BooleanTest *) node;
GenericExprState *gstate = makeNode(GenericExprState);
gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalBooleanTest;
gstate->arg = ExecInitExpr(btest->arg, parent);
state = (ExprState *) gstate;
}
......@@ -2686,6 +2770,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
CoerceToDomain *ctest = (CoerceToDomain *) node;
CoerceToDomainState *cstate = makeNode(CoerceToDomainState);
cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCoerceToDomain;
cstate->arg = ExecInitExpr(ctest->arg, parent);
cstate->constraints = GetDomainConstraints(ctest->resulttype);
state = (ExprState *) cstate;
......@@ -2696,6 +2781,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
TargetEntry *tle = (TargetEntry *) node;
GenericExprState *gstate = makeNode(GenericExprState);
gstate->xprstate.evalfunc = NULL; /* not used */
gstate->arg = ExecInitExpr(tle->expr, parent);
state = (ExprState *) gstate;
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.82 2004/02/03 17:34:02 tgl Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.83 2004/03/17 01:02:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -532,6 +532,7 @@ ExecHashGetBucket(HashJoinTable hashtable,
foreach(hk, hashkeys)
{
ExprState *keyexpr = (ExprState *) lfirst(hk);
Datum keyval;
bool isNull;
......@@ -541,8 +542,7 @@ ExecHashGetBucket(HashJoinTable hashtable,
/*
* Get the join attribute value of the tuple
*/
keyval = ExecEvalExpr((ExprState *) lfirst(hk),
econtext, &isNull, NULL);
keyval = ExecEvalExpr(keyexpr, econtext, &isNull, NULL);
/*
* Compute the hash function
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.63 2003/11/29 19:51:48 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.64 2004/03/17 01:02:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -191,6 +191,8 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
eqclause = eqQual;
foreach(clause, compareQual)
{
ExprState *clauseexpr = (ExprState *) lfirst(clause);
ExprState *eqclauseexpr = (ExprState *) lfirst(eqclause);
Datum const_value;
bool isNull;
......@@ -200,10 +202,7 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
*
* A NULL result is considered false.
*/
const_value = ExecEvalExpr((ExprState *) lfirst(clause),
econtext,
&isNull,
NULL);
const_value = ExecEvalExpr(clauseexpr, econtext, &isNull, NULL);
if (DatumGetBool(const_value) && !isNull)
{
......@@ -217,10 +216,7 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
* key1 = key2 so we move on to the next pair of keys.
*-----------
*/
const_value = ExecEvalExpr((ExprState *) lfirst(eqclause),
econtext,
&isNull,
NULL);
const_value = ExecEvalExpr(eqclauseexpr, econtext, &isNull, NULL);
if (!DatumGetBool(const_value) || isNull)
break; /* return false */
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.60 2004/01/14 23:01:54 tgl Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.61 2004/03/17 01:02:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -47,10 +47,16 @@ static bool tupleAllNulls(HeapTuple tuple);
Datum
ExecSubPlan(SubPlanState *node,
ExprContext *econtext,
bool *isNull)
bool *isNull,
ExprDoneCond *isDone)
{
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
/* Set default values for result flags: non-null, not a set result */
*isNull = false;
if (isDone)
*isDone = ExprSingleResult;
if (subplan->setParam != NIL)
elog(ERROR, "cannot set parent params from subquery");
......@@ -819,6 +825,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
expr);
tlestate = makeNode(GenericExprState);
tlestate->xprstate.expr = (Expr *) tle;
tlestate->xprstate.evalfunc = NULL;
tlestate->arg = exstate;
lefttlist = lappend(lefttlist, tlestate);
leftptlist = lappend(leftptlist, tle);
......@@ -834,6 +841,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
expr);
tlestate = makeNode(GenericExprState);
tlestate->xprstate.expr = (Expr *) tle;
tlestate->xprstate.evalfunc = NULL;
tlestate->arg = exstate;
righttlist = lappend(righttlist, tlestate);
rightptlist = lappend(rightptlist, tle);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.107 2004/03/02 18:56:15 tgl Exp $
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.108 2004/03/17 01:02:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -17,17 +17,26 @@
#include "executor/execdesc.h"
/* ----------------
/*
* TupIsNull
*
* This is used mainly to detect when there are no more
* tuples to process.
* ----------------
*/
/* return: true if tuple in slot is NULL, slot is slot to test */
#define TupIsNull(slot) \
((slot) == NULL || (slot)->val == NULL)
/*
* ExecEvalExpr was formerly a function containing a switch statement;
* now it's just a macro invoking the function pointed to by an ExprState
* node. Beware of double evaluation of the ExprState argument!
*/
#define ExecEvalExpr(expr, econtext, isNull, isDone) \
((*(expr)->evalfunc) (expr, econtext, isNull, isDone))
/*
* prototypes from functions in execAmi.c
*/
......@@ -125,8 +134,6 @@ extern Tuplestorestate *ExecMakeTableFunctionResult(ExprState *funcexpr,
ExprContext *econtext,
TupleDesc expectedDesc,
TupleDesc *returnDesc);
extern Datum ExecEvalExpr(ExprState *expression, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/executor/nodeSubplan.h,v 1.19 2003/11/29 22:41:01 pgsql Exp $
* $PostgreSQL: pgsql/src/include/executor/nodeSubplan.h,v 1.20 2004/03/17 01:02:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -19,7 +19,8 @@
extern void ExecInitSubPlan(SubPlanState *node, EState *estate);
extern Datum ExecSubPlan(SubPlanState *node,
ExprContext *econtext,
bool *isNull);
bool *isNull,
ExprDoneCond *isDone);
extern void ExecEndSubPlan(SubPlanState *node);
extern void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.112 2004/02/28 19:46:06 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.113 2004/03/17 01:02:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -390,13 +390,25 @@ typedef HASH_SEQ_STATUS TupleHashIterator;
*
* It can also be instantiated directly for leaf Expr nodes that need no
* local run-time state (such as Var, Const, or Param).
*
* To save on dispatch overhead, each ExprState node contains a function
* pointer to the routine to execute to evaluate the node.
* ----------------
*/
typedef struct ExprState
typedef struct ExprState ExprState;
typedef Datum (*ExprStateEvalFunc) (ExprState *expression,
ExprContext *econtext,
bool *isNull,
ExprDoneCond *isDone);
struct ExprState
{
NodeTag type;
Expr *expr; /* associated Expr node */
} ExprState;
ExprStateEvalFunc evalfunc; /* routine to run to execute node */
};
/* ----------------
* GenericExprState node
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment