diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/rows.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/rows.scala index cfc68fc00bea..1cdfbc98f916 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/rows.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/rows.scala @@ -201,7 +201,7 @@ class GenericRow(protected[sql] val values: Array[Any]) extends Row { override def toSeq: Seq[Any] = values.toSeq - override def copy(): Row = this + override def copy(): Row = new GenericRow(values.clone()) } class GenericRowWithSchema(values: Array[Any], override val schema: StructType) diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/RowTest.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/RowTest.scala index 5c22a7219254..08f072e5b828 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/RowTest.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/RowTest.scala @@ -104,4 +104,20 @@ class RowTest extends FunSpec with Matchers { internalRow shouldEqual internalRow2 } } + + describe("row copy") { + val noSchemaRowCopy = noSchemaRow.copy() + it("equality check for copied rows") { + noSchemaRowCopy shouldEqual noSchemaRow + } + + val noSchemaRowCopySec = noSchemaRow.copy() + val array = noSchemaRowCopySec.toSeq.toArray + array(0) = "value3" + val newRow = Row.fromSeq(array) + it("check mutating a copied row's internal array does not affect the original row") { + newRow.getAs[String](0) shouldBe "value3" + noSchemaRow.getAs[String](0) shouldBe "value1" + } + } }