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