diff --git i/src/backend/executor/execExpr.c w/src/backend/executor/execExpr.c
index e0a1fb76aa8..a53a00bfc8f 100644
--- i/src/backend/executor/execExpr.c
+++ w/src/backend/executor/execExpr.c
@@ -2826,12 +2826,13 @@ ExecInitSubPlanExpr(SubPlan *subplan,
 	/*
 	 * Generate steps to evaluate input arguments for the subplan.
 	 *
-	 * We evaluate the argument expressions into ExprState's resvalue/resnull,
-	 * and then use PARAM_SET to update the parameter. We do that, instead of
-	 * evaluating directly into the param, to avoid depending on the pointer
-	 * value remaining stable / being included in the generated expression. No
-	 * danger of conflicts with other uses of resvalue/resnull as storing and
-	 * using the value always is in subsequent steps.
+	 * We evaluate the argument expressions into resv/resnull, and then use
+	 * PARAM_SET to update the parameter. We do that, instead of evaluating
+	 * directly into the param, to avoid depending on the pointer value
+	 * remaining stable / being included in the generated expression. It's ok
+	 * to use resv/resnull fo multiple params, as each parameter evaluation is
+	 * immediately followed by an EEOP_PARAM_SET (and thus are saved before
+	 * they could be overwritten again).
 	 *
 	 * Any calculation we have to do can be done in the parent econtext, since
 	 * the Param values don't need to have per-query lifetime.
@@ -2842,10 +2843,11 @@ ExecInitSubPlanExpr(SubPlan *subplan,
 		int			paramid = lfirst_int(l);
 		Expr	   *arg = (Expr *) lfirst(pvar);
 
-		ExecInitExprRec(arg, state,
-						&state->resvalue, &state->resnull);
+		ExecInitExprRec(arg, state, resv, resnull);
 
 		scratch.opcode = EEOP_PARAM_SET;
+		scratch.resvalue = resv;
+		scratch.resnull = resnull;
 		scratch.d.param.paramid = paramid;
 		/* paramtype's not actually used, but we might as well fill it */
 		scratch.d.param.paramtype = exprType((Node *) arg);
diff --git i/src/backend/executor/execExprInterp.c w/src/backend/executor/execExprInterp.c
index 86ab3704b66..a7a5ac1e83b 100644
--- i/src/backend/executor/execExprInterp.c
+++ w/src/backend/executor/execExprInterp.c
@@ -3107,7 +3107,7 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
 /*
  * Set value of a param (currently always PARAM_EXEC) from
- * state->res{value,null}.
+ * op->res{value,null}.
  */
 void
 ExecEvalParamSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
@@ -3119,8 +3119,8 @@ ExecEvalParamSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 	/* Shouldn't have a pending evaluation anymore */
 	Assert(prm->execPlan == NULL);
 
-	prm->value = state->resvalue;
-	prm->isnull = state->resnull;
+	prm->value = *op->resvalue;
+	prm->isnull = *op->resnull;
 }
 
 /*
