*
*
* 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"
/* static function decls */
-static Datum ExecEvalAggref(AggrefExprState *aggref,
- ExprContext *econtext,
- bool *isNull);
static Datum ExecEvalArrayRef(ArrayRefExprState *astate,
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 ExecEvalAggref(AggrefExprState *aggref,
+ ExprContext *econtext,
+ 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,
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);
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone);
static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
- ExprContext *econtext,
- bool *isNull);
-static Datum ExecEvalNullIf(FuncExprState *nullIfExpr, ExprContext *econtext,
- bool *isNull);
+ ExprContext *econtext,
+ 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);
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.
+ * ----------------------------------------------------------------
+ */
/*----------
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 *)
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));
{
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));
* ----------------------------------------------------------------
*/
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");
* 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
*/
ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);
ExecSetSlotDescriptor(tempSlot, tuple_type, false);
MemoryContextSwitchTo(oldContext);
+ *isNull = false;
return PointerGetDatum(tempSlot);
}
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
*
* ----------------------------------------------------------------
*/
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)
{
/*
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);
/*
* 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.
*/
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
bool *isNull,
ExprDoneCond *isDone)
{
- /*
- * Initialize function cache if first time through
- */
- if (fcache->func.fn_oid == InvalidOid)
- {
- FuncExpr *func = (FuncExpr *) fcache->xprstate.expr;
+ /* This is called only the first time through */
+ 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);
}
bool *isNull,
ExprDoneCond *isDone)
{
- /*
- * Initialize function cache if first time through
- */
- if (fcache->func.fn_oid == InvalidOid)
- {
- OpExpr *op = (OpExpr *) fcache->xprstate.expr;
+ /* This is called only the first time through */
+ 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);
}
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
*/
*/
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;
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
*/
* ----------------------------------------------------------------
*/
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);
* ----------------------------------------------------------------
*/
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;
/*
*/
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.
* ----------------------------------------------------------------
*/
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;
/*
*/
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.
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
foreach(clause, clauses)
{
CaseWhenState *wclause = lfirst(clause);
+ Datum clause_value;
clause_value = ExecEvalExpr(wclause->expr,
econtext,
*/
static Datum
ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
- bool *isNull)
+ bool *isNull, ExprDoneCond *isDone)
{
ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr;
ArrayType *result;
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 */
*/
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)
{
* ----------------------------------------------------------------
*/
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,
* 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;
}
}
/* ----------------------------------------------------------------
- * 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
- *
- * 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.
+ * ExecEvalRelabelType
*
- * 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,
- ExprContext *econtext,
- bool *isNull,
- ExprDoneCond *isDone)
+static Datum
+ExecEvalRelabelType(GenericExprState *exprstate,
+ ExprContext *econtext,
+ 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,
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;
ArrayRef *aref = (ArrayRef *) node;
ArrayRefExprState *astate = makeNode(ArrayRefExprState);
+ astate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalArrayRef;
astate->refupperindexpr = (List *)
ExecInitExpr((Expr *) aref->refupperindexpr, parent);
astate->reflowerindexpr = (List *)
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 */
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 */
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 */
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 */
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;
SubPlan *subplan = (SubPlan *) node;
SubPlanState *sstate = makeNode(SubPlanState);
+ sstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecSubPlan;
+
if (!parent)
elog(ERROR, "SubPlan found with no parent plan");
FieldSelect *fselect = (FieldSelect *) node;
GenericExprState *gstate = makeNode(GenericExprState);
+ gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalFieldSelect;
gstate->arg = ExecInitExpr(fselect->arg, parent);
state = (ExprState *) gstate;
}
RelabelType *relabel = (RelabelType *) node;
GenericExprState *gstate = makeNode(GenericExprState);
+ gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalRelabelType;
gstate->arg = ExecInitExpr(relabel->arg, parent);
state = (ExprState *) gstate;
}
FastList outlist;
List *inlist;
+ cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCase;
FastListInit(&outlist);
foreach(inlist, caseexpr->args)
{
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);
FastList outlist;
List *inlist;
+ astate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalArray;
FastListInit(&outlist);
foreach(inlist, arrayexpr->elements)
{
FastList outlist;
List *inlist;
+ cstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCoalesce;
FastListInit(&outlist);
foreach(inlist, coalesceexpr->args)
{
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 */
NullTest *ntest = (NullTest *) node;
GenericExprState *gstate = makeNode(GenericExprState);
+ gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalNullTest;
gstate->arg = ExecInitExpr(ntest->arg, parent);
state = (ExprState *) gstate;
}
BooleanTest *btest = (BooleanTest *) node;
GenericExprState *gstate = makeNode(GenericExprState);
+ gstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalBooleanTest;
gstate->arg = ExecInitExpr(btest->arg, parent);
state = (ExprState *) gstate;
}
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;
TargetEntry *tle = (TargetEntry *) node;
GenericExprState *gstate = makeNode(GenericExprState);
+ gstate->xprstate.evalfunc = NULL; /* not used */
gstate->arg = ExecInitExpr(tle->expr, parent);
state = (ExprState *) gstate;
}