aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execExpr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-12-21 12:57:41 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2017-12-21 12:57:45 -0500
commit6719b238e8f0ea83c39d2b1728c7670cdaa34e06 (patch)
treed7a0a144b2321577c486334c1aafd98adadce170 /src/backend/executor/execExpr.c
parent8a0596cb656e357c391cccf12854beb2e05f3901 (diff)
downloadpostgresql-6719b238e8f0ea83c39d2b1728c7670cdaa34e06.tar.gz
postgresql-6719b238e8f0ea83c39d2b1728c7670cdaa34e06.zip
Rearrange execution of PARAM_EXTERN Params for plpgsql's benefit.
This patch does three interrelated things: * Create a new expression execution step type EEOP_PARAM_CALLBACK and add the infrastructure needed for add-on modules to generate that. As discussed, the best control mechanism for that seems to be to add another hook function to ParamListInfo, which will be called by ExecInitExpr if it's supplied and a PARAM_EXTERN Param is found. For stand-alone expressions, we add a new entry point to allow the ParamListInfo to be specified directly, since it can't be retrieved from the parent plan node's EState. * Redesign the API for the ParamListInfo paramFetch hook so that the ParamExternData array can be entirely virtual. This also lets us get rid of ParamListInfo.paramMask, instead leaving it to the paramFetch hook to decide which param IDs should be accessible or not. plpgsql_param_fetch was already doing the identical masking check, so having callers do it too seemed redundant. While I was at it, I added a "speculative" flag to paramFetch that the planner can specify as TRUE to avoid unwanted failures. This solves an ancient problem for plpgsql that it couldn't provide values of non-DTYPE_VAR variables to the planner for fear of triggering premature "record not assigned yet" or "field not found" errors during planning. * Rework plpgsql to get rid of the need for "unshared" parameter lists, by dint of turning the single ParamListInfo per estate into a nearly read-only data structure that doesn't instantiate any per-variable data. Instead, the paramFetch hook controls access to per-variable data and can make the right decisions on the fly, replacing the cases that we used to need multiple ParamListInfos for. This might perhaps have been a performance loss on its own, but by using a paramCompile hook we can bypass plpgsql_param_fetch entirely during normal query execution. (It's now only called when, eg, we copy the ParamListInfo into a cursor portal. copyParamList() or SerializeParamList() effectively instantiate the virtual parameter array as a simple physical array without a paramFetch hook, which is what we want in those cases.) This allows reverting most of commit 6c82d8d1f, though I kept the cosmetic code-consolidation aspects of that (eg the assign_simple_var function). Performance testing shows this to be at worst a break-even change, and it can provide wins ranging up to 20% in test cases involving accesses to fields of "record" variables. The fact that values of such variables can now be exposed to the planner might produce wins in some situations, too, but I've not pursued that angle. In passing, remove the "parent" pointer from the arguments to ExecInitExprRec and related functions, instead storing that pointer in a transient field in ExprState. The ParamListInfo pointer for a stand-alone expression is handled the same way; we'd otherwise have had to add yet another recursively-passed-down argument in expression compilation. Discussion: https://postgr.es/m/32589.1513706441@sss.pgh.pa.us
Diffstat (limited to 'src/backend/executor/execExpr.c')
-rw-r--r--src/backend/executor/execExpr.c231
1 files changed, 152 insertions, 79 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index e0839616e19..55bb9251917 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -55,22 +55,21 @@ typedef struct LastAttnumInfo
} LastAttnumInfo;
static void ExecReadyExpr(ExprState *state);
-static void ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
+static void ExecInitExprRec(Expr *node, ExprState *state,
Datum *resv, bool *resnull);
-static void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s);
static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args,
- Oid funcid, Oid inputcollid, PlanState *parent,
+ Oid funcid, Oid inputcollid,
ExprState *state);
static void ExecInitExprSlots(ExprState *state, Node *node);
static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info);
static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable,
- PlanState *parent);
+ ExprState *state);
static void ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
- PlanState *parent, ExprState *state,
+ ExprState *state,
Datum *resv, bool *resnull);
static bool isAssignmentIndirectionExpr(Expr *expr);
static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest,
- PlanState *parent, ExprState *state,
+ ExprState *state,
Datum *resv, bool *resnull);
@@ -122,12 +121,51 @@ ExecInitExpr(Expr *node, PlanState *parent)
/* Initialize ExprState with empty step list */
state = makeNode(ExprState);
state->expr = node;
+ state->parent = parent;
+ state->ext_params = NULL;
/* Insert EEOP_*_FETCHSOME steps as needed */
ExecInitExprSlots(state, (Node *) node);
/* Compile the expression proper */
- ExecInitExprRec(node, parent, state, &state->resvalue, &state->resnull);
+ ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
+
+ /* Finally, append a DONE step */
+ scratch.opcode = EEOP_DONE;
+ ExprEvalPushStep(state, &scratch);
+
+ ExecReadyExpr(state);
+
+ return state;
+}
+
+/*
+ * ExecInitExprWithParams: prepare a standalone expression tree for execution
+ *
+ * This is the same as ExecInitExpr, except that there is no parent PlanState,
+ * and instead we may have a ParamListInfo describing PARAM_EXTERN Params.
+ */
+ExprState *
+ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
+{
+ ExprState *state;
+ ExprEvalStep scratch;
+
+ /* Special case: NULL expression produces a NULL ExprState pointer */
+ if (node == NULL)
+ return NULL;
+
+ /* Initialize ExprState with empty step list */
+ state = makeNode(ExprState);
+ state->expr = node;
+ state->parent = NULL;
+ state->ext_params = ext_params;
+
+ /* Insert EEOP_*_FETCHSOME steps as needed */
+ ExecInitExprSlots(state, (Node *) node);
+
+ /* Compile the expression proper */
+ ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
/* Finally, append a DONE step */
scratch.opcode = EEOP_DONE;
@@ -172,6 +210,9 @@ ExecInitQual(List *qual, PlanState *parent)
state = makeNode(ExprState);
state->expr = (Expr *) qual;
+ state->parent = parent;
+ state->ext_params = NULL;
+
/* mark expression as to be used with ExecQual() */
state->flags = EEO_FLAG_IS_QUAL;
@@ -198,7 +239,7 @@ ExecInitQual(List *qual, PlanState *parent)
Expr *node = (Expr *) lfirst(lc);
/* first evaluate expression */
- ExecInitExprRec(node, parent, state, &state->resvalue, &state->resnull);
+ ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
/* then emit EEOP_QUAL to detect if it's false (or null) */
scratch.d.qualexpr.jumpdone = -1;
@@ -314,6 +355,9 @@ ExecBuildProjectionInfo(List *targetList,
projInfo->pi_state.tag.type = T_ExprState;
state = &projInfo->pi_state;
state->expr = (Expr *) targetList;
+ state->parent = parent;
+ state->ext_params = NULL;
+
state->resultslot = slot;
/* Insert EEOP_*_FETCHSOME steps as needed */
@@ -398,7 +442,7 @@ ExecBuildProjectionInfo(List *targetList,
* matter) can change between executions. We instead evaluate
* into the ExprState's resvalue/resnull and then move.
*/
- ExecInitExprRec(tle->expr, parent, state,
+ ExecInitExprRec(tle->expr, state,
&state->resvalue, &state->resnull);
/*
@@ -581,12 +625,11 @@ ExecReadyExpr(ExprState *state)
* possibly recursing into sub-expressions of node.
*
* node - expression to evaluate
- * parent - parent executor node (or NULL if a standalone expression)
* state - ExprState to whose ->steps to append the necessary operations
* resv / resnull - where to store the result of the node into
*/
static void
-ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
+ExecInitExprRec(Expr *node, ExprState *state,
Datum *resv, bool *resnull)
{
ExprEvalStep scratch;
@@ -609,7 +652,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
if (variable->varattno == InvalidAttrNumber)
{
/* whole-row Var */
- ExecInitWholeRowVar(&scratch, variable, parent);
+ ExecInitWholeRowVar(&scratch, variable, state);
}
else if (variable->varattno <= 0)
{
@@ -674,6 +717,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
case T_Param:
{
Param *param = (Param *) node;
+ ParamListInfo params;
switch (param->paramkind)
{
@@ -681,19 +725,41 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
scratch.opcode = EEOP_PARAM_EXEC;
scratch.d.param.paramid = param->paramid;
scratch.d.param.paramtype = param->paramtype;
+ ExprEvalPushStep(state, &scratch);
break;
case PARAM_EXTERN:
- scratch.opcode = EEOP_PARAM_EXTERN;
- scratch.d.param.paramid = param->paramid;
- scratch.d.param.paramtype = param->paramtype;
+
+ /*
+ * If we have a relevant ParamCompileHook, use it;
+ * otherwise compile a standard EEOP_PARAM_EXTERN
+ * step. ext_params, if supplied, takes precedence
+ * over info from the parent node's EState (if any).
+ */
+ if (state->ext_params)
+ params = state->ext_params;
+ else if (state->parent &&
+ state->parent->state)
+ params = state->parent->state->es_param_list_info;
+ else
+ params = NULL;
+ if (params && params->paramCompile)
+ {
+ params->paramCompile(params, param, state,
+ resv, resnull);
+ }
+ else
+ {
+ scratch.opcode = EEOP_PARAM_EXTERN;
+ scratch.d.param.paramid = param->paramid;
+ scratch.d.param.paramtype = param->paramtype;
+ ExprEvalPushStep(state, &scratch);
+ }
break;
default:
elog(ERROR, "unrecognized paramkind: %d",
(int) param->paramkind);
break;
}
-
- ExprEvalPushStep(state, &scratch);
break;
}
@@ -706,9 +772,9 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
scratch.d.aggref.astate = astate;
astate->aggref = aggref;
- if (parent && IsA(parent, AggState))
+ if (state->parent && IsA(state->parent, AggState))
{
- AggState *aggstate = (AggState *) parent;
+ AggState *aggstate = (AggState *) state->parent;
aggstate->aggs = lcons(astate, aggstate->aggs);
aggstate->numaggs++;
@@ -728,14 +794,14 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
GroupingFunc *grp_node = (GroupingFunc *) node;
Agg *agg;
- if (!parent || !IsA(parent, AggState) ||
- !IsA(parent->plan, Agg))
+ if (!state->parent || !IsA(state->parent, AggState) ||
+ !IsA(state->parent->plan, Agg))
elog(ERROR, "GroupingFunc found in non-Agg plan node");
scratch.opcode = EEOP_GROUPING_FUNC;
- scratch.d.grouping_func.parent = (AggState *) parent;
+ scratch.d.grouping_func.parent = (AggState *) state->parent;
- agg = (Agg *) (parent->plan);
+ agg = (Agg *) (state->parent->plan);
if (agg->groupingSets)
scratch.d.grouping_func.clauses = grp_node->cols;
@@ -753,9 +819,9 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
wfstate->wfunc = wfunc;
- if (parent && IsA(parent, WindowAggState))
+ if (state->parent && IsA(state->parent, WindowAggState))
{
- WindowAggState *winstate = (WindowAggState *) parent;
+ WindowAggState *winstate = (WindowAggState *) state->parent;
int nfuncs;
winstate->funcs = lcons(wfstate, winstate->funcs);
@@ -764,9 +830,10 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
winstate->numaggs++;
/* for now initialize agg using old style expressions */
- wfstate->args = ExecInitExprList(wfunc->args, parent);
+ wfstate->args = ExecInitExprList(wfunc->args,
+ state->parent);
wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter,
- parent);
+ state->parent);
/*
* Complain if the windowfunc's arguments contain any
@@ -795,7 +862,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
{
ArrayRef *aref = (ArrayRef *) node;
- ExecInitArrayRef(&scratch, aref, parent, state, resv, resnull);
+ ExecInitArrayRef(&scratch, aref, state, resv, resnull);
break;
}
@@ -805,7 +872,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
ExecInitFunc(&scratch, node,
func->args, func->funcid, func->inputcollid,
- parent, state);
+ state);
ExprEvalPushStep(state, &scratch);
break;
}
@@ -816,7 +883,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
ExecInitFunc(&scratch, node,
op->args, op->opfuncid, op->inputcollid,
- parent, state);
+ state);
ExprEvalPushStep(state, &scratch);
break;
}
@@ -827,7 +894,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
ExecInitFunc(&scratch, node,
op->args, op->opfuncid, op->inputcollid,
- parent, state);
+ state);
/*
* Change opcode of call instruction to EEOP_DISTINCT.
@@ -849,7 +916,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
ExecInitFunc(&scratch, node,
op->args, op->opfuncid, op->inputcollid,
- parent, state);
+ state);
/*
* Change opcode of call instruction to EEOP_NULLIF.
@@ -896,7 +963,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
opexpr->inputcollid, NULL, NULL);
/* Evaluate scalar directly into left function argument */
- ExecInitExprRec(scalararg, parent, state,
+ ExecInitExprRec(scalararg, state,
&fcinfo->arg[0], &fcinfo->argnull[0]);
/*
@@ -905,7 +972,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
* be overwritten by EEOP_SCALARARRAYOP, and will not be
* passed to any other expression.
*/
- ExecInitExprRec(arrayarg, parent, state, resv, resnull);
+ ExecInitExprRec(arrayarg, state, resv, resnull);
/* And perform the operation */
scratch.opcode = EEOP_SCALARARRAYOP;
@@ -949,7 +1016,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
Expr *arg = (Expr *) lfirst(lc);
/* Evaluate argument into our output variable */
- ExecInitExprRec(arg, parent, state, resv, resnull);
+ ExecInitExprRec(arg, state, resv, resnull);
/* Perform the appropriate step type */
switch (boolexpr->boolop)
@@ -1009,13 +1076,14 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
SubPlan *subplan = (SubPlan *) node;
SubPlanState *sstate;
- if (!parent)
+ if (!state->parent)
elog(ERROR, "SubPlan found with no parent plan");
- sstate = ExecInitSubPlan(subplan, parent);
+ sstate = ExecInitSubPlan(subplan, state->parent);
- /* add SubPlanState nodes to parent->subPlan */
- parent->subPlan = lappend(parent->subPlan, sstate);
+ /* add SubPlanState nodes to state->parent->subPlan */
+ state->parent->subPlan = lappend(state->parent->subPlan,
+ sstate);
scratch.opcode = EEOP_SUBPLAN;
scratch.d.subplan.sstate = sstate;
@@ -1029,10 +1097,10 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
AlternativeSubPlanState *asstate;
- if (!parent)
+ if (!state->parent)
elog(ERROR, "AlternativeSubPlan found with no parent plan");
- asstate = ExecInitAlternativeSubPlan(asplan, parent);
+ asstate = ExecInitAlternativeSubPlan(asplan, state->parent);
scratch.opcode = EEOP_ALTERNATIVE_SUBPLAN;
scratch.d.alternative_subplan.asstate = asstate;
@@ -1046,7 +1114,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
FieldSelect *fselect = (FieldSelect *) node;
/* evaluate row/record argument into result area */
- ExecInitExprRec(fselect->arg, parent, state, resv, resnull);
+ ExecInitExprRec(fselect->arg, state, resv, resnull);
/* and extract field */
scratch.opcode = EEOP_FIELDSELECT;
@@ -1083,7 +1151,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
*descp = NULL;
/* emit code to evaluate the composite input value */
- ExecInitExprRec(fstore->arg, parent, state, resv, resnull);
+ ExecInitExprRec(fstore->arg, state, resv, resnull);
/* next, deform the input tuple into our workspace */
scratch.opcode = EEOP_FIELDSTORE_DEFORM;
@@ -1134,7 +1202,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
state->innermost_caseval = &values[fieldnum - 1];
state->innermost_casenull = &nulls[fieldnum - 1];
- ExecInitExprRec(e, parent, state,
+ ExecInitExprRec(e, state,
&values[fieldnum - 1],
&nulls[fieldnum - 1]);
@@ -1158,7 +1226,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
/* relabel doesn't need to do anything at runtime */
RelabelType *relabel = (RelabelType *) node;
- ExecInitExprRec(relabel->arg, parent, state, resv, resnull);
+ ExecInitExprRec(relabel->arg, state, resv, resnull);
break;
}
@@ -1171,7 +1239,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
FunctionCallInfo fcinfo_in;
/* evaluate argument into step's result area */
- ExecInitExprRec(iocoerce->arg, parent, state, resv, resnull);
+ ExecInitExprRec(iocoerce->arg, state, resv, resnull);
/*
* Prepare both output and input function calls, to be
@@ -1228,7 +1296,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
ExprState *elemstate;
/* evaluate argument into step's result area */
- ExecInitExprRec(acoerce->arg, parent, state, resv, resnull);
+ ExecInitExprRec(acoerce->arg, state, resv, resnull);
resultelemtype = get_element_type(acoerce->resulttype);
if (!OidIsValid(resultelemtype))
@@ -1244,10 +1312,13 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
*/
elemstate = makeNode(ExprState);
elemstate->expr = acoerce->elemexpr;
+ elemstate->parent = state->parent;
+ elemstate->ext_params = state->ext_params;
+
elemstate->innermost_caseval = (Datum *) palloc(sizeof(Datum));
elemstate->innermost_casenull = (bool *) palloc(sizeof(bool));
- ExecInitExprRec(acoerce->elemexpr, parent, elemstate,
+ ExecInitExprRec(acoerce->elemexpr, elemstate,
&elemstate->resvalue, &elemstate->resnull);
if (elemstate->steps_len == 1 &&
@@ -1290,7 +1361,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
/* evaluate argument into step's result area */
- ExecInitExprRec(convert->arg, parent, state, resv, resnull);
+ ExecInitExprRec(convert->arg, state, resv, resnull);
/* and push conversion step */
scratch.opcode = EEOP_CONVERT_ROWTYPE;
@@ -1324,7 +1395,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
caseval = palloc(sizeof(Datum));
casenull = palloc(sizeof(bool));
- ExecInitExprRec(caseExpr->arg, parent, state,
+ ExecInitExprRec(caseExpr->arg, state,
caseval, casenull);
/*
@@ -1375,7 +1446,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
state->innermost_casenull = casenull;
/* evaluate condition into CASE's result variables */
- ExecInitExprRec(when->expr, parent, state, resv, resnull);
+ ExecInitExprRec(when->expr, state, resv, resnull);
state->innermost_caseval = save_innermost_caseval;
state->innermost_casenull = save_innermost_casenull;
@@ -1390,7 +1461,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
* If WHEN result is true, evaluate THEN result, storing
* it into the CASE's result variables.
*/
- ExecInitExprRec(when->result, parent, state, resv, resnull);
+ ExecInitExprRec(when->result, state, resv, resnull);
/* Emit JUMP step to jump to end of CASE's code */
scratch.opcode = EEOP_JUMP;
@@ -1415,7 +1486,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
Assert(caseExpr->defresult);
/* evaluate ELSE expr into CASE's result variables */
- ExecInitExprRec(caseExpr->defresult, parent, state,
+ ExecInitExprRec(caseExpr->defresult, state,
resv, resnull);
/* adjust jump targets */
@@ -1484,7 +1555,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
{
Expr *e = (Expr *) lfirst(lc);
- ExecInitExprRec(e, parent, state,
+ ExecInitExprRec(e, state,
&scratch.d.arrayexpr.elemvalues[elemoff],
&scratch.d.arrayexpr.elemnulls[elemoff]);
elemoff++;
@@ -1578,7 +1649,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
}
/* Evaluate column expr into appropriate workspace slot */
- ExecInitExprRec(e, parent, state,
+ ExecInitExprRec(e, state,
&scratch.d.row.elemvalues[i],
&scratch.d.row.elemnulls[i]);
i++;
@@ -1667,9 +1738,9 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
*/
/* evaluate left and right args directly into fcinfo */
- ExecInitExprRec(left_expr, parent, state,
+ ExecInitExprRec(left_expr, state,
&fcinfo->arg[0], &fcinfo->argnull[0]);
- ExecInitExprRec(right_expr, parent, state,
+ ExecInitExprRec(right_expr, state,
&fcinfo->arg[1], &fcinfo->argnull[1]);
scratch.opcode = EEOP_ROWCOMPARE_STEP;
@@ -1738,7 +1809,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
Expr *e = (Expr *) lfirst(lc);
/* evaluate argument, directly into result datum */
- ExecInitExprRec(e, parent, state, resv, resnull);
+ ExecInitExprRec(e, state, resv, resnull);
/* if it's not null, skip to end of COALESCE expr */
scratch.opcode = EEOP_JUMP_IF_NOT_NULL;
@@ -1820,7 +1891,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
{
Expr *e = (Expr *) lfirst(lc);
- ExecInitExprRec(e, parent, state,
+ ExecInitExprRec(e, state,
&scratch.d.minmax.values[off],
&scratch.d.minmax.nulls[off]);
off++;
@@ -1886,7 +1957,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
{
Expr *e = (Expr *) lfirst(arg);
- ExecInitExprRec(e, parent, state,
+ ExecInitExprRec(e, state,
&scratch.d.xmlexpr.named_argvalue[off],
&scratch.d.xmlexpr.named_argnull[off]);
off++;
@@ -1897,7 +1968,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
{
Expr *e = (Expr *) lfirst(arg);
- ExecInitExprRec(e, parent, state,
+ ExecInitExprRec(e, state,
&scratch.d.xmlexpr.argvalue[off],
&scratch.d.xmlexpr.argnull[off]);
off++;
@@ -1935,7 +2006,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
scratch.d.nulltest_row.argdesc = NULL;
/* first evaluate argument into result variable */
- ExecInitExprRec(ntest->arg, parent, state,
+ ExecInitExprRec(ntest->arg, state,
resv, resnull);
/* then push the test of that argument */
@@ -1953,7 +2024,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
* and will get overwritten by the below EEOP_BOOLTEST_IS_*
* step.
*/
- ExecInitExprRec(btest->arg, parent, state, resv, resnull);
+ ExecInitExprRec(btest->arg, state, resv, resnull);
switch (btest->booltesttype)
{
@@ -1990,7 +2061,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
{
CoerceToDomain *ctest = (CoerceToDomain *) node;
- ExecInitCoerceToDomain(&scratch, ctest, parent, state,
+ ExecInitCoerceToDomain(&scratch, ctest, state,
resv, resnull);
break;
}
@@ -2046,7 +2117,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
* Note that this potentially re-allocates es->steps, therefore no pointer
* into that array may be used while the expression is still being built.
*/
-static void
+void
ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
{
if (es->steps_alloc == 0)
@@ -2074,7 +2145,7 @@ ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
*/
static void
ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
- Oid inputcollid, PlanState *parent, ExprState *state)
+ Oid inputcollid, ExprState *state)
{
int nargs = list_length(args);
AclResult aclresult;
@@ -2126,8 +2197,9 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set"),
- parent ? executor_errposition(parent->state,
- exprLocation((Node *) node)) : 0));
+ state->parent ?
+ executor_errposition(state->parent->state,
+ exprLocation((Node *) node)) : 0));
/* Build code to evaluate arguments directly into the fcinfo struct */
argno = 0;
@@ -2148,7 +2220,7 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
}
else
{
- ExecInitExprRec(arg, parent, state,
+ ExecInitExprRec(arg, state,
&fcinfo->arg[argno], &fcinfo->argnull[argno]);
}
argno++;
@@ -2260,8 +2332,10 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info)
* The caller still has to push the step.
*/
static void
-ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, PlanState *parent)
+ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state)
{
+ PlanState *parent = state->parent;
+
/* fill in all but the target */
scratch->opcode = EEOP_WHOLEROW;
scratch->d.wholerow.var = variable;
@@ -2331,7 +2405,7 @@ ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, PlanState *parent)
* Prepare evaluation of an ArrayRef expression.
*/
static void
-ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
+ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
ExprState *state, Datum *resv, bool *resnull)
{
bool isAssignment = (aref->refassgnexpr != NULL);
@@ -2355,7 +2429,7 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
* be overwritten by the final EEOP_ARRAYREF_FETCH/ASSIGN step, which is
* pushed last.
*/
- ExecInitExprRec(aref->refexpr, parent, state, resv, resnull);
+ ExecInitExprRec(aref->refexpr, state, resv, resnull);
/*
* If refexpr yields NULL, and it's a fetch, then result is NULL. We can
@@ -2401,7 +2475,7 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
arefstate->upperprovided[i] = true;
/* Each subscript is evaluated into subscriptvalue/subscriptnull */
- ExecInitExprRec(e, parent, state,
+ ExecInitExprRec(e, state,
&arefstate->subscriptvalue, &arefstate->subscriptnull);
/* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */
@@ -2434,7 +2508,7 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
arefstate->lowerprovided[i] = true;
/* Each subscript is evaluated into subscriptvalue/subscriptnull */
- ExecInitExprRec(e, parent, state,
+ ExecInitExprRec(e, state,
&arefstate->subscriptvalue, &arefstate->subscriptnull);
/* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */
@@ -2488,7 +2562,7 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
state->innermost_casenull = &arefstate->prevnull;
/* evaluate replacement value into replacevalue/replacenull */
- ExecInitExprRec(aref->refassgnexpr, parent, state,
+ ExecInitExprRec(aref->refassgnexpr, state,
&arefstate->replacevalue, &arefstate->replacenull);
state->innermost_caseval = save_innermost_caseval;
@@ -2566,8 +2640,7 @@ isAssignmentIndirectionExpr(Expr *expr)
*/
static void
ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest,
- PlanState *parent, ExprState *state,
- Datum *resv, bool *resnull)
+ ExprState *state, Datum *resv, bool *resnull)
{
ExprEvalStep scratch2;
DomainConstraintRef *constraint_ref;
@@ -2587,7 +2660,7 @@ ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest,
* if there's constraint failures there'll be errors, otherwise it's what
* needs to be returned.
*/
- ExecInitExprRec(ctest->arg, parent, state, resv, resnull);
+ ExecInitExprRec(ctest->arg, state, resv, resnull);
/*
* Note: if the argument is of varlena type, it could be a R/W expanded
@@ -2684,7 +2757,7 @@ ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest,
state->innermost_domainnull = domainnull;
/* evaluate check expression value */
- ExecInitExprRec(con->check_expr, parent, state,
+ ExecInitExprRec(con->check_expr, state,
scratch->d.domaincheck.checkvalue,
scratch->d.domaincheck.checknull);