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

pvary pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git


The following commit(s) were added to refs/heads/main by this push:
     new 001f4e4852 API: Propagate allowMissing to nested structs in 
StructProjection (#17052)
001f4e4852 is described below

commit 001f4e485285cabbbd123e86889df93150da6b1d
Author: Eunbin Son <[email protected]>
AuthorDate: Thu Jul 30 17:31:45 2026 +0900

    API: Propagate allowMissing to nested structs in StructProjection (#17052)
---
 .../org/apache/iceberg/util/StructProjection.java  |  4 +-
 .../apache/iceberg/util/TestStructProjection.java  | 72 ++++++++++++++++++++++
 2 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/api/src/main/java/org/apache/iceberg/util/StructProjection.java 
b/api/src/main/java/org/apache/iceberg/util/StructProjection.java
index 08dedf0fe1..9db90a061c 100644
--- a/api/src/main/java/org/apache/iceberg/util/StructProjection.java
+++ b/api/src/main/java/org/apache/iceberg/util/StructProjection.java
@@ -123,7 +123,9 @@ public class StructProjection implements StructLike {
             case STRUCT:
               nestedProjections[pos] =
                   new StructProjection(
-                      dataField.type().asStructType(), 
projectedField.type().asStructType());
+                      dataField.type().asStructType(),
+                      projectedField.type().asStructType(),
+                      allowMissing);
               break;
             case MAP:
               MapType projectedMap = projectedField.type().asMapType();
diff --git 
a/api/src/test/java/org/apache/iceberg/util/TestStructProjection.java 
b/api/src/test/java/org/apache/iceberg/util/TestStructProjection.java
new file mode 100644
index 0000000000..579918c755
--- /dev/null
+++ b/api/src/test/java/org/apache/iceberg/util/TestStructProjection.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iceberg.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.Set;
+import org.apache.iceberg.StructLike;
+import org.apache.iceberg.TestHelpers.Row;
+import org.apache.iceberg.types.TypeUtil;
+import org.apache.iceberg.types.Types;
+import org.apache.iceberg.types.Types.NestedField;
+import org.apache.iceberg.types.Types.StructType;
+import org.junit.jupiter.api.Test;
+
+class TestStructProjection {
+
+  // projected schema asks for the optional "middle" field nested inside 
"person"
+  private static final StructType PROJECTED_STRUCT =
+      StructType.of(
+          NestedField.required(1, "id", Types.LongType.get()),
+          NestedField.required(
+              2,
+              "person",
+              StructType.of(
+                  NestedField.required(3, "first", Types.StringType.get()),
+                  NestedField.optional(4, "middle", Types.StringType.get()),
+                  NestedField.required(5, "last", Types.StringType.get()))));
+
+  // data schema is missing the optional "middle" field inside the nested 
"person" struct
+  private static final StructType DATA_STRUCT_MISSING_NESTED_FIELD =
+      TypeUtil.selectNot(PROJECTED_STRUCT, Set.of(4));
+
+  @Test
+  void createAllowMissingAllowsMissingOptionalFieldInNestedStruct() {
+    Row row = Row.of(1L, Row.of("John", "Doe"));
+
+    StructProjection projection =
+        StructProjection.createAllowMissing(DATA_STRUCT_MISSING_NESTED_FIELD, 
PROJECTED_STRUCT);
+    projection.wrap(row);
+
+    StructLike projectedPerson = projection.get(1, StructLike.class);
+    assertThat(projectedPerson.get(0, String.class)).isEqualTo("John");
+    assertThat(projectedPerson.get(1, String.class)).isNull();
+    assertThat(projectedPerson.get(2, String.class)).isEqualTo("Doe");
+  }
+
+  @Test
+  void createStillThrowsForMissingOptionalFieldInNestedStruct() {
+    assertThatThrownBy(
+            () -> StructProjection.create(DATA_STRUCT_MISSING_NESTED_FIELD, 
PROJECTED_STRUCT))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessageStartingWith("Cannot find field");
+  }
+}

Reply via email to