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

yihua pushed a commit to branch release-0.14.2
in repository https://gitbox.apache.org/repos/asf/hudi.git


The following commit(s) were added to refs/heads/release-0.14.2 by this push:
     new faa3730f3b5e fix(HUDI-9597): Do not evolve schema if reconciled schema 
keeps unchanged except version id (#17873)
faa3730f3b5e is described below

commit faa3730f3b5e74ab4ea725d631e70ce2468440e4
Author: Lokesh Jain <[email protected]>
AuthorDate: Thu Feb 12 05:43:47 2026 +0530

    fix(HUDI-9597): Do not evolve schema if reconciled schema keeps unchanged 
except version id (#17873)
    
    Co-authored-by: Shuo Cheng <[email protected]>
    Co-authored-by: Lokesh Jain <[email protected]>
    Co-authored-by: Lokesh Jain <[email protected]>
---
 .../hudi/internal/schema/InternalSchema.java       | 10 ++++++++++
 .../schema/utils/AvroSchemaEvolutionUtils.java     |  7 ++++++-
 .../schema/utils/TestAvroSchemaEvolutionUtils.java | 23 ++++++++++++++++++++++
 3 files changed, 39 insertions(+), 1 deletion(-)

diff --git 
a/hudi-common/src/main/java/org/apache/hudi/internal/schema/InternalSchema.java 
b/hudi-common/src/main/java/org/apache/hudi/internal/schema/InternalSchema.java
index ce5f8f259da2..99403f8b6b83 100644
--- 
a/hudi-common/src/main/java/org/apache/hudi/internal/schema/InternalSchema.java
+++ 
b/hudi-common/src/main/java/org/apache/hudi/internal/schema/InternalSchema.java
@@ -289,6 +289,16 @@ public class InternalSchema implements Serializable {
     return record.equals(that.record);
   }
 
+  public boolean equalsIgnoringVersion(Object o) {
+    if (this == o) {
+      return true;
+    } else if (!(o instanceof InternalSchema)) {
+      return false;
+    }
+    InternalSchema that = (InternalSchema) o;
+    return record.equals(that.record);
+  }
+
   @Override
   public int hashCode() {
     return record.hashCode();
diff --git 
a/hudi-common/src/main/java/org/apache/hudi/internal/schema/utils/AvroSchemaEvolutionUtils.java
 
b/hudi-common/src/main/java/org/apache/hudi/internal/schema/utils/AvroSchemaEvolutionUtils.java
index 35ca13820f24..746dcf1fb124 100644
--- 
a/hudi-common/src/main/java/org/apache/hudi/internal/schema/utils/AvroSchemaEvolutionUtils.java
+++ 
b/hudi-common/src/main/java/org/apache/hudi/internal/schema/utils/AvroSchemaEvolutionUtils.java
@@ -115,7 +115,12 @@ public class AvroSchemaEvolutionUtils {
       typeChange.updateColumnType(col, inComingInternalSchema.findType(col));
     });
 
-    return 
SchemaChangeUtils.applyTableChanges2Schema(internalSchemaAfterAddColumns, 
typeChange);
+    InternalSchema evolvedSchema = 
SchemaChangeUtils.applyTableChanges2Schema(internalSchemaAfterAddColumns, 
typeChange);
+    // If evolvedSchema is exactly the same as the oldSchema, except the 
version number, return the old schema
+    if (evolvedSchema.equalsIgnoringVersion(oldTableSchema)) {
+      return oldTableSchema;
+    }
+    return evolvedSchema;
   }
 
   public static Schema reconcileSchema(Schema incomingSchema, Schema 
oldTableSchema) {
diff --git 
a/hudi-common/src/test/java/org/apache/hudi/internal/schema/utils/TestAvroSchemaEvolutionUtils.java
 
b/hudi-common/src/test/java/org/apache/hudi/internal/schema/utils/TestAvroSchemaEvolutionUtils.java
index 0be0a5f89c52..5f2439b85113 100644
--- 
a/hudi-common/src/test/java/org/apache/hudi/internal/schema/utils/TestAvroSchemaEvolutionUtils.java
+++ 
b/hudi-common/src/test/java/org/apache/hudi/internal/schema/utils/TestAvroSchemaEvolutionUtils.java
@@ -502,4 +502,27 @@ public class TestAvroSchemaEvolutionUtils {
         .reconcileSchema(incomingSchema, 
AvroInternalSchemaConverter.convert(schema)), "schemaNameFallback");
     Assertions.assertEquals(simpleReconcileSchema, simpleCheckSchema);
   }
+
+  @Test
+  public void testNotEvolveSchemaIfReconciledSchemaUnchanged() {
+    // a: boolean, c: long, c_1: long, d: date
+    Schema oldSchema = create("simple",
+        new Schema.Field("a", 
AvroInternalSchemaConverter.nullableSchema(Schema.create(Schema.Type.BOOLEAN)), 
null, JsonProperties.NULL_VALUE),
+        new Schema.Field("b", 
AvroInternalSchemaConverter.nullableSchema(Schema.create(Schema.Type.INT)), 
null, JsonProperties.NULL_VALUE),
+        new Schema.Field("c", 
AvroInternalSchemaConverter.nullableSchema(Schema.create(Schema.Type.LONG)), 
null, JsonProperties.NULL_VALUE),
+        new Schema.Field("d", 
AvroInternalSchemaConverter.nullableSchema(LogicalTypes.date().addToSchema(Schema.create(Schema.Type.INT))),
 null, JsonProperties.NULL_VALUE));
+    // incoming schema is part of old schema
+    // a: boolean, b: int, c: long
+    Schema incomingSchema = create("simple",
+        new Schema.Field("a", 
AvroInternalSchemaConverter.nullableSchema(Schema.create(Schema.Type.BOOLEAN)), 
null, JsonProperties.NULL_VALUE),
+        new Schema.Field("b", 
AvroInternalSchemaConverter.nullableSchema(Schema.create(Schema.Type.INT)), 
null, JsonProperties.NULL_VALUE),
+        new Schema.Field("c", 
AvroInternalSchemaConverter.nullableSchema(Schema.create(Schema.Type.LONG)), 
null, JsonProperties.NULL_VALUE));
+
+    InternalSchema oldInternalSchema = 
AvroInternalSchemaConverter.convert(oldSchema);
+    // set a non-default schema id for old table schema, e.g., 2.
+    oldInternalSchema.setSchemaId(2);
+    InternalSchema evolvedSchema = 
AvroSchemaEvolutionUtils.reconcileSchema(incomingSchema, oldInternalSchema);
+    // the evolved schema should be the old table schema, since there is no 
type change at all.
+    Assertions.assertEquals(oldInternalSchema, evolvedSchema);
+  }
 }

Reply via email to