This is an automated email from the ASF dual-hosted git repository. singhpk234 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 be03c998d9 Core: Use safeContainsKey to avoid NPE for CountNonNull (#13980) be03c998d9 is described below commit be03c998d96d0d1fae13aa8c53d6c7c87e2d60ba Author: jackylee <qcsd2...@gmail.com> AuthorDate: Thu Sep 4 08:50:03 2025 +0800 Core: Use safeContainsKey to avoid NPE for CountNonNull (#13980) --- .../apache/iceberg/expressions/CountNonNull.java | 2 +- .../expressions/TestAggregateEvaluator.java | 34 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/iceberg/expressions/CountNonNull.java b/api/src/main/java/org/apache/iceberg/expressions/CountNonNull.java index ecc83c9ef6..2b8708b10b 100644 --- a/api/src/main/java/org/apache/iceberg/expressions/CountNonNull.java +++ b/api/src/main/java/org/apache/iceberg/expressions/CountNonNull.java @@ -40,7 +40,7 @@ public class CountNonNull<T> extends CountAggregate<T> { @Override protected boolean hasValue(DataFile file) { return safeContainsKey(file.valueCounts(), fieldId) - && file.nullValueCounts().containsKey(fieldId); + && safeContainsKey(file.nullValueCounts(), fieldId); } @Override diff --git a/api/src/test/java/org/apache/iceberg/expressions/TestAggregateEvaluator.java b/api/src/test/java/org/apache/iceberg/expressions/TestAggregateEvaluator.java index aa15d36de3..384836ec30 100644 --- a/api/src/test/java/org/apache/iceberg/expressions/TestAggregateEvaluator.java +++ b/api/src/test/java/org/apache/iceberg/expressions/TestAggregateEvaluator.java @@ -91,6 +91,22 @@ public class TestAggregateEvaluator { // upper bounds ImmutableMap.of(1, toByteBuffer(IntegerType.get(), 3333))); + private static final DataFile MISSING_SOME_STATS = + new TestDataFile( + "file_missing_stats.avro", + Row.of(), + 20, + // any value counts, including nulls + ImmutableMap.of(1, 20L, 4, 10L), + // null value counts + null, + // nan value counts + null, + // lower bounds + ImmutableMap.of(1, toByteBuffer(IntegerType.get(), -3)), + // upper bounds + ImmutableMap.of(1, toByteBuffer(IntegerType.get(), 1333))); + private static final DataFile[] DATA_FILES = { FILE, MISSING_SOME_NULLS_STATS_1, MISSING_SOME_NULLS_STATS_2 }; @@ -225,6 +241,24 @@ public class TestAggregateEvaluator { assertEvaluatorResult(result, expected); } + @Test + public void testMissingSomeStats() { + List<Expression> list = + ImmutableList.of( + Expressions.countStar(), + Expressions.count("some_nulls"), + Expressions.max("some_nulls"), + Expressions.min("some_nulls")); + AggregateEvaluator aggregateEvaluator = AggregateEvaluator.create(SCHEMA, list); + + aggregateEvaluator.update(MISSING_SOME_STATS); + + assertThat(aggregateEvaluator.allAggregatorsValid()).isFalse(); + StructLike result = aggregateEvaluator.result(); + Object[] expected = {20L, null, null, null}; + assertEvaluatorResult(result, expected); + } + private void assertEvaluatorResult(StructLike result, Object[] expected) { Object[] actual = new Object[result.size()]; for (int i = 0; i < result.size(); i++) {