diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/Encoder.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/Encoder.scala index 9853a4fcc2f9d..29d81c553ff61 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/Encoder.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/Encoder.scala @@ -80,4 +80,10 @@ trait Encoder[T] extends Serializable { * A ClassTag that can be used to construct an Array to contain a collection of `T`. */ def clsTag: ClassTag[T] + + /** + * Create a copied [[Encoder]]. The implementation may just copy internal reusable fields to speed + * up the [[Encoder]] creation. + */ + def makeCopy: Encoder[T] } diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/encoders/ExpressionEncoder.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/encoders/ExpressionEncoder.scala index c97303be1d27c..bd499671d6441 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/encoders/ExpressionEncoder.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/encoders/ExpressionEncoder.scala @@ -382,6 +382,8 @@ case class ExpressionEncoder[T]( .map { case(f, a) => s"${f.name}$a: ${f.dataType.simpleString}"}.mkString(", ") override def toString: String = s"class[$schemaString]" + + override def makeCopy: ExpressionEncoder[T] = copy() } // A dummy logical plan that can hold expressions and go through optimizer rules. diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/encoders/ExpressionEncoderSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/encoders/ExpressionEncoderSuite.scala index f4feeca1d05ad..9380c7e3f5f72 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/encoders/ExpressionEncoderSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/encoders/ExpressionEncoderSuite.scala @@ -427,6 +427,10 @@ class ExpressionEncoderSuite extends CodegenInterpretedPlanTest with AnalysisTes testOverflowingBigNumeric(BigInt("9" * 100), "scala very large big int") testOverflowingBigNumeric(new BigInteger("9" * 100), "java very big int") + encodeDecodeTest("foo" -> 1L, "makeCopy") { + Encoders.product[(String, Long)].makeCopy.asInstanceOf[ExpressionEncoder[(String, Long)]] + } + private def testOverflowingBigNumeric[T: TypeTag](bigNumeric: T, testName: String): Unit = { Seq(true, false).foreach { allowNullOnOverflow => testAndVerifyNotLeakingReflectionObjects(