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

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


The following commit(s) were added to refs/heads/master by this push:
     new ba7fec94b9 [common] Reject non-struct inner fields in variant 
shredding schema (#9518)
ba7fec94b9 is described below

commit ba7fec94b926ac2841e06ba6c4bbec24a8f964e2
Author: YangJie <[email protected]>
AuthorDate: Wed Sep 2 02:41:16 2026 -0400

    [common] Reject non-struct inner fields in variant shredding schema (#9518)
---
 .../paimon/data/variant/PaimonShreddingUtils.java  | 14 ++++++-------
 .../data/variant/PaimonShreddingUtilsTest.java     | 24 ++++++++++++++++++++++
 2 files changed, 30 insertions(+), 8 deletions(-)

diff --git 
a/paimon-common/src/main/java/org/apache/paimon/data/variant/PaimonShreddingUtils.java
 
b/paimon-common/src/main/java/org/apache/paimon/data/variant/PaimonShreddingUtils.java
index 1fa297b0cb..371baaac44 100644
--- 
a/paimon-common/src/main/java/org/apache/paimon/data/variant/PaimonShreddingUtils.java
+++ 
b/paimon-common/src/main/java/org/apache/paimon/data/variant/PaimonShreddingUtils.java
@@ -346,19 +346,17 @@ public class PaimonShreddingUtils {
                     typedIdx = i;
                     switch (field.type().getTypeRoot()) {
                         case ROW:
-                            if (!(dataType instanceof RowType)) {
-                                throw invalidVariantShreddingSchema(rowType);
-                            }
                             RowType r = (RowType) dataType;
                             List<DataField> rFields = r.getFields();
-                            // The struct must not be empty or contain 
duplicate field names.
-                            if (fields.isEmpty()
-                                    || fields.stream().distinct().count() != 
fields.size()) {
-                                throw invalidVariantShreddingSchema(rowType);
-                            }
+                            // Every field of an object's typed_value is 
itself a
+                            // value/typed_value struct. An empty struct 
shreds nothing and
+                            // stays legal.
                             objectSchema = new 
VariantSchema.ObjectField[rFields.size()];
                             for (int index = 0; index < rFields.size(); 
index++) {
                                 DataField f = rFields.get(index);
+                                if (!(f.type() instanceof RowType)) {
+                                    throw 
invalidVariantShreddingSchema(rowType);
+                                }
                                 objectSchema[index] =
                                         new VariantSchema.ObjectField(
                                                 f.name(),
diff --git 
a/paimon-common/src/test/java/org/apache/paimon/data/variant/PaimonShreddingUtilsTest.java
 
b/paimon-common/src/test/java/org/apache/paimon/data/variant/PaimonShreddingUtilsTest.java
index 14ae33c4ab..19ebca4fbf 100644
--- 
a/paimon-common/src/test/java/org/apache/paimon/data/variant/PaimonShreddingUtilsTest.java
+++ 
b/paimon-common/src/test/java/org/apache/paimon/data/variant/PaimonShreddingUtilsTest.java
@@ -64,6 +64,30 @@ import static 
org.assertj.core.api.Assertions.assertThatThrownBy;
 /** Test for PaimonShreddingUtils. */
 public class PaimonShreddingUtilsTest {
 
+    @Test
+    void testBuildVariantSchemaAcceptsEmptyInnerStruct() {
+        // An empty typed_value struct shreds no field, and stays a legal 
schema.
+        RowType physicalType = variantShreddingSchema(RowType.of(new 
DataType[0], new String[0]));
+        assertThat(buildVariantSchema(physicalType).objectSchema).isEmpty();
+    }
+
+    @Test
+    void testBuildVariantSchemaRejectsNonStructInnerField() {
+        RowType physicalType =
+                RowType.of(
+                        new DataType[] {
+                            DataTypes.BYTES(),
+                            DataTypes.BYTES(),
+                            RowType.of(new DataType[] {DataTypes.INT()}, new 
String[] {"x"})
+                        },
+                        new String[] {"metadata", "value", "typed_value"});
+        // Everything except the inner field's type is valid here, and the 
message is what
+        // separates the two outcomes: before, the cast below raised a bare 
ClassCastException.
+        assertThatThrownBy(() -> buildVariantSchema(physicalType))
+                .isInstanceOf(RuntimeException.class)
+                .hasMessageContaining("Invalid variant shredding schema");
+    }
+
     @Test
     void testAssembleColumnarShreddedVariant() {
         RowType shreddedType = RowType.of(new DataType[] {DataTypes.INT()}, 
new String[] {"a"});

Reply via email to