aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execExpr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execExpr.c')
-rw-r--r--src/backend/executor/execExpr.c149
1 files changed, 107 insertions, 42 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 823b7590713..ac9a3004fe0 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -48,12 +48,15 @@
#include "utils/typcache.h"
-typedef struct LastAttnumInfo
+typedef struct ExprSetupInfo
{
+ /* Highest attribute numbers fetched from inner/outer/scan tuple slots: */
AttrNumber last_inner;
AttrNumber last_outer;
AttrNumber last_scan;
-} LastAttnumInfo;
+ /* MULTIEXPR SubPlan nodes appearing in the expression: */
+ List *multiexpr_subplans;
+} ExprSetupInfo;
static void ExecReadyExpr(ExprState *state);
static void ExecInitExprRec(Expr *node, ExprState *state,
@@ -61,9 +64,9 @@ static void ExecInitExprRec(Expr *node, ExprState *state,
static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args,
Oid funcid, Oid inputcollid,
ExprState *state);
-static void ExecInitExprSlots(ExprState *state, Node *node);
-static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info);
-static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info);
+static void ExecCreateExprSetupSteps(ExprState *state, Node *node);
+static void ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info);
+static bool expr_setup_walker(Node *node, ExprSetupInfo *info);
static void ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op);
static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable,
ExprState *state);
@@ -132,8 +135,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
state->parent = parent;
state->ext_params = NULL;
- /* Insert EEOP_*_FETCHSOME steps as needed */
- ExecInitExprSlots(state, (Node *) node);
+ /* Insert setup steps as needed */
+ ExecCreateExprSetupSteps(state, (Node *) node);
/* Compile the expression proper */
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
@@ -169,8 +172,8 @@ ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
state->parent = NULL;
state->ext_params = ext_params;
- /* Insert EEOP_*_FETCHSOME steps as needed */
- ExecInitExprSlots(state, (Node *) node);
+ /* Insert setup steps as needed */
+ ExecCreateExprSetupSteps(state, (Node *) node);
/* Compile the expression proper */
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
@@ -224,8 +227,8 @@ ExecInitQual(List *qual, PlanState *parent)
/* mark expression as to be used with ExecQual() */
state->flags = EEO_FLAG_IS_QUAL;
- /* Insert EEOP_*_FETCHSOME steps as needed */
- ExecInitExprSlots(state, (Node *) qual);
+ /* Insert setup steps as needed */
+ ExecCreateExprSetupSteps(state, (Node *) qual);
/*
* ExecQual() needs to return false for an expression returning NULL. That
@@ -394,8 +397,8 @@ ExecBuildProjectionInfoExt(List *targetList,
state->resultslot = slot;
- /* Insert EEOP_*_FETCHSOME steps as needed */
- ExecInitExprSlots(state, (Node *) targetList);
+ /* Insert setup steps as needed */
+ ExecCreateExprSetupSteps(state, (Node *) targetList);
/* Now compile each tlist column */
foreach(lc, targetList)
@@ -1117,6 +1120,21 @@ ExecInitExprRec(Expr *node, ExprState *state,
SubPlan *subplan = (SubPlan *) node;
SubPlanState *sstate;
+ /*
+ * Real execution of a MULTIEXPR SubPlan has already been
+ * done. What we have to do here is return a dummy NULL record
+ * value in case this targetlist element is assigned
+ * someplace.
+ */
+ if (subplan->subLinkType == MULTIEXPR_SUBLINK)
+ {
+ scratch.opcode = EEOP_CONST;
+ scratch.d.constval.value = (Datum) 0;
+ scratch.d.constval.isnull = true;
+ ExprEvalPushStep(state, &scratch);
+ break;
+ }
+
if (!state->parent)
elog(ERROR, "SubPlan found with no parent plan");
@@ -2285,36 +2303,38 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
}
/*
- * Add expression steps deforming the ExprState's inner/outer/scan slots
- * as much as required by the expression.
+ * Add expression steps performing setup that's needed before any of the
+ * main execution of the expression.
*/
static void
-ExecInitExprSlots(ExprState *state, Node *node)
+ExecCreateExprSetupSteps(ExprState *state, Node *node)
{
- LastAttnumInfo info = {0, 0, 0};
+ ExprSetupInfo info = {0, 0, 0, NIL};
- /*
- * Figure out which attributes we're going to need.
- */
- get_last_attnums_walker(node, &info);
+ /* Prescan to find out what we need. */
+ expr_setup_walker(node, &info);
- ExecPushExprSlots(state, &info);
+ /* And generate those steps. */
+ ExecPushExprSetupSteps(state, &info);
}
/*
- * Add steps deforming the ExprState's inner/out/scan slots as much as
- * indicated by info. This is useful when building an ExprState covering more
- * than one expression.
+ * Add steps performing expression setup as indicated by "info".
+ * This is useful when building an ExprState covering more than one expression.
*/
static void
-ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
+ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
{
ExprEvalStep scratch = {0};
+ ListCell *lc;
scratch.resvalue = NULL;
scratch.resnull = NULL;
- /* Emit steps as needed */
+ /*
+ * Add steps deforming the ExprState's inner/outer/scan slots as much as
+ * required by any Vars appearing in the expression.
+ */
if (info->last_inner > 0)
{
scratch.opcode = EEOP_INNER_FETCHSOME;
@@ -2345,13 +2365,48 @@ ExecPushExprSlots(ExprState *state, LastAttnumInfo *info)
ExecComputeSlotInfo(state, &scratch);
ExprEvalPushStep(state, &scratch);
}
+
+ /*
+ * Add steps to execute any MULTIEXPR SubPlans appearing in the
+ * expression. We need to evaluate these before any of the Params
+ * referencing their outputs are used, but after we've prepared for any
+ * Var references they may contain. (There cannot be cross-references
+ * between MULTIEXPR SubPlans, so we needn't worry about their order.)
+ */
+ foreach(lc, info->multiexpr_subplans)
+ {
+ SubPlan *subplan = (SubPlan *) lfirst(lc);
+ SubPlanState *sstate;
+
+ Assert(subplan->subLinkType == MULTIEXPR_SUBLINK);
+
+ /* This should match what ExecInitExprRec does for other SubPlans: */
+
+ if (!state->parent)
+ elog(ERROR, "SubPlan found with no parent plan");
+
+ sstate = ExecInitSubPlan(subplan, state->parent);
+
+ /* add SubPlanState nodes to state->parent->subPlan */
+ state->parent->subPlan = lappend(state->parent->subPlan,
+ sstate);
+
+ scratch.opcode = EEOP_SUBPLAN;
+ scratch.d.subplan.sstate = sstate;
+
+ /* The result can be ignored, but we better put it somewhere */
+ scratch.resvalue = &state->resvalue;
+ scratch.resnull = &state->resnull;
+
+ ExprEvalPushStep(state, &scratch);
+ }
}
/*
- * get_last_attnums_walker: expression walker for ExecInitExprSlots
+ * expr_setup_walker: expression walker for ExecCreateExprSetupSteps
*/
static bool
-get_last_attnums_walker(Node *node, LastAttnumInfo *info)
+expr_setup_walker(Node *node, ExprSetupInfo *info)
{
if (node == NULL)
return false;
@@ -2379,6 +2434,16 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
return false;
}
+ /* Collect all MULTIEXPR SubPlans, too */
+ if (IsA(node, SubPlan))
+ {
+ SubPlan *subplan = (SubPlan *) node;
+
+ if (subplan->subLinkType == MULTIEXPR_SUBLINK)
+ info->multiexpr_subplans = lappend(info->multiexpr_subplans,
+ subplan);
+ }
+
/*
* Don't examine the arguments or filters of Aggrefs or WindowFuncs,
* because those do not represent expressions to be evaluated within the
@@ -2391,7 +2456,7 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
return false;
if (IsA(node, GroupingFunc))
return false;
- return expression_tree_walker(node, get_last_attnums_walker,
+ return expression_tree_walker(node, expr_setup_walker,
(void *) info);
}
@@ -2968,7 +3033,7 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
int transno = 0;
int setoff = 0;
bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
- LastAttnumInfo deform = {0, 0, 0};
+ ExprSetupInfo deform = {0, 0, 0, NIL};
state->expr = (Expr *) aggstate;
state->parent = parent;
@@ -2984,18 +3049,18 @@ ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase,
{
AggStatePerTrans pertrans = &aggstate->pertrans[transno];
- get_last_attnums_walker((Node *) pertrans->aggref->aggdirectargs,
- &deform);
- get_last_attnums_walker((Node *) pertrans->aggref->args,
- &deform);
- get_last_attnums_walker((Node *) pertrans->aggref->aggorder,
- &deform);
- get_last_attnums_walker((Node *) pertrans->aggref->aggdistinct,
- &deform);
- get_last_attnums_walker((Node *) pertrans->aggref->aggfilter,
- &deform);
+ expr_setup_walker((Node *) pertrans->aggref->aggdirectargs,
+ &deform);
+ expr_setup_walker((Node *) pertrans->aggref->args,
+ &deform);
+ expr_setup_walker((Node *) pertrans->aggref->aggorder,
+ &deform);
+ expr_setup_walker((Node *) pertrans->aggref->aggdistinct,
+ &deform);
+ expr_setup_walker((Node *) pertrans->aggref->aggfilter,
+ &deform);
}
- ExecPushExprSlots(state, &deform);
+ ExecPushExprSetupSteps(state, &deform);
/*
* Emit instructions for each transition value / grouping set combination.