|
|
|
@ -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);
|
|
|
|
|
|
|
|
|
|