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);
+ }
}