]> granicus.if.org Git - postgresql/commitdiff
Replace the switching function ExecEvalExpr() with a macro that jumps
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 17 Mar 2004 01:02:24 +0000 (01:02 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 17 Mar 2004 01:02:24 +0000 (01:02 +0000)
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.

src/backend/executor/execQual.c
src/backend/executor/nodeHash.c
src/backend/executor/nodeMergejoin.c
src/backend/executor/nodeSubplan.c
src/include/executor/executor.h
src/include/executor/nodeSubplan.h
src/include/nodes/execnodes.h

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