*** a/src/backend/executor/execExpr.c --- b/src/backend/executor/execExpr.c *************** *** 45,50 **** --- 45,51 ---- #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/typcache.h" + #include "sys/param.h" typedef struct LastAttnumInfo *************** *** 57,78 **** typedef struct LastAttnumInfo static void ExecReadyExpr(ExprState *state); static void ExecInitExprRec(Expr *node, PlanState *parent, 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, ! 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); ! static void ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent, ExprState *state, Datum *resv, bool *resnull); static bool isAssignmentIndirectionExpr(Expr *expr); ! static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, PlanState *parent, ExprState *state, Datum *resv, bool *resnull); /* * ExecInitExpr: prepare an expression tree for execution --- 58,166 ---- static void ExecReadyExpr(ExprState *state); static void ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, Datum *resv, bool *resnull); ! static ExprEvalStep *ExprEvalPushStep(ExprState *es, const ExprEvalOp opcode, ! Datum *resv, bool *resnull); ! static void ExecInitFunc(Expr *node, List *args, Oid funcid, Oid inputcollid, PlanState *parent, ! ExprState *state, Datum *resv, bool *resnull); static void ExecInitExprSlots(ExprState *state, Node *node); static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info); ! static void ExecInitWholeRowVar(ExprState *state, Var *variable, ! PlanState *parent, Datum *resv, bool *resnull); ! static void ExecInitArrayRef(ArrayRef *aref, PlanState *parent, ExprState *state, Datum *resv, bool *resnull); static bool isAssignmentIndirectionExpr(Expr *expr); ! static void ExecInitCoerceToDomain(CoerceToDomain *ctest, PlanState *parent, ExprState *state, Datum *resv, bool *resnull); + /* + * Lookup array for the size of each op + */ + #define EEOPSIZE(t) MAXALIGN(sizeof(t)) + static size_t eeop_size[] = + { + /* EEOP_DONE */ EEOPSIZE(ExprEvalStep), + /* EEOP_INNER_FETCHSOME */ EEOPSIZE(ExprEvalStep_fetch), + /* EEOP_OUTER_FETCHSOME */ EEOPSIZE(ExprEvalStep_fetch), + /* EEOP_SCAN_FETCHSOME */ EEOPSIZE(ExprEvalStep_fetch), + /* EEOP_INNER_VAR_FIRST */ EEOPSIZE(ExprEvalStep_var), + /* EEOP_INNER_VAR */ EEOPSIZE(ExprEvalStep_var), + /* EEOP_OUTER_VAR_FIRST */ EEOPSIZE(ExprEvalStep_var), + /* EEOP_OUTER_VAR */ EEOPSIZE(ExprEvalStep_var), + /* EEOP_SCAN_VAR_FIRST */ EEOPSIZE(ExprEvalStep_var), + /* EEOP_SCAN_VAR */ EEOPSIZE(ExprEvalStep_var), + /* EEOP_INNER_SYSVAR */ EEOPSIZE(ExprEvalStep_var), + /* EEOP_OUTER_SYSVAR */ EEOPSIZE(ExprEvalStep_var), + /* EEOP_SCAN_SYSVAR */ EEOPSIZE(ExprEvalStep_var), + /* EEOP_WHOLEROW */ EEOPSIZE(ExprEvalStep_wholerow), + /* EEOP_ASSIGN_INNER_VAR */ EEOPSIZE(ExprEvalStep_assign_var), + /* EEOP_ASSIGN_OUTER_VAR */ EEOPSIZE(ExprEvalStep_assign_var), + /* EEOP_ASSIGN_SCAN_VAR */ EEOPSIZE(ExprEvalStep_assign_var), + /* EEOP_ASSIGN_TMP */ EEOPSIZE(ExprEvalStep_assign_tmp), + /* EEOP_ASSIGN_TMP_MAKE_RO */ EEOPSIZE(ExprEvalStep_assign_tmp), + /* EEOP_CONST */ EEOPSIZE(ExprEvalStep_constval), + /* EEOP_FUNCEXPR */ EEOPSIZE(ExprEvalStep_func), + /* EEOP_FUNCEXPR_STRICT */ EEOPSIZE(ExprEvalStep_func), + /* EEOP_FUNCEXPR_FUSAGE */ EEOPSIZE(ExprEvalStep_func), + /* EEOP_FUNCEXPR_STRICT_FUSAGE */ EEOPSIZE(ExprEvalStep_func), + /* EEOP_BOOL_AND_STEP_FIRST */ EEOPSIZE(ExprEvalStep_boolexpr), + /* EEOP_BOOL_AND_STEP */ EEOPSIZE(ExprEvalStep_boolexpr), + /* EEOP_BOOL_AND_STEP_LAST */ EEOPSIZE(ExprEvalStep_boolexpr), + /* EEOP_BOOL_OR_STEP_FIRST */ EEOPSIZE(ExprEvalStep_boolexpr), + /* EEOP_BOOL_OR_STEP */ EEOPSIZE(ExprEvalStep_boolexpr), + /* EEOP_BOOL_OR_STEP_LAST */ EEOPSIZE(ExprEvalStep_boolexpr), + /* EEOP_BOOL_NOT_STEP */ EEOPSIZE(ExprEvalStep_boolexpr), + /* EEOP_QUAL */ EEOPSIZE(ExprEvalStep_qualexpr), + /* EEOP_JUMP */ EEOPSIZE(ExprEvalStep_jump), + /* EEOP_JUMP_IF_NULL */ EEOPSIZE(ExprEvalStep_jump), + /* EEOP_JUMP_IF_NOT_NULL */ EEOPSIZE(ExprEvalStep_jump), + /* EEOP_JUMP_IF_NOT_TRUE */ EEOPSIZE(ExprEvalStep_jump), + /* EEOP_NULLTEST_ISNULL */ EEOPSIZE(ExprEvalStep_nulltest_row), + /* EEOP_NULLTEST_ISNOTNULL */ EEOPSIZE(ExprEvalStep_nulltest_row), + /* EEOP_NULLTEST_ROWISNULL */ EEOPSIZE(ExprEvalStep_nulltest_row), + /* EEOP_NULLTEST_ROWISNOTNULL */ EEOPSIZE(ExprEvalStep_nulltest_row), + /* EEOP_BOOLTEST_IS_TRUE */ EEOPSIZE(ExprEvalStep), + /* EEOP_BOOLTEST_IS_NOT_TRUE */ EEOPSIZE(ExprEvalStep), + /* EEOP_BOOLTEST_IS_FALSE */ EEOPSIZE(ExprEvalStep), + /* EEOP_BOOLTEST_IS_NOT_FALSE */ EEOPSIZE(ExprEvalStep), + /* EEOP_PARAM_EXEC */ EEOPSIZE(ExprEvalStep_param), + /* EEOP_PARAM_EXTERN */ EEOPSIZE(ExprEvalStep_param), + /* EEOP_CASE_TESTVAL */ EEOPSIZE(ExprEvalStep_casetest), + /* EEOP_MAKE_READONLY */ EEOPSIZE(ExprEvalStep_make_readonly), + /* EEOP_IOCOERCE */ EEOPSIZE(ExprEvalStep_iocoerce), + /* EEOP_DISTINCT */ EEOPSIZE(ExprEvalStep_func), + /* EEOP_NULLIF */ EEOPSIZE(ExprEvalStep_func), + /* EEOP_SQLVALUEFUNCTION */ EEOPSIZE(ExprEvalStep_sqlvaluefunction), + /* EEOP_CURRENTOFEXPR */ EEOPSIZE(ExprEvalStep), + /* EEOP_NEXTVALUEEXPR */ EEOPSIZE(ExprEvalStep_nextvalueexpr), + /* EEOP_ARRAYEXPR */ EEOPSIZE(ExprEvalStep_arrayexpr), + /* EEOP_ARRAYCOERCE */ EEOPSIZE(ExprEvalStep_arraycoerce), + /* EEOP_ROW */ EEOPSIZE(ExprEvalStep_row), + /* EEOP_ROWCOMPARE_STEP */ EEOPSIZE(ExprEvalStep_rowcompare_step), + /* EEOP_ROWCOMPARE_FINAL */ EEOPSIZE(ExprEvalStep_rowcompare_final), + /* EEOP_MINMAX */ EEOPSIZE(ExprEvalStep_minmax), + /* EEOP_FIELDSELECT */ EEOPSIZE(ExprEvalStep_fieldselect), + /* EEOP_FIELDSTORE_DEFORM */ EEOPSIZE(ExprEvalStep_fieldstore), + /* EEOP_FIELDSTORE_FORM */ EEOPSIZE(ExprEvalStep_fieldstore), + /* EEOP_ARRAYREF_SUBSCRIPT */ EEOPSIZE(ExprEvalStep_arrayref_subscript), + /* EEOP_ARRAYREF_OLD */ EEOPSIZE(ExprEvalStep_arrayref), + /* EEOP_ARRAYREF_ASSIGN */ EEOPSIZE(ExprEvalStep_arrayref), + /* EEOP_ARRAYREF_FETCH */ EEOPSIZE(ExprEvalStep_arrayref), + /* EEOP_DOMAIN_TESTVAL */ EEOPSIZE(ExprEvalStep_casetest), + /* EEOP_DOMAIN_NOTNULL */ EEOPSIZE(ExprEvalStep_domaincheck), + /* EEOP_DOMAIN_CHECK */ EEOPSIZE(ExprEvalStep_domaincheck), + /* EEOP_CONVERT_ROWTYPE */ EEOPSIZE(ExprEvalStep_convert_rowtype), + /* EEOP_SCALARARRAYOP */ EEOPSIZE(ExprEvalStep_scalararrayop), + /* EEOP_XMLEXPR */ EEOPSIZE(ExprEvalStep_xmlexpr), + /* EEOP_AGGREF */ EEOPSIZE(ExprEvalStep_aggref), + /* EEOP_GROUPING_FUNC */ EEOPSIZE(ExprEvalStep_grouping_func), + /* EEOP_WINDOW_FUNC */ EEOPSIZE(ExprEvalStep_window_func), + /* EEOP_SUBPLAN */ EEOPSIZE(ExprEvalStep_subplan), + /* EEOP_ALTERNATIVE_SUBPLAN */ EEOPSIZE(ExprEvalStep_alternative_subplan), + /* EEOP_LAST */ 0 + }; /* * ExecInitExpr: prepare an expression tree for execution *************** *** 113,119 **** ExprState * ExecInitExpr(Expr *node, PlanState *parent) { ExprState *state; - ExprEvalStep scratch; /* Special case: NULL expression produces a NULL ExprState pointer */ if (node == NULL) --- 201,206 ---- *************** *** 130,137 **** ExecInitExpr(Expr *node, PlanState *parent) ExecInitExprRec(node, parent, state, &state->resvalue, &state->resnull); /* Finally, append a DONE step */ ! scratch.opcode = EEOP_DONE; ! ExprEvalPushStep(state, &scratch); ExecReadyExpr(state); --- 217,223 ---- ExecInitExprRec(node, parent, state, &state->resvalue, &state->resnull); /* Finally, append a DONE step */ ! ExprEvalPushStep(state, EEOP_DONE, NULL, NULL); ExecReadyExpr(state); *************** *** 160,166 **** ExprState * ExecInitQual(List *qual, PlanState *parent) { ExprState *state; ! ExprEvalStep scratch; List *adjust_jumps = NIL; ListCell *lc; --- 246,252 ---- ExecInitQual(List *qual, PlanState *parent) { ExprState *state; ! ExprEvalStep_qualexpr *scratch; List *adjust_jumps = NIL; ListCell *lc; *************** *** 185,197 **** ExecInitQual(List *qual, PlanState *parent) * special opcode for qual evaluation that's simpler than BOOL_AND (which * has more complex NULL handling). */ - scratch.opcode = EEOP_QUAL; - - /* - * We can use ExprState's resvalue/resnull as target for each qual expr. - */ - scratch.resvalue = &state->resvalue; - scratch.resnull = &state->resnull; foreach(lc, qual) { --- 271,276 ---- *************** *** 200,229 **** ExecInitQual(List *qual, PlanState *parent) /* first evaluate expression */ ExecInitExprRec(node, parent, state, &state->resvalue, &state->resnull); ! /* then emit EEOP_QUAL to detect if it's false (or null) */ ! scratch.d.qualexpr.jumpdone = -1; ! ExprEvalPushStep(state, &scratch); ! adjust_jumps = lappend_int(adjust_jumps, ! state->steps_len - 1); ! } ! ! /* adjust jump targets */ ! foreach(lc, adjust_jumps) ! { ! ExprEvalStep *as = &state->steps[lfirst_int(lc)]; ! Assert(as->opcode == EEOP_QUAL); ! Assert(as->d.qualexpr.jumpdone == -1); ! as->d.qualexpr.jumpdone = state->steps_len; } /* * At the end, we don't need to do anything more. The last qual expr must * have yielded TRUE, and since its result is stored in the desired output * location, we're done. */ ! scratch.opcode = EEOP_DONE; ! ExprEvalPushStep(state, &scratch); ExecReadyExpr(state); --- 279,307 ---- /* first evaluate expression */ ExecInitExprRec(node, parent, state, &state->resvalue, &state->resnull); ! /* ! * Then emit EEOP_QUAL to detect if it's false (or null) ! * We can use ExprState's resvalue/resnull as target for each qual expr. ! */ ! scratch = (ExprEvalStep_qualexpr *) ! ExprEvalPushStep(state, ! EEOP_QUAL, ! &state->resvalue, ! &state->resnull); ! scratch->jumpdone = NULL; ! adjust_jumps = lappend(adjust_jumps, &scratch->jumpdone); } + /* Resolve the jumpdone pointers when the next operator is created */ + state->adjust_jumps = adjust_jumps; + /* * At the end, we don't need to do anything more. The last qual expr must * have yielded TRUE, and since its result is stored in the desired output * location, we're done. */ ! ExprEvalPushStep(state, EEOP_DONE, NULL, NULL); ExecReadyExpr(state); *************** *** 306,312 **** ExecBuildProjectionInfo(List *targetList, { ProjectionInfo *projInfo = makeNode(ProjectionInfo); ExprState *state; - ExprEvalStep scratch; ListCell *lc; projInfo->pi_exprContext = econtext; --- 384,389 ---- *************** *** 363,395 **** ExecBuildProjectionInfo(List *targetList, if (isSafeVar) { /* Fast-path: just generate an EEOP_ASSIGN_*_VAR step */ switch (variable->varno) { case INNER_VAR: /* get the tuple from the inner node */ ! scratch.opcode = EEOP_ASSIGN_INNER_VAR; break; case OUTER_VAR: /* get the tuple from the outer node */ ! scratch.opcode = EEOP_ASSIGN_OUTER_VAR; break; /* INDEX_VAR is handled by default case */ default: /* get the tuple from the relation being scanned */ ! scratch.opcode = EEOP_ASSIGN_SCAN_VAR; break; } ! scratch.d.assign_var.attnum = attnum - 1; ! scratch.d.assign_var.resultnum = tle->resno - 1; ! ExprEvalPushStep(state, &scratch); } else { /* * Otherwise, compile the column expression normally. * --- 440,482 ---- if (isSafeVar) { + ExprEvalStep_assign_var *scratch; + ExprEvalOp opcode; + /* Fast-path: just generate an EEOP_ASSIGN_*_VAR step */ switch (variable->varno) { case INNER_VAR: /* get the tuple from the inner node */ ! opcode = EEOP_ASSIGN_INNER_VAR; break; case OUTER_VAR: /* get the tuple from the outer node */ ! opcode = EEOP_ASSIGN_OUTER_VAR; break; /* INDEX_VAR is handled by default case */ default: /* get the tuple from the relation being scanned */ ! opcode = EEOP_ASSIGN_SCAN_VAR; break; } ! scratch = (ExprEvalStep_assign_var *) ! ExprEvalPushStep(state, ! opcode, ! NULL, ! NULL); ! scratch->attnum = attnum - 1; ! scratch->resultnum = tle->resno - 1; } else { + ExprEvalStep_assign_tmp *scratch; + ExprEvalOp opcode; + /* * Otherwise, compile the column expression normally. * *************** *** 406,421 **** ExecBuildProjectionInfo(List *targetList, * force value to R/O - but only if it could be an expanded datum. */ if (get_typlen(exprType((Node *) tle->expr)) == -1) ! scratch.opcode = EEOP_ASSIGN_TMP_MAKE_RO; else ! scratch.opcode = EEOP_ASSIGN_TMP; ! scratch.d.assign_tmp.resultnum = tle->resno - 1; ! ExprEvalPushStep(state, &scratch); } } ! scratch.opcode = EEOP_DONE; ! ExprEvalPushStep(state, &scratch); ExecReadyExpr(state); --- 493,511 ---- * force value to R/O - but only if it could be an expanded datum. */ if (get_typlen(exprType((Node *) tle->expr)) == -1) ! opcode = EEOP_ASSIGN_TMP_MAKE_RO; else ! opcode = EEOP_ASSIGN_TMP; ! scratch = (ExprEvalStep_assign_tmp *) ! ExprEvalPushStep(state, ! opcode, ! NULL, ! NULL); ! scratch->resultnum = tle->resno - 1; } } ! ExprEvalPushStep(state, EEOP_DONE, NULL, NULL); ExecReadyExpr(state); *************** *** 589,691 **** static void ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, Datum *resv, bool *resnull) { ! ExprEvalStep scratch; /* Guard against stack overflow due to overly complex expressions */ check_stack_depth(); /* Step's output location is always what the caller gave us */ Assert(resv != NULL && resnull != NULL); - scratch.resvalue = resv; - scratch.resnull = resnull; /* cases should be ordered as they are in enum NodeTag */ switch (nodeTag(node)) { case T_Var: { Var *variable = (Var *) node; if (variable->varattno == InvalidAttrNumber) { /* whole-row Var */ ! ExecInitWholeRowVar(&scratch, variable, parent); } else if (variable->varattno <= 0) { /* system column */ - scratch.d.var.attnum = variable->varattno; - scratch.d.var.vartype = variable->vartype; switch (variable->varno) { case INNER_VAR: ! scratch.opcode = EEOP_INNER_SYSVAR; break; case OUTER_VAR: ! scratch.opcode = EEOP_OUTER_SYSVAR; break; /* INDEX_VAR is handled by default case */ default: ! scratch.opcode = EEOP_SCAN_SYSVAR; break; } } else { /* regular user column */ - scratch.d.var.attnum = variable->varattno - 1; - scratch.d.var.vartype = variable->vartype; /* select EEOP_*_FIRST opcode to force one-time checks */ switch (variable->varno) { case INNER_VAR: ! scratch.opcode = EEOP_INNER_VAR_FIRST; break; case OUTER_VAR: ! scratch.opcode = EEOP_OUTER_VAR_FIRST; break; /* INDEX_VAR is handled by default case */ default: ! scratch.opcode = EEOP_SCAN_VAR_FIRST; break; } } - - ExprEvalPushStep(state, &scratch); break; } case T_Const: { Const *con = (Const *) node; ! scratch.opcode = EEOP_CONST; ! scratch.d.constval.value = con->constvalue; ! scratch.d.constval.isnull = con->constisnull; ! ! ExprEvalPushStep(state, &scratch); break; } case T_Param: { Param *param = (Param *) node; switch (param->paramkind) { case PARAM_EXEC: ! scratch.opcode = EEOP_PARAM_EXEC; ! scratch.d.param.paramid = param->paramid; ! scratch.d.param.paramtype = param->paramtype; break; case PARAM_EXTERN: ! scratch.opcode = EEOP_PARAM_EXTERN; ! scratch.d.param.paramid = param->paramid; ! scratch.d.param.paramtype = param->paramtype; break; default: elog(ERROR, "unrecognized paramkind: %d", --- 679,789 ---- ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, Datum *resv, bool *resnull) { ! ExprEvalOp opcode; /* Guard against stack overflow due to overly complex expressions */ check_stack_depth(); /* Step's output location is always what the caller gave us */ Assert(resv != NULL && resnull != NULL); /* cases should be ordered as they are in enum NodeTag */ switch (nodeTag(node)) { case T_Var: { + ExprEvalStep_var *scratch; Var *variable = (Var *) node; if (variable->varattno == InvalidAttrNumber) { /* whole-row Var */ ! ExecInitWholeRowVar(state, variable, parent, resv, resnull); } else if (variable->varattno <= 0) { /* system column */ switch (variable->varno) { case INNER_VAR: ! opcode = EEOP_INNER_SYSVAR; break; case OUTER_VAR: ! opcode = EEOP_OUTER_SYSVAR; break; /* INDEX_VAR is handled by default case */ default: ! opcode = EEOP_SCAN_SYSVAR; break; } + + scratch = (ExprEvalStep_var *) + ExprEvalPushStep(state, + opcode, + resv, + resnull); + scratch->attnum = variable->varattno; + scratch->vartype = variable->vartype; } else { /* regular user column */ /* select EEOP_*_FIRST opcode to force one-time checks */ switch (variable->varno) { case INNER_VAR: ! opcode = EEOP_INNER_VAR_FIRST; break; case OUTER_VAR: ! opcode = EEOP_OUTER_VAR_FIRST; break; /* INDEX_VAR is handled by default case */ default: ! opcode = EEOP_SCAN_VAR_FIRST; break; } + scratch = (ExprEvalStep_var *) + ExprEvalPushStep(state, + opcode, + resv, + resnull); + scratch->attnum = variable->varattno - 1; + scratch->vartype = variable->vartype; } break; } case T_Const: { + ExprEvalStep_constval *scratch; Const *con = (Const *) node; ! scratch = (ExprEvalStep_constval *) ! ExprEvalPushStep(state, ! EEOP_CONST, ! resv, ! resnull); ! scratch->value = con->constvalue; ! scratch->isnull = con->constisnull; break; } case T_Param: { + ExprEvalStep_param *scratch; Param *param = (Param *) node; switch (param->paramkind) { case PARAM_EXEC: ! opcode = EEOP_PARAM_EXEC; break; case PARAM_EXTERN: ! opcode = EEOP_PARAM_EXTERN; break; default: elog(ERROR, "unrecognized paramkind: %d", *************** *** 693,709 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, break; } ! ExprEvalPushStep(state, &scratch); break; } case T_Aggref: { Aggref *aggref = (Aggref *) node; AggrefExprState *astate = makeNode(AggrefExprState); ! scratch.opcode = EEOP_AGGREF; ! scratch.d.aggref.astate = astate; astate->aggref = aggref; if (parent && IsA(parent, AggState)) --- 791,818 ---- break; } ! scratch = (ExprEvalStep_param *) ! ExprEvalPushStep(state, ! opcode, ! resv, ! resnull); ! scratch->paramid = param->paramid; ! scratch->paramtype = param->paramtype; break; } case T_Aggref: { + ExprEvalStep_aggref *scratch; Aggref *aggref = (Aggref *) node; AggrefExprState *astate = makeNode(AggrefExprState); ! scratch = (ExprEvalStep_aggref *) ! ExprEvalPushStep(state, ! EEOP_AGGREF, ! resv, ! resnull); ! scratch->astate = astate; astate->aggref = aggref; if (parent && IsA(parent, AggState)) *************** *** 718,730 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, /* planner messed up */ elog(ERROR, "Aggref found in non-Agg plan node"); } - - ExprEvalPushStep(state, &scratch); break; } case T_GroupingFunc: { GroupingFunc *grp_node = (GroupingFunc *) node; Agg *agg; --- 827,838 ---- /* planner messed up */ elog(ERROR, "Aggref found in non-Agg plan node"); } break; } case T_GroupingFunc: { + ExprEvalStep_grouping_func *scratch; GroupingFunc *grp_node = (GroupingFunc *) node; Agg *agg; *************** *** 732,753 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, !IsA(parent->plan, Agg)) elog(ERROR, "GroupingFunc found in non-Agg plan node"); ! scratch.opcode = EEOP_GROUPING_FUNC; ! scratch.d.grouping_func.parent = (AggState *) parent; agg = (Agg *) (parent->plan); if (agg->groupingSets) ! scratch.d.grouping_func.clauses = grp_node->cols; else ! scratch.d.grouping_func.clauses = NIL; ! ! ExprEvalPushStep(state, &scratch); break; } case T_WindowFunc: { WindowFunc *wfunc = (WindowFunc *) node; WindowFuncExprState *wfstate = makeNode(WindowFuncExprState); --- 840,864 ---- !IsA(parent->plan, Agg)) elog(ERROR, "GroupingFunc found in non-Agg plan node"); ! scratch = (ExprEvalStep_grouping_func *) ! ExprEvalPushStep(state, ! EEOP_GROUPING_FUNC, ! resv, ! resnull); ! scratch->parent = (AggState *) parent; agg = (Agg *) (parent->plan); if (agg->groupingSets) ! scratch->clauses = grp_node->cols; else ! scratch->clauses = NIL; break; } case T_WindowFunc: { + ExprEvalStep_window_func *scratch; WindowFunc *wfunc = (WindowFunc *) node; WindowFuncExprState *wfstate = makeNode(WindowFuncExprState); *************** *** 785,793 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, elog(ERROR, "WindowFunc found in non-WindowAgg plan node"); } ! scratch.opcode = EEOP_WINDOW_FUNC; ! scratch.d.window_func.wfstate = wfstate; ! ExprEvalPushStep(state, &scratch); break; } --- 896,907 ---- elog(ERROR, "WindowFunc found in non-WindowAgg plan node"); } ! scratch = (ExprEvalStep_window_func *) ! ExprEvalPushStep(state, ! EEOP_WINDOW_FUNC, ! resv, ! resnull); ! scratch->wfstate = wfstate; break; } *************** *** 795,801 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, { ArrayRef *aref = (ArrayRef *) node; ! ExecInitArrayRef(&scratch, aref, parent, state, resv, resnull); break; } --- 909,915 ---- { ArrayRef *aref = (ArrayRef *) node; ! ExecInitArrayRef(aref, parent, state, resv, resnull); break; } *************** *** 803,812 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, { FuncExpr *func = (FuncExpr *) node; ! ExecInitFunc(&scratch, node, func->args, func->funcid, func->inputcollid, ! parent, state); ! ExprEvalPushStep(state, &scratch); break; } --- 917,925 ---- { FuncExpr *func = (FuncExpr *) node; ! ExecInitFunc(node, func->args, func->funcid, func->inputcollid, ! parent, state, resv, resnull); break; } *************** *** 814,823 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, { OpExpr *op = (OpExpr *) node; ! ExecInitFunc(&scratch, node, op->args, op->opfuncid, op->inputcollid, ! parent, state); ! ExprEvalPushStep(state, &scratch); break; } --- 927,935 ---- { OpExpr *op = (OpExpr *) node; ! ExecInitFunc(node, op->args, op->opfuncid, op->inputcollid, ! parent, state, resv, resnull); break; } *************** *** 825,833 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, { DistinctExpr *op = (DistinctExpr *) node; ! ExecInitFunc(&scratch, node, op->args, op->opfuncid, op->inputcollid, ! parent, state); /* * Change opcode of call instruction to EEOP_DISTINCT. --- 937,945 ---- { DistinctExpr *op = (DistinctExpr *) node; ! ExecInitFunc(node, op->args, op->opfuncid, op->inputcollid, ! parent, state, resv, resnull); /* * Change opcode of call instruction to EEOP_DISTINCT. *************** *** 838,845 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, * we decided to do that here, we'd probably want separate * opcodes for FUSAGE or not. */ ! scratch.opcode = EEOP_DISTINCT; ! ExprEvalPushStep(state, &scratch); break; } --- 950,956 ---- * we decided to do that here, we'd probably want separate * opcodes for FUSAGE or not. */ ! state->last_step->opcode = EEOP_DISTINCT; break; } *************** *** 847,855 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, { NullIfExpr *op = (NullIfExpr *) node; ! ExecInitFunc(&scratch, node, op->args, op->opfuncid, op->inputcollid, ! parent, state); /* * Change opcode of call instruction to EEOP_NULLIF. --- 958,966 ---- { NullIfExpr *op = (NullIfExpr *) node; ! ExecInitFunc(node, op->args, op->opfuncid, op->inputcollid, ! parent, state, resv, resnull); /* * Change opcode of call instruction to EEOP_NULLIF. *************** *** 860,872 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, * we decided to do that here, we'd probably want separate * opcodes for FUSAGE or not. */ ! scratch.opcode = EEOP_NULLIF; ! ExprEvalPushStep(state, &scratch); break; } case T_ScalarArrayOpExpr: { ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; Expr *scalararg; Expr *arrayarg; --- 971,983 ---- * we decided to do that here, we'd probably want separate * opcodes for FUSAGE or not. */ ! state->last_step->opcode = EEOP_NULLIF; break; } case T_ScalarArrayOpExpr: { + ExprEvalStep_scalararrayop *scratch; ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; Expr *scalararg; Expr *arrayarg; *************** *** 908,934 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, ExecInitExprRec(arrayarg, parent, state, resv, resnull); /* And perform the operation */ ! scratch.opcode = EEOP_SCALARARRAYOP; ! scratch.d.scalararrayop.element_type = InvalidOid; ! scratch.d.scalararrayop.useOr = opexpr->useOr; ! scratch.d.scalararrayop.finfo = finfo; ! scratch.d.scalararrayop.fcinfo_data = fcinfo; ! scratch.d.scalararrayop.fn_addr = finfo->fn_addr; ! ExprEvalPushStep(state, &scratch); break; } case T_BoolExpr: { BoolExpr *boolexpr = (BoolExpr *) node; int nargs = list_length(boolexpr->args); List *adjust_jumps = NIL; int off; ListCell *lc; /* allocate scratch memory used by all steps of AND/OR */ if (boolexpr->boolop != NOT_EXPR) ! scratch.d.boolexpr.anynull = (bool *) palloc(sizeof(bool)); /* * For each argument evaluate the argument itself, then --- 1019,1050 ---- ExecInitExprRec(arrayarg, parent, state, resv, resnull); /* And perform the operation */ ! scratch = (ExprEvalStep_scalararrayop *) ! ExprEvalPushStep(state, ! EEOP_SCALARARRAYOP, ! resv, ! resnull); ! scratch->element_type = InvalidOid; ! scratch->useOr = opexpr->useOr; ! scratch->finfo = finfo; ! scratch->fcinfo_data = fcinfo; ! scratch->fn_addr = finfo->fn_addr; break; } case T_BoolExpr: { + ExprEvalStep_boolexpr *scratch; BoolExpr *boolexpr = (BoolExpr *) node; int nargs = list_length(boolexpr->args); List *adjust_jumps = NIL; int off; ListCell *lc; + bool *anynull = NULL; /* allocate scratch memory used by all steps of AND/OR */ if (boolexpr->boolop != NOT_EXPR) ! anynull = (bool *) palloc(sizeof(bool)); /* * For each argument evaluate the argument itself, then *************** *** 958,983 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, Assert(nargs >= 2); if (off == 0) ! scratch.opcode = EEOP_BOOL_AND_STEP_FIRST; else if (off + 1 == nargs) ! scratch.opcode = EEOP_BOOL_AND_STEP_LAST; else ! scratch.opcode = EEOP_BOOL_AND_STEP; break; case OR_EXPR: Assert(nargs >= 2); if (off == 0) ! scratch.opcode = EEOP_BOOL_OR_STEP_FIRST; else if (off + 1 == nargs) ! scratch.opcode = EEOP_BOOL_OR_STEP_LAST; else ! scratch.opcode = EEOP_BOOL_OR_STEP; break; case NOT_EXPR: Assert(nargs == 1); ! scratch.opcode = EEOP_BOOL_NOT_STEP; break; default: elog(ERROR, "unrecognized boolop: %d", --- 1074,1099 ---- Assert(nargs >= 2); if (off == 0) ! opcode = EEOP_BOOL_AND_STEP_FIRST; else if (off + 1 == nargs) ! opcode = EEOP_BOOL_AND_STEP_LAST; else ! opcode = EEOP_BOOL_AND_STEP; break; case OR_EXPR: Assert(nargs >= 2); if (off == 0) ! opcode = EEOP_BOOL_OR_STEP_FIRST; else if (off + 1 == nargs) ! opcode = EEOP_BOOL_OR_STEP_LAST; else ! opcode = EEOP_BOOL_OR_STEP; break; case NOT_EXPR: Assert(nargs == 1); ! opcode = EEOP_BOOL_NOT_STEP; break; default: elog(ERROR, "unrecognized boolop: %d", *************** *** 985,1011 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, break; } ! scratch.d.boolexpr.jumpdone = -1; ! ExprEvalPushStep(state, &scratch); ! adjust_jumps = lappend_int(adjust_jumps, ! state->steps_len - 1); off++; } ! /* adjust jump targets */ ! foreach(lc, adjust_jumps) ! { ! ExprEvalStep *as = &state->steps[lfirst_int(lc)]; ! ! Assert(as->d.boolexpr.jumpdone == -1); ! as->d.boolexpr.jumpdone = state->steps_len; ! } break; } case T_SubPlan: { SubPlan *subplan = (SubPlan *) node; SubPlanState *sstate; --- 1101,1126 ---- break; } ! scratch = (ExprEvalStep_boolexpr *) ! ExprEvalPushStep(state, ! opcode, ! resv, ! resnull); ! scratch->jumpdone = NULL; ! scratch->anynull = anynull; ! adjust_jumps = lappend(adjust_jumps, &scratch->jumpdone); off++; } ! /* Resolve the jumpdone pointers when the next operator is created */ ! state->adjust_jumps = adjust_jumps; break; } case T_SubPlan: { + ExprEvalStep_subplan *scratch; SubPlan *subplan = (SubPlan *) node; SubPlanState *sstate; *************** *** 1017,1031 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, /* add SubPlanState nodes to parent->subPlan */ parent->subPlan = lappend(parent->subPlan, sstate); ! scratch.opcode = EEOP_SUBPLAN; ! scratch.d.subplan.sstate = sstate; ! ! ExprEvalPushStep(state, &scratch); break; } case T_AlternativeSubPlan: { AlternativeSubPlan *asplan = (AlternativeSubPlan *) node; AlternativeSubPlanState *asstate; --- 1132,1149 ---- /* add SubPlanState nodes to parent->subPlan */ parent->subPlan = lappend(parent->subPlan, sstate); ! scratch = (ExprEvalStep_subplan *) ! ExprEvalPushStep(state, ! EEOP_SUBPLAN, ! resv, ! resnull); ! scratch->sstate = sstate; break; } case T_AlternativeSubPlan: { + ExprEvalStep_alternative_subplan *scratch; AlternativeSubPlan *asplan = (AlternativeSubPlan *) node; AlternativeSubPlanState *asstate; *************** *** 1034,1065 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, asstate = ExecInitAlternativeSubPlan(asplan, parent); ! scratch.opcode = EEOP_ALTERNATIVE_SUBPLAN; ! scratch.d.alternative_subplan.asstate = asstate; ! ! ExprEvalPushStep(state, &scratch); break; } case T_FieldSelect: { FieldSelect *fselect = (FieldSelect *) node; /* evaluate row/record argument into result area */ ExecInitExprRec(fselect->arg, parent, state, resv, resnull); /* and extract field */ ! scratch.opcode = EEOP_FIELDSELECT; ! scratch.d.fieldselect.fieldnum = fselect->fieldnum; ! scratch.d.fieldselect.resulttype = fselect->resulttype; ! scratch.d.fieldselect.argdesc = NULL; ! ! ExprEvalPushStep(state, &scratch); break; } case T_FieldStore: { FieldStore *fstore = (FieldStore *) node; TupleDesc tupDesc; TupleDesc *descp; --- 1152,1189 ---- asstate = ExecInitAlternativeSubPlan(asplan, parent); ! scratch = (ExprEvalStep_alternative_subplan *) ! ExprEvalPushStep(state, ! EEOP_ALTERNATIVE_SUBPLAN, ! resv, ! resnull); ! scratch->asstate = asstate; break; } case T_FieldSelect: { + ExprEvalStep_fieldselect *scratch; FieldSelect *fselect = (FieldSelect *) node; /* evaluate row/record argument into result area */ ExecInitExprRec(fselect->arg, parent, state, resv, resnull); /* and extract field */ ! scratch = (ExprEvalStep_fieldselect *) ! ExprEvalPushStep(state, ! EEOP_FIELDSELECT, ! resv, ! resnull); ! scratch->fieldnum = fselect->fieldnum; ! scratch->resulttype = fselect->resulttype; ! scratch->argdesc = NULL; break; } case T_FieldStore: { + ExprEvalStep_fieldstore *scratch; FieldStore *fstore = (FieldStore *) node; TupleDesc tupDesc; TupleDesc *descp; *************** *** 1086,1098 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, ExecInitExprRec(fstore->arg, parent, state, resv, resnull); /* next, deform the input tuple into our workspace */ ! scratch.opcode = EEOP_FIELDSTORE_DEFORM; ! scratch.d.fieldstore.fstore = fstore; ! scratch.d.fieldstore.argdesc = descp; ! scratch.d.fieldstore.values = values; ! scratch.d.fieldstore.nulls = nulls; ! scratch.d.fieldstore.ncolumns = ncolumns; ! ExprEvalPushStep(state, &scratch); /* evaluate new field values, store in workspace columns */ forboth(l1, fstore->newvals, l2, fstore->fieldnums) --- 1210,1225 ---- ExecInitExprRec(fstore->arg, parent, state, resv, resnull); /* next, deform the input tuple into our workspace */ ! scratch = (ExprEvalStep_fieldstore *) ! ExprEvalPushStep(state, ! EEOP_FIELDSTORE_DEFORM, ! resv, ! resnull); ! scratch->fstore = fstore; ! scratch->argdesc = descp; ! scratch->values = values; ! scratch->nulls = nulls; ! scratch->ncolumns = ncolumns; /* evaluate new field values, store in workspace columns */ forboth(l1, fstore->newvals, l2, fstore->fieldnums) *************** *** 1143,1155 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, } /* finally, form result tuple */ ! scratch.opcode = EEOP_FIELDSTORE_FORM; ! scratch.d.fieldstore.fstore = fstore; ! scratch.d.fieldstore.argdesc = descp; ! scratch.d.fieldstore.values = values; ! scratch.d.fieldstore.nulls = nulls; ! scratch.d.fieldstore.ncolumns = ncolumns; ! ExprEvalPushStep(state, &scratch); break; } --- 1270,1285 ---- } /* finally, form result tuple */ ! scratch = (ExprEvalStep_fieldstore *) ! ExprEvalPushStep(state, ! EEOP_FIELDSTORE_FORM, ! resv, ! resnull); ! scratch->fstore = fstore; ! scratch->argdesc = descp; ! scratch->values = values; ! scratch->nulls = nulls; ! scratch->ncolumns = ncolumns; break; } *************** *** 1164,1169 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, --- 1294,1300 ---- case T_CoerceViaIO: { + ExprEvalStep_iocoerce *scratch; CoerceViaIO *iocoerce = (CoerceViaIO *) node; Oid iofunc; bool typisvarlena; *************** *** 1181,1228 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, * We don't check permissions here as a type's input/output * function are assumed to be executable by everyone. */ ! scratch.opcode = EEOP_IOCOERCE; /* lookup the source type's output function */ ! scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo)); ! scratch.d.iocoerce.fcinfo_data_out = palloc0(sizeof(FunctionCallInfoData)); getTypeOutputInfo(exprType((Node *) iocoerce->arg), &iofunc, &typisvarlena); ! fmgr_info(iofunc, scratch.d.iocoerce.finfo_out); ! fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out); ! InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out, ! scratch.d.iocoerce.finfo_out, 1, InvalidOid, NULL, NULL); /* lookup the result type's input function */ ! scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo)); ! scratch.d.iocoerce.fcinfo_data_in = palloc0(sizeof(FunctionCallInfoData)); getTypeInputInfo(iocoerce->resulttype, &iofunc, &typioparam); ! fmgr_info(iofunc, scratch.d.iocoerce.finfo_in); ! fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in); ! InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in, ! scratch.d.iocoerce.finfo_in, 3, InvalidOid, NULL, NULL); /* * We can preload the second and third arguments for the input * function, since they're constants. */ ! fcinfo_in = scratch.d.iocoerce.fcinfo_data_in; fcinfo_in->arg[1] = ObjectIdGetDatum(typioparam); fcinfo_in->argnull[1] = false; fcinfo_in->arg[2] = Int32GetDatum(-1); fcinfo_in->argnull[2] = false; - - ExprEvalPushStep(state, &scratch); break; } case T_ArrayCoerceExpr: { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; Oid resultelemtype; --- 1312,1362 ---- * We don't check permissions here as a type's input/output * function are assumed to be executable by everyone. */ ! scratch = (ExprEvalStep_iocoerce *) ! ExprEvalPushStep(state, ! EEOP_IOCOERCE, ! resv, ! resnull); /* lookup the source type's output function */ ! scratch->finfo_out = palloc0(sizeof(FmgrInfo)); ! scratch->fcinfo_data_out = palloc0(sizeof(FunctionCallInfoData)); getTypeOutputInfo(exprType((Node *) iocoerce->arg), &iofunc, &typisvarlena); ! fmgr_info(iofunc, scratch->finfo_out); ! fmgr_info_set_expr((Node *) node, scratch->finfo_out); ! InitFunctionCallInfoData(*scratch->fcinfo_data_out, ! scratch->finfo_out, 1, InvalidOid, NULL, NULL); /* lookup the result type's input function */ ! scratch->finfo_in = palloc0(sizeof(FmgrInfo)); ! scratch->fcinfo_data_in = palloc0(sizeof(FunctionCallInfoData)); getTypeInputInfo(iocoerce->resulttype, &iofunc, &typioparam); ! fmgr_info(iofunc, scratch->finfo_in); ! fmgr_info_set_expr((Node *) node, scratch->finfo_in); ! InitFunctionCallInfoData(*scratch->fcinfo_data_in, ! scratch->finfo_in, 3, InvalidOid, NULL, NULL); /* * We can preload the second and third arguments for the input * function, since they're constants. */ ! fcinfo_in = scratch->fcinfo_data_in; fcinfo_in->arg[1] = ObjectIdGetDatum(typioparam); fcinfo_in->argnull[1] = false; fcinfo_in->arg[2] = Int32GetDatum(-1); fcinfo_in->argnull[2] = false; break; } case T_ArrayCoerceExpr: { + ExprEvalStep_arraycoerce *scratch; ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; Oid resultelemtype; *************** *** 1237,1245 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, /* Arrays over domains aren't supported yet */ Assert(getBaseType(resultelemtype) == resultelemtype); ! scratch.opcode = EEOP_ARRAYCOERCE; ! scratch.d.arraycoerce.coerceexpr = acoerce; ! scratch.d.arraycoerce.resultelemtype = resultelemtype; if (OidIsValid(acoerce->elemfuncid)) { --- 1371,1383 ---- /* Arrays over domains aren't supported yet */ Assert(getBaseType(resultelemtype) == resultelemtype); ! scratch = (ExprEvalStep_arraycoerce *) ! ExprEvalPushStep(state, ! EEOP_ARRAYCOERCE, ! resv, ! resnull); ! scratch->coerceexpr = acoerce; ! scratch->resultelemtype = resultelemtype; if (OidIsValid(acoerce->elemfuncid)) { *************** *** 1255,1298 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, InvokeFunctionExecuteHook(acoerce->elemfuncid); /* Set up the primary fmgr lookup information */ ! scratch.d.arraycoerce.elemfunc = (FmgrInfo *) palloc0(sizeof(FmgrInfo)); fmgr_info(acoerce->elemfuncid, ! scratch.d.arraycoerce.elemfunc); fmgr_info_set_expr((Node *) acoerce, ! scratch.d.arraycoerce.elemfunc); /* Set up workspace for array_map */ ! scratch.d.arraycoerce.amstate = (ArrayMapState *) palloc0(sizeof(ArrayMapState)); } else { /* Don't need workspace if there's no conversion func */ ! scratch.d.arraycoerce.elemfunc = NULL; ! scratch.d.arraycoerce.amstate = NULL; } - - ExprEvalPushStep(state, &scratch); break; } case T_ConvertRowtypeExpr: { ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node; /* evaluate argument into step's result area */ ExecInitExprRec(convert->arg, parent, state, resv, resnull); /* and push conversion step */ ! scratch.opcode = EEOP_CONVERT_ROWTYPE; ! scratch.d.convert_rowtype.convert = convert; ! scratch.d.convert_rowtype.indesc = NULL; ! scratch.d.convert_rowtype.outdesc = NULL; ! scratch.d.convert_rowtype.map = NULL; ! scratch.d.convert_rowtype.initialized = false; ! ! ExprEvalPushStep(state, &scratch); break; } --- 1393,1437 ---- InvokeFunctionExecuteHook(acoerce->elemfuncid); /* Set up the primary fmgr lookup information */ ! scratch->elemfunc = (FmgrInfo *) palloc0(sizeof(FmgrInfo)); fmgr_info(acoerce->elemfuncid, ! scratch->elemfunc); fmgr_info_set_expr((Node *) acoerce, ! scratch->elemfunc); /* Set up workspace for array_map */ ! scratch->amstate = (ArrayMapState *) palloc0(sizeof(ArrayMapState)); } else { /* Don't need workspace if there's no conversion func */ ! scratch->elemfunc = NULL; ! scratch->amstate = NULL; } break; } case T_ConvertRowtypeExpr: { + ExprEvalStep_convert_rowtype *scratch; ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node; /* evaluate argument into step's result area */ ExecInitExprRec(convert->arg, parent, state, resv, resnull); /* and push conversion step */ ! scratch = (ExprEvalStep_convert_rowtype *) ! ExprEvalPushStep(state, ! EEOP_CONVERT_ROWTYPE, ! resv, ! resnull); ! scratch->convert = convert; ! scratch->indesc = NULL; ! scratch->outdesc = NULL; ! scratch->map = NULL; ! scratch->initialized = false; break; } *************** *** 1325,1340 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, */ if (get_typlen(exprType((Node *) caseExpr->arg)) == -1) { /* change caseval in-place */ ! scratch.opcode = EEOP_MAKE_READONLY; ! scratch.resvalue = caseval; ! scratch.resnull = casenull; ! scratch.d.make_readonly.value = caseval; ! scratch.d.make_readonly.isnull = casenull; ! ExprEvalPushStep(state, &scratch); ! /* restore normal settings of scratch fields */ ! scratch.resvalue = resv; ! scratch.resnull = resnull; } } --- 1464,1479 ---- */ if (get_typlen(exprType((Node *) caseExpr->arg)) == -1) { + ExprEvalStep_make_readonly *scratch; + /* change caseval in-place */ ! scratch = (ExprEvalStep_make_readonly *) ! ExprEvalPushStep(state, ! EEOP_MAKE_READONLY, ! caseval, ! casenull); ! scratch->value = caseval; ! scratch->isnull = casenull; } } *************** *** 1346,1355 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, */ foreach(lc, caseExpr->args) { CaseWhen *when = (CaseWhen *) lfirst(lc); Datum *save_innermost_caseval; bool *save_innermost_casenull; ! int whenstep; /* * Make testexpr result available to CaseTestExpr nodes --- 1485,1495 ---- */ foreach(lc, caseExpr->args) { + ExprEvalStep_jump *scratch; CaseWhen *when = (CaseWhen *) lfirst(lc); Datum *save_innermost_caseval; bool *save_innermost_casenull; ! ExprEvalStep_jump *whenstep; /* * Make testexpr result available to CaseTestExpr nodes *************** *** 1373,1382 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, state->innermost_casenull = save_innermost_casenull; /* If WHEN result isn't true, jump to next CASE arm */ ! scratch.opcode = EEOP_JUMP_IF_NOT_TRUE; ! scratch.d.jump.jumpdone = -1; /* computed later */ ! ExprEvalPushStep(state, &scratch); ! whenstep = state->steps_len - 1; /* * If WHEN result is true, evaluate THEN result, storing --- 1513,1525 ---- state->innermost_casenull = save_innermost_casenull; /* If WHEN result isn't true, jump to next CASE arm */ ! scratch = (ExprEvalStep_jump *) ! ExprEvalPushStep(state, ! EEOP_JUMP_IF_NOT_TRUE, ! resv, ! resnull); ! scratch->jumpdone = NULL; /* computed later */ ! whenstep = scratch; /* * If WHEN result is true, evaluate THEN result, storing *************** *** 1385,1406 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, ExecInitExprRec(when->result, parent, state, resv, resnull); /* Emit JUMP step to jump to end of CASE's code */ ! scratch.opcode = EEOP_JUMP; ! scratch.d.jump.jumpdone = -1; /* computed later */ ! ExprEvalPushStep(state, &scratch); /* * Don't know address for that jump yet, compute once the * whole CASE expression is built. */ ! adjust_jumps = lappend_int(adjust_jumps, ! state->steps_len - 1); /* * But we can set WHEN test's jump target now, to make it * jump to the next WHEN subexpression or the ELSE. */ ! state->steps[whenstep].d.jump.jumpdone = state->steps_len; } /* transformCaseExpr always adds a default */ --- 1528,1554 ---- ExecInitExprRec(when->result, parent, state, resv, resnull); /* Emit JUMP step to jump to end of CASE's code */ ! scratch = (ExprEvalStep_jump *) ! ExprEvalPushStep(state, ! EEOP_JUMP, ! resv, ! resnull); ! scratch->jumpdone = NULL; /* computed later */ /* * Don't know address for that jump yet, compute once the * whole CASE expression is built. */ ! adjust_jumps = lappend(adjust_jumps, &scratch->jumpdone); /* * But we can set WHEN test's jump target now, to make it * jump to the next WHEN subexpression or the ELSE. + * Since we only have one pointer to resolve, just put it + * directly into state->adjust_jumps. */ ! state->adjust_jumps = lappend(state->adjust_jumps, ! &whenstep->jumpdone); } /* transformCaseExpr always adds a default */ *************** *** 1410,1430 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, ExecInitExprRec(caseExpr->defresult, parent, state, resv, resnull); ! /* adjust jump targets */ ! foreach(lc, adjust_jumps) ! { ! ExprEvalStep *as = &state->steps[lfirst_int(lc)]; ! ! Assert(as->opcode == EEOP_JUMP); ! Assert(as->d.jump.jumpdone == -1); ! as->d.jump.jumpdone = state->steps_len; ! } break; } case T_CaseTestExpr: { /* * Read from location identified by innermost_caseval. Note * that innermost_caseval could be NULL, if this node isn't --- 1558,1581 ---- ExecInitExprRec(caseExpr->defresult, parent, state, resv, resnull); ! /* ! * Resolve the jumpdone pointers when the next operator is created ! * If it happens that the ELSE expr didn't generate any operators ! * then there will still be an entry in state->adjust_jumps ! * for the last whenstep. We don't want to lose it, so add it ! * to the current list. ! */ ! if (state->adjust_jumps != NIL) ! adjust_jumps = list_concat(adjust_jumps, state->adjust_jumps); ! state->adjust_jumps = adjust_jumps; break; } case T_CaseTestExpr: { + ExprEvalStep_casetest *scratch; + /* * Read from location identified by innermost_caseval. Note * that innermost_caseval could be NULL, if this node isn't *************** *** 1433,1474 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, * supplied in econtext->caseValue_datum. We'll take care of * that scenario at runtime. */ ! scratch.opcode = EEOP_CASE_TESTVAL; ! scratch.d.casetest.value = state->innermost_caseval; ! scratch.d.casetest.isnull = state->innermost_casenull; ! ! ExprEvalPushStep(state, &scratch); break; } case T_ArrayExpr: { ArrayExpr *arrayexpr = (ArrayExpr *) node; int nelems = list_length(arrayexpr->elements); ListCell *lc; int elemoff; /* * Evaluate by computing each element, and then forming the * array. Elements are computed into scratch arrays * associated with the ARRAYEXPR step. */ - scratch.opcode = EEOP_ARRAYEXPR; - scratch.d.arrayexpr.elemvalues = - (Datum *) palloc(sizeof(Datum) * nelems); - scratch.d.arrayexpr.elemnulls = - (bool *) palloc(sizeof(bool) * nelems); - scratch.d.arrayexpr.nelems = nelems; ! /* fill remaining fields of step */ ! scratch.d.arrayexpr.multidims = arrayexpr->multidims; ! scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid; ! ! /* do one-time catalog lookup for type info */ ! get_typlenbyvalalign(arrayexpr->element_typeid, ! &scratch.d.arrayexpr.elemlength, ! &scratch.d.arrayexpr.elembyval, ! &scratch.d.arrayexpr.elemalign); /* prepare to evaluate all arguments */ elemoff = 0; --- 1584,1617 ---- * supplied in econtext->caseValue_datum. We'll take care of * that scenario at runtime. */ ! scratch = (ExprEvalStep_casetest *) ! ExprEvalPushStep(state, ! EEOP_CASE_TESTVAL, ! resv, ! resnull); ! scratch->value = state->innermost_caseval; ! scratch->isnull = state->innermost_casenull; break; } case T_ArrayExpr: { + ExprEvalStep_arrayexpr *scratch; ArrayExpr *arrayexpr = (ArrayExpr *) node; int nelems = list_length(arrayexpr->elements); ListCell *lc; int elemoff; + Datum *elemvalues; + bool *elemnulls; /* * Evaluate by computing each element, and then forming the * array. Elements are computed into scratch arrays * associated with the ARRAYEXPR step. */ ! elemvalues = (Datum *) palloc(sizeof(Datum) * nelems); ! elemnulls = (bool *) palloc(sizeof(bool) * nelems); /* prepare to evaluate all arguments */ elemoff = 0; *************** *** 1477,1497 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, Expr *e = (Expr *) lfirst(lc); ExecInitExprRec(e, parent, state, ! &scratch.d.arrayexpr.elemvalues[elemoff], ! &scratch.d.arrayexpr.elemnulls[elemoff]); elemoff++; } /* and then collect all into an array */ ! ExprEvalPushStep(state, &scratch); break; } case T_RowExpr: { RowExpr *rowexpr = (RowExpr *) node; int nelems = list_length(rowexpr->args); TupleDesc tupdesc; Form_pg_attribute *attrs; int i; ListCell *l; --- 1620,1660 ---- Expr *e = (Expr *) lfirst(lc); ExecInitExprRec(e, parent, state, ! &elemvalues[elemoff], ! &elemnulls[elemoff]); elemoff++; } /* and then collect all into an array */ ! scratch = (ExprEvalStep_arrayexpr *) ! ExprEvalPushStep(state, ! EEOP_ARRAYEXPR, ! resv, ! resnull); ! scratch->elemvalues = elemvalues; ! scratch->elemnulls = elemnulls; ! scratch->nelems = nelems; ! ! /* fill remaining fields of step */ ! scratch->multidims = arrayexpr->multidims; ! scratch->elemtype = arrayexpr->element_typeid; ! ! /* do one-time catalog lookup for type info */ ! get_typlenbyvalalign(arrayexpr->element_typeid, ! &scratch->elemlength, ! &scratch->elembyval, ! &scratch->elemalign); break; } case T_RowExpr: { + ExprEvalStep_row *scratch; RowExpr *rowexpr = (RowExpr *) node; int nelems = list_length(rowexpr->args); TupleDesc tupdesc; + Datum *elemvalues; + bool *elemnulls; Form_pg_attribute *attrs; int i; ListCell *l; *************** *** 1527,1542 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, * Evaluate by first building datums for each field, and then * a final step forming the composite datum. */ - scratch.opcode = EEOP_ROW; - scratch.d.row.tupdesc = tupdesc; /* space for the individual field datums */ ! scratch.d.row.elemvalues = ! (Datum *) palloc(sizeof(Datum) * nelems); ! scratch.d.row.elemnulls = ! (bool *) palloc(sizeof(bool) * nelems); /* as explained above, make sure any extra columns are null */ ! memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems); /* Set up evaluation, skipping any deleted columns */ attrs = tupdesc->attrs; --- 1690,1702 ---- * Evaluate by first building datums for each field, and then * a final step forming the composite datum. */ /* space for the individual field datums */ ! elemvalues = (Datum *) palloc(sizeof(Datum) * nelems); ! elemnulls = (bool *) palloc(sizeof(bool) * nelems); ! /* as explained above, make sure any extra columns are null */ ! memset(elemnulls, true, sizeof(bool) * nelems); /* Set up evaluation, skipping any deleted columns */ attrs = tupdesc->attrs; *************** *** 1572,1589 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, /* Evaluate column expr into appropriate workspace slot */ ExecInitExprRec(e, parent, state, ! &scratch.d.row.elemvalues[i], ! &scratch.d.row.elemnulls[i]); i++; } /* And finally build the row value */ ! ExprEvalPushStep(state, &scratch); break; } case T_RowCompareExpr: { RowCompareExpr *rcexpr = (RowCompareExpr *) node; int nopers = list_length(rcexpr->opnos); List *adjust_jumps = NIL; --- 1732,1757 ---- /* Evaluate column expr into appropriate workspace slot */ ExecInitExprRec(e, parent, state, ! &elemvalues[i], ! &elemnulls[i]); i++; } /* And finally build the row value */ ! scratch = (ExprEvalStep_row *) ! ExprEvalPushStep(state, ! EEOP_ROW, ! resv, ! resnull); ! scratch->tupdesc = tupdesc; ! scratch->elemvalues = elemvalues; ! scratch->elemnulls = elemnulls; break; } case T_RowCompareExpr: { + ExprEvalStep_rowcompare_final *scratch; RowCompareExpr *rcexpr = (RowCompareExpr *) node; int nopers = list_length(rcexpr->opnos); List *adjust_jumps = NIL; *************** *** 1620,1625 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, --- 1788,1794 ---- l_opfamily = lnext(l_opfamily), l_inputcollid = lnext(l_inputcollid)) { + ExprEvalStep_rowcompare_step *scratch; Expr *left_expr = (Expr *) lfirst(l_left_expr); Expr *right_expr = (Expr *) lfirst(l_right_expr); Oid opno = lfirst_oid(l_opno); *************** *** 1665,1681 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, ExecInitExprRec(right_expr, parent, state, &fcinfo->arg[1], &fcinfo->argnull[1]); ! scratch.opcode = EEOP_ROWCOMPARE_STEP; ! scratch.d.rowcompare_step.finfo = finfo; ! scratch.d.rowcompare_step.fcinfo_data = fcinfo; ! scratch.d.rowcompare_step.fn_addr = finfo->fn_addr; /* jump targets filled below */ ! scratch.d.rowcompare_step.jumpnull = -1; ! scratch.d.rowcompare_step.jumpdone = -1; ! ExprEvalPushStep(state, &scratch); ! adjust_jumps = lappend_int(adjust_jumps, ! state->steps_len - 1); } /* --- 1834,1852 ---- ExecInitExprRec(right_expr, parent, state, &fcinfo->arg[1], &fcinfo->argnull[1]); ! scratch = (ExprEvalStep_rowcompare_step *) ! ExprEvalPushStep(state, ! EEOP_ROWCOMPARE_STEP, ! resv, ! resnull); ! scratch->finfo = finfo; ! scratch->fcinfo_data = fcinfo; ! scratch->fn_addr = finfo->fn_addr; /* jump targets filled below */ ! scratch->jumpnull = NULL; ! scratch->jumpdone = NULL; ! adjust_jumps = lappend(adjust_jumps, scratch); } /* *************** *** 1684,1713 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, */ if (nopers == 0) { ! scratch.opcode = EEOP_CONST; ! scratch.d.constval.value = Int32GetDatum(0); ! scratch.d.constval.isnull = false; ! ExprEvalPushStep(state, &scratch); } /* Finally, examine the last comparison result */ ! scratch.opcode = EEOP_ROWCOMPARE_FINAL; ! scratch.d.rowcompare_final.rctype = rcexpr->rctype; ! ExprEvalPushStep(state, &scratch); /* adjust jump targetss */ foreach(lc, adjust_jumps) { ! ExprEvalStep *as = &state->steps[lfirst_int(lc)]; Assert(as->opcode == EEOP_ROWCOMPARE_STEP); ! Assert(as->d.rowcompare_step.jumpdone == -1); ! Assert(as->d.rowcompare_step.jumpnull == -1); /* jump to comparison evaluation */ ! as->d.rowcompare_step.jumpdone = state->steps_len - 1; /* jump to the following expression */ ! as->d.rowcompare_step.jumpnull = state->steps_len; } break; --- 1855,1894 ---- */ if (nopers == 0) { ! ExprEvalStep_constval *scratch; ! ! scratch = (ExprEvalStep_constval *) ! ExprEvalPushStep(state, ! EEOP_CONST, ! resv, ! resnull); ! scratch->value = Int32GetDatum(0); ! scratch->isnull = false; } /* Finally, examine the last comparison result */ ! scratch = (ExprEvalStep_rowcompare_final *) ! ExprEvalPushStep(state, ! EEOP_ROWCOMPARE_FINAL, ! resv, ! resnull); ! scratch->rctype = rcexpr->rctype; /* adjust jump targetss */ foreach(lc, adjust_jumps) { ! ExprEvalStep_rowcompare_step *as = ! (ExprEvalStep_rowcompare_step*)lfirst(lc); Assert(as->opcode == EEOP_ROWCOMPARE_STEP); ! Assert(as->jumpdone == NULL); ! Assert(as->jumpnull == NULL); /* jump to comparison evaluation */ ! as->jumpdone = (ExprEvalStep *)scratch; /* jump to the following expression */ ! state->adjust_jumps = lappend(state->adjust_jumps, ! &as->jumpnull); } break; *************** *** 1728,1745 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, */ foreach(lc, coalesce->args) { Expr *e = (Expr *) lfirst(lc); /* evaluate argument, directly into result datum */ ExecInitExprRec(e, parent, state, resv, resnull); /* if it's not null, skip to end of COALESCE expr */ ! scratch.opcode = EEOP_JUMP_IF_NOT_NULL; ! scratch.d.jump.jumpdone = -1; /* adjust later */ ! ExprEvalPushStep(state, &scratch); ! adjust_jumps = lappend_int(adjust_jumps, ! state->steps_len - 1); } /* --- 1909,1929 ---- */ foreach(lc, coalesce->args) { + ExprEvalStep_jump *scratch; Expr *e = (Expr *) lfirst(lc); /* evaluate argument, directly into result datum */ ExecInitExprRec(e, parent, state, resv, resnull); /* if it's not null, skip to end of COALESCE expr */ ! scratch = (ExprEvalStep_jump *) ! ExprEvalPushStep(state, ! EEOP_JUMP_IF_NOT_NULL, ! resv, ! resnull); ! scratch->jumpdone = NULL; /* adjust later */ ! adjust_jumps = lappend(adjust_jumps, &scratch->jumpdone); } /* *************** *** 1748,1774 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, * returned. */ ! /* adjust jump targets */ ! foreach(lc, adjust_jumps) ! { ! ExprEvalStep *as = &state->steps[lfirst_int(lc)]; ! ! Assert(as->opcode == EEOP_JUMP_IF_NOT_NULL); ! Assert(as->d.jump.jumpdone == -1); ! as->d.jump.jumpdone = state->steps_len; ! } break; } case T_MinMaxExpr: { MinMaxExpr *minmaxexpr = (MinMaxExpr *) node; int nelems = list_length(minmaxexpr->args); TypeCacheEntry *typentry; FmgrInfo *finfo; FunctionCallInfo fcinfo; ListCell *lc; int off; /* Look up the btree comparison function for the datatype */ --- 1932,1954 ---- * returned. */ ! /* Resolve the jumpdone pointers when the next operator is created */ ! state->adjust_jumps = adjust_jumps; break; } case T_MinMaxExpr: { + ExprEvalStep_minmax *scratch; MinMaxExpr *minmaxexpr = (MinMaxExpr *) node; int nelems = list_length(minmaxexpr->args); TypeCacheEntry *typentry; FmgrInfo *finfo; FunctionCallInfo fcinfo; ListCell *lc; + Datum *values; + bool *nulls; int off; /* Look up the btree comparison function for the datatype */ *************** *** 1795,1811 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, InitFunctionCallInfoData(*fcinfo, finfo, 2, minmaxexpr->inputcollid, NULL, NULL); - scratch.opcode = EEOP_MINMAX; /* allocate space to store arguments */ ! scratch.d.minmax.values = ! (Datum *) palloc(sizeof(Datum) * nelems); ! scratch.d.minmax.nulls = ! (bool *) palloc(sizeof(bool) * nelems); ! scratch.d.minmax.nelems = nelems; ! ! scratch.d.minmax.op = minmaxexpr->op; ! scratch.d.minmax.finfo = finfo; ! scratch.d.minmax.fcinfo_data = fcinfo; /* evaluate expressions into minmax->values/nulls */ off = 0; --- 1975,1983 ---- InitFunctionCallInfoData(*fcinfo, finfo, 2, minmaxexpr->inputcollid, NULL, NULL); /* allocate space to store arguments */ ! values = (Datum *) palloc(sizeof(Datum) * nelems); ! nulls = (bool *) palloc(sizeof(bool) * nelems); /* evaluate expressions into minmax->values/nulls */ off = 0; *************** *** 1814,1876 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, Expr *e = (Expr *) lfirst(lc); ExecInitExprRec(e, parent, state, ! &scratch.d.minmax.values[off], ! &scratch.d.minmax.nulls[off]); off++; } /* and push the final comparison */ ! ExprEvalPushStep(state, &scratch); break; } case T_SQLValueFunction: { SQLValueFunction *svf = (SQLValueFunction *) node; ! scratch.opcode = EEOP_SQLVALUEFUNCTION; ! scratch.d.sqlvaluefunction.svf = svf; ! ! ExprEvalPushStep(state, &scratch); break; } case T_XmlExpr: { XmlExpr *xexpr = (XmlExpr *) node; int nnamed = list_length(xexpr->named_args); int nargs = list_length(xexpr->args); int off; ListCell *arg; ! ! scratch.opcode = EEOP_XMLEXPR; ! scratch.d.xmlexpr.xexpr = xexpr; /* allocate space for storing all the arguments */ if (nnamed) { ! scratch.d.xmlexpr.named_argvalue = ! (Datum *) palloc(sizeof(Datum) * nnamed); ! scratch.d.xmlexpr.named_argnull = ! (bool *) palloc(sizeof(bool) * nnamed); ! } ! else ! { ! scratch.d.xmlexpr.named_argvalue = NULL; ! scratch.d.xmlexpr.named_argnull = NULL; } if (nargs) { ! scratch.d.xmlexpr.argvalue = ! (Datum *) palloc(sizeof(Datum) * nargs); ! scratch.d.xmlexpr.argnull = ! (bool *) palloc(sizeof(bool) * nargs); ! } ! else ! { ! scratch.d.xmlexpr.argvalue = NULL; ! scratch.d.xmlexpr.argnull = NULL; } /* prepare argument execution */ --- 1986,2049 ---- Expr *e = (Expr *) lfirst(lc); ExecInitExprRec(e, parent, state, ! &values[off], ! &nulls[off]); off++; } /* and push the final comparison */ ! scratch = (ExprEvalStep_minmax *) ! ExprEvalPushStep(state, ! EEOP_MINMAX, ! resv, ! resnull); ! scratch->values = values; ! scratch->nulls = nulls; ! scratch->nelems = nelems; ! scratch->op = minmaxexpr->op; ! scratch->finfo = finfo; ! scratch->fcinfo_data = fcinfo; break; } case T_SQLValueFunction: { + ExprEvalStep_sqlvaluefunction *scratch; SQLValueFunction *svf = (SQLValueFunction *) node; ! scratch = (ExprEvalStep_sqlvaluefunction *) ! ExprEvalPushStep(state, ! EEOP_SQLVALUEFUNCTION, ! resv, ! resnull); ! scratch->svf = svf; break; } case T_XmlExpr: { + ExprEvalStep_xmlexpr *scratch; XmlExpr *xexpr = (XmlExpr *) node; int nnamed = list_length(xexpr->named_args); int nargs = list_length(xexpr->args); int off; ListCell *arg; ! Datum *named_argvalue = NULL; ! bool *named_argnull = NULL; ! Datum *argvalue = NULL; ! bool *argnull = NULL; /* allocate space for storing all the arguments */ if (nnamed) { ! named_argvalue = (Datum *) palloc(sizeof(Datum) * nnamed); ! named_argnull = (bool *) palloc(sizeof(bool) * nnamed); } if (nargs) { ! argvalue = (Datum *) palloc(sizeof(Datum) * nargs); ! argnull = (bool *) palloc(sizeof(bool) * nargs); } /* prepare argument execution */ *************** *** 1880,1887 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, Expr *e = (Expr *) lfirst(arg); ExecInitExprRec(e, parent, state, ! &scratch.d.xmlexpr.named_argvalue[off], ! &scratch.d.xmlexpr.named_argnull[off]); off++; } --- 2053,2060 ---- Expr *e = (Expr *) lfirst(arg); ExecInitExprRec(e, parent, state, ! &named_argvalue[off], ! &named_argnull[off]); off++; } *************** *** 1891,1938 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, Expr *e = (Expr *) lfirst(arg); ExecInitExprRec(e, parent, state, ! &scratch.d.xmlexpr.argvalue[off], ! &scratch.d.xmlexpr.argnull[off]); off++; } /* and evaluate the actual XML expression */ ! ExprEvalPushStep(state, &scratch); break; } case T_NullTest: { NullTest *ntest = (NullTest *) node; if (ntest->nulltesttype == IS_NULL) { if (ntest->argisrow) ! scratch.opcode = EEOP_NULLTEST_ROWISNULL; else ! scratch.opcode = EEOP_NULLTEST_ISNULL; } else if (ntest->nulltesttype == IS_NOT_NULL) { if (ntest->argisrow) ! scratch.opcode = EEOP_NULLTEST_ROWISNOTNULL; else ! scratch.opcode = EEOP_NULLTEST_ISNOTNULL; } else { elog(ERROR, "unrecognized nulltesttype: %d", (int) ntest->nulltesttype); } - /* initialize cache in case it's a row test */ - scratch.d.nulltest_row.argdesc = NULL; /* first evaluate argument into result variable */ ExecInitExprRec(ntest->arg, parent, state, resv, resnull); /* then push the test of that argument */ ! ExprEvalPushStep(state, &scratch); break; } --- 2064,2127 ---- Expr *e = (Expr *) lfirst(arg); ExecInitExprRec(e, parent, state, ! &argvalue[off], ! &argnull[off]); off++; } /* and evaluate the actual XML expression */ ! scratch = (ExprEvalStep_xmlexpr *) ! ExprEvalPushStep(state, ! EEOP_XMLEXPR, ! resv, ! resnull); ! scratch->xexpr = xexpr; ! scratch->named_argvalue = named_argvalue; ! scratch->named_argnull = named_argnull; ! scratch->argvalue = argvalue; ! scratch->argnull = argnull; break; } case T_NullTest: { + ExprEvalStep_nulltest_row *scratch; NullTest *ntest = (NullTest *) node; if (ntest->nulltesttype == IS_NULL) { if (ntest->argisrow) ! opcode = EEOP_NULLTEST_ROWISNULL; else ! opcode = EEOP_NULLTEST_ISNULL; } else if (ntest->nulltesttype == IS_NOT_NULL) { if (ntest->argisrow) ! opcode = EEOP_NULLTEST_ROWISNOTNULL; else ! opcode = EEOP_NULLTEST_ISNOTNULL; } else { elog(ERROR, "unrecognized nulltesttype: %d", (int) ntest->nulltesttype); } /* first evaluate argument into result variable */ ExecInitExprRec(ntest->arg, parent, state, resv, resnull); /* then push the test of that argument */ ! scratch = (ExprEvalStep_nulltest_row *) ! ExprEvalPushStep(state, ! opcode, ! resv, ! resnull); ! ! /* initialize cache in case it's a row test */ ! scratch->argdesc = NULL; ! break; } *************** *** 1951,1981 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, switch (btest->booltesttype) { case IS_TRUE: ! scratch.opcode = EEOP_BOOLTEST_IS_TRUE; break; case IS_NOT_TRUE: ! scratch.opcode = EEOP_BOOLTEST_IS_NOT_TRUE; break; case IS_FALSE: ! scratch.opcode = EEOP_BOOLTEST_IS_FALSE; break; case IS_NOT_FALSE: ! scratch.opcode = EEOP_BOOLTEST_IS_NOT_FALSE; break; case IS_UNKNOWN: /* Same as scalar IS NULL test */ ! scratch.opcode = EEOP_NULLTEST_ISNULL; break; case IS_NOT_UNKNOWN: /* Same as scalar IS NOT NULL test */ ! scratch.opcode = EEOP_NULLTEST_ISNOTNULL; break; default: elog(ERROR, "unrecognized booltesttype: %d", (int) btest->booltesttype); } ! ExprEvalPushStep(state, &scratch); break; } --- 2140,2173 ---- switch (btest->booltesttype) { case IS_TRUE: ! opcode = EEOP_BOOLTEST_IS_TRUE; break; case IS_NOT_TRUE: ! opcode = EEOP_BOOLTEST_IS_NOT_TRUE; break; case IS_FALSE: ! opcode = EEOP_BOOLTEST_IS_FALSE; break; case IS_NOT_FALSE: ! opcode = EEOP_BOOLTEST_IS_NOT_FALSE; break; case IS_UNKNOWN: /* Same as scalar IS NULL test */ ! opcode = EEOP_NULLTEST_ISNULL; break; case IS_NOT_UNKNOWN: /* Same as scalar IS NOT NULL test */ ! opcode = EEOP_NULLTEST_ISNOTNULL; break; default: elog(ERROR, "unrecognized booltesttype: %d", (int) btest->booltesttype); } ! ExprEvalPushStep(state, ! opcode, ! resv, ! resnull); break; } *************** *** 1983,1995 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, { CoerceToDomain *ctest = (CoerceToDomain *) node; ! ExecInitCoerceToDomain(&scratch, ctest, parent, state, resv, resnull); break; } case T_CoerceToDomainValue: { /* * Read from location identified by innermost_domainval. Note * that innermost_domainval could be NULL, if we're compiling --- 2175,2189 ---- { CoerceToDomain *ctest = (CoerceToDomain *) node; ! ExecInitCoerceToDomain(ctest, parent, state, resv, resnull); break; } case T_CoerceToDomainValue: { + ExprEvalStep_casetest *scratch; + /* * Read from location identified by innermost_domainval. Note * that innermost_domainval could be NULL, if we're compiling *************** *** 1998,2028 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, * econtext->domainValue_datum. We'll take care of that * scenario at runtime. */ ! scratch.opcode = EEOP_DOMAIN_TESTVAL; /* we share instruction union variant with case testval */ ! scratch.d.casetest.value = state->innermost_domainval; ! scratch.d.casetest.isnull = state->innermost_domainnull; ! ! ExprEvalPushStep(state, &scratch); break; } case T_CurrentOfExpr: { ! scratch.opcode = EEOP_CURRENTOFEXPR; ! ExprEvalPushStep(state, &scratch); break; } case T_NextValueExpr: { NextValueExpr *nve = (NextValueExpr *) node; ! scratch.opcode = EEOP_NEXTVALUEEXPR; ! scratch.d.nextvalueexpr.seqid = nve->seqid; ! scratch.d.nextvalueexpr.seqtypid = nve->typeId; ! ! ExprEvalPushStep(state, &scratch); break; } --- 2192,2230 ---- * econtext->domainValue_datum. We'll take care of that * scenario at runtime. */ ! scratch = (ExprEvalStep_casetest *) ! ExprEvalPushStep(state, ! EEOP_DOMAIN_TESTVAL, ! resv, ! resnull); ! /* we share instruction union variant with case testval */ ! scratch->value = state->innermost_domainval; ! scratch->isnull = state->innermost_domainnull; break; } case T_CurrentOfExpr: { ! ExprEvalPushStep(state, ! EEOP_CURRENTOFEXPR, ! resv, ! resnull); break; } case T_NextValueExpr: { + ExprEvalStep_nextvalueexpr *scratch; NextValueExpr *nve = (NextValueExpr *) node; ! scratch = (ExprEvalStep_nextvalueexpr *) ! ExprEvalPushStep(state, ! EEOP_NEXTVALUEEXPR, ! resv, ! resnull); ! scratch->seqid = nve->seqid; ! scratch->seqtypid = nve->typeId; break; } *************** *** 2035,2074 **** ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, /* * Add another expression evaluation step to ExprState->steps. - * - * 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 ! ExprEvalPushStep(ExprState *es, const ExprEvalStep *s) { ! if (es->steps_alloc == 0) { ! es->steps_alloc = 16; ! es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc); } ! else if (es->steps_alloc == es->steps_len) { ! es->steps_alloc *= 2; ! es->steps = repalloc(es->steps, ! sizeof(ExprEvalStep) * es->steps_alloc); } ! memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep)); } /* * Perform setup necessary for the evaluation of a function-like expression, * appending argument evaluation steps to the steps list in *state, and ! * setting up *scratch so it is ready to be pushed. * ! * *scratch is not pushed here, so that callers may override the opcode, ! * which is useful for function-like cases like DISTINCT. */ static void ! ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, ! Oid inputcollid, PlanState *parent, ExprState *state) { int nargs = list_length(args); AclResult aclresult; FmgrInfo *flinfo; --- 2237,2309 ---- /* * Add another expression evaluation step to ExprState->steps. */ ! static ExprEvalStep * ! ExprEvalPushStep(ExprState *es, const ExprEvalOp opcode, ! Datum *resv, bool *resnull) { ! size_t size = eeop_size[opcode]; ! ExprEvalStep *result = NULL; ! ! if (es->buffer_size < size) { ! es->buffer_size = MAX(128, size); ! es->step_buffer = palloc0(es->buffer_size); ! ! if (es->steps == NULL) ! es->steps = (ExprEvalStep *)es->step_buffer; } ! ! result = (ExprEvalStep *)es->step_buffer; ! result->opcode = opcode; ! result->resvalue = resv; ! result->resnull = resnull; ! ! /* Chain steps */ ! if (es->last_step != NULL) ! es->last_step->nextstep = result; ! es->last_step = result; ! ! /* Adjust jump targets if needed */ ! if (es->adjust_jumps != NIL) { ! ListCell *lc; ! ! foreach(lc, es->adjust_jumps) ! { ! ExprEvalStep **as = (ExprEvalStep **)lfirst(lc); ! ! Assert(*as == NULL); ! *as = result; ! } ! ! /* We're done with these pointers */ ! es->adjust_jumps = NIL; } ! /* Advance buffer */ ! es->step_buffer += size; ! es->buffer_size -= size; ! ++es->num_steps; ! ! return result; } /* * Perform setup necessary for the evaluation of a function-like expression, * appending argument evaluation steps to the steps list in *state, and ! * pushing the operator. * ! * Callers may override the opcode, which is useful for function-like cases ! * like DISTINCT, by adjusting state->last_step. */ static void ! ExecInitFunc(Expr *node, List *args, Oid funcid, ! Oid inputcollid, PlanState *parent, ExprState *state, ! Datum *resv, bool *resnull) { + ExprEvalStep_func *scratch; + ExprEvalOp opcode; int nargs = list_length(args); AclResult aclresult; FmgrInfo *flinfo; *************** *** 2097,2106 **** ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, FUNC_MAX_ARGS))); /* Allocate function lookup data and parameter workspace for this call */ ! scratch->d.func.finfo = palloc0(sizeof(FmgrInfo)); ! scratch->d.func.fcinfo_data = palloc0(sizeof(FunctionCallInfoData)); ! flinfo = scratch->d.func.finfo; ! fcinfo = scratch->d.func.fcinfo_data; /* Set up the primary fmgr lookup information */ fmgr_info(funcid, flinfo); --- 2332,2339 ---- FUNC_MAX_ARGS))); /* Allocate function lookup data and parameter workspace for this call */ ! flinfo = palloc0(sizeof(FmgrInfo)); ! fcinfo = palloc0(sizeof(FunctionCallInfoData)); /* Set up the primary fmgr lookup information */ fmgr_info(funcid, flinfo); *************** *** 2110,2119 **** ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, InitFunctionCallInfoData(*fcinfo, flinfo, nargs, inputcollid, NULL, NULL); - /* Keep extra copies of this info to save an indirection at runtime */ - scratch->d.func.fn_addr = flinfo->fn_addr; - scratch->d.func.nargs = nargs; - /* We only support non-set functions here */ if (flinfo->fn_retset) ereport(ERROR, --- 2343,2348 ---- *************** *** 2151,2167 **** ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, if (pgstat_track_functions <= flinfo->fn_stats) { if (flinfo->fn_strict && nargs > 0) ! scratch->opcode = EEOP_FUNCEXPR_STRICT; else ! scratch->opcode = EEOP_FUNCEXPR; } else { if (flinfo->fn_strict && nargs > 0) ! scratch->opcode = EEOP_FUNCEXPR_STRICT_FUSAGE; else ! scratch->opcode = EEOP_FUNCEXPR_FUSAGE; } } /* --- 2380,2407 ---- if (pgstat_track_functions <= flinfo->fn_stats) { if (flinfo->fn_strict && nargs > 0) ! opcode = EEOP_FUNCEXPR_STRICT; else ! opcode = EEOP_FUNCEXPR; } else { if (flinfo->fn_strict && nargs > 0) ! opcode = EEOP_FUNCEXPR_STRICT_FUSAGE; else ! opcode = EEOP_FUNCEXPR_FUSAGE; } + scratch = (ExprEvalStep_func *) + ExprEvalPushStep(state, + opcode, + resv, + resnull); + scratch->finfo = flinfo; + scratch->fcinfo_data = fcinfo; + + /* Keep extra copies of function info to save an indirection at runtime */ + scratch->fn_addr = flinfo->fn_addr; + scratch->nargs = nargs; } /* *************** *** 2172,2178 **** static void ExecInitExprSlots(ExprState *state, Node *node) { LastAttnumInfo info = {0, 0, 0}; ! ExprEvalStep scratch; /* * Figure out which attributes we're going to need. --- 2412,2418 ---- ExecInitExprSlots(ExprState *state, Node *node) { LastAttnumInfo info = {0, 0, 0}; ! ExprEvalStep_fetch *scratch; /* * Figure out which attributes we're going to need. *************** *** 2182,2202 **** ExecInitExprSlots(ExprState *state, Node *node) /* Emit steps as needed */ if (info.last_inner > 0) { ! scratch.opcode = EEOP_INNER_FETCHSOME; ! scratch.d.fetch.last_var = info.last_inner; ! ExprEvalPushStep(state, &scratch); } if (info.last_outer > 0) { ! scratch.opcode = EEOP_OUTER_FETCHSOME; ! scratch.d.fetch.last_var = info.last_outer; ! ExprEvalPushStep(state, &scratch); } if (info.last_scan > 0) { ! scratch.opcode = EEOP_SCAN_FETCHSOME; ! scratch.d.fetch.last_var = info.last_scan; ! ExprEvalPushStep(state, &scratch); } } --- 2422,2451 ---- /* Emit steps as needed */ if (info.last_inner > 0) { ! scratch = (ExprEvalStep_fetch *) ! ExprEvalPushStep(state, ! EEOP_INNER_FETCHSOME, ! NULL, ! NULL); ! scratch->last_var = info.last_inner; } if (info.last_outer > 0) { ! scratch = (ExprEvalStep_fetch *) ! ExprEvalPushStep(state, ! EEOP_OUTER_FETCHSOME, ! NULL, ! NULL); ! scratch->last_var = info.last_outer; } if (info.last_scan > 0) { ! scratch = (ExprEvalStep_fetch *) ! ExprEvalPushStep(state, ! EEOP_SCAN_FETCHSOME, ! NULL, ! NULL); ! scratch->last_var = info.last_scan; } } *************** *** 2249,2267 **** get_last_attnums_walker(Node *node, LastAttnumInfo *info) } /* ! * Prepare step for the evaluation of a whole-row variable. ! * The caller still has to push the step. */ static void ! ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, PlanState *parent) { /* fill in all but the target */ ! scratch->opcode = EEOP_WHOLEROW; ! scratch->d.wholerow.var = variable; ! scratch->d.wholerow.first = true; ! scratch->d.wholerow.slow = false; ! scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */ ! scratch->d.wholerow.junkFilter = NULL; /* * If the input tuple came from a subquery, it might contain "resjunk" --- 2498,2522 ---- } /* ! * Prepare and push step for the evaluation of a whole-row variable. */ static void ! ExecInitWholeRowVar(ExprState *state, Var *variable, ! PlanState *parent, Datum *resv, bool *resnull) { + ExprEvalStep_wholerow *scratch; + /* fill in all but the target */ ! scratch = (ExprEvalStep_wholerow *) ! ExprEvalPushStep(state, ! EEOP_WHOLEROW, ! resv, ! resnull); ! scratch->var = variable; ! scratch->first = true; ! scratch->slow = false; ! scratch->tupdesc = NULL; /* filled at runtime */ ! scratch->junkFilter = NULL; /* * If the input tuple came from a subquery, it might contain "resjunk" *************** *** 2311,2317 **** ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, PlanState *parent) /* If so, build the junkfilter now */ if (junk_filter_needed) { ! scratch->d.wholerow.junkFilter = ExecInitJunkFilter(subplan->plan->targetlist, ExecGetResultType(subplan)->tdhasoid, ExecInitExtraTupleSlot(parent->state)); --- 2566,2572 ---- /* If so, build the junkfilter now */ if (junk_filter_needed) { ! scratch->junkFilter = ExecInitJunkFilter(subplan->plan->targetlist, ExecGetResultType(subplan)->tdhasoid, ExecInitExtraTupleSlot(parent->state)); *************** *** 2324,2330 **** ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, PlanState *parent) * Prepare evaluation of an ArrayRef expression. */ static void ! ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent, ExprState *state, Datum *resv, bool *resnull) { bool isAssignment = (aref->refassgnexpr != NULL); --- 2579,2585 ---- * Prepare evaluation of an ArrayRef expression. */ static void ! ExecInitArrayRef(ArrayRef *aref, PlanState *parent, ExprState *state, Datum *resv, bool *resnull) { bool isAssignment = (aref->refassgnexpr != NULL); *************** *** 2357,2367 **** ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent, */ if (!isAssignment) { ! scratch->opcode = EEOP_JUMP_IF_NULL; ! scratch->d.jump.jumpdone = -1; /* adjust later */ ! ExprEvalPushStep(state, scratch); ! adjust_jumps = lappend_int(adjust_jumps, ! state->steps_len - 1); } /* Verify subscript list lengths are within limit */ --- 2612,2626 ---- */ if (!isAssignment) { ! ExprEvalStep_jump *scratch; ! ! scratch = (ExprEvalStep_jump *) ! ExprEvalPushStep(state, ! EEOP_JUMP_IF_NULL, ! resv, ! resnull); ! scratch->jumpdone = NULL; /* adjust later */ ! adjust_jumps = lappend(adjust_jumps, &scratch->jumpdone); } /* Verify subscript list lengths are within limit */ *************** *** 2381,2386 **** ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent, --- 2640,2646 ---- i = 0; foreach(lc, aref->refupperindexpr) { + ExprEvalStep_arrayref_subscript *scratch; Expr *e = (Expr *) lfirst(lc); /* When slicing, individual subscript bounds can be omitted */ *************** *** 2398,2411 **** ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent, &arefstate->subscriptvalue, &arefstate->subscriptnull); /* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */ ! scratch->opcode = EEOP_ARRAYREF_SUBSCRIPT; ! scratch->d.arrayref_subscript.state = arefstate; ! scratch->d.arrayref_subscript.off = i; ! scratch->d.arrayref_subscript.isupper = true; ! scratch->d.arrayref_subscript.jumpdone = -1; /* adjust later */ ! ExprEvalPushStep(state, scratch); ! adjust_jumps = lappend_int(adjust_jumps, ! state->steps_len - 1); i++; } arefstate->numupper = i; --- 2658,2673 ---- &arefstate->subscriptvalue, &arefstate->subscriptnull); /* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */ ! scratch = (ExprEvalStep_arrayref_subscript *) ! ExprEvalPushStep(state, ! EEOP_ARRAYREF_SUBSCRIPT, ! resv, ! resnull); ! scratch->state = arefstate; ! scratch->off = i; ! scratch->isupper = true; ! scratch->jumpdone = NULL; /* adjust later */ ! adjust_jumps = lappend(adjust_jumps, &scratch->jumpdone); i++; } arefstate->numupper = i; *************** *** 2414,2419 **** ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent, --- 2676,2682 ---- i = 0; foreach(lc, aref->reflowerindexpr) { + ExprEvalStep_arrayref_subscript *scratch; Expr *e = (Expr *) lfirst(lc); /* When slicing, individual subscript bounds can be omitted */ *************** *** 2431,2444 **** ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent, &arefstate->subscriptvalue, &arefstate->subscriptnull); /* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */ ! scratch->opcode = EEOP_ARRAYREF_SUBSCRIPT; ! scratch->d.arrayref_subscript.state = arefstate; ! scratch->d.arrayref_subscript.off = i; ! scratch->d.arrayref_subscript.isupper = false; ! scratch->d.arrayref_subscript.jumpdone = -1; /* adjust later */ ! ExprEvalPushStep(state, scratch); ! adjust_jumps = lappend_int(adjust_jumps, ! state->steps_len - 1); i++; } arefstate->numlower = i; --- 2694,2709 ---- &arefstate->subscriptvalue, &arefstate->subscriptnull); /* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */ ! scratch = (ExprEvalStep_arrayref_subscript *) ! ExprEvalPushStep(state, ! EEOP_ARRAYREF_SUBSCRIPT, ! resv, ! resnull); ! scratch->state = arefstate; ! scratch->off = i; ! scratch->isupper = false; ! scratch->jumpdone = NULL; /* adjust later */ ! adjust_jumps = lappend(adjust_jumps, &scratch->jumpdone); i++; } arefstate->numlower = i; *************** *** 2450,2455 **** ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent, --- 2715,2721 ---- if (isAssignment) { + ExprEvalStep_arrayref *scratch; Datum *save_innermost_caseval; bool *save_innermost_casenull; *************** *** 2469,2477 **** ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent, */ if (isAssignmentIndirectionExpr(aref->refassgnexpr)) { ! scratch->opcode = EEOP_ARRAYREF_OLD; ! scratch->d.arrayref.state = arefstate; ! ExprEvalPushStep(state, scratch); } /* ARRAYREF_OLD puts extracted value into prevvalue/prevnull */ --- 2735,2746 ---- */ if (isAssignmentIndirectionExpr(aref->refassgnexpr)) { ! scratch = (ExprEvalStep_arrayref *) ! ExprEvalPushStep(state, ! EEOP_ARRAYREF_OLD, ! resv, ! resnull); ! scratch->state = arefstate; } /* ARRAYREF_OLD puts extracted value into prevvalue/prevnull */ *************** *** 2488,2522 **** ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent, state->innermost_casenull = save_innermost_casenull; /* and perform the assignment */ ! scratch->opcode = EEOP_ARRAYREF_ASSIGN; ! scratch->d.arrayref.state = arefstate; ! ExprEvalPushStep(state, scratch); } else { /* array fetch is much simpler */ ! scratch->opcode = EEOP_ARRAYREF_FETCH; ! scratch->d.arrayref.state = arefstate; ! ExprEvalPushStep(state, scratch); } ! /* adjust jump targets */ ! foreach(lc, adjust_jumps) ! { ! ExprEvalStep *as = &state->steps[lfirst_int(lc)]; ! ! if (as->opcode == EEOP_ARRAYREF_SUBSCRIPT) ! { ! Assert(as->d.arrayref_subscript.jumpdone == -1); ! as->d.arrayref_subscript.jumpdone = state->steps_len; ! } ! else ! { ! Assert(as->opcode == EEOP_JUMP_IF_NULL); ! Assert(as->d.jump.jumpdone == -1); ! as->d.jump.jumpdone = state->steps_len; ! } ! } } /* --- 2757,2784 ---- state->innermost_casenull = save_innermost_casenull; /* and perform the assignment */ ! scratch = (ExprEvalStep_arrayref *) ! ExprEvalPushStep(state, ! EEOP_ARRAYREF_ASSIGN, ! resv, ! resnull); ! scratch->state = arefstate; } else { + ExprEvalStep_arrayref *scratch; + /* array fetch is much simpler */ ! scratch = (ExprEvalStep_arrayref *) ! ExprEvalPushStep(state, ! EEOP_ARRAYREF_FETCH, ! resv, ! resnull); ! scratch->state = arefstate; } ! /* Resolve the jumpdone pointers when the next operator is created */ ! state->adjust_jumps = adjust_jumps; } /* *************** *** 2558,2568 **** isAssignmentIndirectionExpr(Expr *expr) * Prepare evaluation of a CoerceToDomain expression. */ static void ! ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, PlanState *parent, ExprState *state, Datum *resv, bool *resnull) { ! ExprEvalStep scratch2; DomainConstraintRef *constraint_ref; Datum *domainval = NULL; bool *domainnull = NULL; --- 2820,2830 ---- * Prepare evaluation of a CoerceToDomain expression. */ static void ! ExecInitCoerceToDomain(CoerceToDomain *ctest, PlanState *parent, ExprState *state, Datum *resv, bool *resnull) { ! ExprEvalStep_domaincheck *scratch; DomainConstraintRef *constraint_ref; Datum *domainval = NULL; bool *domainnull = NULL; *************** *** 2570,2579 **** ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, bool *save_innermost_domainnull; ListCell *l; - scratch->d.domaincheck.resulttype = ctest->resulttype; /* we'll allocate workspace only if needed */ ! scratch->d.domaincheck.checkvalue = NULL; ! scratch->d.domaincheck.checknull = NULL; /* * Evaluate argument - it's fine to directly store it into resv/resnull, --- 2832,2840 ---- bool *save_innermost_domainnull; ListCell *l; /* we'll allocate workspace only if needed */ ! Datum *checkvalue = NULL; ! bool *checknull = NULL; /* * Evaluate argument - it's fine to directly store it into resv/resnull, *************** *** 2615,2636 **** ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, { DomainConstraintState *con = (DomainConstraintState *) lfirst(l); - scratch->d.domaincheck.constraintname = con->name; - switch (con->constrainttype) { case DOM_CONSTRAINT_NOTNULL: ! scratch->opcode = EEOP_DOMAIN_NOTNULL; ! ExprEvalPushStep(state, scratch); break; case DOM_CONSTRAINT_CHECK: /* Allocate workspace for CHECK output if we didn't yet */ ! if (scratch->d.domaincheck.checkvalue == NULL) { ! scratch->d.domaincheck.checkvalue = ! (Datum *) palloc(sizeof(Datum)); ! scratch->d.domaincheck.checknull = ! (bool *) palloc(sizeof(bool)); } /* --- 2876,2901 ---- { DomainConstraintState *con = (DomainConstraintState *) lfirst(l); switch (con->constrainttype) { case DOM_CONSTRAINT_NOTNULL: ! scratch = (ExprEvalStep_domaincheck *) ! ExprEvalPushStep(state, ! EEOP_DOMAIN_NOTNULL, ! resv, ! resnull); ! scratch->resulttype = ctest->resulttype; ! scratch->checkvalue = NULL; ! scratch->checknull = NULL; ! scratch->constraintname = con->name; ! break; case DOM_CONSTRAINT_CHECK: /* Allocate workspace for CHECK output if we didn't yet */ ! if (checkvalue == NULL) { ! checkvalue = (Datum *) palloc(sizeof(Datum)); ! checknull = (bool *) palloc(sizeof(bool)); } /* *************** *** 2645,2661 **** ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, */ if (get_typlen(ctest->resulttype) == -1) { /* Yes, so make output workspace for MAKE_READONLY */ domainval = (Datum *) palloc(sizeof(Datum)); domainnull = (bool *) palloc(sizeof(bool)); /* Emit MAKE_READONLY */ ! scratch2.opcode = EEOP_MAKE_READONLY; ! scratch2.resvalue = domainval; ! scratch2.resnull = domainnull; ! scratch2.d.make_readonly.value = resv; ! scratch2.d.make_readonly.isnull = resnull; ! ExprEvalPushStep(state, &scratch2); } else { --- 2910,2929 ---- */ if (get_typlen(ctest->resulttype) == -1) { + ExprEvalStep_make_readonly *scratch2; + /* Yes, so make output workspace for MAKE_READONLY */ domainval = (Datum *) palloc(sizeof(Datum)); domainnull = (bool *) palloc(sizeof(bool)); /* Emit MAKE_READONLY */ ! scratch2 = (ExprEvalStep_make_readonly *) ! ExprEvalPushStep(state, ! EEOP_MAKE_READONLY, ! domainval, ! domainnull); ! scratch2->value = resv; ! scratch2->isnull = resnull; } else { *************** *** 2678,2692 **** ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, /* evaluate check expression value */ ExecInitExprRec(con->check_expr, parent, state, ! scratch->d.domaincheck.checkvalue, ! scratch->d.domaincheck.checknull); state->innermost_domainval = save_innermost_domainval; state->innermost_domainnull = save_innermost_domainnull; /* now test result */ ! scratch->opcode = EEOP_DOMAIN_CHECK; ! ExprEvalPushStep(state, scratch); break; default: --- 2946,2966 ---- /* evaluate check expression value */ ExecInitExprRec(con->check_expr, parent, state, ! checkvalue, checknull); state->innermost_domainval = save_innermost_domainval; state->innermost_domainnull = save_innermost_domainnull; /* now test result */ ! scratch = (ExprEvalStep_domaincheck *) ! ExprEvalPushStep(state, ! EEOP_DOMAIN_CHECK, ! resv, ! resnull); ! scratch->resulttype = ctest->resulttype; ! scratch->checkvalue = checkvalue; ! scratch->checknull = checknull; ! scratch->constraintname = con->name; break; default: *** a/src/backend/executor/execExprInterp.c --- b/src/backend/executor/execExprInterp.c *************** *** 116,128 **** static const void **dispatch_table = NULL; #define EEO_NEXT() \ do { \ ! op++; \ EEO_DISPATCH(); \ } while (0) ! #define EEO_JUMP(stepno) \ do { \ ! op = &state->steps[stepno]; \ EEO_DISPATCH(); \ } while (0) --- 116,128 ---- #define EEO_NEXT() \ do { \ ! op = op->nextstep; \ EEO_DISPATCH(); \ } while (0) ! #define EEO_JUMP(step) \ do { \ ! op = step; \ EEO_DISPATCH(); \ } while (0) *************** *** 135,141 **** static void CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vart static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod, TupleDesc *cache_field, ExprContext *econtext); static void ShutdownTupleDescRef(Datum arg); ! static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op, ExprContext *econtext, bool checkisnull); /* fast-path evaluation functions */ --- 135,141 ---- static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod, TupleDesc *cache_field, ExprContext *econtext); static void ShutdownTupleDescRef(Datum arg); ! static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep_nulltest_row *sop, ExprContext *econtext, bool checkisnull); /* fast-path evaluation functions */ *************** *** 152,157 **** static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool --- 152,163 ---- /* + * Macro to define a specific operator "sop" by casting the generic "op" + * to the right type. + */ + #define DEF_SOP(type) type *sop = (type *)op + + /* * Prepare ExprState for interpreted execution. */ void *************** *** 161,168 **** ExecReadyInterpretedExpr(ExprState *state) ExecInitInterpreter(); /* Simple validity checks on expression */ ! Assert(state->steps_len >= 1); ! Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE); /* * Don't perform redundant initialization. This is unreachable in current --- 167,173 ---- ExecInitInterpreter(); /* Simple validity checks on expression */ ! Assert(state->steps != NULL); /* * Don't perform redundant initialization. This is unreachable in current *************** *** 189,198 **** ExecReadyInterpretedExpr(ExprState *state) * enough that the overhead of ExecInterpExpr matters. For more complex * expressions it's cheaper to use ExecInterpExpr always. */ ! if (state->steps_len == 3) { ! ExprEvalOp step0 = state->steps[0].opcode; ! ExprEvalOp step1 = state->steps[1].opcode; if (step0 == EEOP_INNER_FETCHSOME && step1 == EEOP_INNER_VAR_FIRST) --- 194,203 ---- * enough that the overhead of ExecInterpExpr matters. For more complex * expressions it's cheaper to use ExecInterpExpr always. */ ! if (state->num_steps == 3) { ! ExprEvalOp step0 = state->steps->opcode; ! ExprEvalOp step1 = state->steps->nextstep->opcode; if (step0 == EEOP_INNER_FETCHSOME && step1 == EEOP_INNER_VAR_FIRST) *************** *** 231,238 **** ExecReadyInterpretedExpr(ExprState *state) return; } } ! else if (state->steps_len == 2 && ! state->steps[0].opcode == EEOP_CONST) { state->evalfunc = ExecJustConst; return; --- 236,243 ---- return; } } ! else if (state->num_steps == 2 && ! state->steps->opcode == EEOP_CONST) { state->evalfunc = ExecJustConst; return; *************** *** 245,258 **** ExecReadyInterpretedExpr(ExprState *state) * address to jump to. (Use ExecEvalStepOp() to get back the opcode.) */ { ! int off; ! ! for (off = 0; off < state->steps_len; off++) ! { ! ExprEvalStep *op = &state->steps[off]; op->opcode = EEO_OPCODE(op->opcode); - } state->flags |= EEO_FLAG_DIRECT_THREADED; } --- 250,264 ---- * address to jump to. (Use ExecEvalStepOp() to get back the opcode.) */ { ! ExprEvalStep *op = state->steps; + /* + * We explicitly don't stop at EEO_DONE here because we need to + * resolve that opcode. Instead, depend on the NULL nextstep to + * indicate the end of the list. + */ + for (op = state->steps; op != NULL; op = op->nextstep) op->opcode = EEO_OPCODE(op->opcode); state->flags |= EEO_FLAG_DIRECT_THREADED; } *************** *** 395,439 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_INNER_FETCHSOME) { /* XXX: worthwhile to check tts_nvalid inline first? */ ! slot_getsomeattrs(innerslot, op->d.fetch.last_var); EEO_NEXT(); } EEO_CASE(EEOP_OUTER_FETCHSOME) { ! slot_getsomeattrs(outerslot, op->d.fetch.last_var); EEO_NEXT(); } EEO_CASE(EEOP_SCAN_FETCHSOME) { ! slot_getsomeattrs(scanslot, op->d.fetch.last_var); EEO_NEXT(); } EEO_CASE(EEOP_INNER_VAR_FIRST) { ! int attnum = op->d.var.attnum; /* * First time through, check whether attribute matches Var. Might * not be ok anymore, due to schema changes. */ ! CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype); /* Skip that check on subsequent evaluations */ ! op->opcode = EEO_OPCODE(EEOP_INNER_VAR); /* FALL THROUGH to EEOP_INNER_VAR */ } EEO_CASE(EEOP_INNER_VAR) { ! int attnum = op->d.var.attnum; /* * Since we already extracted all referenced columns from the --- 401,453 ---- EEO_CASE(EEOP_INNER_FETCHSOME) { + DEF_SOP(ExprEvalStep_fetch); + /* XXX: worthwhile to check tts_nvalid inline first? */ ! slot_getsomeattrs(innerslot, sop->last_var); EEO_NEXT(); } EEO_CASE(EEOP_OUTER_FETCHSOME) { ! DEF_SOP(ExprEvalStep_fetch); ! ! slot_getsomeattrs(outerslot, sop->last_var); EEO_NEXT(); } EEO_CASE(EEOP_SCAN_FETCHSOME) { ! DEF_SOP(ExprEvalStep_fetch); ! ! slot_getsomeattrs(scanslot, sop->last_var); EEO_NEXT(); } EEO_CASE(EEOP_INNER_VAR_FIRST) { ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum; /* * First time through, check whether attribute matches Var. Might * not be ok anymore, due to schema changes. */ ! CheckVarSlotCompatibility(innerslot, attnum + 1, sop->vartype); /* Skip that check on subsequent evaluations */ ! sop->opcode = EEO_OPCODE(EEOP_INNER_VAR); /* FALL THROUGH to EEOP_INNER_VAR */ } EEO_CASE(EEOP_INNER_VAR) { ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum; /* * Since we already extracted all referenced columns from the *************** *** 442,563 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) * have an Assert to check that that did happen. */ Assert(attnum >= 0 && attnum < innerslot->tts_nvalid); ! *op->resvalue = innerslot->tts_values[attnum]; ! *op->resnull = innerslot->tts_isnull[attnum]; EEO_NEXT(); } EEO_CASE(EEOP_OUTER_VAR_FIRST) { ! int attnum = op->d.var.attnum; /* See EEOP_INNER_VAR_FIRST comments */ ! CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype); ! op->opcode = EEO_OPCODE(EEOP_OUTER_VAR); /* FALL THROUGH to EEOP_OUTER_VAR */ } EEO_CASE(EEOP_OUTER_VAR) { ! int attnum = op->d.var.attnum; /* See EEOP_INNER_VAR comments */ Assert(attnum >= 0 && attnum < outerslot->tts_nvalid); ! *op->resvalue = outerslot->tts_values[attnum]; ! *op->resnull = outerslot->tts_isnull[attnum]; EEO_NEXT(); } EEO_CASE(EEOP_SCAN_VAR_FIRST) { ! int attnum = op->d.var.attnum; /* See EEOP_INNER_VAR_FIRST comments */ ! CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype); ! op->opcode = EEO_OPCODE(EEOP_SCAN_VAR); /* FALL THROUGH to EEOP_SCAN_VAR */ } EEO_CASE(EEOP_SCAN_VAR) { ! int attnum = op->d.var.attnum; /* See EEOP_INNER_VAR comments */ Assert(attnum >= 0 && attnum < scanslot->tts_nvalid); ! *op->resvalue = scanslot->tts_values[attnum]; ! *op->resnull = scanslot->tts_isnull[attnum]; EEO_NEXT(); } EEO_CASE(EEOP_INNER_SYSVAR) { ! int attnum = op->d.var.attnum; /* these asserts must match defenses in slot_getattr */ Assert(innerslot->tts_tuple != NULL); Assert(innerslot->tts_tuple != &(innerslot->tts_minhdr)); /* heap_getsysattr has sufficient defenses against bad attnums */ ! *op->resvalue = heap_getsysattr(innerslot->tts_tuple, attnum, innerslot->tts_tupleDescriptor, ! op->resnull); EEO_NEXT(); } EEO_CASE(EEOP_OUTER_SYSVAR) { ! int attnum = op->d.var.attnum; /* these asserts must match defenses in slot_getattr */ Assert(outerslot->tts_tuple != NULL); Assert(outerslot->tts_tuple != &(outerslot->tts_minhdr)); /* heap_getsysattr has sufficient defenses against bad attnums */ ! *op->resvalue = heap_getsysattr(outerslot->tts_tuple, attnum, outerslot->tts_tupleDescriptor, ! op->resnull); EEO_NEXT(); } EEO_CASE(EEOP_SCAN_SYSVAR) { ! int attnum = op->d.var.attnum; /* these asserts must match defenses in slot_getattr */ Assert(scanslot->tts_tuple != NULL); Assert(scanslot->tts_tuple != &(scanslot->tts_minhdr)); /* heap_getsysattr has sufficient defenses against bad attnums */ ! *op->resvalue = heap_getsysattr(scanslot->tts_tuple, attnum, scanslot->tts_tupleDescriptor, ! op->resnull); EEO_NEXT(); } EEO_CASE(EEOP_WHOLEROW) { /* too complex for an inline implementation */ ! ExecEvalWholeRowVar(state, op, econtext); EEO_NEXT(); } EEO_CASE(EEOP_ASSIGN_INNER_VAR) { ! int resultnum = op->d.assign_var.resultnum; ! int attnum = op->d.assign_var.attnum; /* * We do not need CheckVarSlotCompatibility here; that was taken --- 456,588 ---- * have an Assert to check that that did happen. */ Assert(attnum >= 0 && attnum < innerslot->tts_nvalid); ! *sop->resvalue = innerslot->tts_values[attnum]; ! *sop->resnull = innerslot->tts_isnull[attnum]; EEO_NEXT(); } EEO_CASE(EEOP_OUTER_VAR_FIRST) { ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum; /* See EEOP_INNER_VAR_FIRST comments */ ! CheckVarSlotCompatibility(outerslot, attnum + 1, sop->vartype); ! sop->opcode = EEO_OPCODE(EEOP_OUTER_VAR); /* FALL THROUGH to EEOP_OUTER_VAR */ } EEO_CASE(EEOP_OUTER_VAR) { ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum; /* See EEOP_INNER_VAR comments */ Assert(attnum >= 0 && attnum < outerslot->tts_nvalid); ! *sop->resvalue = outerslot->tts_values[attnum]; ! *sop->resnull = outerslot->tts_isnull[attnum]; EEO_NEXT(); } EEO_CASE(EEOP_SCAN_VAR_FIRST) { ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum; /* See EEOP_INNER_VAR_FIRST comments */ ! CheckVarSlotCompatibility(scanslot, attnum + 1, sop->vartype); ! sop->opcode = EEO_OPCODE(EEOP_SCAN_VAR); /* FALL THROUGH to EEOP_SCAN_VAR */ } EEO_CASE(EEOP_SCAN_VAR) { ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum; /* See EEOP_INNER_VAR comments */ Assert(attnum >= 0 && attnum < scanslot->tts_nvalid); ! *sop->resvalue = scanslot->tts_values[attnum]; ! *sop->resnull = scanslot->tts_isnull[attnum]; EEO_NEXT(); } EEO_CASE(EEOP_INNER_SYSVAR) { ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum; /* these asserts must match defenses in slot_getattr */ Assert(innerslot->tts_tuple != NULL); Assert(innerslot->tts_tuple != &(innerslot->tts_minhdr)); /* heap_getsysattr has sufficient defenses against bad attnums */ ! *sop->resvalue = heap_getsysattr(innerslot->tts_tuple, attnum, innerslot->tts_tupleDescriptor, ! sop->resnull); EEO_NEXT(); } EEO_CASE(EEOP_OUTER_SYSVAR) { ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum; /* these asserts must match defenses in slot_getattr */ Assert(outerslot->tts_tuple != NULL); Assert(outerslot->tts_tuple != &(outerslot->tts_minhdr)); /* heap_getsysattr has sufficient defenses against bad attnums */ ! *sop->resvalue = heap_getsysattr(outerslot->tts_tuple, attnum, outerslot->tts_tupleDescriptor, ! sop->resnull); EEO_NEXT(); } EEO_CASE(EEOP_SCAN_SYSVAR) { ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum; /* these asserts must match defenses in slot_getattr */ Assert(scanslot->tts_tuple != NULL); Assert(scanslot->tts_tuple != &(scanslot->tts_minhdr)); /* heap_getsysattr has sufficient defenses against bad attnums */ ! *sop->resvalue = heap_getsysattr(scanslot->tts_tuple, attnum, scanslot->tts_tupleDescriptor, ! sop->resnull); EEO_NEXT(); } EEO_CASE(EEOP_WHOLEROW) { + DEF_SOP(ExprEvalStep_wholerow); + /* too complex for an inline implementation */ ! ExecEvalWholeRowVar(state, sop, econtext); EEO_NEXT(); } EEO_CASE(EEOP_ASSIGN_INNER_VAR) { ! DEF_SOP(ExprEvalStep_assign_var); ! ! int resultnum = sop->resultnum; ! int attnum = sop->attnum; /* * We do not need CheckVarSlotCompatibility here; that was taken *************** *** 572,579 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_ASSIGN_OUTER_VAR) { ! int resultnum = op->d.assign_var.resultnum; ! int attnum = op->d.assign_var.attnum; /* * We do not need CheckVarSlotCompatibility here; that was taken --- 597,605 ---- EEO_CASE(EEOP_ASSIGN_OUTER_VAR) { ! DEF_SOP(ExprEvalStep_assign_var); ! int resultnum = sop->resultnum; ! int attnum = sop->attnum; /* * We do not need CheckVarSlotCompatibility here; that was taken *************** *** 588,595 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_ASSIGN_SCAN_VAR) { ! int resultnum = op->d.assign_var.resultnum; ! int attnum = op->d.assign_var.attnum; /* * We do not need CheckVarSlotCompatibility here; that was taken --- 614,622 ---- EEO_CASE(EEOP_ASSIGN_SCAN_VAR) { ! DEF_SOP(ExprEvalStep_assign_var); ! int resultnum = sop->resultnum; ! int attnum = sop->attnum; /* * We do not need CheckVarSlotCompatibility here; that was taken *************** *** 604,610 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_ASSIGN_TMP) { ! int resultnum = op->d.assign_tmp.resultnum; resultslot->tts_values[resultnum] = state->resvalue; resultslot->tts_isnull[resultnum] = state->resnull; --- 631,638 ---- EEO_CASE(EEOP_ASSIGN_TMP) { ! DEF_SOP(ExprEvalStep_assign_tmp); ! int resultnum = sop->resultnum; resultslot->tts_values[resultnum] = state->resvalue; resultslot->tts_isnull[resultnum] = state->resnull; *************** *** 614,620 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO) { ! int resultnum = op->d.assign_tmp.resultnum; resultslot->tts_isnull[resultnum] = state->resnull; if (!resultslot->tts_isnull[resultnum]) --- 642,649 ---- EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO) { ! DEF_SOP(ExprEvalStep_assign_tmp); ! int resultnum = sop->resultnum; resultslot->tts_isnull[resultnum] = state->resnull; if (!resultslot->tts_isnull[resultnum]) *************** *** 628,635 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_CONST) { ! *op->resnull = op->d.constval.isnull; ! *op->resvalue = op->d.constval.value; EEO_NEXT(); } --- 657,666 ---- EEO_CASE(EEOP_CONST) { ! DEF_SOP(ExprEvalStep_constval); ! ! *sop->resnull = sop->isnull; ! *sop->resvalue = sop->value; EEO_NEXT(); } *************** *** 644,676 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) */ EEO_CASE(EEOP_FUNCEXPR) { ! FunctionCallInfo fcinfo = op->d.func.fcinfo_data; fcinfo->isnull = false; ! *op->resvalue = (op->d.func.fn_addr) (fcinfo); ! *op->resnull = fcinfo->isnull; EEO_NEXT(); } EEO_CASE(EEOP_FUNCEXPR_STRICT) { ! FunctionCallInfo fcinfo = op->d.func.fcinfo_data; bool *argnull = fcinfo->argnull; int argno; /* strict function, so check for NULL args */ ! for (argno = 0; argno < op->d.func.nargs; argno++) { if (argnull[argno]) { ! *op->resnull = true; goto strictfail; } } fcinfo->isnull = false; ! *op->resvalue = (op->d.func.fn_addr) (fcinfo); ! *op->resnull = fcinfo->isnull; strictfail: EEO_NEXT(); --- 675,709 ---- */ EEO_CASE(EEOP_FUNCEXPR) { ! DEF_SOP(ExprEvalStep_func); ! FunctionCallInfo fcinfo = sop->fcinfo_data; fcinfo->isnull = false; ! *sop->resvalue = (sop->fn_addr) (fcinfo); ! *sop->resnull = fcinfo->isnull; EEO_NEXT(); } EEO_CASE(EEOP_FUNCEXPR_STRICT) { ! DEF_SOP(ExprEvalStep_func); ! FunctionCallInfo fcinfo = sop->fcinfo_data; bool *argnull = fcinfo->argnull; int argno; /* strict function, so check for NULL args */ ! for (argno = 0; argno < sop->nargs; argno++) { if (argnull[argno]) { ! *sop->resnull = true; goto strictfail; } } fcinfo->isnull = false; ! *sop->resvalue = (sop->fn_addr) (fcinfo); ! *sop->resnull = fcinfo->isnull; strictfail: EEO_NEXT(); *************** *** 678,691 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_FUNCEXPR_FUSAGE) { ! FunctionCallInfo fcinfo = op->d.func.fcinfo_data; PgStat_FunctionCallUsage fcusage; pgstat_init_function_usage(fcinfo, &fcusage); fcinfo->isnull = false; ! *op->resvalue = (op->d.func.fn_addr) (fcinfo); ! *op->resnull = fcinfo->isnull; pgstat_end_function_usage(&fcusage, true); --- 711,725 ---- EEO_CASE(EEOP_FUNCEXPR_FUSAGE) { ! DEF_SOP(ExprEvalStep_func); ! FunctionCallInfo fcinfo = sop->fcinfo_data; PgStat_FunctionCallUsage fcusage; pgstat_init_function_usage(fcinfo, &fcusage); fcinfo->isnull = false; ! *sop->resvalue = (sop->fn_addr) (fcinfo); ! *sop->resnull = fcinfo->isnull; pgstat_end_function_usage(&fcusage, true); *************** *** 694,710 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE) { ! FunctionCallInfo fcinfo = op->d.func.fcinfo_data; PgStat_FunctionCallUsage fcusage; bool *argnull = fcinfo->argnull; int argno; /* strict function, so check for NULL args */ ! for (argno = 0; argno < op->d.func.nargs; argno++) { if (argnull[argno]) { ! *op->resnull = true; goto strictfail_fusage; } } --- 728,745 ---- EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE) { ! DEF_SOP(ExprEvalStep_func); ! FunctionCallInfo fcinfo = sop->fcinfo_data; PgStat_FunctionCallUsage fcusage; bool *argnull = fcinfo->argnull; int argno; /* strict function, so check for NULL args */ ! for (argno = 0; argno < sop->nargs; argno++) { if (argnull[argno]) { ! *sop->resnull = true; goto strictfail_fusage; } } *************** *** 712,719 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) pgstat_init_function_usage(fcinfo, &fcusage); fcinfo->isnull = false; ! *op->resvalue = (op->d.func.fn_addr) (fcinfo); ! *op->resnull = fcinfo->isnull; pgstat_end_function_usage(&fcusage, true); --- 747,754 ---- pgstat_init_function_usage(fcinfo, &fcusage); fcinfo->isnull = false; ! *sop->resvalue = (sop->fn_addr) (fcinfo); ! *sop->resnull = fcinfo->isnull; pgstat_end_function_usage(&fcusage, true); *************** *** 733,739 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) */ EEO_CASE(EEOP_BOOL_AND_STEP_FIRST) { ! *op->d.boolexpr.anynull = false; /* * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the --- 768,776 ---- */ EEO_CASE(EEOP_BOOL_AND_STEP_FIRST) { ! DEF_SOP(ExprEvalStep_boolexpr); ! ! *sop->anynull = false; /* * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the *************** *** 745,759 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_BOOL_AND_STEP) { ! if (*op->resnull) { ! *op->d.boolexpr.anynull = true; } ! else if (!DatumGetBool(*op->resvalue)) { /* result is already set to FALSE, need not change it */ /* bail out early */ ! EEO_JUMP(op->d.boolexpr.jumpdone); } EEO_NEXT(); --- 782,798 ---- EEO_CASE(EEOP_BOOL_AND_STEP) { ! DEF_SOP(ExprEvalStep_boolexpr); ! ! if (*sop->resnull) { ! *sop->anynull = true; } ! else if (!DatumGetBool(*sop->resvalue)) { /* result is already set to FALSE, need not change it */ /* bail out early */ ! EEO_JUMP(sop->jumpdone); } EEO_NEXT(); *************** *** 761,771 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_BOOL_AND_STEP_LAST) { ! if (*op->resnull) { /* result is already set to NULL, need not change it */ } ! else if (!DatumGetBool(*op->resvalue)) { /* result is already set to FALSE, need not change it */ --- 800,812 ---- EEO_CASE(EEOP_BOOL_AND_STEP_LAST) { ! DEF_SOP(ExprEvalStep_boolexpr); ! ! if (*sop->resnull) { /* result is already set to NULL, need not change it */ } ! else if (!DatumGetBool(*sop->resvalue)) { /* result is already set to FALSE, need not change it */ *************** *** 775,784 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) * except more expensive. */ } ! else if (*op->d.boolexpr.anynull) { ! *op->resvalue = (Datum) 0; ! *op->resnull = true; } else { --- 816,825 ---- * except more expensive. */ } ! else if (*sop->anynull) { ! *sop->resvalue = (Datum) 0; ! *sop->resnull = true; } else { *************** *** 800,806 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) */ EEO_CASE(EEOP_BOOL_OR_STEP_FIRST) { ! *op->d.boolexpr.anynull = false; /* * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same --- 841,849 ---- */ EEO_CASE(EEOP_BOOL_OR_STEP_FIRST) { ! DEF_SOP(ExprEvalStep_boolexpr); ! ! *sop->anynull = false; /* * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same *************** *** 812,826 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_BOOL_OR_STEP) { ! if (*op->resnull) { ! *op->d.boolexpr.anynull = true; } ! else if (DatumGetBool(*op->resvalue)) { /* result is already set to TRUE, need not change it */ /* bail out early */ ! EEO_JUMP(op->d.boolexpr.jumpdone); } EEO_NEXT(); --- 855,871 ---- EEO_CASE(EEOP_BOOL_OR_STEP) { ! DEF_SOP(ExprEvalStep_boolexpr); ! ! if (*sop->resnull) { ! *sop->anynull = true; } ! else if (DatumGetBool(*sop->resvalue)) { /* result is already set to TRUE, need not change it */ /* bail out early */ ! EEO_JUMP(sop->jumpdone); } EEO_NEXT(); *************** *** 828,838 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_BOOL_OR_STEP_LAST) { ! if (*op->resnull) { /* result is already set to NULL, need not change it */ } ! else if (DatumGetBool(*op->resvalue)) { /* result is already set to TRUE, need not change it */ --- 873,885 ---- EEO_CASE(EEOP_BOOL_OR_STEP_LAST) { ! DEF_SOP(ExprEvalStep_boolexpr); ! ! if (*sop->resnull) { /* result is already set to NULL, need not change it */ } ! else if (DatumGetBool(*sop->resvalue)) { /* result is already set to TRUE, need not change it */ *************** *** 842,851 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) * more expensive. */ } ! else if (*op->d.boolexpr.anynull) { ! *op->resvalue = (Datum) 0; ! *op->resnull = true; } else { --- 889,898 ---- * more expensive. */ } ! else if (*sop->anynull) { ! *sop->resvalue = (Datum) 0; ! *sop->resnull = true; } else { *************** *** 857,885 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_BOOL_NOT_STEP) { /* * Evaluation of 'not' is simple... if expr is false, then return * 'true' and vice versa. It's safe to do this even on a * nominally null value, so we ignore resnull; that means that * NULL in produces NULL out, which is what we want. */ ! *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); EEO_NEXT(); } EEO_CASE(EEOP_QUAL) { /* simplified version of BOOL_AND_STEP for use by ExecQual() */ /* If argument (also result) is false or null ... */ ! if (*op->resnull || ! !DatumGetBool(*op->resvalue)) { /* ... bail out early, returning FALSE */ ! *op->resnull = false; ! *op->resvalue = BoolGetDatum(false); ! EEO_JUMP(op->d.qualexpr.jumpdone); } /* --- 904,936 ---- EEO_CASE(EEOP_BOOL_NOT_STEP) { + DEF_SOP(ExprEvalStep_boolexpr); + /* * Evaluation of 'not' is simple... if expr is false, then return * 'true' and vice versa. It's safe to do this even on a * nominally null value, so we ignore resnull; that means that * NULL in produces NULL out, which is what we want. */ ! *sop->resvalue = BoolGetDatum(!DatumGetBool(*sop->resvalue)); EEO_NEXT(); } EEO_CASE(EEOP_QUAL) { + DEF_SOP(ExprEvalStep_qualexpr); + /* simplified version of BOOL_AND_STEP for use by ExecQual() */ /* If argument (also result) is false or null ... */ ! if (*sop->resnull || ! !DatumGetBool(*sop->resvalue)) { /* ... bail out early, returning FALSE */ ! *sop->resnull = false; ! *sop->resvalue = BoolGetDatum(false); ! EEO_JUMP(sop->jumpdone); } /* *************** *** 892,956 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_JUMP) { /* Unconditionally jump to target step */ ! EEO_JUMP(op->d.jump.jumpdone); } EEO_CASE(EEOP_JUMP_IF_NULL) { /* Transfer control if current result is null */ ! if (*op->resnull) ! EEO_JUMP(op->d.jump.jumpdone); EEO_NEXT(); } EEO_CASE(EEOP_JUMP_IF_NOT_NULL) { /* Transfer control if current result is non-null */ ! if (!*op->resnull) ! EEO_JUMP(op->d.jump.jumpdone); EEO_NEXT(); } EEO_CASE(EEOP_JUMP_IF_NOT_TRUE) { /* Transfer control if current result is null or false */ ! if (*op->resnull || !DatumGetBool(*op->resvalue)) ! EEO_JUMP(op->d.jump.jumpdone); EEO_NEXT(); } EEO_CASE(EEOP_NULLTEST_ISNULL) { ! *op->resvalue = BoolGetDatum(*op->resnull); ! *op->resnull = false; EEO_NEXT(); } EEO_CASE(EEOP_NULLTEST_ISNOTNULL) { ! *op->resvalue = BoolGetDatum(!*op->resnull); ! *op->resnull = false; EEO_NEXT(); } EEO_CASE(EEOP_NULLTEST_ROWISNULL) { /* out of line implementation: too large */ ! ExecEvalRowNull(state, op, econtext); EEO_NEXT(); } EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL) { /* out of line implementation: too large */ ! ExecEvalRowNotNull(state, op, econtext); EEO_NEXT(); } --- 943,1023 ---- EEO_CASE(EEOP_JUMP) { + DEF_SOP(ExprEvalStep_jump); + /* Unconditionally jump to target step */ ! EEO_JUMP(sop->jumpdone); } EEO_CASE(EEOP_JUMP_IF_NULL) { + DEF_SOP(ExprEvalStep_jump); + /* Transfer control if current result is null */ ! if (*sop->resnull) ! EEO_JUMP(sop->jumpdone); EEO_NEXT(); } EEO_CASE(EEOP_JUMP_IF_NOT_NULL) { + DEF_SOP(ExprEvalStep_jump); + /* Transfer control if current result is non-null */ ! if (!*sop->resnull) ! EEO_JUMP(sop->jumpdone); EEO_NEXT(); } EEO_CASE(EEOP_JUMP_IF_NOT_TRUE) { + DEF_SOP(ExprEvalStep_jump); + /* Transfer control if current result is null or false */ ! if (*sop->resnull || !DatumGetBool(*sop->resvalue)) ! EEO_JUMP(sop->jumpdone); EEO_NEXT(); } EEO_CASE(EEOP_NULLTEST_ISNULL) { ! DEF_SOP(ExprEvalStep_nulltest_row); ! ! *sop->resvalue = BoolGetDatum(*sop->resnull); ! *sop->resnull = false; EEO_NEXT(); } EEO_CASE(EEOP_NULLTEST_ISNOTNULL) { ! DEF_SOP(ExprEvalStep_nulltest_row); ! ! *sop->resvalue = BoolGetDatum(!*sop->resnull); ! *sop->resnull = false; EEO_NEXT(); } EEO_CASE(EEOP_NULLTEST_ROWISNULL) { + DEF_SOP(ExprEvalStep_nulltest_row); + /* out of line implementation: too large */ ! ExecEvalRowNull(state, sop, econtext); EEO_NEXT(); } EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL) { + DEF_SOP(ExprEvalStep_nulltest_row); + /* out of line implementation: too large */ ! ExecEvalRowNotNull(state, sop, econtext); EEO_NEXT(); } *************** *** 959,968 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_BOOLTEST_IS_TRUE) { ! if (*op->resnull) { ! *op->resvalue = BoolGetDatum(false); ! *op->resnull = false; } /* else, input value is the correct output as well */ --- 1026,1037 ---- EEO_CASE(EEOP_BOOLTEST_IS_TRUE) { ! DEF_SOP(ExprEvalStep); ! ! if (*sop->resnull) { ! *sop->resvalue = BoolGetDatum(false); ! *sop->resnull = false; } /* else, input value is the correct output as well */ *************** *** 971,1006 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE) { ! if (*op->resnull) { ! *op->resvalue = BoolGetDatum(true); ! *op->resnull = false; } else ! *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); EEO_NEXT(); } EEO_CASE(EEOP_BOOLTEST_IS_FALSE) { ! if (*op->resnull) { ! *op->resvalue = BoolGetDatum(false); ! *op->resnull = false; } else ! *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue)); EEO_NEXT(); } EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE) { ! if (*op->resnull) { ! *op->resvalue = BoolGetDatum(true); ! *op->resnull = false; } /* else, input value is the correct output as well */ --- 1040,1081 ---- EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE) { ! DEF_SOP(ExprEvalStep); ! ! if (*sop->resnull) { ! *sop->resvalue = BoolGetDatum(true); ! *sop->resnull = false; } else ! *sop->resvalue = BoolGetDatum(!DatumGetBool(*sop->resvalue)); EEO_NEXT(); } EEO_CASE(EEOP_BOOLTEST_IS_FALSE) { ! DEF_SOP(ExprEvalStep); ! ! if (*sop->resnull) { ! *sop->resvalue = BoolGetDatum(false); ! *sop->resnull = false; } else ! *sop->resvalue = BoolGetDatum(!DatumGetBool(*sop->resvalue)); EEO_NEXT(); } EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE) { ! DEF_SOP(ExprEvalStep); ! ! if (*sop->resnull) { ! *sop->resvalue = BoolGetDatum(true); ! *sop->resnull = false; } /* else, input value is the correct output as well */ *************** *** 1009,1029 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_PARAM_EXEC) { /* out of line implementation: too large */ ! ExecEvalParamExec(state, op, econtext); EEO_NEXT(); } EEO_CASE(EEOP_PARAM_EXTERN) { /* out of line implementation: too large */ ! ExecEvalParamExtern(state, op, econtext); EEO_NEXT(); } EEO_CASE(EEOP_CASE_TESTVAL) { /* * Normally upper parts of the expression tree have setup the * values to be returned here, but some parts of the system --- 1084,1110 ---- EEO_CASE(EEOP_PARAM_EXEC) { + DEF_SOP(ExprEvalStep_param); + /* out of line implementation: too large */ ! ExecEvalParamExec(state, sop, econtext); EEO_NEXT(); } EEO_CASE(EEOP_PARAM_EXTERN) { + DEF_SOP(ExprEvalStep_param); + /* out of line implementation: too large */ ! ExecEvalParamExtern(state, sop, econtext); EEO_NEXT(); } EEO_CASE(EEOP_CASE_TESTVAL) { + DEF_SOP(ExprEvalStep_casetest); + /* * Normally upper parts of the expression tree have setup the * values to be returned here, but some parts of the system *************** *** 1033,1047 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) * and this is unlikely to be performance sensitive enough to * worry about an extra branch. */ ! if (op->d.casetest.value) { ! *op->resvalue = *op->d.casetest.value; ! *op->resnull = *op->d.casetest.isnull; } else { ! *op->resvalue = econtext->caseValue_datum; ! *op->resnull = econtext->caseValue_isNull; } EEO_NEXT(); --- 1114,1128 ---- * and this is unlikely to be performance sensitive enough to * worry about an extra branch. */ ! if (sop->value) { ! *sop->resvalue = *sop->value; ! *sop->resnull = *sop->isnull; } else { ! *sop->resvalue = econtext->caseValue_datum; ! *sop->resnull = econtext->caseValue_isNull; } EEO_NEXT(); *************** *** 1049,1066 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_DOMAIN_TESTVAL) { /* * See EEOP_CASE_TESTVAL comment. */ ! if (op->d.casetest.value) { ! *op->resvalue = *op->d.casetest.value; ! *op->resnull = *op->d.casetest.isnull; } else { ! *op->resvalue = econtext->domainValue_datum; ! *op->resnull = econtext->domainValue_isNull; } EEO_NEXT(); --- 1130,1149 ---- EEO_CASE(EEOP_DOMAIN_TESTVAL) { + DEF_SOP(ExprEvalStep_casetest); + /* * See EEOP_CASE_TESTVAL comment. */ ! if (sop->value) { ! *sop->resvalue = *sop->value; ! *sop->resnull = *sop->isnull; } else { ! *sop->resvalue = econtext->domainValue_datum; ! *sop->resnull = econtext->domainValue_isNull; } EEO_NEXT(); *************** *** 1068,1086 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_MAKE_READONLY) { /* * Force a varlena value that might be read multiple times to R/O */ ! if (!*op->d.make_readonly.isnull) ! *op->resvalue = ! MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value); ! *op->resnull = *op->d.make_readonly.isnull; EEO_NEXT(); } EEO_CASE(EEOP_IOCOERCE) { /* * Evaluate a CoerceViaIO node. This can be quite a hot path, so * inline as much work as possible. The source value is in our --- 1151,1173 ---- EEO_CASE(EEOP_MAKE_READONLY) { + DEF_SOP(ExprEvalStep_make_readonly); + /* * Force a varlena value that might be read multiple times to R/O */ ! if (!*sop->isnull) ! *sop->resvalue = ! MakeExpandedObjectReadOnlyInternal(*sop->value); ! *sop->resnull = *sop->isnull; EEO_NEXT(); } EEO_CASE(EEOP_IOCOERCE) { + DEF_SOP(ExprEvalStep_iocoerce); + /* * Evaluate a CoerceViaIO node. This can be quite a hot path, so * inline as much work as possible. The source value is in our *************** *** 1089,1095 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) char *str; /* call output function (similar to OutputFunctionCall) */ ! if (*op->resnull) { /* output functions are not called on nulls */ str = NULL; --- 1176,1182 ---- char *str; /* call output function (similar to OutputFunctionCall) */ ! if (*sop->resnull) { /* output functions are not called on nulls */ str = NULL; *************** *** 1098,1105 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) { FunctionCallInfo fcinfo_out; ! fcinfo_out = op->d.iocoerce.fcinfo_data_out; ! fcinfo_out->arg[0] = *op->resvalue; fcinfo_out->argnull[0] = false; fcinfo_out->isnull = false; --- 1185,1192 ---- { FunctionCallInfo fcinfo_out; ! fcinfo_out = sop->fcinfo_data_out; ! fcinfo_out->arg[0] = *sop->resvalue; fcinfo_out->argnull[0] = false; fcinfo_out->isnull = false; *************** *** 1110,1136 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) } /* call input function (similar to InputFunctionCall) */ ! if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL) { FunctionCallInfo fcinfo_in; ! fcinfo_in = op->d.iocoerce.fcinfo_data_in; fcinfo_in->arg[0] = PointerGetDatum(str); ! fcinfo_in->argnull[0] = *op->resnull; /* second and third arguments are already set up */ fcinfo_in->isnull = false; ! *op->resvalue = FunctionCallInvoke(fcinfo_in); /* Should get null result if and only if str is NULL */ if (str == NULL) { ! Assert(*op->resnull); Assert(fcinfo_in->isnull); } else { ! Assert(!*op->resnull); Assert(!fcinfo_in->isnull); } } --- 1197,1223 ---- } /* call input function (similar to InputFunctionCall) */ ! if (!sop->finfo_in->fn_strict || str != NULL) { FunctionCallInfo fcinfo_in; ! fcinfo_in = sop->fcinfo_data_in; fcinfo_in->arg[0] = PointerGetDatum(str); ! fcinfo_in->argnull[0] = *sop->resnull; /* second and third arguments are already set up */ fcinfo_in->isnull = false; ! *sop->resvalue = FunctionCallInvoke(fcinfo_in); /* Should get null result if and only if str is NULL */ if (str == NULL) { ! Assert(*sop->resnull); Assert(fcinfo_in->isnull); } else { ! Assert(!*sop->resnull); Assert(!fcinfo_in->isnull); } } *************** *** 1140,1145 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) --- 1227,1234 ---- EEO_CASE(EEOP_DISTINCT) { + DEF_SOP(ExprEvalStep_func); + /* * IS DISTINCT FROM must evaluate arguments (already done into * fcinfo->arg/argnull) to determine whether they are NULL; if *************** *** 1149,1168 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) * care whether that function is strict. Because the handling of * nulls is different, we can't just reuse EEOP_FUNCEXPR. */ ! FunctionCallInfo fcinfo = op->d.func.fcinfo_data; /* check function arguments for NULLness */ if (fcinfo->argnull[0] && fcinfo->argnull[1]) { /* Both NULL? Then is not distinct... */ ! *op->resvalue = BoolGetDatum(false); ! *op->resnull = false; } else if (fcinfo->argnull[0] || fcinfo->argnull[1]) { /* Only one is NULL? Then is distinct... */ ! *op->resvalue = BoolGetDatum(true); ! *op->resnull = false; } else { --- 1238,1257 ---- * care whether that function is strict. Because the handling of * nulls is different, we can't just reuse EEOP_FUNCEXPR. */ ! FunctionCallInfo fcinfo = sop->fcinfo_data; /* check function arguments for NULLness */ if (fcinfo->argnull[0] && fcinfo->argnull[1]) { /* Both NULL? Then is not distinct... */ ! *sop->resvalue = BoolGetDatum(false); ! *sop->resnull = false; } else if (fcinfo->argnull[0] || fcinfo->argnull[1]) { /* Only one is NULL? Then is distinct... */ ! *sop->resvalue = BoolGetDatum(true); ! *sop->resnull = false; } else { *************** *** 1170,1179 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) Datum eqresult; fcinfo->isnull = false; ! eqresult = (op->d.func.fn_addr) (fcinfo); /* Must invert result of "="; safe to do even if null */ ! *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult)); ! *op->resnull = fcinfo->isnull; } EEO_NEXT(); --- 1259,1268 ---- Datum eqresult; fcinfo->isnull = false; ! eqresult = (sop->fn_addr) (fcinfo); /* Must invert result of "="; safe to do even if null */ ! *sop->resvalue = BoolGetDatum(!DatumGetBool(eqresult)); ! *sop->resnull = fcinfo->isnull; } EEO_NEXT(); *************** *** 1181,1190 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_NULLIF) { /* * The arguments are already evaluated into fcinfo->arg/argnull. */ ! FunctionCallInfo fcinfo = op->d.func.fcinfo_data; /* if either argument is NULL they can't be equal */ if (!fcinfo->argnull[0] && !fcinfo->argnull[1]) --- 1270,1281 ---- EEO_CASE(EEOP_NULLIF) { + DEF_SOP(ExprEvalStep_func); + /* * The arguments are already evaluated into fcinfo->arg/argnull. */ ! FunctionCallInfo fcinfo = sop->fcinfo_data; /* if either argument is NULL they can't be equal */ if (!fcinfo->argnull[0] && !fcinfo->argnull[1]) *************** *** 1192,1298 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) Datum result; fcinfo->isnull = false; ! result = (op->d.func.fn_addr) (fcinfo); /* if the arguments are equal return null */ if (!fcinfo->isnull && DatumGetBool(result)) { ! *op->resvalue = (Datum) 0; ! *op->resnull = true; EEO_NEXT(); } } /* Arguments aren't equal, so return the first one */ ! *op->resvalue = fcinfo->arg[0]; ! *op->resnull = fcinfo->argnull[0]; EEO_NEXT(); } EEO_CASE(EEOP_SQLVALUEFUNCTION) { /* * Doesn't seem worthwhile to have an inline implementation * efficiency-wise. */ ! ExecEvalSQLValueFunction(state, op); EEO_NEXT(); } EEO_CASE(EEOP_CURRENTOFEXPR) { /* error invocation uses space, and shouldn't ever occur */ ! ExecEvalCurrentOfExpr(state, op); EEO_NEXT(); } EEO_CASE(EEOP_NEXTVALUEEXPR) { /* * Doesn't seem worthwhile to have an inline implementation * efficiency-wise. */ ! ExecEvalNextValueExpr(state, op); EEO_NEXT(); } EEO_CASE(EEOP_ARRAYEXPR) { /* too complex for an inline implementation */ ! ExecEvalArrayExpr(state, op); EEO_NEXT(); } EEO_CASE(EEOP_ARRAYCOERCE) { /* too complex for an inline implementation */ ! ExecEvalArrayCoerce(state, op); EEO_NEXT(); } EEO_CASE(EEOP_ROW) { /* too complex for an inline implementation */ ! ExecEvalRow(state, op); EEO_NEXT(); } EEO_CASE(EEOP_ROWCOMPARE_STEP) { ! FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data; /* force NULL result if strict fn and NULL input */ ! if (op->d.rowcompare_step.finfo->fn_strict && (fcinfo->argnull[0] || fcinfo->argnull[1])) { ! *op->resnull = true; ! EEO_JUMP(op->d.rowcompare_step.jumpnull); } /* Apply comparison function */ fcinfo->isnull = false; ! *op->resvalue = (op->d.rowcompare_step.fn_addr) (fcinfo); /* force NULL result if NULL function result */ if (fcinfo->isnull) { ! *op->resnull = true; ! EEO_JUMP(op->d.rowcompare_step.jumpnull); } ! *op->resnull = false; /* If unequal, no need to compare remaining columns */ ! if (DatumGetInt32(*op->resvalue) != 0) { ! EEO_JUMP(op->d.rowcompare_step.jumpdone); } EEO_NEXT(); --- 1283,1402 ---- Datum result; fcinfo->isnull = false; ! result = (sop->fn_addr) (fcinfo); /* if the arguments are equal return null */ if (!fcinfo->isnull && DatumGetBool(result)) { ! *sop->resvalue = (Datum) 0; ! *sop->resnull = true; EEO_NEXT(); } } /* Arguments aren't equal, so return the first one */ ! *sop->resvalue = fcinfo->arg[0]; ! *sop->resnull = fcinfo->argnull[0]; EEO_NEXT(); } EEO_CASE(EEOP_SQLVALUEFUNCTION) { + DEF_SOP(ExprEvalStep_sqlvaluefunction); + /* * Doesn't seem worthwhile to have an inline implementation * efficiency-wise. */ ! ExecEvalSQLValueFunction(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_CURRENTOFEXPR) { + DEF_SOP(ExprEvalStep); + /* error invocation uses space, and shouldn't ever occur */ ! ExecEvalCurrentOfExpr(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_NEXTVALUEEXPR) { + DEF_SOP(ExprEvalStep_nextvalueexpr); + /* * Doesn't seem worthwhile to have an inline implementation * efficiency-wise. */ ! ExecEvalNextValueExpr(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_ARRAYEXPR) { + DEF_SOP(ExprEvalStep_arrayexpr); + /* too complex for an inline implementation */ ! ExecEvalArrayExpr(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_ARRAYCOERCE) { + DEF_SOP(ExprEvalStep_arraycoerce); + /* too complex for an inline implementation */ ! ExecEvalArrayCoerce(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_ROW) { + DEF_SOP(ExprEvalStep_row); + /* too complex for an inline implementation */ ! ExecEvalRow(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_ROWCOMPARE_STEP) { ! DEF_SOP(ExprEvalStep_rowcompare_step); ! FunctionCallInfo fcinfo = sop->fcinfo_data; /* force NULL result if strict fn and NULL input */ ! if (sop->finfo->fn_strict && (fcinfo->argnull[0] || fcinfo->argnull[1])) { ! *sop->resnull = true; ! EEO_JUMP(sop->jumpnull); } /* Apply comparison function */ fcinfo->isnull = false; ! *sop->resvalue = (sop->fn_addr) (fcinfo); /* force NULL result if NULL function result */ if (fcinfo->isnull) { ! *sop->resnull = true; ! EEO_JUMP(sop->jumpnull); } ! *sop->resnull = false; /* If unequal, no need to compare remaining columns */ ! if (DatumGetInt32(*sop->resvalue) != 0) { ! EEO_JUMP(sop->jumpdone); } EEO_NEXT(); *************** *** 1300,1323 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_ROWCOMPARE_FINAL) { ! int32 cmpresult = DatumGetInt32(*op->resvalue); ! RowCompareType rctype = op->d.rowcompare_final.rctype; ! *op->resnull = false; switch (rctype) { /* EQ and NE cases aren't allowed here */ case ROWCOMPARE_LT: ! *op->resvalue = BoolGetDatum(cmpresult < 0); break; case ROWCOMPARE_LE: ! *op->resvalue = BoolGetDatum(cmpresult <= 0); break; case ROWCOMPARE_GE: ! *op->resvalue = BoolGetDatum(cmpresult >= 0); break; case ROWCOMPARE_GT: ! *op->resvalue = BoolGetDatum(cmpresult > 0); break; default: Assert(false); --- 1404,1428 ---- EEO_CASE(EEOP_ROWCOMPARE_FINAL) { ! DEF_SOP(ExprEvalStep_rowcompare_final); ! int32 cmpresult = DatumGetInt32(*sop->resvalue); ! RowCompareType rctype = sop->rctype; ! *sop->resnull = false; switch (rctype) { /* EQ and NE cases aren't allowed here */ case ROWCOMPARE_LT: ! *sop->resvalue = BoolGetDatum(cmpresult < 0); break; case ROWCOMPARE_LE: ! *sop->resvalue = BoolGetDatum(cmpresult <= 0); break; case ROWCOMPARE_GE: ! *sop->resvalue = BoolGetDatum(cmpresult >= 0); break; case ROWCOMPARE_GT: ! *sop->resvalue = BoolGetDatum(cmpresult > 0); break; default: Assert(false); *************** *** 1329,1382 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_CASE(EEOP_MINMAX) { /* too complex for an inline implementation */ ! ExecEvalMinMax(state, op); EEO_NEXT(); } EEO_CASE(EEOP_FIELDSELECT) { /* too complex for an inline implementation */ ! ExecEvalFieldSelect(state, op, econtext); EEO_NEXT(); } EEO_CASE(EEOP_FIELDSTORE_DEFORM) { /* too complex for an inline implementation */ ! ExecEvalFieldStoreDeForm(state, op, econtext); EEO_NEXT(); } EEO_CASE(EEOP_FIELDSTORE_FORM) { /* too complex for an inline implementation */ ! ExecEvalFieldStoreForm(state, op, econtext); EEO_NEXT(); } EEO_CASE(EEOP_ARRAYREF_SUBSCRIPT) { /* Process an array subscript */ /* too complex for an inline implementation */ ! if (ExecEvalArrayRefSubscript(state, op)) { EEO_NEXT(); } else { /* Subscript is null, short-circuit ArrayRef to NULL */ ! EEO_JUMP(op->d.arrayref_subscript.jumpdone); } } EEO_CASE(EEOP_ARRAYREF_OLD) { /* * Fetch the old value in an arrayref assignment, in case it's * referenced (via a CaseTestExpr) inside the assignment --- 1434,1499 ---- EEO_CASE(EEOP_MINMAX) { + DEF_SOP(ExprEvalStep_minmax); + /* too complex for an inline implementation */ ! ExecEvalMinMax(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_FIELDSELECT) { + DEF_SOP(ExprEvalStep_fieldselect); + /* too complex for an inline implementation */ ! ExecEvalFieldSelect(state, sop, econtext); EEO_NEXT(); } EEO_CASE(EEOP_FIELDSTORE_DEFORM) { + DEF_SOP(ExprEvalStep_fieldstore); + /* too complex for an inline implementation */ ! ExecEvalFieldStoreDeForm(state, sop, econtext); EEO_NEXT(); } EEO_CASE(EEOP_FIELDSTORE_FORM) { + DEF_SOP(ExprEvalStep_fieldstore); + /* too complex for an inline implementation */ ! ExecEvalFieldStoreForm(state, sop, econtext); EEO_NEXT(); } EEO_CASE(EEOP_ARRAYREF_SUBSCRIPT) { + DEF_SOP(ExprEvalStep_arrayref_subscript); + /* Process an array subscript */ /* too complex for an inline implementation */ ! if (ExecEvalArrayRefSubscript(state, sop)) { EEO_NEXT(); } else { /* Subscript is null, short-circuit ArrayRef to NULL */ ! EEO_JUMP(sop->jumpdone); } } EEO_CASE(EEOP_ARRAYREF_OLD) { + DEF_SOP(ExprEvalStep_arrayref); + /* * Fetch the old value in an arrayref assignment, in case it's * referenced (via a CaseTestExpr) inside the assignment *************** *** 1384,1390 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) */ /* too complex for an inline implementation */ ! ExecEvalArrayRefOld(state, op); EEO_NEXT(); } --- 1501,1507 ---- */ /* too complex for an inline implementation */ ! ExecEvalArrayRefOld(state, sop); EEO_NEXT(); } *************** *** 1394,1401 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) */ EEO_CASE(EEOP_ARRAYREF_ASSIGN) { /* too complex for an inline implementation */ ! ExecEvalArrayRefAssign(state, op); EEO_NEXT(); } --- 1511,1520 ---- */ EEO_CASE(EEOP_ARRAYREF_ASSIGN) { + DEF_SOP(ExprEvalStep_arrayref); + /* too complex for an inline implementation */ ! ExecEvalArrayRefAssign(state, sop); EEO_NEXT(); } *************** *** 1405,1452 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) */ EEO_CASE(EEOP_ARRAYREF_FETCH) { /* too complex for an inline implementation */ ! ExecEvalArrayRefFetch(state, op); EEO_NEXT(); } EEO_CASE(EEOP_CONVERT_ROWTYPE) { /* too complex for an inline implementation */ ! ExecEvalConvertRowtype(state, op, econtext); EEO_NEXT(); } EEO_CASE(EEOP_SCALARARRAYOP) { /* too complex for an inline implementation */ ! ExecEvalScalarArrayOp(state, op); EEO_NEXT(); } EEO_CASE(EEOP_DOMAIN_NOTNULL) { /* too complex for an inline implementation */ ! ExecEvalConstraintNotNull(state, op); EEO_NEXT(); } EEO_CASE(EEOP_DOMAIN_CHECK) { /* too complex for an inline implementation */ ! ExecEvalConstraintCheck(state, op); EEO_NEXT(); } EEO_CASE(EEOP_XMLEXPR) { /* too complex for an inline implementation */ ! ExecEvalXmlExpr(state, op); EEO_NEXT(); } --- 1524,1583 ---- */ EEO_CASE(EEOP_ARRAYREF_FETCH) { + DEF_SOP(ExprEvalStep_arrayref); + /* too complex for an inline implementation */ ! ExecEvalArrayRefFetch(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_CONVERT_ROWTYPE) { + DEF_SOP(ExprEvalStep_convert_rowtype); + /* too complex for an inline implementation */ ! ExecEvalConvertRowtype(state, sop, econtext); EEO_NEXT(); } EEO_CASE(EEOP_SCALARARRAYOP) { + DEF_SOP(ExprEvalStep_scalararrayop); + /* too complex for an inline implementation */ ! ExecEvalScalarArrayOp(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_DOMAIN_NOTNULL) { + DEF_SOP(ExprEvalStep_domaincheck); + /* too complex for an inline implementation */ ! ExecEvalConstraintNotNull(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_DOMAIN_CHECK) { + DEF_SOP(ExprEvalStep_domaincheck); + /* too complex for an inline implementation */ ! ExecEvalConstraintCheck(state, sop); EEO_NEXT(); } EEO_CASE(EEOP_XMLEXPR) { + DEF_SOP(ExprEvalStep_xmlexpr); + /* too complex for an inline implementation */ ! ExecEvalXmlExpr(state, sop); EEO_NEXT(); } *************** *** 1457,1476 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) * Returns a Datum whose value is the precomputed aggregate value * found in the given expression context. */ ! AggrefExprState *aggref = op->d.aggref.astate; Assert(econtext->ecxt_aggvalues != NULL); ! *op->resvalue = econtext->ecxt_aggvalues[aggref->aggno]; ! *op->resnull = econtext->ecxt_aggnulls[aggref->aggno]; EEO_NEXT(); } EEO_CASE(EEOP_GROUPING_FUNC) { /* too complex/uncommon for an inline implementation */ ! ExecEvalGroupingFunc(state, op); EEO_NEXT(); } --- 1588,1610 ---- * Returns a Datum whose value is the precomputed aggregate value * found in the given expression context. */ ! DEF_SOP(ExprEvalStep_aggref); ! AggrefExprState *aggref = sop->astate; Assert(econtext->ecxt_aggvalues != NULL); ! *sop->resvalue = econtext->ecxt_aggvalues[aggref->aggno]; ! *sop->resnull = econtext->ecxt_aggnulls[aggref->aggno]; EEO_NEXT(); } EEO_CASE(EEOP_GROUPING_FUNC) { + DEF_SOP(ExprEvalStep_grouping_func); + /* too complex/uncommon for an inline implementation */ ! ExecEvalGroupingFunc(state, sop); EEO_NEXT(); } *************** *** 1480,1507 **** ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) /* * Like Aggref, just return a precomputed value from the econtext. */ ! WindowFuncExprState *wfunc = op->d.window_func.wfstate; Assert(econtext->ecxt_aggvalues != NULL); ! *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno]; ! *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno]; EEO_NEXT(); } EEO_CASE(EEOP_SUBPLAN) { /* too complex for an inline implementation */ ! ExecEvalSubPlan(state, op, econtext); EEO_NEXT(); } EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN) { /* too complex for an inline implementation */ ! ExecEvalAlternativeSubPlan(state, op, econtext); EEO_NEXT(); } --- 1614,1646 ---- /* * Like Aggref, just return a precomputed value from the econtext. */ ! DEF_SOP(ExprEvalStep_window_func); ! WindowFuncExprState *wfunc = sop->wfstate; Assert(econtext->ecxt_aggvalues != NULL); ! *sop->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno]; ! *sop->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno]; EEO_NEXT(); } EEO_CASE(EEOP_SUBPLAN) { + DEF_SOP(ExprEvalStep_subplan); + /* too complex for an inline implementation */ ! ExecEvalSubPlan(state, sop, econtext); EEO_NEXT(); } EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN) { + DEF_SOP(ExprEvalStep_alternative_subplan); + /* too complex for an inline implementation */ ! ExecEvalAlternativeSubPlan(state, sop, econtext); EEO_NEXT(); } *************** *** 1635,1648 **** ShutdownTupleDescRef(Datum arg) static Datum ExecJustInnerVarFirst(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = &state->steps[1]; ! int attnum = op->d.var.attnum + 1; TupleTableSlot *slot = econtext->ecxt_innertuple; /* See ExecInterpExpr()'s comments for EEOP_INNER_VAR_FIRST */ ! CheckVarSlotCompatibility(slot, attnum, op->d.var.vartype); ! op->opcode = EEOP_INNER_VAR; /* just for cleanliness */ state->evalfunc = ExecJustInnerVar; /* --- 1774,1788 ---- static Datum ExecJustInnerVarFirst(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = state->steps->nextstep; ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum + 1; TupleTableSlot *slot = econtext->ecxt_innertuple; /* See ExecInterpExpr()'s comments for EEOP_INNER_VAR_FIRST */ ! CheckVarSlotCompatibility(slot, attnum, sop->vartype); ! sop->opcode = EEOP_INNER_VAR; /* just for cleanliness */ state->evalfunc = ExecJustInnerVar; /* *************** *** 1657,1664 **** ExecJustInnerVarFirst(ExprState *state, ExprContext *econtext, bool *isnull) static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = &state->steps[1]; ! int attnum = op->d.var.attnum + 1; TupleTableSlot *slot = econtext->ecxt_innertuple; /* See comments in ExecJustInnerVarFirst */ --- 1797,1805 ---- static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = state->steps->nextstep; ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum + 1; TupleTableSlot *slot = econtext->ecxt_innertuple; /* See comments in ExecJustInnerVarFirst */ *************** *** 1669,1680 **** ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull) static Datum ExecJustOuterVarFirst(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = &state->steps[1]; ! int attnum = op->d.var.attnum + 1; TupleTableSlot *slot = econtext->ecxt_outertuple; ! CheckVarSlotCompatibility(slot, attnum, op->d.var.vartype); ! op->opcode = EEOP_OUTER_VAR; /* just for cleanliness */ state->evalfunc = ExecJustOuterVar; /* See comments in ExecJustInnerVarFirst */ --- 1810,1822 ---- static Datum ExecJustOuterVarFirst(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = state->steps->nextstep; ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum + 1; TupleTableSlot *slot = econtext->ecxt_outertuple; ! CheckVarSlotCompatibility(slot, attnum, sop->vartype); ! sop->opcode = EEOP_OUTER_VAR; /* just for cleanliness */ state->evalfunc = ExecJustOuterVar; /* See comments in ExecJustInnerVarFirst */ *************** *** 1685,1692 **** ExecJustOuterVarFirst(ExprState *state, ExprContext *econtext, bool *isnull) static Datum ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = &state->steps[1]; ! int attnum = op->d.var.attnum + 1; TupleTableSlot *slot = econtext->ecxt_outertuple; /* See comments in ExecJustInnerVarFirst */ --- 1827,1835 ---- static Datum ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = state->steps->nextstep; ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum + 1; TupleTableSlot *slot = econtext->ecxt_outertuple; /* See comments in ExecJustInnerVarFirst */ *************** *** 1697,1708 **** ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull) static Datum ExecJustScanVarFirst(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = &state->steps[1]; ! int attnum = op->d.var.attnum + 1; TupleTableSlot *slot = econtext->ecxt_scantuple; ! CheckVarSlotCompatibility(slot, attnum, op->d.var.vartype); ! op->opcode = EEOP_SCAN_VAR; /* just for cleanliness */ state->evalfunc = ExecJustScanVar; /* See comments in ExecJustInnerVarFirst */ --- 1840,1852 ---- static Datum ExecJustScanVarFirst(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = state->steps->nextstep; ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum + 1; TupleTableSlot *slot = econtext->ecxt_scantuple; ! CheckVarSlotCompatibility(slot, attnum, sop->vartype); ! sop->opcode = EEOP_SCAN_VAR; /* just for cleanliness */ state->evalfunc = ExecJustScanVar; /* See comments in ExecJustInnerVarFirst */ *************** *** 1713,1720 **** ExecJustScanVarFirst(ExprState *state, ExprContext *econtext, bool *isnull) static Datum ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = &state->steps[1]; ! int attnum = op->d.var.attnum + 1; TupleTableSlot *slot = econtext->ecxt_scantuple; /* See comments in ExecJustInnerVarFirst */ --- 1857,1865 ---- static Datum ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = state->steps->nextstep; ! DEF_SOP(ExprEvalStep_var); ! int attnum = sop->attnum + 1; TupleTableSlot *slot = econtext->ecxt_scantuple; /* See comments in ExecJustInnerVarFirst */ *************** *** 1725,1743 **** ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull) static Datum ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = &state->steps[0]; ! *isnull = op->d.constval.isnull; ! return op->d.constval.value; } /* Evaluate inner Var and assign to appropriate column of result tuple */ static Datum ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = &state->steps[1]; ! int attnum = op->d.assign_var.attnum + 1; ! int resultnum = op->d.assign_var.resultnum; TupleTableSlot *inslot = econtext->ecxt_innertuple; TupleTableSlot *outslot = state->resultslot; --- 1870,1890 ---- static Datum ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = state->steps; ! DEF_SOP(ExprEvalStep_constval); ! *isnull = sop->isnull; ! return sop->value; } /* Evaluate inner Var and assign to appropriate column of result tuple */ static Datum ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = state->steps->nextstep; ! DEF_SOP(ExprEvalStep_assign_var); ! int attnum = sop->attnum + 1; ! int resultnum = sop->resultnum; TupleTableSlot *inslot = econtext->ecxt_innertuple; TupleTableSlot *outslot = state->resultslot; *************** *** 1758,1766 **** ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull) static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = &state->steps[1]; ! int attnum = op->d.assign_var.attnum + 1; ! int resultnum = op->d.assign_var.resultnum; TupleTableSlot *inslot = econtext->ecxt_outertuple; TupleTableSlot *outslot = state->resultslot; --- 1905,1914 ---- static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = state->steps->nextstep; ! DEF_SOP(ExprEvalStep_assign_var); ! int attnum = sop->attnum + 1; ! int resultnum = sop->resultnum; TupleTableSlot *inslot = econtext->ecxt_outertuple; TupleTableSlot *outslot = state->resultslot; *************** *** 1774,1782 **** ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull) static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = &state->steps[1]; ! int attnum = op->d.assign_var.attnum + 1; ! int resultnum = op->d.assign_var.resultnum; TupleTableSlot *inslot = econtext->ecxt_scantuple; TupleTableSlot *outslot = state->resultslot; --- 1922,1931 ---- static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull) { ! ExprEvalStep *op = state->steps->nextstep; ! DEF_SOP(ExprEvalStep_assign_var); ! int attnum = sop->attnum + 1; ! int resultnum = sop->resultnum; TupleTableSlot *inslot = econtext->ecxt_scantuple; TupleTableSlot *outslot = state->resultslot; *************** *** 1844,1854 **** ExecEvalStepOp(ExprState *state, ExprEvalStep *op) * ecxt_param_exec_vals array, and can be accessed by array index. */ void ! ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { ParamExecData *prm; ! prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]); if (unlikely(prm->execPlan != NULL)) { /* Parameter not evaluated yet, so go do it */ --- 1993,2004 ---- * ecxt_param_exec_vals array, and can be accessed by array index. */ void ! ExecEvalParamExec(ExprState *state, ExprEvalStep_param *sop, ! ExprContext *econtext) { ParamExecData *prm; ! prm = &(econtext->ecxt_param_exec_vals[sop->paramid]); if (unlikely(prm->execPlan != NULL)) { /* Parameter not evaluated yet, so go do it */ *************** *** 1856,1863 **** ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext) /* ExecSetParamPlan should have processed this param... */ Assert(prm->execPlan == NULL); } ! *op->resvalue = prm->value; ! *op->resnull = prm->isnull; } /* --- 2006,2013 ---- /* ExecSetParamPlan should have processed this param... */ Assert(prm->execPlan == NULL); } ! *sop->resvalue = prm->value; ! *sop->resnull = prm->isnull; } /* *************** *** 1866,1875 **** ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext) * PARAM_EXTERN parameters must be sought in ecxt_param_list_info. */ void ! ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { ParamListInfo paramInfo = econtext->ecxt_param_list_info; ! int paramId = op->d.param.paramid; if (likely(paramInfo && paramId > 0 && paramId <= paramInfo->numParams)) --- 2016,2026 ---- * PARAM_EXTERN parameters must be sought in ecxt_param_list_info. */ void ! ExecEvalParamExtern(ExprState *state, ExprEvalStep_param *sop, ! ExprContext *econtext) { ParamListInfo paramInfo = econtext->ecxt_param_list_info; ! int paramId = sop->paramid; if (likely(paramInfo && paramId > 0 && paramId <= paramInfo->numParams)) *************** *** 1883,1897 **** ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext) if (likely(OidIsValid(prm->ptype))) { /* safety check in case hook did something unexpected */ ! if (unlikely(prm->ptype != op->d.param.paramtype)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)", paramId, format_type_be(prm->ptype), ! format_type_be(op->d.param.paramtype)))); ! *op->resvalue = prm->value; ! *op->resnull = prm->isnull; return; } } --- 2034,2048 ---- if (likely(OidIsValid(prm->ptype))) { /* safety check in case hook did something unexpected */ ! if (unlikely(prm->ptype != sop->paramtype)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)", paramId, format_type_be(prm->ptype), ! format_type_be(sop->paramtype)))); ! *sop->resvalue = prm->value; ! *sop->resnull = prm->isnull; return; } } *************** *** 1905,1916 **** ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext) * Evaluate a SQLValueFunction expression. */ void ! ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op) { ! SQLValueFunction *svf = op->d.sqlvaluefunction.svf; FunctionCallInfoData fcinfo; ! *op->resnull = false; /* * Note: current_schema() can return NULL. current_user() etc currently --- 2056,2067 ---- * Evaluate a SQLValueFunction expression. */ void ! ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep_sqlvaluefunction *sop) { ! SQLValueFunction *svf = sop->svf; FunctionCallInfoData fcinfo; ! *sop->resnull = false; /* * Note: current_schema() can return NULL. current_user() etc currently *************** *** 1919,1963 **** ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op) switch (svf->op) { case SVFOP_CURRENT_DATE: ! *op->resvalue = DateADTGetDatum(GetSQLCurrentDate()); break; case SVFOP_CURRENT_TIME: case SVFOP_CURRENT_TIME_N: ! *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod)); break; case SVFOP_CURRENT_TIMESTAMP: case SVFOP_CURRENT_TIMESTAMP_N: ! *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod)); break; case SVFOP_LOCALTIME: case SVFOP_LOCALTIME_N: ! *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod)); break; case SVFOP_LOCALTIMESTAMP: case SVFOP_LOCALTIMESTAMP_N: ! *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod)); break; case SVFOP_CURRENT_ROLE: case SVFOP_CURRENT_USER: case SVFOP_USER: InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); ! *op->resvalue = current_user(&fcinfo); ! *op->resnull = fcinfo.isnull; break; case SVFOP_SESSION_USER: InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); ! *op->resvalue = session_user(&fcinfo); ! *op->resnull = fcinfo.isnull; break; case SVFOP_CURRENT_CATALOG: InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); ! *op->resvalue = current_database(&fcinfo); ! *op->resnull = fcinfo.isnull; break; case SVFOP_CURRENT_SCHEMA: InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); ! *op->resvalue = current_schema(&fcinfo); ! *op->resnull = fcinfo.isnull; break; } } --- 2070,2114 ---- switch (svf->op) { case SVFOP_CURRENT_DATE: ! *sop->resvalue = DateADTGetDatum(GetSQLCurrentDate()); break; case SVFOP_CURRENT_TIME: case SVFOP_CURRENT_TIME_N: ! *sop->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod)); break; case SVFOP_CURRENT_TIMESTAMP: case SVFOP_CURRENT_TIMESTAMP_N: ! *sop->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod)); break; case SVFOP_LOCALTIME: case SVFOP_LOCALTIME_N: ! *sop->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod)); break; case SVFOP_LOCALTIMESTAMP: case SVFOP_LOCALTIMESTAMP_N: ! *sop->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod)); break; case SVFOP_CURRENT_ROLE: case SVFOP_CURRENT_USER: case SVFOP_USER: InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); ! *sop->resvalue = current_user(&fcinfo); ! *sop->resnull = fcinfo.isnull; break; case SVFOP_SESSION_USER: InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); ! *sop->resvalue = session_user(&fcinfo); ! *sop->resnull = fcinfo.isnull; break; case SVFOP_CURRENT_CATALOG: InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); ! *sop->resvalue = current_database(&fcinfo); ! *sop->resnull = fcinfo.isnull; break; case SVFOP_CURRENT_SCHEMA: InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); ! *sop->resvalue = current_schema(&fcinfo); ! *sop->resnull = fcinfo.isnull; break; } } *************** *** 1972,1978 **** ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op) * table whose FDW doesn't handle it, and complain accordingly. */ void ! ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), --- 2123,2129 ---- * table whose FDW doesn't handle it, and complain accordingly. */ void ! ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *sop) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), *************** *** 1983,2035 **** ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op) * Evaluate NextValueExpr. */ void ! ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op) { ! int64 newval = nextval_internal(op->d.nextvalueexpr.seqid, false); ! switch (op->d.nextvalueexpr.seqtypid) { case INT2OID: ! *op->resvalue = Int16GetDatum((int16) newval); break; case INT4OID: ! *op->resvalue = Int32GetDatum((int32) newval); break; case INT8OID: ! *op->resvalue = Int64GetDatum((int64) newval); break; default: elog(ERROR, "unsupported sequence type %u", ! op->d.nextvalueexpr.seqtypid); } ! *op->resnull = false; } /* * Evaluate NullTest / IS NULL for rows. */ void ! ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { ! ExecEvalRowNullInt(state, op, econtext, true); } /* * Evaluate NullTest / IS NOT NULL for rows. */ void ! ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { ! ExecEvalRowNullInt(state, op, econtext, false); } /* Common code for IS [NOT] NULL on a row value */ static void ! ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op, ExprContext *econtext, bool checkisnull) { ! Datum value = *op->resvalue; ! bool isnull = *op->resnull; HeapTupleHeader tuple; Oid tupType; int32 tupTypmod; --- 2134,2188 ---- * Evaluate NextValueExpr. */ void ! ExecEvalNextValueExpr(ExprState *state, ExprEvalStep_nextvalueexpr *sop) { ! int64 newval = nextval_internal(sop->seqid, false); ! switch (sop->seqtypid) { case INT2OID: ! *sop->resvalue = Int16GetDatum((int16) newval); break; case INT4OID: ! *sop->resvalue = Int32GetDatum((int32) newval); break; case INT8OID: ! *sop->resvalue = Int64GetDatum((int64) newval); break; default: elog(ERROR, "unsupported sequence type %u", ! sop->seqtypid); } ! *sop->resnull = false; } /* * Evaluate NullTest / IS NULL for rows. */ void ! ExecEvalRowNull(ExprState *state, ExprEvalStep_nulltest_row *sop, ! ExprContext *econtext) { ! ExecEvalRowNullInt(state, sop, econtext, true); } /* * Evaluate NullTest / IS NOT NULL for rows. */ void ! ExecEvalRowNotNull(ExprState *state, ExprEvalStep_nulltest_row *sop, ! ExprContext *econtext) { ! ExecEvalRowNullInt(state, sop, econtext, false); } /* Common code for IS [NOT] NULL on a row value */ static void ! ExecEvalRowNullInt(ExprState *state, ExprEvalStep_nulltest_row *sop, ExprContext *econtext, bool checkisnull) { ! Datum value = *sop->resvalue; ! bool isnull = *sop->resnull; HeapTupleHeader tuple; Oid tupType; int32 tupTypmod; *************** *** 2037,2048 **** ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op, HeapTupleData tmptup; int att; ! *op->resnull = false; /* NULL row variables are treated just as NULL scalar columns */ if (isnull) { ! *op->resvalue = BoolGetDatum(checkisnull); return; } --- 2190,2201 ---- HeapTupleData tmptup; int att; ! *sop->resnull = false; /* NULL row variables are treated just as NULL scalar columns */ if (isnull) { ! *sop->resvalue = BoolGetDatum(checkisnull); return; } *************** *** 2069,2075 **** ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op, /* Lookup tupdesc if first time through or if type changes */ tupDesc = get_cached_rowtype(tupType, tupTypmod, ! &op->d.nulltest_row.argdesc, econtext); /* --- 2222,2228 ---- /* Lookup tupdesc if first time through or if type changes */ tupDesc = get_cached_rowtype(tupType, tupTypmod, ! &sop->argdesc, econtext); /* *************** *** 2088,2094 **** ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op, /* null field disproves IS NOT NULL */ if (!checkisnull) { ! *op->resvalue = BoolGetDatum(false); return; } } --- 2241,2247 ---- /* null field disproves IS NOT NULL */ if (!checkisnull) { ! *sop->resvalue = BoolGetDatum(false); return; } } *************** *** 2097,2140 **** ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op, /* non-null field disproves IS NULL */ if (checkisnull) { ! *op->resvalue = BoolGetDatum(false); return; } } } ! *op->resvalue = BoolGetDatum(true); } /* * Evaluate an ARRAY[] expression. * * The individual array elements (or subarrays) have already been evaluated ! * into op->d.arrayexpr.elemvalues[]/elemnulls[]. */ void ! ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op) { ArrayType *result; ! Oid element_type = op->d.arrayexpr.elemtype; ! int nelems = op->d.arrayexpr.nelems; int ndims = 0; int dims[MAXDIM]; int lbs[MAXDIM]; /* Set non-null as default */ ! *op->resnull = false; ! if (!op->d.arrayexpr.multidims) { /* Elements are presumably of scalar type */ ! Datum *dvalues = op->d.arrayexpr.elemvalues; ! bool *dnulls = op->d.arrayexpr.elemnulls; /* Shouldn't happen here, but if length is 0, return empty array */ if (nelems == 0) { ! *op->resvalue = PointerGetDatum(construct_empty_array(element_type)); return; } --- 2250,2293 ---- /* non-null field disproves IS NULL */ if (checkisnull) { ! *sop->resvalue = BoolGetDatum(false); return; } } } ! *sop->resvalue = BoolGetDatum(true); } /* * Evaluate an ARRAY[] expression. * * The individual array elements (or subarrays) have already been evaluated ! * into sop->elemvalues[]/elemnulls[]. */ void ! ExecEvalArrayExpr(ExprState *state, ExprEvalStep_arrayexpr *sop) { ArrayType *result; ! Oid element_type = sop->elemtype; ! int nelems = sop->nelems; int ndims = 0; int dims[MAXDIM]; int lbs[MAXDIM]; /* Set non-null as default */ ! *sop->resnull = false; ! if (!sop->multidims) { /* Elements are presumably of scalar type */ ! Datum *dvalues = sop->elemvalues; ! bool *dnulls = sop->elemnulls; /* Shouldn't happen here, but if length is 0, return empty array */ if (nelems == 0) { ! *sop->resvalue = PointerGetDatum(construct_empty_array(element_type)); return; } *************** *** 2146,2154 **** ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op) result = construct_md_array(dvalues, dnulls, ndims, dims, lbs, element_type, ! op->d.arrayexpr.elemlength, ! op->d.arrayexpr.elembyval, ! op->d.arrayexpr.elemalign); } else { --- 2299,2307 ---- result = construct_md_array(dvalues, dnulls, ndims, dims, lbs, element_type, ! sop->elemlength, ! sop->elembyval, ! sop->elemalign); } else { *************** *** 2185,2192 **** ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op) ArrayType *array; int this_ndims; ! arraydatum = op->d.arrayexpr.elemvalues[elemoff]; ! eisnull = op->d.arrayexpr.elemnulls[elemoff]; /* temporarily ignore null subarrays */ if (eisnull) --- 2338,2345 ---- ArrayType *array; int this_ndims; ! arraydatum = sop->elemvalues[elemoff]; ! eisnull = sop->elemnulls[elemoff]; /* temporarily ignore null subarrays */ if (eisnull) *************** *** 2268,2274 **** ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op) { if (ndims == 0) /* didn't find any nonempty array */ { ! *op->resvalue = PointerGetDatum(construct_empty_array(element_type)); return; } ereport(ERROR, --- 2421,2427 ---- { if (ndims == 0) /* didn't find any nonempty array */ { ! *sop->resvalue = PointerGetDatum(construct_empty_array(element_type)); return; } ereport(ERROR, *************** *** 2319,2325 **** ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op) } } ! *op->resvalue = PointerGetDatum(result); } /* --- 2472,2478 ---- } } ! *sop->resvalue = PointerGetDatum(result); } /* *************** *** 2328,2344 **** ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op) * Source array is in step's result variable. */ void ! ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op) { ! ArrayCoerceExpr *acoerce = op->d.arraycoerce.coerceexpr; Datum arraydatum; FunctionCallInfoData locfcinfo; /* NULL array -> NULL result */ ! if (*op->resnull) return; ! arraydatum = *op->resvalue; /* * If it's binary-compatible, modify the element type in the array header, --- 2481,2497 ---- * Source array is in step's result variable. */ void ! ExecEvalArrayCoerce(ExprState *state, ExprEvalStep_arraycoerce *sop) { ! ArrayCoerceExpr *acoerce = sop->coerceexpr; Datum arraydatum; FunctionCallInfoData locfcinfo; /* NULL array -> NULL result */ ! if (*sop->resnull) return; ! arraydatum = *sop->resvalue; /* * If it's binary-compatible, modify the element type in the array header, *************** *** 2349,2356 **** ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op) /* Detoast input array if necessary, and copy in any case */ ArrayType *array = DatumGetArrayTypePCopy(arraydatum); ! ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype; ! *op->resvalue = PointerGetDatum(array); return; } --- 2502,2509 ---- /* Detoast input array if necessary, and copy in any case */ ArrayType *array = DatumGetArrayTypePCopy(arraydatum); ! ARR_ELEMTYPE(array) = sop->resultelemtype; ! *sop->resvalue = PointerGetDatum(array); return; } *************** *** 2362,2368 **** ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op) * * Note: coercion functions are assumed to not use collation. */ ! InitFunctionCallInfoData(locfcinfo, op->d.arraycoerce.elemfunc, 3, InvalidOid, NULL, NULL); locfcinfo.arg[0] = arraydatum; locfcinfo.arg[1] = Int32GetDatum(acoerce->resulttypmod); --- 2515,2521 ---- * * Note: coercion functions are assumed to not use collation. */ ! InitFunctionCallInfoData(locfcinfo, sop->elemfunc, 3, InvalidOid, NULL, NULL); locfcinfo.arg[0] = arraydatum; locfcinfo.arg[1] = Int32GetDatum(acoerce->resulttypmod); *************** *** 2371,2413 **** ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op) locfcinfo.argnull[1] = false; locfcinfo.argnull[2] = false; ! *op->resvalue = array_map(&locfcinfo, op->d.arraycoerce.resultelemtype, ! op->d.arraycoerce.amstate); } /* * Evaluate a ROW() expression. * * The individual columns have already been evaluated into ! * op->d.row.elemvalues[]/elemnulls[]. */ void ! ExecEvalRow(ExprState *state, ExprEvalStep *op) { HeapTuple tuple; /* build tuple from evaluated field values */ ! tuple = heap_form_tuple(op->d.row.tupdesc, ! op->d.row.elemvalues, ! op->d.row.elemnulls); ! *op->resvalue = HeapTupleGetDatum(tuple); ! *op->resnull = false; } /* * Evaluate GREATEST() or LEAST() expression (note this is *not* MIN()/MAX()). * * All of the to-be-compared expressions have already been evaluated into ! * op->d.minmax.values[]/nulls[]. */ void ! ExecEvalMinMax(ExprState *state, ExprEvalStep *op) { ! Datum *values = op->d.minmax.values; ! bool *nulls = op->d.minmax.nulls; ! FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data; ! MinMaxOp operator = op->d.minmax.op; int off; /* set at initialization */ --- 2524,2565 ---- locfcinfo.argnull[1] = false; locfcinfo.argnull[2] = false; ! *sop->resvalue = array_map(&locfcinfo, sop->resultelemtype, sop->amstate); } /* * Evaluate a ROW() expression. * * The individual columns have already been evaluated into ! * sop->elemvalues[]/elemnulls[]. */ void ! ExecEvalRow(ExprState *state, ExprEvalStep_row *sop) { HeapTuple tuple; /* build tuple from evaluated field values */ ! tuple = heap_form_tuple(sop->tupdesc, ! sop->elemvalues, ! sop->elemnulls); ! *sop->resvalue = HeapTupleGetDatum(tuple); ! *sop->resnull = false; } /* * Evaluate GREATEST() or LEAST() expression (note this is *not* MIN()/MAX()). * * All of the to-be-compared expressions have already been evaluated into ! * sop->values[]/nulls[]. */ void ! ExecEvalMinMax(ExprState *state, ExprEvalStep_minmax *sop) { ! Datum *values = sop->values; ! bool *nulls = sop->nulls; ! FunctionCallInfo fcinfo = sop->fcinfo_data; ! MinMaxOp operator = sop->op; int off; /* set at initialization */ *************** *** 2415,2440 **** ExecEvalMinMax(ExprState *state, ExprEvalStep *op) Assert(fcinfo->argnull[1] == false); /* default to null result */ ! *op->resnull = true; ! for (off = 0; off < op->d.minmax.nelems; off++) { /* ignore NULL inputs */ if (nulls[off]) continue; ! if (*op->resnull) { /* first nonnull input, adopt value */ ! *op->resvalue = values[off]; ! *op->resnull = false; } else { int cmpresult; /* apply comparison function */ ! fcinfo->arg[0] = *op->resvalue; fcinfo->arg[1] = values[off]; fcinfo->isnull = false; --- 2567,2592 ---- Assert(fcinfo->argnull[1] == false); /* default to null result */ ! *sop->resnull = true; ! for (off = 0; off < sop->nelems; off++) { /* ignore NULL inputs */ if (nulls[off]) continue; ! if (*sop->resnull) { /* first nonnull input, adopt value */ ! *sop->resvalue = values[off]; ! *sop->resnull = false; } else { int cmpresult; /* apply comparison function */ ! fcinfo->arg[0] = *sop->resvalue; fcinfo->arg[1] = values[off]; fcinfo->isnull = false; *************** *** 2443,2451 **** ExecEvalMinMax(ExprState *state, ExprEvalStep *op) continue; if (cmpresult > 0 && operator == IS_LEAST) ! *op->resvalue = values[off]; else if (cmpresult < 0 && operator == IS_GREATEST) ! *op->resvalue = values[off]; } } } --- 2595,2603 ---- continue; if (cmpresult > 0 && operator == IS_LEAST) ! *sop->resvalue = values[off]; else if (cmpresult < 0 && operator == IS_GREATEST) ! *sop->resvalue = values[off]; } } } *************** *** 2456,2464 **** ExecEvalMinMax(ExprState *state, ExprEvalStep *op) * Source record is in step's result variable. */ void ! ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { ! AttrNumber fieldnum = op->d.fieldselect.fieldnum; Datum tupDatum; HeapTupleHeader tuple; Oid tupType; --- 2608,2617 ---- * Source record is in step's result variable. */ void ! ExecEvalFieldSelect(ExprState *state, ExprEvalStep_fieldselect *sop, ! ExprContext *econtext) { ! AttrNumber fieldnum = sop->fieldnum; Datum tupDatum; HeapTupleHeader tuple; Oid tupType; *************** *** 2468,2478 **** ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext) HeapTupleData tmptup; /* NULL record -> NULL result */ ! if (*op->resnull) return; /* Get the composite datum and extract its type fields */ ! tupDatum = *op->resvalue; tuple = DatumGetHeapTupleHeader(tupDatum); tupType = HeapTupleHeaderGetTypeId(tuple); --- 2621,2631 ---- HeapTupleData tmptup; /* NULL record -> NULL result */ ! if (*sop->resnull) return; /* Get the composite datum and extract its type fields */ ! tupDatum = *sop->resvalue; tuple = DatumGetHeapTupleHeader(tupDatum); tupType = HeapTupleHeaderGetTypeId(tuple); *************** *** 2480,2486 **** ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext) /* Lookup tupdesc if first time through or if type changes */ tupDesc = get_cached_rowtype(tupType, tupTypmod, ! &op->d.fieldselect.argdesc, econtext); /* --- 2633,2639 ---- /* Lookup tupdesc if first time through or if type changes */ tupDesc = get_cached_rowtype(tupType, tupTypmod, ! &sop->argdesc, econtext); /* *************** *** 2499,2527 **** ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext) /* Check for dropped column, and force a NULL result if so */ if (attr->attisdropped) { ! *op->resnull = true; return; } /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */ /* As in CheckVarSlotCompatibility, we should but can't check typmod */ ! if (op->d.fieldselect.resulttype != attr->atttypid) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("attribute %d has wrong type", fieldnum), errdetail("Table has type %s, but query expects %s.", format_type_be(attr->atttypid), ! format_type_be(op->d.fieldselect.resulttype)))); /* heap_getattr needs a HeapTuple not a bare HeapTupleHeader */ tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); tmptup.t_data = tuple; /* extract the field */ ! *op->resvalue = heap_getattr(&tmptup, fieldnum, tupDesc, ! op->resnull); } /* --- 2652,2680 ---- /* Check for dropped column, and force a NULL result if so */ if (attr->attisdropped) { ! *sop->resnull = true; return; } /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */ /* As in CheckVarSlotCompatibility, we should but can't check typmod */ ! if (sop->resulttype != attr->atttypid) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("attribute %d has wrong type", fieldnum), errdetail("Table has type %s, but query expects %s.", format_type_be(attr->atttypid), ! format_type_be(sop->resulttype)))); /* heap_getattr needs a HeapTuple not a bare HeapTupleHeader */ tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); tmptup.t_data = tuple; /* extract the field */ ! *sop->resvalue = heap_getattr(&tmptup, fieldnum, tupDesc, ! sop->resnull); } /* *************** *** 2534,2557 **** ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext) * Source record is in step's result variable. */ void ! ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { TupleDesc tupDesc; /* Lookup tupdesc if first time through or after rescan */ ! tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1, ! op->d.fieldstore.argdesc, econtext); /* Check that current tupdesc doesn't have more fields than we allocated */ ! if (unlikely(tupDesc->natts > op->d.fieldstore.ncolumns)) elog(ERROR, "too many columns in composite type %u", ! op->d.fieldstore.fstore->resulttype); ! if (*op->resnull) { /* Convert null input tuple into an all-nulls row */ ! memset(op->d.fieldstore.nulls, true, ! op->d.fieldstore.ncolumns * sizeof(bool)); } else { --- 2687,2711 ---- * Source record is in step's result variable. */ void ! ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep_fieldstore *sop, ! ExprContext *econtext) { TupleDesc tupDesc; /* Lookup tupdesc if first time through or after rescan */ ! tupDesc = get_cached_rowtype(sop->fstore->resulttype, -1, ! sop->argdesc, econtext); /* Check that current tupdesc doesn't have more fields than we allocated */ ! if (unlikely(tupDesc->natts > sop->ncolumns)) elog(ERROR, "too many columns in composite type %u", ! sop->fstore->resulttype); ! if (*sop->resnull) { /* Convert null input tuple into an all-nulls row */ ! memset(sop->nulls, true, ! sop->ncolumns * sizeof(bool)); } else { *************** *** 2559,2565 **** ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econte * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. We * set all the fields in the struct just in case. */ ! Datum tupDatum = *op->resvalue; HeapTupleHeader tuphdr; HeapTupleData tmptup; --- 2713,2719 ---- * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. We * set all the fields in the struct just in case. */ ! Datum tupDatum = *sop->resvalue; HeapTupleHeader tuphdr; HeapTupleData tmptup; *************** *** 2570,2577 **** ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econte tmptup.t_data = tuphdr; heap_deform_tuple(&tmptup, tupDesc, ! op->d.fieldstore.values, ! op->d.fieldstore.nulls); } } --- 2724,2731 ---- tmptup.t_data = tuphdr; heap_deform_tuple(&tmptup, tupDesc, ! sop->values, ! sop->nulls); } } *************** *** 2580,2596 **** ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econte * FieldStore expression has been evaluated. */ void ! ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { HeapTuple tuple; /* argdesc should already be valid from the DeForm step */ ! tuple = heap_form_tuple(*op->d.fieldstore.argdesc, ! op->d.fieldstore.values, ! op->d.fieldstore.nulls); ! *op->resvalue = HeapTupleGetDatum(tuple); ! *op->resnull = false; } /* --- 2734,2751 ---- * FieldStore expression has been evaluated. */ void ! ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep_fieldstore *sop, ! ExprContext *econtext) { HeapTuple tuple; /* argdesc should already be valid from the DeForm step */ ! tuple = heap_form_tuple(*sop->argdesc, ! sop->values, ! sop->nulls); ! *sop->resvalue = HeapTupleGetDatum(tuple); ! *sop->resnull = false; } /* *************** *** 2605,2613 **** ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext * lowerindex[] for use later. */ bool ! ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op) { ! ArrayRefState *arefstate = op->d.arrayref_subscript.state; int *indexes; int off; --- 2760,2769 ---- * lowerindex[] for use later. */ bool ! ExecEvalArrayRefSubscript(ExprState *state, ! ExprEvalStep_arrayref_subscript *sop) { ! ArrayRefState *arefstate = sop->state; int *indexes; int off; *************** *** 2617,2633 **** ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op) if (arefstate->isassignment) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), ! errmsg("array subscript in assignment must not be null"))); ! *op->resnull = true; return false; } /* Convert datum to int, save in appropriate place */ ! if (op->d.arrayref_subscript.isupper) indexes = arefstate->upperindex; else indexes = arefstate->lowerindex; ! off = op->d.arrayref_subscript.off; indexes[off] = DatumGetInt32(arefstate->subscriptvalue); --- 2773,2789 ---- if (arefstate->isassignment) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), ! errmsg("array subscript in assignment must not be null"))); ! *sop->resnull = true; return false; } /* Convert datum to int, save in appropriate place */ ! if (sop->isupper) indexes = arefstate->upperindex; else indexes = arefstate->lowerindex; ! off = sop->off; indexes[off] = DatumGetInt32(arefstate->subscriptvalue); *************** *** 2640,2677 **** ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op) * Source array is in step's result variable. */ void ! ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep *op) { ! ArrayRefState *arefstate = op->d.arrayref.state; /* Should not get here if source array (or any subscript) is null */ ! Assert(!(*op->resnull)); if (arefstate->numlower == 0) { /* Scalar case */ ! *op->resvalue = array_get_element(*op->resvalue, ! arefstate->numupper, ! arefstate->upperindex, ! arefstate->refattrlength, ! arefstate->refelemlength, ! arefstate->refelembyval, ! arefstate->refelemalign, ! op->resnull); } else { /* Slice case */ ! *op->resvalue = array_get_slice(*op->resvalue, ! arefstate->numupper, ! arefstate->upperindex, ! arefstate->lowerindex, ! arefstate->upperprovided, ! arefstate->lowerprovided, ! arefstate->refattrlength, ! arefstate->refelemlength, ! arefstate->refelembyval, ! arefstate->refelemalign); } } --- 2796,2833 ---- * Source array is in step's result variable. */ void ! ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep_arrayref *sop) { ! ArrayRefState *arefstate = sop->state; /* Should not get here if source array (or any subscript) is null */ ! Assert(!(*sop->resnull)); if (arefstate->numlower == 0) { /* Scalar case */ ! *sop->resvalue = array_get_element(*sop->resvalue, ! arefstate->numupper, ! arefstate->upperindex, ! arefstate->refattrlength, ! arefstate->refelemlength, ! arefstate->refelembyval, ! arefstate->refelemalign, ! sop->resnull); } else { /* Slice case */ ! *sop->resvalue = array_get_slice(*sop->resvalue, ! arefstate->numupper, ! arefstate->upperindex, ! arefstate->lowerindex, ! arefstate->upperprovided, ! arefstate->lowerprovided, ! arefstate->refattrlength, ! arefstate->refelemlength, ! arefstate->refelembyval, ! arefstate->refelemalign); } } *************** *** 2682,2692 **** ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep *op) * ArrayRefState's prevvalue/prevnull fields. */ void ! ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op) { ! ArrayRefState *arefstate = op->d.arrayref.state; ! if (*op->resnull) { /* whole array is null, so any element or slice is too */ arefstate->prevvalue = (Datum) 0; --- 2838,2848 ---- * ArrayRefState's prevvalue/prevnull fields. */ void ! ExecEvalArrayRefOld(ExprState *state, ExprEvalStep_arrayref *sop) { ! ArrayRefState *arefstate = sop->state; ! if (*sop->resnull) { /* whole array is null, so any element or slice is too */ arefstate->prevvalue = (Datum) 0; *************** *** 2695,2701 **** ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op) else if (arefstate->numlower == 0) { /* Scalar case */ ! arefstate->prevvalue = array_get_element(*op->resvalue, arefstate->numupper, arefstate->upperindex, arefstate->refattrlength, --- 2851,2857 ---- else if (arefstate->numlower == 0) { /* Scalar case */ ! arefstate->prevvalue = array_get_element(*sop->resvalue, arefstate->numupper, arefstate->upperindex, arefstate->refattrlength, *************** *** 2708,2714 **** ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op) { /* Slice case */ /* this is currently unreachable */ ! arefstate->prevvalue = array_get_slice(*op->resvalue, arefstate->numupper, arefstate->upperindex, arefstate->lowerindex, --- 2864,2870 ---- { /* Slice case */ /* this is currently unreachable */ ! arefstate->prevvalue = array_get_slice(*sop->resvalue, arefstate->numupper, arefstate->upperindex, arefstate->lowerindex, *************** *** 2729,2737 **** ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op) * ArrayRefState's replacevalue/replacenull. */ void ! ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op) { ! ArrayRefState *arefstate = op->d.arrayref.state; /* * For an assignment to a fixed-length array type, both the original array --- 2885,2893 ---- * ArrayRefState's replacevalue/replacenull. */ void ! ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep_arrayref *sop) { ! ArrayRefState *arefstate = sop->state; /* * For an assignment to a fixed-length array type, both the original array *************** *** 2740,2746 **** ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op) */ if (arefstate->refattrlength > 0) /* fixed-length array? */ { ! if (*op->resnull || arefstate->replacenull) return; } --- 2896,2902 ---- */ if (arefstate->refattrlength > 0) /* fixed-length array? */ { ! if (*sop->resnull || arefstate->replacenull) return; } *************** *** 2750,2789 **** ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op) * element will result in a singleton array value. It does not matter * whether the new element is NULL. */ ! if (*op->resnull) { ! *op->resvalue = PointerGetDatum(construct_empty_array(arefstate->refelemtype)); ! *op->resnull = false; } if (arefstate->numlower == 0) { /* Scalar case */ ! *op->resvalue = array_set_element(*op->resvalue, ! arefstate->numupper, ! arefstate->upperindex, ! arefstate->replacevalue, ! arefstate->replacenull, ! arefstate->refattrlength, ! arefstate->refelemlength, ! arefstate->refelembyval, ! arefstate->refelemalign); } else { /* Slice case */ ! *op->resvalue = array_set_slice(*op->resvalue, ! arefstate->numupper, ! arefstate->upperindex, ! arefstate->lowerindex, ! arefstate->upperprovided, ! arefstate->lowerprovided, ! arefstate->replacevalue, ! arefstate->replacenull, ! arefstate->refattrlength, ! arefstate->refelemlength, ! arefstate->refelembyval, ! arefstate->refelemalign); } } --- 2906,2945 ---- * element will result in a singleton array value. It does not matter * whether the new element is NULL. */ ! if (*sop->resnull) { ! *sop->resvalue = PointerGetDatum(construct_empty_array(arefstate->refelemtype)); ! *sop->resnull = false; } if (arefstate->numlower == 0) { /* Scalar case */ ! *sop->resvalue = array_set_element(*sop->resvalue, ! arefstate->numupper, ! arefstate->upperindex, ! arefstate->replacevalue, ! arefstate->replacenull, ! arefstate->refattrlength, ! arefstate->refelemlength, ! arefstate->refelembyval, ! arefstate->refelemalign); } else { /* Slice case */ ! *sop->resvalue = array_set_slice(*sop->resvalue, ! arefstate->numupper, ! arefstate->upperindex, ! arefstate->lowerindex, ! arefstate->upperprovided, ! arefstate->lowerprovided, ! arefstate->replacevalue, ! arefstate->replacenull, ! arefstate->refattrlength, ! arefstate->refelemlength, ! arefstate->refelembyval, ! arefstate->refelemalign); } } *************** *** 2794,2802 **** ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op) * Source record is in step's result variable. */ void ! ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { ! ConvertRowtypeExpr *convert = op->d.convert_rowtype.convert; HeapTuple result; Datum tupDatum; HeapTupleHeader tuple; --- 2950,2959 ---- * Source record is in step's result variable. */ void ! ExecEvalConvertRowtype(ExprState *state, ExprEvalStep_convert_rowtype *sop, ! ExprContext *econtext) { ! ConvertRowtypeExpr *convert = sop->convert; HeapTuple result; Datum tupDatum; HeapTupleHeader tuple; *************** *** 2805,2834 **** ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext outdesc; /* NULL in -> NULL out */ ! if (*op->resnull) return; ! tupDatum = *op->resvalue; tuple = DatumGetHeapTupleHeader(tupDatum); /* Lookup tupdescs if first time through or after rescan */ ! if (op->d.convert_rowtype.indesc == NULL) { get_cached_rowtype(exprType((Node *) convert->arg), -1, ! &op->d.convert_rowtype.indesc, econtext); ! op->d.convert_rowtype.initialized = false; } ! if (op->d.convert_rowtype.outdesc == NULL) { get_cached_rowtype(convert->resulttype, -1, ! &op->d.convert_rowtype.outdesc, econtext); ! op->d.convert_rowtype.initialized = false; } ! indesc = op->d.convert_rowtype.indesc; ! outdesc = op->d.convert_rowtype.outdesc; /* * We used to be able to assert that incoming tuples are marked with --- 2962,2991 ---- outdesc; /* NULL in -> NULL out */ ! if (*sop->resnull) return; ! tupDatum = *sop->resvalue; tuple = DatumGetHeapTupleHeader(tupDatum); /* Lookup tupdescs if first time through or after rescan */ ! if (sop->indesc == NULL) { get_cached_rowtype(exprType((Node *) convert->arg), -1, ! &sop->indesc, econtext); ! sop->initialized = false; } ! if (sop->outdesc == NULL) { get_cached_rowtype(convert->resulttype, -1, ! &sop->outdesc, econtext); ! sop->initialized = false; } ! indesc = sop->indesc; ! outdesc = sop->outdesc; /* * We used to be able to assert that incoming tuples are marked with *************** *** 2840,2846 **** ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext HeapTupleHeaderGetTypeId(tuple) == RECORDOID); /* if first time through, initialize conversion map */ ! if (!op->d.convert_rowtype.initialized) { MemoryContext old_cxt; --- 2997,3003 ---- HeapTupleHeaderGetTypeId(tuple) == RECORDOID); /* if first time through, initialize conversion map */ ! if (!sop->initialized) { MemoryContext old_cxt; *************** *** 2848,2857 **** ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); /* prepare map from old to new attribute numbers */ ! op->d.convert_rowtype.map = convert_tuples_by_name(indesc, outdesc, gettext_noop("could not convert row type")); ! op->d.convert_rowtype.initialized = true; MemoryContextSwitchTo(old_cxt); } --- 3005,3014 ---- old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory); /* prepare map from old to new attribute numbers */ ! sop->map = convert_tuples_by_name(indesc, outdesc, gettext_noop("could not convert row type")); ! sop->initialized = true; MemoryContextSwitchTo(old_cxt); } *************** *** 2860,2871 **** ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); tmptup.t_data = tuple; ! if (op->d.convert_rowtype.map != NULL) { /* Full conversion with attribute rearrangement needed */ ! result = do_convert_tuple(&tmptup, op->d.convert_rowtype.map); /* Result already has appropriate composite-datum header fields */ ! *op->resvalue = HeapTupleGetDatum(result); } else { --- 3017,3028 ---- tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); tmptup.t_data = tuple; ! if (sop->map != NULL) { /* Full conversion with attribute rearrangement needed */ ! result = do_convert_tuple(&tmptup, sop->map); /* Result already has appropriate composite-datum header fields */ ! *sop->resvalue = HeapTupleGetDatum(result); } else { *************** *** 2879,2885 **** ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext * datum, so it shouldn't contain any. So heap_copy_tuple_as_datum() * is overkill here, but its check for external fields is cheap. */ ! *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc); } } --- 3036,3042 ---- * datum, so it shouldn't contain any. So heap_copy_tuple_as_datum() * is overkill here, but its check for external fields is cheap. */ ! *sop->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc); } } *************** *** 2894,2904 **** ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext * we short-circuit as soon as the result is known. */ void ! ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) { ! FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data; ! bool useOr = op->d.scalararrayop.useOr; ! bool strictfunc = op->d.scalararrayop.finfo->fn_strict; ArrayType *arr; int nitems; Datum result; --- 3051,3061 ---- * we short-circuit as soon as the result is known. */ void ! ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep_scalararrayop *sop) { ! FunctionCallInfo fcinfo = sop->fcinfo_data; ! bool useOr = sop->useOr; ! bool strictfunc = sop->finfo->fn_strict; ArrayType *arr; int nitems; Datum result; *************** *** 2915,2925 **** ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) * If the array is NULL then we return NULL --- it's not very meaningful * to do anything else, even if the operator isn't strict. */ ! if (*op->resnull) return; /* Else okay to fetch and detoast the array */ ! arr = DatumGetArrayTypeP(*op->resvalue); /* * If the array is empty, we return either FALSE or TRUE per the useOr --- 3072,3082 ---- * If the array is NULL then we return NULL --- it's not very meaningful * to do anything else, even if the operator isn't strict. */ ! if (*sop->resnull) return; /* Else okay to fetch and detoast the array */ ! arr = DatumGetArrayTypeP(*sop->resvalue); /* * If the array is empty, we return either FALSE or TRUE per the useOr *************** *** 2930,2937 **** ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr)); if (nitems <= 0) { ! *op->resvalue = BoolGetDatum(!useOr); ! *op->resnull = false; return; } --- 3087,3094 ---- nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr)); if (nitems <= 0) { ! *sop->resvalue = BoolGetDatum(!useOr); ! *sop->resnull = false; return; } *************** *** 2941,2947 **** ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) */ if (fcinfo->argnull[0] && strictfunc) { ! *op->resnull = true; return; } --- 3098,3104 ---- */ if (fcinfo->argnull[0] && strictfunc) { ! *sop->resnull = true; return; } *************** *** 2949,2966 **** ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) * We arrange to look up info about the element type only once per series * of calls, assuming the element type doesn't change underneath us. */ ! if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr)) { get_typlenbyvalalign(ARR_ELEMTYPE(arr), ! &op->d.scalararrayop.typlen, ! &op->d.scalararrayop.typbyval, ! &op->d.scalararrayop.typalign); ! op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr); } ! typlen = op->d.scalararrayop.typlen; ! typbyval = op->d.scalararrayop.typbyval; ! typalign = op->d.scalararrayop.typalign; /* Initialize result appropriately depending on useOr */ result = BoolGetDatum(!useOr); --- 3106,3123 ---- * We arrange to look up info about the element type only once per series * of calls, assuming the element type doesn't change underneath us. */ ! if (sop->element_type != ARR_ELEMTYPE(arr)) { get_typlenbyvalalign(ARR_ELEMTYPE(arr), ! &sop->typlen, ! &sop->typbyval, ! &sop->typalign); ! sop->element_type = ARR_ELEMTYPE(arr); } ! typlen = sop->typlen; ! typbyval = sop->typbyval; ! typalign = sop->typalign; /* Initialize result appropriately depending on useOr */ result = BoolGetDatum(!useOr); *************** *** 3000,3006 **** ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) else { fcinfo->isnull = false; ! thisresult = (op->d.scalararrayop.fn_addr) (fcinfo); } /* Combine results per OR or AND semantics */ --- 3157,3163 ---- else { fcinfo->isnull = false; ! thisresult = (sop->fn_addr) (fcinfo); } /* Combine results per OR or AND semantics */ *************** *** 3037,3075 **** ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op) } } ! *op->resvalue = result; ! *op->resnull = resultnull; } /* * Evaluate a NOT NULL domain constraint. */ void ! ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op) { ! if (*op->resnull) ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION), errmsg("domain %s does not allow null values", ! format_type_be(op->d.domaincheck.resulttype)), ! errdatatype(op->d.domaincheck.resulttype))); } /* * Evaluate a CHECK domain constraint. */ void ! ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op) { ! if (!*op->d.domaincheck.checknull && ! !DatumGetBool(*op->d.domaincheck.checkvalue)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), ! errmsg("value for domain %s violates check constraint \"%s\"", ! format_type_be(op->d.domaincheck.resulttype), ! op->d.domaincheck.constraintname), ! errdomainconstraint(op->d.domaincheck.resulttype, ! op->d.domaincheck.constraintname))); } /* --- 3194,3232 ---- } } ! *sop->resvalue = result; ! *sop->resnull = resultnull; } /* * Evaluate a NOT NULL domain constraint. */ void ! ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep_domaincheck *sop) { ! if (*sop->resnull) ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION), errmsg("domain %s does not allow null values", ! format_type_be(sop->resulttype)), ! errdatatype(sop->resulttype))); } /* * Evaluate a CHECK domain constraint. */ void ! ExecEvalConstraintCheck(ExprState *state, ExprEvalStep_domaincheck *sop) { ! if (!*sop->checknull && ! !DatumGetBool(*sop->checkvalue)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), ! errmsg("value for domain %s violates check constraint \"%s\"", ! format_type_be(sop->resulttype), ! sop->constraintname), ! errdomainconstraint(sop->resulttype, ! sop->constraintname))); } /* *************** *** 3079,3099 **** ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op) * and/or argvalue/argnull arrays. */ void ! ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) { ! XmlExpr *xexpr = op->d.xmlexpr.xexpr; Datum value; int i; ! *op->resnull = true; /* until we get a result */ ! *op->resvalue = (Datum) 0; switch (xexpr->op) { case IS_XMLCONCAT: { ! Datum *argvalue = op->d.xmlexpr.argvalue; ! bool *argnull = op->d.xmlexpr.argnull; List *values = NIL; for (i = 0; i < list_length(xexpr->args); i++) --- 3236,3256 ---- * and/or argvalue/argnull arrays. */ void ! ExecEvalXmlExpr(ExprState *state, ExprEvalStep_xmlexpr *sop) { ! XmlExpr *xexpr = sop->xexpr; Datum value; int i; ! *sop->resnull = true; /* until we get a result */ ! *sop->resvalue = (Datum) 0; switch (xexpr->op) { case IS_XMLCONCAT: { ! Datum *argvalue = sop->argvalue; ! bool *argnull = sop->argnull; List *values = NIL; for (i = 0; i < list_length(xexpr->args); i++) *************** *** 3104,3119 **** ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) if (values != NIL) { ! *op->resvalue = PointerGetDatum(xmlconcat(values)); ! *op->resnull = false; } } break; case IS_XMLFOREST: { ! Datum *argvalue = op->d.xmlexpr.named_argvalue; ! bool *argnull = op->d.xmlexpr.named_argnull; StringInfoData buf; ListCell *lc; ListCell *lc2; --- 3261,3276 ---- if (values != NIL) { ! *sop->resvalue = PointerGetDatum(xmlconcat(values)); ! *sop->resnull = false; } } break; case IS_XMLFOREST: { ! Datum *argvalue = sop->named_argvalue; ! bool *argnull = sop->named_argnull; StringInfoData buf; ListCell *lc; ListCell *lc2; *************** *** 3134,3150 **** ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) map_sql_value_to_xml_value(value, exprType((Node *) e), true), argname); ! *op->resnull = false; } i++; } ! if (!*op->resnull) { text *result; result = cstring_to_text_with_len(buf.data, buf.len); ! *op->resvalue = PointerGetDatum(result); } pfree(buf.data); --- 3291,3307 ---- map_sql_value_to_xml_value(value, exprType((Node *) e), true), argname); ! *sop->resnull = false; } i++; } ! if (!*sop->resnull) { text *result; result = cstring_to_text_with_len(buf.data, buf.len); ! *sop->resvalue = PointerGetDatum(result); } pfree(buf.data); *************** *** 3152,3169 **** ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) break; case IS_XMLELEMENT: ! *op->resvalue = PointerGetDatum(xmlelement(xexpr, ! op->d.xmlexpr.named_argvalue, ! op->d.xmlexpr.named_argnull, ! op->d.xmlexpr.argvalue, ! op->d.xmlexpr.argnull)); ! *op->resnull = false; break; case IS_XMLPARSE: { ! Datum *argvalue = op->d.xmlexpr.argvalue; ! bool *argnull = op->d.xmlexpr.argnull; text *data; bool preserve_whitespace; --- 3309,3326 ---- break; case IS_XMLELEMENT: ! *sop->resvalue = PointerGetDatum(xmlelement(xexpr, ! sop->named_argvalue, ! sop->named_argnull, ! sop->argvalue, ! sop->argnull)); ! *sop->resnull = false; break; case IS_XMLPARSE: { ! Datum *argvalue = sop->argvalue; ! bool *argnull = sop->argnull; text *data; bool preserve_whitespace; *************** *** 3180,3189 **** ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) value = argvalue[1]; preserve_whitespace = DatumGetBool(value); ! *op->resvalue = PointerGetDatum(xmlparse(data, ! xexpr->xmloption, ! preserve_whitespace)); ! *op->resnull = false; } break; --- 3337,3346 ---- value = argvalue[1]; preserve_whitespace = DatumGetBool(value); ! *sop->resvalue = PointerGetDatum(xmlparse(data, ! xexpr->xmloption, ! preserve_whitespace)); ! *sop->resnull = false; } break; *************** *** 3197,3207 **** ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) if (xexpr->args) { ! isnull = op->d.xmlexpr.argnull[0]; if (isnull) arg = NULL; else ! arg = DatumGetTextPP(op->d.xmlexpr.argvalue[0]); } else { --- 3354,3364 ---- if (xexpr->args) { ! isnull = sop->argnull[0]; if (isnull) arg = NULL; else ! arg = DatumGetTextPP(sop->argvalue[0]); } else { *************** *** 3209,3225 **** ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) isnull = false; } ! *op->resvalue = PointerGetDatum(xmlpi(xexpr->name, ! arg, ! isnull, ! op->resnull)); } break; case IS_XMLROOT: { ! Datum *argvalue = op->d.xmlexpr.argvalue; ! bool *argnull = op->d.xmlexpr.argnull; xmltype *data; text *version; int standalone; --- 3366,3382 ---- isnull = false; } ! *sop->resvalue = PointerGetDatum(xmlpi(xexpr->name, ! arg, ! isnull, ! sop->resnull)); } break; case IS_XMLROOT: { ! Datum *argvalue = sop->argvalue; ! bool *argnull = sop->argnull; xmltype *data; text *version; int standalone; *************** *** 3239,3255 **** ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) Assert(!argnull[2]); /* always present */ standalone = DatumGetInt32(argvalue[2]); ! *op->resvalue = PointerGetDatum(xmlroot(data, version, standalone)); ! *op->resnull = false; } break; case IS_XMLSERIALIZE: { ! Datum *argvalue = op->d.xmlexpr.argvalue; ! bool *argnull = op->d.xmlexpr.argnull; /* argument type is known to be xml */ Assert(list_length(xexpr->args) == 1); --- 3396,3412 ---- Assert(!argnull[2]); /* always present */ standalone = DatumGetInt32(argvalue[2]); ! *sop->resvalue = PointerGetDatum(xmlroot(data, version, standalone)); ! *sop->resnull = false; } break; case IS_XMLSERIALIZE: { ! Datum *argvalue = sop->argvalue; ! bool *argnull = sop->argnull; /* argument type is known to be xml */ Assert(list_length(xexpr->args) == 1); *************** *** 3258,3274 **** ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) return; value = argvalue[0]; ! *op->resvalue = PointerGetDatum( ! xmltotext_with_xmloption(DatumGetXmlP(value), ! xexpr->xmloption)); ! *op->resnull = false; } break; case IS_DOCUMENT: { ! Datum *argvalue = op->d.xmlexpr.argvalue; ! bool *argnull = op->d.xmlexpr.argnull; /* optional argument is known to be xml */ Assert(list_length(xexpr->args) == 1); --- 3415,3431 ---- return; value = argvalue[0]; ! *sop->resvalue = PointerGetDatum( ! xmltotext_with_xmloption(DatumGetXmlP(value), ! xexpr->xmloption)); ! *sop->resnull = false; } break; case IS_DOCUMENT: { ! Datum *argvalue = sop->argvalue; ! bool *argnull = sop->argnull; /* optional argument is known to be xml */ Assert(list_length(xexpr->args) == 1); *************** *** 3277,3285 **** ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) return; value = argvalue[0]; ! *op->resvalue = BoolGetDatum(xml_is_document(DatumGetXmlP(value))); ! *op->resnull = false; } break; --- 3434,3442 ---- return; value = argvalue[0]; ! *sop->resvalue = BoolGetDatum(xml_is_document(DatumGetXmlP(value))); ! *sop->resnull = false; } break; *************** *** 3299,3311 **** ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op) * grouping expressions in the current grouping set. */ void ! ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op) { int result = 0; ! Bitmapset *grouped_cols = op->d.grouping_func.parent->grouped_cols; ListCell *lc; ! foreach(lc, op->d.grouping_func.clauses) { int attnum = lfirst_int(lc); --- 3456,3468 ---- * grouping expressions in the current grouping set. */ void ! ExecEvalGroupingFunc(ExprState *state, ExprEvalStep_grouping_func *sop) { int result = 0; ! Bitmapset *grouped_cols = sop->parent->grouped_cols; ListCell *lc; ! foreach(lc, sop->clauses) { int attnum = lfirst_int(lc); *************** *** 3315,3350 **** ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op) result |= 1; } ! *op->resvalue = Int32GetDatum(result); ! *op->resnull = false; } /* * Hand off evaluation of a subplan to nodeSubplan.c */ void ! ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { ! SubPlanState *sstate = op->d.subplan.sstate; /* could potentially be nested, so make sure there's enough stack */ check_stack_depth(); ! *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull); } /* * Hand off evaluation of an alternative subplan to nodeSubplan.c */ void ! ExecEvalAlternativeSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { ! AlternativeSubPlanState *asstate = op->d.alternative_subplan.asstate; /* could potentially be nested, so make sure there's enough stack */ check_stack_depth(); ! *op->resvalue = ExecAlternativeSubPlan(asstate, econtext, op->resnull); } /* --- 3472,3510 ---- result |= 1; } ! *sop->resvalue = Int32GetDatum(result); ! *sop->resnull = false; } /* * Hand off evaluation of a subplan to nodeSubplan.c */ void ! ExecEvalSubPlan(ExprState *state, ExprEvalStep_subplan *sop, ! ExprContext *econtext) { ! SubPlanState *sstate = sop->sstate; /* could potentially be nested, so make sure there's enough stack */ check_stack_depth(); ! *sop->resvalue = ExecSubPlan(sstate, econtext, sop->resnull); } /* * Hand off evaluation of an alternative subplan to nodeSubplan.c */ void ! ExecEvalAlternativeSubPlan(ExprState *state, ! ExprEvalStep_alternative_subplan *sop, ! ExprContext *econtext) { ! AlternativeSubPlanState *asstate = sop->asstate; /* could potentially be nested, so make sure there's enough stack */ check_stack_depth(); ! *sop->resvalue = ExecAlternativeSubPlan(asstate, econtext, sop->resnull); } /* *************** *** 3354,3362 **** ExecEvalAlternativeSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econ * with respect to given expression context. */ void ! ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) { ! Var *variable = op->d.wholerow.var; TupleTableSlot *slot; TupleDesc output_tupdesc; MemoryContext oldcontext; --- 3514,3523 ---- * with respect to given expression context. */ void ! ExecEvalWholeRowVar(ExprState *state, ExprEvalStep_wholerow *sop, ! ExprContext *econtext) { ! Var *variable = sop->var; TupleTableSlot *slot; TupleDesc output_tupdesc; MemoryContext oldcontext; *************** *** 3388,3395 **** ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) } /* Apply the junkfilter if any */ ! if (op->d.wholerow.junkFilter != NULL) ! slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot); /* * If first time through, obtain tuple descriptor and check compatibility. --- 3549,3556 ---- } /* Apply the junkfilter if any */ ! if (sop->junkFilter != NULL) ! slot = ExecFilterJunk(sop->junkFilter, slot); /* * If first time through, obtain tuple descriptor and check compatibility. *************** *** 3398,3407 **** ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) * initialization phase, but due to using slots that's currently not * feasible. */ ! if (op->d.wholerow.first) { /* optimistically assume we don't need slow path */ ! op->d.wholerow.slow = false; /* * If the Var identifies a named composite type, we must check that --- 3559,3568 ---- * initialization phase, but due to using slots that's currently not * feasible. */ ! if (sop->first) { /* optimistically assume we don't need slow path */ ! sop->slow = false; /* * If the Var identifies a named composite type, we must check that *************** *** 3457,3463 **** ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) if (vattr->attlen != sattr->attlen || vattr->attalign != sattr->attalign) ! op->d.wholerow.slow = true; /* need to check for nulls */ } /* --- 3618,3624 ---- if (vattr->attlen != sattr->attlen || vattr->attalign != sattr->attalign) ! sop->slow = true; /* need to check for nulls */ } /* *************** *** 3518,3526 **** ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) } /* Bless the tupdesc if needed, and save it in the execution state */ ! op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc); ! op->d.wholerow.first = false; } /* --- 3679,3687 ---- } /* Bless the tupdesc if needed, and save it in the execution state */ ! sop->tupdesc = BlessTupleDesc(output_tupdesc); ! sop->first = false; } /* *************** *** 3529,3539 **** ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) */ slot_getallattrs(slot); ! if (op->d.wholerow.slow) { /* Check to see if any dropped attributes are non-null */ TupleDesc tupleDesc = slot->tts_tupleDescriptor; ! TupleDesc var_tupdesc = op->d.wholerow.tupdesc; int i; Assert(var_tupdesc->natts == tupleDesc->natts); --- 3690,3700 ---- */ slot_getallattrs(slot); ! if (sop->slow) { /* Check to see if any dropped attributes are non-null */ TupleDesc tupleDesc = slot->tts_tupleDescriptor; ! TupleDesc var_tupdesc = sop->tupdesc; int i; Assert(var_tupdesc->natts == tupleDesc->natts); *************** *** 3570,3581 **** ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) /* * Label the datum with the composite type info we identified before. * ! * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to * the tuple build step; but that seems a tad risky so let's not.) */ ! HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid); ! HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod); ! *op->resvalue = PointerGetDatum(dtuple); ! *op->resnull = false; } --- 3731,3742 ---- /* * Label the datum with the composite type info we identified before. * ! * (Note: we could skip doing this by passing sop->tupdesc to * the tuple build step; but that seems a tad risky so let's not.) */ ! HeapTupleHeaderSetTypeId(dtuple, sop->tupdesc->tdtypeid); ! HeapTupleHeaderSetTypMod(dtuple, sop->tupdesc->tdtypmod); ! *sop->resvalue = PointerGetDatum(dtuple); ! *sop->resnull = false; } *** a/src/include/executor/execExpr.h --- b/src/include/executor/execExpr.h *************** *** 217,568 **** typedef enum ExprEvalOp } ExprEvalOp; typedef struct ExprEvalStep { ! /* ! * Instruction to be executed. During instruction preparation this is an ! * enum ExprEvalOp, but later it can be changed to some other type, e.g. a ! * pointer for computed goto (that's why it's an intptr_t). ! */ ! intptr_t opcode; ! ! /* where to store the result of this step */ ! Datum *resvalue; ! bool *resnull; ! ! /* ! * Inline data for the operation. Inline data is faster to access, but ! * also bloats the size of all instructions. The union should be kept to ! * no more than 40 bytes on 64-bit systems (so that the entire struct is ! * no more than 64 bytes, a single cacheline on common systems). ! */ ! union ! { ! /* for EEOP_INNER/OUTER/SCAN_FETCHSOME */ ! struct ! { ! /* attribute number up to which to fetch (inclusive) */ ! int last_var; ! } fetch; ! ! /* for EEOP_INNER/OUTER/SCAN_[SYS]VAR[_FIRST] */ ! struct ! { ! /* attnum is attr number - 1 for regular VAR ... */ ! /* but it's just the normal (negative) attr number for SYSVAR */ ! int attnum; ! Oid vartype; /* type OID of variable */ ! } var; ! ! /* for EEOP_WHOLEROW */ ! struct ! { ! Var *var; /* original Var node in plan tree */ ! bool first; /* first time through, need to initialize? */ ! bool slow; /* need runtime check for nulls? */ ! TupleDesc tupdesc; /* descriptor for resulting tuples */ ! JunkFilter *junkFilter; /* JunkFilter to remove resjunk cols */ ! } wholerow; ! ! /* for EEOP_ASSIGN_*_VAR */ ! struct ! { ! /* target index in ExprState->resultslot->tts_values/nulls */ ! int resultnum; ! /* source attribute number - 1 */ ! int attnum; ! } assign_var; ! ! /* for EEOP_ASSIGN_TMP[_MAKE_RO] */ ! struct ! { ! /* target index in ExprState->resultslot->tts_values/nulls */ ! int resultnum; ! } assign_tmp; ! ! /* for EEOP_CONST */ ! struct ! { ! /* constant's value */ ! Datum value; ! bool isnull; ! } constval; ! ! /* for EEOP_FUNCEXPR_* / NULLIF / DISTINCT */ ! struct ! { ! FmgrInfo *finfo; /* function's lookup data */ ! FunctionCallInfo fcinfo_data; /* arguments etc */ ! /* faster to access without additional indirection: */ ! PGFunction fn_addr; /* actual call address */ ! int nargs; /* number of arguments */ ! } func; ! ! /* for EEOP_BOOL_*_STEP */ ! struct ! { ! bool *anynull; /* track if any input was NULL */ ! int jumpdone; /* jump here if result determined */ ! } boolexpr; ! ! /* for EEOP_QUAL */ ! struct ! { ! int jumpdone; /* jump here on false or null */ ! } qualexpr; ! ! /* for EEOP_JUMP[_CONDITION] */ ! struct ! { ! int jumpdone; /* target instruction's index */ ! } jump; ! ! /* for EEOP_NULLTEST_ROWIS[NOT]NULL */ ! struct ! { ! /* cached tupdesc pointer - filled at runtime */ ! TupleDesc argdesc; ! } nulltest_row; ! ! /* for EEOP_PARAM_EXEC/EXTERN */ ! struct ! { ! int paramid; /* numeric ID for parameter */ ! Oid paramtype; /* OID of parameter's datatype */ ! } param; ! ! /* for EEOP_CASE_TESTVAL/DOMAIN_TESTVAL */ ! struct ! { ! Datum *value; /* value to return */ ! bool *isnull; ! } casetest; ! ! /* for EEOP_MAKE_READONLY */ ! struct ! { ! Datum *value; /* value to coerce to read-only */ ! bool *isnull; ! } make_readonly; ! ! /* for EEOP_IOCOERCE */ ! struct ! { ! /* lookup and call info for source type's output function */ ! FmgrInfo *finfo_out; ! FunctionCallInfo fcinfo_data_out; ! /* lookup and call info for result type's input function */ ! FmgrInfo *finfo_in; ! FunctionCallInfo fcinfo_data_in; ! } iocoerce; ! ! /* for EEOP_SQLVALUEFUNCTION */ ! struct ! { ! SQLValueFunction *svf; ! } sqlvaluefunction; ! ! /* for EEOP_NEXTVALUEEXPR */ ! struct ! { ! Oid seqid; ! Oid seqtypid; ! } nextvalueexpr; ! ! /* for EEOP_ARRAYEXPR */ ! struct ! { ! Datum *elemvalues; /* element values get stored here */ ! bool *elemnulls; ! int nelems; /* length of the above arrays */ ! Oid elemtype; /* array element type */ ! int16 elemlength; /* typlen of the array element type */ ! bool elembyval; /* is the element type pass-by-value? */ ! char elemalign; /* typalign of the element type */ ! bool multidims; /* is array expression multi-D? */ ! } arrayexpr; ! ! /* for EEOP_ARRAYCOERCE */ ! struct ! { ! ArrayCoerceExpr *coerceexpr; ! Oid resultelemtype; /* element type of result array */ ! FmgrInfo *elemfunc; /* lookup info for element coercion ! * function */ ! struct ArrayMapState *amstate; /* workspace for array_map */ ! } arraycoerce; ! ! /* for EEOP_ROW */ ! struct ! { ! TupleDesc tupdesc; /* descriptor for result tuples */ ! /* workspace for the values constituting the row: */ ! Datum *elemvalues; ! bool *elemnulls; ! } row; ! ! /* for EEOP_ROWCOMPARE_STEP */ ! struct ! { ! /* lookup and call data for column comparison function */ ! FmgrInfo *finfo; ! FunctionCallInfo fcinfo_data; ! PGFunction fn_addr; ! /* target for comparison resulting in NULL */ ! int jumpnull; ! /* target for comparison yielding inequality */ ! int jumpdone; ! } rowcompare_step; ! ! /* for EEOP_ROWCOMPARE_FINAL */ ! struct ! { ! RowCompareType rctype; ! } rowcompare_final; ! ! /* for EEOP_MINMAX */ ! struct ! { ! /* workspace for argument values */ ! Datum *values; ! bool *nulls; ! int nelems; ! /* is it GREATEST or LEAST? */ ! MinMaxOp op; ! /* lookup and call data for comparison function */ ! FmgrInfo *finfo; ! FunctionCallInfo fcinfo_data; ! } minmax; ! ! /* for EEOP_FIELDSELECT */ ! struct ! { ! AttrNumber fieldnum; /* field number to extract */ ! Oid resulttype; /* field's type */ ! /* cached tupdesc pointer - filled at runtime */ ! TupleDesc argdesc; ! } fieldselect; ! ! /* for EEOP_FIELDSTORE_DEFORM / FIELDSTORE_FORM */ ! struct ! { ! /* original expression node */ ! FieldStore *fstore; ! ! /* cached tupdesc pointer - filled at runtime */ ! /* note that a DEFORM and FORM pair share the same tupdesc */ ! TupleDesc *argdesc; ! ! /* workspace for column values */ ! Datum *values; ! bool *nulls; ! int ncolumns; ! } fieldstore; ! ! /* for EEOP_ARRAYREF_SUBSCRIPT */ ! struct ! { ! /* too big to have inline */ ! struct ArrayRefState *state; ! int off; /* 0-based index of this subscript */ ! bool isupper; /* is it upper or lower subscript? */ ! int jumpdone; /* jump here on null */ ! } arrayref_subscript; ! ! /* for EEOP_ARRAYREF_OLD / ASSIGN / FETCH */ ! struct ! { ! /* too big to have inline */ ! struct ArrayRefState *state; ! } arrayref; ! ! /* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */ ! struct ! { ! /* name of constraint */ ! char *constraintname; ! /* where the result of a CHECK constraint will be stored */ ! Datum *checkvalue; ! bool *checknull; ! /* OID of domain type */ ! Oid resulttype; ! } domaincheck; ! ! /* for EEOP_CONVERT_ROWTYPE */ ! struct ! { ! ConvertRowtypeExpr *convert; /* original expression */ ! /* these three fields are filled at runtime: */ ! TupleDesc indesc; /* tupdesc for input type */ ! TupleDesc outdesc; /* tupdesc for output type */ ! TupleConversionMap *map; /* column mapping */ ! bool initialized; /* initialized for current types? */ ! } convert_rowtype; ! ! /* for EEOP_SCALARARRAYOP */ ! struct ! { ! /* element_type/typlen/typbyval/typalign are filled at runtime */ ! Oid element_type; /* InvalidOid if not yet filled */ ! bool useOr; /* use OR or AND semantics? */ ! int16 typlen; /* array element type storage info */ ! bool typbyval; ! char typalign; ! FmgrInfo *finfo; /* function's lookup data */ ! FunctionCallInfo fcinfo_data; /* arguments etc */ ! /* faster to access without additional indirection: */ ! PGFunction fn_addr; /* actual call address */ ! } scalararrayop; ! ! /* for EEOP_XMLEXPR */ ! struct ! { ! XmlExpr *xexpr; /* original expression node */ ! /* workspace for evaluating named args, if any */ ! Datum *named_argvalue; ! bool *named_argnull; ! /* workspace for evaluating unnamed args, if any */ ! Datum *argvalue; ! bool *argnull; ! } xmlexpr; ! ! /* for EEOP_AGGREF */ ! struct ! { ! /* out-of-line state, modified by nodeAgg.c */ ! AggrefExprState *astate; ! } aggref; ! ! /* for EEOP_GROUPING_FUNC */ ! struct ! { ! AggState *parent; /* parent Agg */ ! List *clauses; /* integer list of column numbers */ ! } grouping_func; ! ! /* for EEOP_WINDOW_FUNC */ ! struct ! { ! /* out-of-line state, modified by nodeWindowFunc.c */ ! WindowFuncExprState *wfstate; ! } window_func; ! ! /* for EEOP_SUBPLAN */ ! struct ! { ! /* out-of-line state, created by nodeSubplan.c */ ! SubPlanState *sstate; ! } subplan; ! ! /* for EEOP_ALTERNATIVE_SUBPLAN */ ! struct ! { ! /* out-of-line state, created by nodeSubplan.c */ ! AlternativeSubPlanState *asstate; ! } alternative_subplan; ! } d; } ExprEvalStep; /* Non-inline data for array operations */ typedef struct ArrayRefState --- 217,648 ---- } ExprEvalOp; + /* + * All ExecEvalStep* structures need to be interchangeable and start with + * the same fields. Use a #define to make the declarations consistent. + * + * The fields are: + * + * opcode + * Instruction to be executed. During instruction preparation this is an + * enum ExprEvalOp, but later it can be changed to some other type, e.g. a + * pointer for computed goto (that's why it's an intptr_t). + * + * + * resvalue + * resnull + * Where to store the result of the step. + * + * nextstep + * Next step to execute. + */ + #define EXPR_EVAL_STEP_HEADER \ + intptr_t opcode; \ + Datum *resvalue; \ + bool *resnull; \ + struct ExprEvalStep *nextstep; + + /* Generic step - all steps are castable to this type */ typedef struct ExprEvalStep { ! EXPR_EVAL_STEP_HEADER; } ExprEvalStep; + /* for EEOP_INNER/OUTER/SCAN_FETCHSOME */ + typedef struct ExprEvalStep_fetch + { + EXPR_EVAL_STEP_HEADER; + + /* attribute number up to which to fetch (inclusive) */ + int last_var; + } ExprEvalStep_fetch; + + /* for EEOP_INNER/OUTER/SCAN_[SYS]VAR[_FIRST] */ + typedef struct ExprEvalStep_var + { + EXPR_EVAL_STEP_HEADER; + + /* attnum is attr number - 1 for regular VAR ... */ + /* but it's just the normal (negative) attr number for SYSVAR */ + int attnum; + Oid vartype; /* type OID of variable */ + } ExprEvalStep_var; + + /* for EEOP_WHOLEROW */ + typedef struct ExprEvalStep_wholerow + { + EXPR_EVAL_STEP_HEADER; + + Var *var; /* original Var node in plan tree */ + bool first; /* first time through, need to initialize? */ + bool slow; /* need runtime check for nulls? */ + TupleDesc tupdesc; /* descriptor for resulting tuples */ + JunkFilter *junkFilter; /* JunkFilter to remove resjunk cols */ + } ExprEvalStep_wholerow; + + /* for EEOP_ASSIGN_*_VAR */ + typedef struct ExprEvalStep_assign_var + { + EXPR_EVAL_STEP_HEADER; + + /* target index in ExprState->resultslot->tts_values/nulls */ + int resultnum; + /* source attribute number - 1 */ + int attnum; + } ExprEvalStep_assign_var; + + /* for EEOP_ASSIGN_TMP[_MAKE_RO] */ + typedef struct ExprEvalStep_assign_tmp + { + EXPR_EVAL_STEP_HEADER; + + /* target index in ExprState->resultslot->tts_values/nulls */ + int resultnum; + } ExprEvalStep_assign_tmp; + + /* for EEOP_CONST */ + typedef struct ExprEvalStep_constval + { + EXPR_EVAL_STEP_HEADER; + + /* constant's value */ + Datum value; + bool isnull; + } ExprEvalStep_constval; + + /* for EEOP_FUNCEXPR_* / NULLIF / DISTINCT */ + typedef struct ExprEvalStep_func + { + EXPR_EVAL_STEP_HEADER; + + FmgrInfo *finfo; /* function's lookup data */ + FunctionCallInfo fcinfo_data; /* arguments etc */ + /* faster to access without additional indirection: */ + PGFunction fn_addr; /* actual call address */ + int nargs; /* number of arguments */ + } ExprEvalStep_func; + + /* for EEOP_BOOL_*_STEP */ + typedef struct ExprEvalStep_boolexpr + { + EXPR_EVAL_STEP_HEADER; + + bool *anynull; /* track if any input was NULL */ + ExprEvalStep *jumpdone; /* jump here if result determined */ + } ExprEvalStep_boolexpr; + + /* for EEOP_QUAL */ + typedef struct ExprEvalStep_qualexpr + { + EXPR_EVAL_STEP_HEADER; + + ExprEvalStep *jumpdone; /* jump here on false or null */ + } ExprEvalStep_qualexpr; + + /* for EEOP_JUMP[_CONDITION] */ + typedef struct ExprEvalStep_jump + { + EXPR_EVAL_STEP_HEADER; + + ExprEvalStep *jumpdone; /* target instruction's index */ + } ExprEvalStep_jump; + + /* for EEOP_NULLTEST_ROWIS[NOT]NULL */ + typedef struct ExprEvalStep_nulltest_row + { + EXPR_EVAL_STEP_HEADER; + + /* cached tupdesc pointer - filled at runtime */ + TupleDesc argdesc; + } ExprEvalStep_nulltest_row; + + /* for EEOP_PARAM_EXEC/EXTERN */ + typedef struct ExprEvalStep_param + { + EXPR_EVAL_STEP_HEADER; + + int paramid; /* numeric ID for parameter */ + Oid paramtype; /* OID of parameter's datatype */ + } ExprEvalStep_param; + + /* for EEOP_CASE_TESTVAL/DOMAIN_TESTVAL */ + typedef struct ExprEvalStep_casetest + { + EXPR_EVAL_STEP_HEADER; + + Datum *value; /* value to return */ + bool *isnull; + } ExprEvalStep_casetest; + + /* for EEOP_MAKE_READONLY */ + typedef struct ExprEvalStep_make_readonly + { + EXPR_EVAL_STEP_HEADER; + + Datum *value; /* value to coerce to read-only */ + bool *isnull; + } ExprEvalStep_make_readonly; + + /* for EEOP_IOCOERCE */ + typedef struct ExprEvalStep_iocoerce + { + EXPR_EVAL_STEP_HEADER; + + /* lookup and call info for source type's output function */ + FmgrInfo *finfo_out; + FunctionCallInfo fcinfo_data_out; + /* lookup and call info for result type's input function */ + FmgrInfo *finfo_in; + FunctionCallInfo fcinfo_data_in; + } ExprEvalStep_iocoerce; + + /* for EEOP_SQLVALUEFUNCTION */ + typedef struct ExprEvalStep_sqlvaluefunction + { + EXPR_EVAL_STEP_HEADER; + + SQLValueFunction *svf; + } ExprEvalStep_sqlvaluefunction; + + /* for EEOP_NEXTVALUEEXPR */ + typedef struct ExprEvalStep_nextvalueexpr + { + EXPR_EVAL_STEP_HEADER; + + Oid seqid; + Oid seqtypid; + } ExprEvalStep_nextvalueexpr; + + /* for EEOP_ARRAYEXPR */ + typedef struct ExprEvalStep_arrayexpr + { + EXPR_EVAL_STEP_HEADER; + + Datum *elemvalues; /* element values get stored here */ + bool *elemnulls; + int nelems; /* length of the above arrays */ + Oid elemtype; /* array element type */ + int16 elemlength; /* typlen of the array element type */ + bool elembyval; /* is the element type pass-by-value? */ + char elemalign; /* typalign of the element type */ + bool multidims; /* is array expression multi-D? */ + } ExprEvalStep_arrayexpr; + + /* for EEOP_ARRAYCOERCE */ + typedef struct ExprEvalStep_arraycoerce + { + EXPR_EVAL_STEP_HEADER; + + ArrayCoerceExpr *coerceexpr; + Oid resultelemtype; /* element type of result array */ + FmgrInfo *elemfunc; /* lookup info for element coercion + * function */ + struct ArrayMapState *amstate; /* workspace for array_map */ + } ExprEvalStep_arraycoerce; + + /* for EEOP_ROW */ + typedef struct ExprEvalStep_row + { + EXPR_EVAL_STEP_HEADER; + + TupleDesc tupdesc; /* descriptor for result tuples */ + /* workspace for the values constituting the row: */ + Datum *elemvalues; + bool *elemnulls; + } ExprEvalStep_row; + + /* for EEOP_ROWCOMPARE_STEP */ + typedef struct ExprEvalStep_rowcompare_step + { + EXPR_EVAL_STEP_HEADER; + + /* lookup and call data for column comparison function */ + FmgrInfo *finfo; + FunctionCallInfo fcinfo_data; + PGFunction fn_addr; + /* target for comparison resulting in NULL */ + ExprEvalStep *jumpnull; + /* target for comparison yielding inequality */ + ExprEvalStep *jumpdone; + } ExprEvalStep_rowcompare_step; + + /* for EEOP_ROWCOMPARE_FINAL */ + typedef struct ExprEvalStep_rowcompare_final + { + EXPR_EVAL_STEP_HEADER; + + RowCompareType rctype; + } ExprEvalStep_rowcompare_final; + + /* for EEOP_MINMAX */ + typedef struct ExprEvalStep_minmax + { + EXPR_EVAL_STEP_HEADER; + + /* workspace for argument values */ + Datum *values; + bool *nulls; + int nelems; + /* is it GREATEST or LEAST? */ + MinMaxOp op; + /* lookup and call data for comparison function */ + FmgrInfo *finfo; + FunctionCallInfo fcinfo_data; + } ExprEvalStep_minmax; + + /* for EEOP_FIELDSELECT */ + typedef struct ExprEvalStep_fieldselect + { + EXPR_EVAL_STEP_HEADER; + + AttrNumber fieldnum; /* field number to extract */ + Oid resulttype; /* field's type */ + /* cached tupdesc pointer - filled at runtime */ + TupleDesc argdesc; + } ExprEvalStep_fieldselect; + + /* for EEOP_FIELDSTORE_DEFORM / FIELDSTORE_FORM */ + typedef struct ExprEvalStep_fieldstore + { + EXPR_EVAL_STEP_HEADER; + + /* original expression node */ + FieldStore *fstore; + + /* cached tupdesc pointer - filled at runtime */ + /* note that a DEFORM and FORM pair share the same tupdesc */ + TupleDesc *argdesc; + + /* workspace for column values */ + Datum *values; + bool *nulls; + int ncolumns; + } ExprEvalStep_fieldstore; + + /* for EEOP_ARRAYREF_SUBSCRIPT */ + typedef struct ExprEvalStep_arrayref_subscript + { + EXPR_EVAL_STEP_HEADER; + + /* too big to have inline */ + struct ArrayRefState *state; + int off; /* 0-based index of this subscript */ + bool isupper; /* is it upper or lower subscript? */ + ExprEvalStep *jumpdone; /* jump here on null */ + } ExprEvalStep_arrayref_subscript; + + /* for EEOP_ARRAYREF_OLD / ASSIGN / FETCH */ + typedef struct ExprEvalStep_arrayref + { + EXPR_EVAL_STEP_HEADER; + + /* too big to have inline */ + struct ArrayRefState *state; + } ExprEvalStep_arrayref; + + /* for EEOP_DOMAIN_NOTNULL / DOMAIN_CHECK */ + typedef struct ExprEvalStep_domaincheck + { + EXPR_EVAL_STEP_HEADER; + + /* name of constraint */ + char *constraintname; + /* where the result of a CHECK constraint will be stored */ + Datum *checkvalue; + bool *checknull; + /* OID of domain type */ + Oid resulttype; + } ExprEvalStep_domaincheck; + + /* for EEOP_CONVERT_ROWTYPE */ + typedef struct ExprEvalStep_convert_rowtype + { + EXPR_EVAL_STEP_HEADER; + + ConvertRowtypeExpr *convert; /* original expression */ + /* these three fields are filled at runtime: */ + TupleDesc indesc; /* tupdesc for input type */ + TupleDesc outdesc; /* tupdesc for output type */ + TupleConversionMap *map; /* column mapping */ + bool initialized; /* initialized for current types? */ + } ExprEvalStep_convert_rowtype; + + /* for EEOP_SCALARARRAYOP */ + typedef struct ExprEvalStep_scalararrayop + { + EXPR_EVAL_STEP_HEADER; + + /* element_type/typlen/typbyval/typalign are filled at runtime */ + Oid element_type; /* InvalidOid if not yet filled */ + bool useOr; /* use OR or AND semantics? */ + int16 typlen; /* array element type storage info */ + bool typbyval; + char typalign; + FmgrInfo *finfo; /* function's lookup data */ + FunctionCallInfo fcinfo_data; /* arguments etc */ + /* faster to access without additional indirection: */ + PGFunction fn_addr; /* actual call address */ + } ExprEvalStep_scalararrayop; + + /* for EEOP_XMLEXPR */ + typedef struct ExprEvalStep_xmlexpr + { + EXPR_EVAL_STEP_HEADER; + + XmlExpr *xexpr; /* original expression node */ + /* workspace for evaluating named args, if any */ + Datum *named_argvalue; + bool *named_argnull; + /* workspace for evaluating unnamed args, if any */ + Datum *argvalue; + bool *argnull; + } ExprEvalStep_xmlexpr; + + /* for EEOP_AGGREF */ + typedef struct ExprEvalStep_aggref + { + EXPR_EVAL_STEP_HEADER; + + /* out-of-line state, modified by nodeAgg.c */ + AggrefExprState *astate; + } ExprEvalStep_aggref; + + /* for EEOP_GROUPING_FUNC */ + typedef struct ExprEvalStep_grouping_func + { + EXPR_EVAL_STEP_HEADER; + + AggState *parent; /* parent Agg */ + List *clauses; /* integer list of column numbers */ + } ExprEvalStep_grouping_func; + + /* for EEOP_WINDOW_FUNC */ + typedef struct ExprEvalStep_window_func + { + EXPR_EVAL_STEP_HEADER; + + /* out-of-line state, modified by nodeWindowFunc.c */ + WindowFuncExprState *wfstate; + } ExprEvalStep_window_func; + + /* for EEOP_SUBPLAN */ + typedef struct ExprEvalStep_subplan + { + EXPR_EVAL_STEP_HEADER; + + /* out-of-line state, created by nodeSubplan.c */ + SubPlanState *sstate; + } ExprEvalStep_subplan; + + /* for EEOP_ALTERNATIVE_SUBPLAN */ + typedef struct ExprEvalStep_alternative_subplan + { + EXPR_EVAL_STEP_HEADER; + + /* out-of-line state, created by nodeSubplan.c */ + AlternativeSubPlanState *asstate; + } ExprEvalStep_alternative_subplan; + /* Non-inline data for array operations */ typedef struct ArrayRefState *************** *** 609,651 **** extern ExprEvalOp ExecEvalStepOp(ExprState *state, ExprEvalStep *op); * execExprInterp.c, because that allows them to be used by other methods of * expression evaluation, reducing code duplication. */ ! extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext); ! extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext); ! extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext); ! extern void ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext); ! extern void ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalRow(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalMinMax(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext); ! extern void ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ! ExprContext *econtext); ! extern void ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext); ! extern bool ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ! ExprContext *econtext); ! extern void ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op); ! extern void ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext); ! extern void ExecEvalAlternativeSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext); ! extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext); #endif /* EXEC_EXPR_H */ --- 689,741 ---- * execExprInterp.c, because that allows them to be used by other methods of * expression evaluation, reducing code duplication. */ ! extern void ExecEvalParamExec(ExprState *state, ExprEvalStep_param *sop, ExprContext *econtext); ! extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep_param *sop, ExprContext *econtext); ! extern void ExecEvalSQLValueFunction(ExprState *state, ! ExprEvalStep_sqlvaluefunction *sop); ! extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *sop); ! extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep_nextvalueexpr *sop); ! extern void ExecEvalRowNull(ExprState *state, ExprEvalStep_nulltest_row *sop, ExprContext *econtext); ! extern void ExecEvalRowNotNull(ExprState *state, ExprEvalStep_nulltest_row *sop, ExprContext *econtext); ! extern void ExecEvalArrayExpr(ExprState *state, ExprEvalStep_arrayexpr *sop); ! extern void ExecEvalArrayCoerce(ExprState *state, ! ExprEvalStep_arraycoerce *sop); ! extern void ExecEvalRow(ExprState *state, ExprEvalStep_row *sop); ! extern void ExecEvalMinMax(ExprState *state, ExprEvalStep_minmax *sop); ! extern void ExecEvalFieldSelect(ExprState *state, ExprEvalStep_fieldselect *sop, ExprContext *econtext); ! extern void ExecEvalFieldStoreDeForm(ExprState *state, ! ExprEvalStep_fieldstore *sop, ExprContext *econtext); ! extern void ExecEvalFieldStoreForm(ExprState *state, ! ExprEvalStep_fieldstore *sop, ExprContext *econtext); ! extern bool ExecEvalArrayRefSubscript(ExprState *state, ! ExprEvalStep_arrayref_subscript *sop); ! extern void ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep_arrayref *sop); ! extern void ExecEvalArrayRefOld(ExprState *state, ExprEvalStep_arrayref *sop); ! extern void ExecEvalArrayRefAssign(ExprState *state, ! ExprEvalStep_arrayref *sop); ! extern void ExecEvalConvertRowtype(ExprState *state, ! ExprEvalStep_convert_rowtype *sop, ExprContext *econtext); ! extern void ExecEvalScalarArrayOp(ExprState *state, ! ExprEvalStep_scalararrayop *sop); ! extern void ExecEvalConstraintNotNull(ExprState *state, ! ExprEvalStep_domaincheck *sop); ! extern void ExecEvalConstraintCheck(ExprState *state, ! ExprEvalStep_domaincheck *sop); ! extern void ExecEvalXmlExpr(ExprState *state, ExprEvalStep_xmlexpr *sop); ! extern void ExecEvalGroupingFunc(ExprState *state, ! ExprEvalStep_grouping_func *sop); ! extern void ExecEvalSubPlan(ExprState *state, ExprEvalStep_subplan *sop, ExprContext *econtext); ! extern void ExecEvalAlternativeSubPlan(ExprState *state, ! ExprEvalStep_alternative_subplan *sop, ExprContext *econtext); ! extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep_wholerow *sop, ExprContext *econtext); #endif /* EXEC_EXPR_H */ *** a/src/include/nodes/execnodes.h --- b/src/include/nodes/execnodes.h *************** *** 72,77 **** typedef struct ExprState --- 72,78 ---- * Instructions to compute expression's return value. */ struct ExprEvalStep *steps; + int num_steps; /* * Function that actually evaluates the expression. This can be set to *************** *** 86,93 **** typedef struct ExprState * XXX: following only needed during "compilation", could be thrown away. */ ! int steps_len; /* number of steps currently */ ! int steps_alloc; /* allocated length of steps array */ Datum *innermost_caseval; bool *innermost_casenull; --- 87,101 ---- * XXX: following only needed during "compilation", could be thrown away. */ ! struct ExprEvalStep *last_step; /* Last step created */ ! char *step_buffer; /* Memory buffer for steps */ ! size_t buffer_size; /* Size of remaining buffer */ ! List *adjust_jumps; /* "jumpdone" pointers to be resolved ! when the next operator is created. ! Generally, this list should be ! created as a local variable and only ! attached here when it is time to ! resolve the pointers. */ Datum *innermost_caseval; bool *innermost_casenull;