*** 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;
