You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by do...@apache.org on 2025/08/15 15:55:52 UTC

(spark) branch master updated: [SPARK-53290][SQL][CONNECT] Fix Metadata backward-compatibility breaking

This is an automated email from the ASF dual-hosted git repository.

dongjoon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new c68cf9405030 [SPARK-53290][SQL][CONNECT] Fix Metadata backward-compatibility breaking
c68cf9405030 is described below

commit c68cf9405030b4871fd53192dac50721e4df5928
Author: Kent Yao <ya...@apache.org>
AuthorDate: Fri Aug 15 08:55:41 2025 -0700

    [SPARK-53290][SQL][CONNECT] Fix Metadata backward-compatibility breaking
    
    ### What changes were proposed in this pull request?
    
    This PR adds the SerialVersionUID annotation and moves the newly added runtimeMap out from the ctor.
    
    ### Why are the changes needed?
    
    With a v400 client to a v410 server,  ```java.io.InvalidClassException: org.apache.spark.sql.types.Metadata;``` raised
    
    ```
    Welcome to
          ____              __
         / __/__  ___ _____/ /__
        _\ \/ _ \/ _ `/ __/  '_/
       /___/ .__/\_,_/_/ /_/\_\   version 4.0.0
          /_/
    
    Type in expressions to have them evaluated.
    Spark connect server version 4.1.0-SNAPSHOT.
    Spark session available as 'spark'.
    
    scala> import spark.implicits._
    import spark.implicits._
    
    scala> spark.catalog.listCatalogs().map(_.name)
    res1: org.apache.spark.sql.connect.Dataset[String] = Invalid Dataframe; [INTERNAL_ERROR] Failed to unpack scala udf. SQLSTATE: XX000
    ```
    
    ### Does this PR introduce _any_ user-facing change?
    no
    
    ### How was this patch tested?
    
    ```
    Welcome to
          ____              __
         / __/__  ___ _____/ /__
        _\ \/ _ \/ _ `/ __/  '_/
       /___/ .__/\_,_/_/ /_/\_\   version 4.0.0
          /_/
    
    Type in expressions to have them evaluated.
    Spark connect server version 4.1.0-SNAPSHOT.
    Spark session available as 'spark'.
    
    scala> import spark.implicits._
    import spark.implicits._
    
    scala> spark.catalog.listCatalogs().map(_.name)
    res1: org.apache.spark.sql.connect.Dataset[String] = [value: string]
    
    scala> spark.catalog.listCatalogs().map(_.name).collect()
    res2: Array[String] = Array("spark_catalog")
    
    ```
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    No
    
    Closes #52037 from yaooqinn/SPARK-53290.
    
    Authored-by: Kent Yao <ya...@apache.org>
    Signed-off-by: Dongjoon Hyun <do...@apache.org>
---
 .../scala/org/apache/spark/sql/types/Metadata.scala    | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/sql/api/src/main/scala/org/apache/spark/sql/types/Metadata.scala b/sql/api/src/main/scala/org/apache/spark/sql/types/Metadata.scala
index 4c86bfba3a18..f2cfcb984594 100644
--- a/sql/api/src/main/scala/org/apache/spark/sql/types/Metadata.scala
+++ b/sql/api/src/main/scala/org/apache/spark/sql/types/Metadata.scala
@@ -40,13 +40,15 @@ import org.apache.spark.util.ArrayImplicits._
  * @since 1.3.0
  */
 @Stable
-sealed class Metadata private[types] (
-    private[types] val map: Map[String, Any],
-    @transient private[types] val runtimeMap: Map[String, Any])
+@SerialVersionUID(-3987058932362209243L)
+sealed class Metadata private[types] (private[types] val map: Map[String, Any])
     extends Serializable {
 
+  @transient private[types] var runtimeMap: Map[String, Any] = _
+  private[types] def setRuntimeMap(map: Map[String, Any]): Unit = runtimeMap = map
+
   /** No-arg constructor for kryo. */
-  protected def this() = this(null, null)
+  protected def this() = this(null)
 
   /** Tests whether this Metadata contains a binding for a key. */
   def contains(key: String): Boolean = map.contains(key)
@@ -137,7 +139,7 @@ sealed class Metadata private[types] (
 @Stable
 object Metadata {
 
-  private[this] val _empty = new Metadata(Map.empty, Map.empty)
+  private[this] val _empty = new Metadata(Map.empty)
 
   /** Returns an empty Metadata. */
   def empty: Metadata = _empty
@@ -309,7 +311,11 @@ class MetadataBuilder {
       // Save some memory when the metadata is empty
       Metadata.empty
     } else {
-      new Metadata(map.toMap, runtimeMap.toMap)
+      val metadata = new Metadata(map.toMap)
+      if (runtimeMap.nonEmpty) {
+        metadata.setRuntimeMap(runtimeMap.toMap)
+      }
+      metadata
     }
   }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org