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 @@ ...@@ -8,28 +8,25 @@
* *
* *
* IDENTIFICATION * 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 * 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 * ExecEvalExprSwitchContext - same, but switch into eval memory context
* ExecQual - return true/false if qualification is satisfied * ExecQual - return true/false if qualification is satisfied
* ExecProject - form a new tuple by projecting the given tuple * ExecProject - form a new tuple by projecting the given tuple
* *
* NOTES * NOTES
* ExecEvalExpr() and ExecEvalVar() are hotspots. making these faster * The more heavily used ExecEvalExpr routines, such as ExecEvalVar(),
* will speed up the entire system. Unfortunately they are currently * are hotspots. Making these faster will speed up the entire system.
* implemented recursively. Eliminating the recursion is bound to
* improve the speed of the executor.
* *
* ExecProject() is used to make tuple projections. Rather then * ExecProject() is used to make tuple projections. Rather then
* trying to speed it up, the execution plan should be pre-processed * trying to speed it up, the execution plan should be pre-processed
* to facilitate attribute sharing between nodes wherever possible, * to facilitate attribute sharing between nodes wherever possible,
* instead of doing needless copying. -cim 5/31/91 * instead of doing needless copying. -cim 5/31/91
*
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -50,41 +47,49 @@ ...@@ -50,41 +47,49 @@
/* static function decls */ /* static function decls */
static Datum ExecEvalAggref(AggrefExprState *aggref,
ExprContext *econtext,
bool *isNull);
static Datum ExecEvalArrayRef(ArrayRefExprState *astate, static Datum ExecEvalArrayRef(ArrayRefExprState *astate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull); static Datum ExecEvalAggref(AggrefExprState *aggref,
static Datum ExecEvalParam(Param *expression, ExprContext *econtext, ExprContext *econtext,
bool *isNull); 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 ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext, static Datum ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext, static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext, static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext,
bool *isNull); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, static Datum ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
ExprContext *econtext, bool *isNull); ExprContext *econtext,
static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo, bool *isNull, ExprDoneCond *isDone);
List *argList, ExprContext *econtext);
static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
bool *isNull); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, static Datum ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext,
bool *isNull); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
bool *isNull); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalArray(ArrayExprState *astate, static Datum ExecEvalArray(ArrayExprState *astate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr, static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
ExprContext *econtext, ExprContext *econtext,
bool *isNull); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalNullIf(FuncExprState *nullIfExpr, ExprContext *econtext, static Datum ExecEvalNullIf(FuncExprState *nullIfExpr,
bool *isNull); ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalNullTest(GenericExprState *nstate, static Datum ExecEvalNullTest(GenericExprState *nstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
...@@ -94,11 +99,74 @@ static Datum ExecEvalBooleanTest(GenericExprState *bstate, ...@@ -94,11 +99,74 @@ static Datum ExecEvalBooleanTest(GenericExprState *bstate,
static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate, static Datum ExecEvalCoerceToDomain(CoerceToDomainState *cstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalCoerceToDomainValue(CoerceToDomainValue *conVal, static Datum ExecEvalCoerceToDomainValue(ExprState *exprstate,
ExprContext *econtext, bool *isNull); ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalFieldSelect(GenericExprState *fstate, static Datum ExecEvalFieldSelect(GenericExprState *fstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); 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, ...@@ -143,6 +211,11 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
lower; lower;
int *lIndex; int *lIndex;
/* Set default values for result flags: non-null, not a set result */
*isNull = false;
if (isDone)
*isDone = ExprSingleResult;
if (arrayRef->refexpr != NULL) if (arrayRef->refexpr != NULL)
{ {
array_source = (ArrayType *) array_source = (ArrayType *)
...@@ -174,13 +247,15 @@ ExecEvalArrayRef(ArrayRefExprState *astate, ...@@ -174,13 +247,15 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
foreach(elt, astate->refupperindexpr) foreach(elt, astate->refupperindexpr)
{ {
ExprState *eltstate = (ExprState *) lfirst(elt);
if (i >= MAXDIM) if (i >= MAXDIM)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
i, MAXDIM))); i, MAXDIM)));
upper.indx[i++] = DatumGetInt32(ExecEvalExpr((ExprState *) lfirst(elt), upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate,
econtext, econtext,
isNull, isNull,
NULL)); NULL));
...@@ -198,13 +273,15 @@ ExecEvalArrayRef(ArrayRefExprState *astate, ...@@ -198,13 +273,15 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
{ {
foreach(elt, astate->reflowerindexpr) foreach(elt, astate->reflowerindexpr)
{ {
ExprState *eltstate = (ExprState *) lfirst(elt);
if (j >= MAXDIM) if (j >= MAXDIM)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
i, MAXDIM))); i, MAXDIM)));
lower.indx[j++] = DatumGetInt32(ExecEvalExpr((ExprState *) lfirst(elt), lower.indx[j++] = DatumGetInt32(ExecEvalExpr(eltstate,
econtext, econtext,
isNull, isNull,
NULL)); NULL));
...@@ -301,8 +378,12 @@ ExecEvalArrayRef(ArrayRefExprState *astate, ...@@ -301,8 +378,12 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static Datum 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 */ if (econtext->ecxt_aggvalues == NULL) /* safety check */
elog(ERROR, "no aggregates in this expression context"); elog(ERROR, "no aggregates in this expression context");
...@@ -317,14 +398,19 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, bool *isNull) ...@@ -317,14 +398,19 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, bool *isNull)
* variable with respect to given expression context. * variable with respect to given expression context.
* ---------------------------------------------------------------- */ * ---------------------------------------------------------------- */
static Datum 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; Datum result;
TupleTableSlot *slot; TupleTableSlot *slot;
AttrNumber attnum; AttrNumber attnum;
HeapTuple heapTuple; HeapTuple heapTuple;
TupleDesc tuple_type; TupleDesc tuple_type;
if (isDone)
*isDone = ExprSingleResult;
/* /*
* get the slot we want * get the slot we want
*/ */
...@@ -415,6 +501,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull) ...@@ -415,6 +501,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
ExecStoreTuple(tup, tempSlot, InvalidBuffer, true); ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);
ExecSetSlotDescriptor(tempSlot, tuple_type, false); ExecSetSlotDescriptor(tempSlot, tuple_type, false);
MemoryContextSwitchTo(oldContext); MemoryContextSwitchTo(oldContext);
*isNull = false;
return PointerGetDatum(tempSlot); return PointerGetDatum(tempSlot);
} }
...@@ -427,6 +514,29 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull) ...@@ -427,6 +514,29 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
return result; 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 * ExecEvalParam
* *
...@@ -442,11 +552,16 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull) ...@@ -442,11 +552,16 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static Datum 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; int thisParamKind = expression->paramkind;
AttrNumber thisParamId = expression->paramid; AttrNumber thisParamId = expression->paramid;
if (isDone)
*isDone = ExprSingleResult;
if (thisParamKind == PARAM_EXEC) if (thisParamKind == PARAM_EXEC)
{ {
/* /*
...@@ -673,9 +788,10 @@ ExecEvalFuncArgs(FunctionCallInfo fcinfo, ...@@ -673,9 +788,10 @@ ExecEvalFuncArgs(FunctionCallInfo fcinfo,
i = 0; i = 0;
foreach(arg, argList) foreach(arg, argList)
{ {
ExprState *argstate = (ExprState *) lfirst(arg);
ExprDoneCond thisArgIsDone; ExprDoneCond thisArgIsDone;
fcinfo->arg[i] = ExecEvalExpr((ExprState *) lfirst(arg), fcinfo->arg[i] = ExecEvalExpr(argstate,
econtext, econtext,
&fcinfo->argnull[i], &fcinfo->argnull[i],
&thisArgIsDone); &thisArgIsDone);
...@@ -889,6 +1005,17 @@ ExecMakeFunctionResult(FuncExprState *fcache, ...@@ -889,6 +1005,17 @@ ExecMakeFunctionResult(FuncExprState *fcache,
/* /*
* Non-set case: much easier. * 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 * If function is strict, and there are any NULL arguments, skip
* calling the function and return NULL. * calling the function and return NULL.
*/ */
...@@ -911,6 +1038,71 @@ ExecMakeFunctionResult(FuncExprState *fcache, ...@@ -911,6 +1038,71 @@ ExecMakeFunctionResult(FuncExprState *fcache,
return result; 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 * ExecMakeTableFunctionResult
...@@ -1201,15 +1393,14 @@ ExecEvalFunc(FuncExprState *fcache, ...@@ -1201,15 +1393,14 @@ ExecEvalFunc(FuncExprState *fcache,
bool *isNull, bool *isNull,
ExprDoneCond *isDone) ExprDoneCond *isDone)
{ {
/* /* This is called only the first time through */
* Initialize function cache if first time through FuncExpr *func = (FuncExpr *) fcache->xprstate.expr;
*/
if (fcache->func.fn_oid == InvalidOid)
{
FuncExpr *func = (FuncExpr *) fcache->xprstate.expr;
init_fcache(func->funcid, fcache, econtext->ecxt_per_query_memory); /* 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); return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);
} }
...@@ -1224,15 +1415,14 @@ ExecEvalOper(FuncExprState *fcache, ...@@ -1224,15 +1415,14 @@ ExecEvalOper(FuncExprState *fcache,
bool *isNull, bool *isNull,
ExprDoneCond *isDone) ExprDoneCond *isDone)
{ {
/* /* This is called only the first time through */
* Initialize function cache if first time through OpExpr *op = (OpExpr *) fcache->xprstate.expr;
*/
if (fcache->func.fn_oid == InvalidOid)
{
OpExpr *op = (OpExpr *) fcache->xprstate.expr;
init_fcache(op->opfuncid, fcache, econtext->ecxt_per_query_memory); /* 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); return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);
} }
...@@ -1251,13 +1441,19 @@ ExecEvalOper(FuncExprState *fcache, ...@@ -1251,13 +1441,19 @@ ExecEvalOper(FuncExprState *fcache,
static Datum static Datum
ExecEvalDistinct(FuncExprState *fcache, ExecEvalDistinct(FuncExprState *fcache,
ExprContext *econtext, ExprContext *econtext,
bool *isNull) bool *isNull,
ExprDoneCond *isDone)
{ {
Datum result; Datum result;
FunctionCallInfoData fcinfo; FunctionCallInfoData fcinfo;
ExprDoneCond argDone; ExprDoneCond argDone;
List *argList; 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 * Initialize function cache if first time through
*/ */
...@@ -1316,7 +1512,8 @@ ExecEvalDistinct(FuncExprState *fcache, ...@@ -1316,7 +1512,8 @@ ExecEvalDistinct(FuncExprState *fcache,
*/ */
static Datum static Datum
ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
ExprContext *econtext, bool *isNull) ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{ {
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) sstate->fxprstate.xprstate.expr; ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) sstate->fxprstate.xprstate.expr;
bool useOr = opexpr->useOr; bool useOr = opexpr->useOr;
...@@ -1332,6 +1529,11 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ...@@ -1332,6 +1529,11 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
char typalign; char typalign;
char *s; 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 * Initialize function cache if first time through
*/ */
...@@ -1468,12 +1670,14 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, ...@@ -1468,12 +1670,14 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static Datum 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; Datum expr_value;
clause = lfirst(notclause->args); if (isDone)
*isDone = ExprSingleResult;
expr_value = ExecEvalExpr(clause, econtext, isNull, NULL); expr_value = ExecEvalExpr(clause, econtext, isNull, NULL);
...@@ -1496,14 +1700,16 @@ ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, bool *isNull) ...@@ -1496,14 +1700,16 @@ ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, bool *isNull)
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static Datum 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; List *clause;
bool AnyNull; bool AnyNull;
Datum clause_value;
clauses = orExpr->args; if (isDone)
*isDone = ExprSingleResult;
AnyNull = false; AnyNull = false;
/* /*
...@@ -1522,8 +1728,10 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, bool *isNull) ...@@ -1522,8 +1728,10 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, bool *isNull)
*/ */
foreach(clause, clauses) foreach(clause, clauses)
{ {
clause_value = ExecEvalExpr((ExprState *) lfirst(clause), ExprState *clausestate = (ExprState *) lfirst(clause);
econtext, isNull, NULL); Datum clause_value;
clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL);
/* /*
* if we have a non-null true result, then return it. * if we have a non-null true result, then return it.
...@@ -1544,14 +1752,16 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, bool *isNull) ...@@ -1544,14 +1752,16 @@ ExecEvalOr(BoolExprState *orExpr, ExprContext *econtext, bool *isNull)
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static Datum 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; List *clause;
bool AnyNull; bool AnyNull;
Datum clause_value;
clauses = andExpr->args; if (isDone)
*isDone = ExprSingleResult;
AnyNull = false; AnyNull = false;
/* /*
...@@ -1564,8 +1774,10 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, bool *isNull) ...@@ -1564,8 +1774,10 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, bool *isNull)
*/ */
foreach(clause, clauses) foreach(clause, clauses)
{ {
clause_value = ExecEvalExpr((ExprState *) lfirst(clause), ExprState *clausestate = (ExprState *) lfirst(clause);
econtext, isNull, NULL); Datum clause_value;
clause_value = ExecEvalExpr(clausestate, econtext, isNull, NULL);
/* /*
* if we have a non-null false result, then return it. * if we have a non-null false result, then return it.
...@@ -1595,11 +1807,11 @@ static Datum ...@@ -1595,11 +1807,11 @@ static Datum
ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone) bool *isNull, ExprDoneCond *isDone)
{ {
List *clauses; List *clauses = caseExpr->args;
List *clause; 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 * we evaluate each of the WHEN clauses in turn, as soon as one is
...@@ -1609,6 +1821,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, ...@@ -1609,6 +1821,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
foreach(clause, clauses) foreach(clause, clauses)
{ {
CaseWhenState *wclause = lfirst(clause); CaseWhenState *wclause = lfirst(clause);
Datum clause_value;
clause_value = ExecEvalExpr(wclause->expr, clause_value = ExecEvalExpr(wclause->expr,
econtext, econtext,
...@@ -1651,7 +1864,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, ...@@ -1651,7 +1864,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
bool *isNull) bool *isNull, ExprDoneCond *isDone)
{ {
ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr; ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr;
ArrayType *result; ArrayType *result;
...@@ -1661,6 +1874,11 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, ...@@ -1661,6 +1874,11 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
int dims[MAXDIM]; int dims[MAXDIM];
int lbs[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) if (!arrayExpr->multidims)
{ {
/* Elements are presumably of scalar type */ /* Elements are presumably of scalar type */
...@@ -1823,10 +2041,13 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, ...@@ -1823,10 +2041,13 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
*/ */
static Datum static Datum
ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext, ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext,
bool *isNull) bool *isNull, ExprDoneCond *isDone)
{ {
List *arg; List *arg;
if (isDone)
*isDone = ExprSingleResult;
/* Simply loop through until something NOT NULL is found */ /* Simply loop through until something NOT NULL is found */
foreach(arg, coalesceExpr->args) foreach(arg, coalesceExpr->args)
{ {
...@@ -1852,33 +2073,37 @@ ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext, ...@@ -1852,33 +2073,37 @@ ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext,
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static Datum static Datum
ExecEvalNullIf(FuncExprState *fcache, ExprContext *econtext, ExecEvalNullIf(FuncExprState *nullIfExpr,
bool *isNull) ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{ {
Datum result; Datum result;
FunctionCallInfoData fcinfo; FunctionCallInfoData fcinfo;
ExprDoneCond argDone; ExprDoneCond argDone;
List *argList; List *argList;
if (isDone)
*isDone = ExprSingleResult;
/* /*
* Initialize function cache if first time through * 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); init_fcache(op->opfuncid, nullIfExpr, econtext->ecxt_per_query_memory);
Assert(!fcache->func.fn_retset); Assert(!nullIfExpr->func.fn_retset);
} }
/* /*
* extract info from fcache * extract info from nullIfExpr
*/ */
argList = fcache->args; argList = nullIfExpr->args;
/* Need to prep callinfo structure */ /* Need to prep callinfo structure */
MemSet(&fcinfo, 0, sizeof(fcinfo)); MemSet(&fcinfo, 0, sizeof(fcinfo));
fcinfo.flinfo = &(fcache->func); fcinfo.flinfo = &(nullIfExpr->func);
argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext); argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext);
if (argDone != ExprSingleResult) if (argDone != ExprSingleResult)
ereport(ERROR, ereport(ERROR,
...@@ -2119,9 +2344,12 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext, ...@@ -2119,9 +2344,12 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
* Return the value stored by CoerceToDomain. * Return the value stored by CoerceToDomain.
*/ */
static Datum static Datum
ExecEvalCoerceToDomainValue(CoerceToDomainValue *conVal, ExecEvalCoerceToDomainValue(ExprState *exprstate,
ExprContext *econtext, bool *isNull) ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{ {
if (isDone)
*isDone = ExprSingleResult;
*isNull = econtext->domainValue_isNull; *isNull = econtext->domainValue_isNull;
return econtext->domainValue_datum; return econtext->domainValue_datum;
} }
...@@ -2158,210 +2386,24 @@ ExecEvalFieldSelect(GenericExprState *fstate, ...@@ -2158,210 +2386,24 @@ ExecEvalFieldSelect(GenericExprState *fstate,
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecEvalExpr * ExecEvalRelabelType
*
* 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
*
* 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 * Evaluate a RelabelType node.
* 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.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
Datum static Datum
ExecEvalExpr(ExprState *expression, ExecEvalRelabelType(GenericExprState *exprstate,
ExprContext *econtext, ExprContext *econtext,
bool *isNull, bool *isNull, ExprDoneCond *isDone)
ExprDoneCond *isDone)
{ {
Datum retDatum; return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone);
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() */
/* /*
* Same as above, but get into the right allocation context explicitly. * ExecEvalExprSwitchContext
*
* Same as ExecEvalExpr, but get into the right allocation context explicitly.
*/ */
Datum Datum
ExecEvalExprSwitchContext(ExprState *expression, ExecEvalExprSwitchContext(ExprState *expression,
...@@ -2421,17 +2463,27 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2421,17 +2463,27 @@ ExecInitExpr(Expr *node, PlanState *parent)
switch (nodeTag(node)) switch (nodeTag(node))
{ {
case T_Var: case T_Var:
state = (ExprState *) makeNode(ExprState);
state->evalfunc = ExecEvalVar;
break;
case T_Const: case T_Const:
state = (ExprState *) makeNode(ExprState);
state->evalfunc = ExecEvalConst;
break;
case T_Param: case T_Param:
state = (ExprState *) makeNode(ExprState);
state->evalfunc = ExecEvalParam;
break;
case T_CoerceToDomainValue: case T_CoerceToDomainValue:
/* No special setup needed for these node types */
state = (ExprState *) makeNode(ExprState); state = (ExprState *) makeNode(ExprState);
state->evalfunc = ExecEvalCoerceToDomainValue;
break; break;
case T_Aggref: case T_Aggref:
{ {
Aggref *aggref = (Aggref *) node; Aggref *aggref = (Aggref *) node;
AggrefExprState *astate = makeNode(AggrefExprState); AggrefExprState *astate = makeNode(AggrefExprState);
astate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalAggref;
if (parent && IsA(parent, AggState)) if (parent && IsA(parent, AggState))
{ {
AggState *aggstate = (AggState *) parent; AggState *aggstate = (AggState *) parent;
...@@ -2466,6 +2518,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2466,6 +2518,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
ArrayRef *aref = (ArrayRef *) node; ArrayRef *aref = (ArrayRef *) node;
ArrayRefExprState *astate = makeNode(ArrayRefExprState); ArrayRefExprState *astate = makeNode(ArrayRefExprState);
astate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalArrayRef;
astate->refupperindexpr = (List *) astate->refupperindexpr = (List *)
ExecInitExpr((Expr *) aref->refupperindexpr, parent); ExecInitExpr((Expr *) aref->refupperindexpr, parent);
astate->reflowerindexpr = (List *) astate->reflowerindexpr = (List *)
...@@ -2487,6 +2540,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2487,6 +2540,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
FuncExpr *funcexpr = (FuncExpr *) node; FuncExpr *funcexpr = (FuncExpr *) node;
FuncExprState *fstate = makeNode(FuncExprState); FuncExprState *fstate = makeNode(FuncExprState);
fstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalFunc;
fstate->args = (List *) fstate->args = (List *)
ExecInitExpr((Expr *) funcexpr->args, parent); ExecInitExpr((Expr *) funcexpr->args, parent);
fstate->func.fn_oid = InvalidOid; /* not initialized */ fstate->func.fn_oid = InvalidOid; /* not initialized */
...@@ -2498,6 +2552,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2498,6 +2552,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
OpExpr *opexpr = (OpExpr *) node; OpExpr *opexpr = (OpExpr *) node;
FuncExprState *fstate = makeNode(FuncExprState); FuncExprState *fstate = makeNode(FuncExprState);
fstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalOper;
fstate->args = (List *) fstate->args = (List *)
ExecInitExpr((Expr *) opexpr->args, parent); ExecInitExpr((Expr *) opexpr->args, parent);
fstate->func.fn_oid = InvalidOid; /* not initialized */ fstate->func.fn_oid = InvalidOid; /* not initialized */
...@@ -2509,6 +2564,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2509,6 +2564,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
DistinctExpr *distinctexpr = (DistinctExpr *) node; DistinctExpr *distinctexpr = (DistinctExpr *) node;
FuncExprState *fstate = makeNode(FuncExprState); FuncExprState *fstate = makeNode(FuncExprState);
fstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalDistinct;
fstate->args = (List *) fstate->args = (List *)
ExecInitExpr((Expr *) distinctexpr->args, parent); ExecInitExpr((Expr *) distinctexpr->args, parent);
fstate->func.fn_oid = InvalidOid; /* not initialized */ fstate->func.fn_oid = InvalidOid; /* not initialized */
...@@ -2520,6 +2576,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2520,6 +2576,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
ScalarArrayOpExprState *sstate = makeNode(ScalarArrayOpExprState); ScalarArrayOpExprState *sstate = makeNode(ScalarArrayOpExprState);
sstate->fxprstate.xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalScalarArrayOp;
sstate->fxprstate.args = (List *) sstate->fxprstate.args = (List *)
ExecInitExpr((Expr *) opexpr->args, parent); ExecInitExpr((Expr *) opexpr->args, parent);
sstate->fxprstate.func.fn_oid = InvalidOid; /* not initialized */ sstate->fxprstate.func.fn_oid = InvalidOid; /* not initialized */
...@@ -2532,6 +2589,22 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2532,6 +2589,22 @@ ExecInitExpr(Expr *node, PlanState *parent)
BoolExpr *boolexpr = (BoolExpr *) node; BoolExpr *boolexpr = (BoolExpr *) node;
BoolExprState *bstate = makeNode(BoolExprState); 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 *) bstate->args = (List *)
ExecInitExpr((Expr *) boolexpr->args, parent); ExecInitExpr((Expr *) boolexpr->args, parent);
state = (ExprState *) bstate; state = (ExprState *) bstate;
...@@ -2543,6 +2616,8 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2543,6 +2616,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
SubPlan *subplan = (SubPlan *) node; SubPlan *subplan = (SubPlan *) node;
SubPlanState *sstate = makeNode(SubPlanState); SubPlanState *sstate = makeNode(SubPlanState);
sstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecSubPlan;
if (!parent) if (!parent)
elog(ERROR, "SubPlan found with no parent plan"); elog(ERROR, "SubPlan found with no parent plan");
...@@ -2568,6 +2643,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2568,6 +2643,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
FieldSelect *fselect = (FieldSelect *) node; FieldSelect *fselect = (FieldSelect *) node;
GenericExprState *gstate = makeNode(GenericExprState); GenericExprState *gstate = makeNode(GenericExprState);
gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalFieldSelect;
gstate->arg = ExecInitExpr(fselect->arg, parent); gstate->arg = ExecInitExpr(fselect->arg, parent);
state = (ExprState *) gstate; state = (ExprState *) gstate;
} }
...@@ -2577,6 +2653,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2577,6 +2653,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
RelabelType *relabel = (RelabelType *) node; RelabelType *relabel = (RelabelType *) node;
GenericExprState *gstate = makeNode(GenericExprState); GenericExprState *gstate = makeNode(GenericExprState);
gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalRelabelType;
gstate->arg = ExecInitExpr(relabel->arg, parent); gstate->arg = ExecInitExpr(relabel->arg, parent);
state = (ExprState *) gstate; state = (ExprState *) gstate;
} }
...@@ -2588,6 +2665,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2588,6 +2665,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
FastList outlist; FastList outlist;
List *inlist; List *inlist;
cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCase;
FastListInit(&outlist); FastListInit(&outlist);
foreach(inlist, caseexpr->args) foreach(inlist, caseexpr->args)
{ {
...@@ -2595,6 +2673,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2595,6 +2673,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
CaseWhenState *wstate = makeNode(CaseWhenState); CaseWhenState *wstate = makeNode(CaseWhenState);
Assert(IsA(when, CaseWhen)); Assert(IsA(when, CaseWhen));
wstate->xprstate.evalfunc = NULL; /* not used */
wstate->xprstate.expr = (Expr *) when; wstate->xprstate.expr = (Expr *) when;
wstate->expr = ExecInitExpr(when->expr, parent); wstate->expr = ExecInitExpr(when->expr, parent);
wstate->result = ExecInitExpr(when->result, parent); wstate->result = ExecInitExpr(when->result, parent);
...@@ -2614,6 +2693,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2614,6 +2693,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
FastList outlist; FastList outlist;
List *inlist; List *inlist;
astate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalArray;
FastListInit(&outlist); FastListInit(&outlist);
foreach(inlist, arrayexpr->elements) foreach(inlist, arrayexpr->elements)
{ {
...@@ -2639,6 +2719,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2639,6 +2719,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
FastList outlist; FastList outlist;
List *inlist; List *inlist;
cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCoalesce;
FastListInit(&outlist); FastListInit(&outlist);
foreach(inlist, coalesceexpr->args) foreach(inlist, coalesceexpr->args)
{ {
...@@ -2657,6 +2738,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2657,6 +2738,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
NullIfExpr *nullifexpr = (NullIfExpr *) node; NullIfExpr *nullifexpr = (NullIfExpr *) node;
FuncExprState *fstate = makeNode(FuncExprState); FuncExprState *fstate = makeNode(FuncExprState);
fstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalNullIf;
fstate->args = (List *) fstate->args = (List *)
ExecInitExpr((Expr *) nullifexpr->args, parent); ExecInitExpr((Expr *) nullifexpr->args, parent);
fstate->func.fn_oid = InvalidOid; /* not initialized */ fstate->func.fn_oid = InvalidOid; /* not initialized */
...@@ -2668,6 +2750,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2668,6 +2750,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
NullTest *ntest = (NullTest *) node; NullTest *ntest = (NullTest *) node;
GenericExprState *gstate = makeNode(GenericExprState); GenericExprState *gstate = makeNode(GenericExprState);
gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalNullTest;
gstate->arg = ExecInitExpr(ntest->arg, parent); gstate->arg = ExecInitExpr(ntest->arg, parent);
state = (ExprState *) gstate; state = (ExprState *) gstate;
} }
...@@ -2677,6 +2760,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2677,6 +2760,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
BooleanTest *btest = (BooleanTest *) node; BooleanTest *btest = (BooleanTest *) node;
GenericExprState *gstate = makeNode(GenericExprState); GenericExprState *gstate = makeNode(GenericExprState);
gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalBooleanTest;
gstate->arg = ExecInitExpr(btest->arg, parent); gstate->arg = ExecInitExpr(btest->arg, parent);
state = (ExprState *) gstate; state = (ExprState *) gstate;
} }
...@@ -2686,6 +2770,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2686,6 +2770,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
CoerceToDomain *ctest = (CoerceToDomain *) node; CoerceToDomain *ctest = (CoerceToDomain *) node;
CoerceToDomainState *cstate = makeNode(CoerceToDomainState); CoerceToDomainState *cstate = makeNode(CoerceToDomainState);
cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCoerceToDomain;
cstate->arg = ExecInitExpr(ctest->arg, parent); cstate->arg = ExecInitExpr(ctest->arg, parent);
cstate->constraints = GetDomainConstraints(ctest->resulttype); cstate->constraints = GetDomainConstraints(ctest->resulttype);
state = (ExprState *) cstate; state = (ExprState *) cstate;
...@@ -2696,6 +2781,7 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2696,6 +2781,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
TargetEntry *tle = (TargetEntry *) node; TargetEntry *tle = (TargetEntry *) node;
GenericExprState *gstate = makeNode(GenericExprState); GenericExprState *gstate = makeNode(GenericExprState);
gstate->xprstate.evalfunc = NULL; /* not used */
gstate->arg = ExecInitExpr(tle->expr, parent); gstate->arg = ExecInitExpr(tle->expr, parent);
state = (ExprState *) gstate; state = (ExprState *) gstate;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -532,6 +532,7 @@ ExecHashGetBucket(HashJoinTable hashtable,
foreach(hk, hashkeys) foreach(hk, hashkeys)
{ {
ExprState *keyexpr = (ExprState *) lfirst(hk);
Datum keyval; Datum keyval;
bool isNull; bool isNull;
...@@ -541,8 +542,7 @@ ExecHashGetBucket(HashJoinTable hashtable, ...@@ -541,8 +542,7 @@ ExecHashGetBucket(HashJoinTable hashtable,
/* /*
* Get the join attribute value of the tuple * Get the join attribute value of the tuple
*/ */
keyval = ExecEvalExpr((ExprState *) lfirst(hk), keyval = ExecEvalExpr(keyexpr, econtext, &isNull, NULL);
econtext, &isNull, NULL);
/* /*
* Compute the hash function * Compute the hash function
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -191,6 +191,8 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
eqclause = eqQual; eqclause = eqQual;
foreach(clause, compareQual) foreach(clause, compareQual)
{ {
ExprState *clauseexpr = (ExprState *) lfirst(clause);
ExprState *eqclauseexpr = (ExprState *) lfirst(eqclause);
Datum const_value; Datum const_value;
bool isNull; bool isNull;
...@@ -200,10 +202,7 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext) ...@@ -200,10 +202,7 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
* *
* A NULL result is considered false. * A NULL result is considered false.
*/ */
const_value = ExecEvalExpr((ExprState *) lfirst(clause), const_value = ExecEvalExpr(clauseexpr, econtext, &isNull, NULL);
econtext,
&isNull,
NULL);
if (DatumGetBool(const_value) && !isNull) if (DatumGetBool(const_value) && !isNull)
{ {
...@@ -217,10 +216,7 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext) ...@@ -217,10 +216,7 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
* key1 = key2 so we move on to the next pair of keys. * key1 = key2 so we move on to the next pair of keys.
*----------- *-----------
*/ */
const_value = ExecEvalExpr((ExprState *) lfirst(eqclause), const_value = ExecEvalExpr(eqclauseexpr, econtext, &isNull, NULL);
econtext,
&isNull,
NULL);
if (!DatumGetBool(const_value) || isNull) if (!DatumGetBool(const_value) || isNull)
break; /* return false */ break; /* return false */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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); ...@@ -47,10 +47,16 @@ static bool tupleAllNulls(HeapTuple tuple);
Datum Datum
ExecSubPlan(SubPlanState *node, ExecSubPlan(SubPlanState *node,
ExprContext *econtext, ExprContext *econtext,
bool *isNull) bool *isNull,
ExprDoneCond *isDone)
{ {
SubPlan *subplan = (SubPlan *) node->xprstate.expr; 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) if (subplan->setParam != NIL)
elog(ERROR, "cannot set parent params from subquery"); elog(ERROR, "cannot set parent params from subquery");
...@@ -819,6 +825,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) ...@@ -819,6 +825,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
expr); expr);
tlestate = makeNode(GenericExprState); tlestate = makeNode(GenericExprState);
tlestate->xprstate.expr = (Expr *) tle; tlestate->xprstate.expr = (Expr *) tle;
tlestate->xprstate.evalfunc = NULL;
tlestate->arg = exstate; tlestate->arg = exstate;
lefttlist = lappend(lefttlist, tlestate); lefttlist = lappend(lefttlist, tlestate);
leftptlist = lappend(leftptlist, tle); leftptlist = lappend(leftptlist, tle);
...@@ -834,6 +841,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) ...@@ -834,6 +841,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
expr); expr);
tlestate = makeNode(GenericExprState); tlestate = makeNode(GenericExprState);
tlestate->xprstate.expr = (Expr *) tle; tlestate->xprstate.expr = (Expr *) tle;
tlestate->xprstate.evalfunc = NULL;
tlestate->arg = exstate; tlestate->arg = exstate;
righttlist = lappend(righttlist, tlestate); righttlist = lappend(righttlist, tlestate);
rightptlist = lappend(rightptlist, tle); rightptlist = lappend(rightptlist, tle);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -17,17 +17,26 @@
#include "executor/execdesc.h" #include "executor/execdesc.h"
/* ---------------- /*
* TupIsNull * TupIsNull
* *
* This is used mainly to detect when there are no more * This is used mainly to detect when there are no more
* tuples to process. * tuples to process.
* ----------------
*/ */
/* return: true if tuple in slot is NULL, slot is slot to test */ /* return: true if tuple in slot is NULL, slot is slot to test */
#define TupIsNull(slot) \ #define TupIsNull(slot) \
((slot) == NULL || (slot)->val == NULL) ((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 * prototypes from functions in execAmi.c
*/ */
...@@ -125,8 +134,6 @@ extern Tuplestorestate *ExecMakeTableFunctionResult(ExprState *funcexpr, ...@@ -125,8 +134,6 @@ extern Tuplestorestate *ExecMakeTableFunctionResult(ExprState *funcexpr,
ExprContext *econtext, ExprContext *econtext,
TupleDesc expectedDesc, TupleDesc expectedDesc,
TupleDesc *returnDesc); TupleDesc *returnDesc);
extern Datum ExecEvalExpr(ExprState *expression, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext, extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone); bool *isNull, ExprDoneCond *isDone);
extern ExprState *ExecInitExpr(Expr *node, PlanState *parent); extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -19,7 +19,8 @@
extern void ExecInitSubPlan(SubPlanState *node, EState *estate); extern void ExecInitSubPlan(SubPlanState *node, EState *estate);
extern Datum ExecSubPlan(SubPlanState *node, extern Datum ExecSubPlan(SubPlanState *node,
ExprContext *econtext, ExprContext *econtext,
bool *isNull); bool *isNull,
ExprDoneCond *isDone);
extern void ExecEndSubPlan(SubPlanState *node); extern void ExecEndSubPlan(SubPlanState *node);
extern void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent); extern void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; ...@@ -390,13 +390,25 @@ typedef HASH_SEQ_STATUS TupleHashIterator;
* *
* It can also be instantiated directly for leaf Expr nodes that need no * It can also be instantiated directly for leaf Expr nodes that need no
* local run-time state (such as Var, Const, or Param). * 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; NodeTag type;
Expr *expr; /* associated Expr node */ Expr *expr; /* associated Expr node */
} ExprState; ExprStateEvalFunc evalfunc; /* routine to run to execute node */
};
/* ---------------- /* ----------------
* GenericExprState 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