diff --git a/core/src/test/java/org/apache/iceberg/TestMetrics.java b/core/src/test/java/org/apache/iceberg/TestMetrics.java index feffc184770e..095feb29382f 100644 --- a/core/src/test/java/org/apache/iceberg/TestMetrics.java +++ b/core/src/test/java/org/apache/iceberg/TestMetrics.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.math.BigDecimal; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.Path; @@ -257,6 +258,37 @@ public void testMetricsForTopLevelFields() throws IOException { } } + @TestTemplate + public void testMetricsForGeospatialTypes() throws IOException { + // Geometry and geography are only written by the Parquet path; other formats do not support + // the geo types yet. + assumeThat(fileFormat()).isEqualTo(FileFormat.PARQUET); + + Schema schema = + new Schema( + required(1, "id", LongType.get()), + optional(2, "geom", Types.GeometryType.crs84()), + optional(3, "geog", Types.GeographyType.crs84())); + + Record first = GenericRecord.create(schema); + first.setField("id", 1L); + first.setField("geom", wkbPoint(30, 10)); + first.setField("geog", wkbPoint(-5, 40)); + Record second = GenericRecord.create(schema); + second.setField("id", 2L); + // both geo columns are left null + + Metrics metrics = getMetrics(schema, first, second); + assertThat(metrics.recordCount()).isEqualTo(2L); + + // geometry and geography keep value/null counts but no bounds: lexicographic WKB min/max is not + // meaningful, so bounds are intentionally skipped (spatial bounds are a separate follow-up). + assertCounts(2, 2L, 1L, metrics); + assertBounds(2, Types.GeometryType.crs84(), null, null, metrics); + assertCounts(3, 2L, 1L, metrics); + assertBounds(3, Types.GeographyType.crs84(), null, null, metrics); + } + @TestTemplate public void testMetricsForDecimals() throws IOException { Schema schema = @@ -761,6 +793,18 @@ public void testMetricsForSortedNestedStructFields() throws IOException { assertBounds(5, LongType.get(), Long.MAX_VALUE, Long.MAX_VALUE, metrics); } + private static ByteBuffer wkbPoint(double xCoord, double yCoord) { + // little-endian WKB encoding of a point + return ByteBuffer.wrap( + ByteBuffer.allocate(21) + .order(ByteOrder.LITTLE_ENDIAN) + .put((byte) 1) // byte order: little endian + .putInt(1) // WKB geometry type: Point + .putDouble(xCoord) + .putDouble(yCoord) + .array()); + } + protected void assertCounts(int fieldId, Long valueCount, Long nullValueCount, Metrics metrics) { assertCounts(fieldId, valueCount, nullValueCount, null, metrics); }