Parquet: Validate geospatial projection parameters - #17578
Conversation
Generated-by: Codex
There was a problem hiding this comment.
Pull request overview
Validates Parquet geospatial annotations against projected Iceberg types.
Changes:
- Reuses primitive-type conversion for validation.
- Rejects CRS and edge-algorithm mismatches.
- Adds focused geospatial projection tests.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
PruneColumns.java |
Validates projected geospatial parameters. |
MessageTypeToType.java |
Extracts reusable primitive conversion. |
TestPruneColumns.java |
Tests matching and mismatched parameters. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Generated-by: Codex
Generated-by: Codex
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (1)
parquet/src/main/java/org/apache/iceberg/parquet/ParquetSchemaUtil.java:165
- This validates only top-level primitives in the ID-less fallback path. When a selected top-level field is a struct, list, or map, the entire Parquet group is retained unchanged, so any projected nested geometry/geography still bypasses the new CRS/edge-algorithm check and can be read with incompatible parameters. Please traverse each matched group positionally against the projected type and validate its nested primitives as well; add a nested ID-less mismatch test to cover this path.
Types.NestedField expectedField = expectedSchema.findField(ordinal);
if (type.isPrimitive() && expectedField.type().isPrimitiveType()) {
PruneColumns.validatePrimitive(
expectedField.type().asPrimitiveType(), type.asPrimitiveType());
|
@huan233usc Please take a look, thanks! |
anoopj
left a comment
There was a problem hiding this comment.
Code change LGTM. Just one comment in the test.
Generated-by: Codex
|
@szehon-ho @singhpk234 Could you please take a look? Thanks! |
uros-b
left a comment
There was a problem hiding this comment.
The validation itself is sound, CI is clean, and there's no backward-compat risk. Leaving a few comments for things that could be worth resolving before merge. Thank you @manuzhang for working on this! And thank you @anoopj and @huan233usc for reviewing the changes!
| int ordinal = 1; | ||
| for (Type type : fileSchema.getFields()) { | ||
| if (selectedIds.contains(ordinal)) { | ||
| Types.NestedField expectedField = expectedSchema.findField(ordinal); |
There was a problem hiding this comment.
Nested types in the fallback path - ParquetSchemaUtil.java:162-171 (pruneColumnsFallback) validates only top-level primitives: the type.isPrimitive() && expectedField.type().isPrimitiveType() guard skips any top-level struct/list/map that contains a nested geometry/geography field, so CRS/algorithm go unchecked on the id-less path (the id-based PruneColumns visitor reaches nested types fine via recursive descent). Either recurse positionally against the projected type, or add an explicit comment documenting the top-level-only scope.
| && (expected.typeId() == TypeID.GEOMETRY || expected.typeId() == TypeID.GEOGRAPHY)) { | ||
| Preconditions.checkArgument( | ||
| TypeUtil.isPromotionAllowed(MessageTypeToType.convertPrimitive(primitive), expected), | ||
| "Cannot read Parquet type %s as Iceberg type %s", |
There was a problem hiding this comment.
Column name in the error - PruneColumns.java:179: "Cannot read Parquet type %s as Iceberg type %s" omits the column name, so on a wide table the user can't tell which field mismatched. TypeWithSchemaVisitor exposes currentPath() (the fieldNames deque, ~line 254) that primitive() can use to include the path, per AGENTS.md:119 (actionable messages).
|
And definitely cc @szehon-ho here for further review, given the context in GeoSpatial. |
Summary
Context
Parquet geospatial values carry their CRS and edge interpolation algorithm in the logical-type annotation rather than in the WKB payload.
PruneColumnspreviously ignored these parameters, so a file could be interpreted using incompatible parameters from the projected Iceberg schema.This is the Java-side counterpart discovered while reviewing apache/iceberg-cpp#880.
Testing
./gradlew :iceberg-parquet:test --tests org.apache.iceberg.parquet.TestPruneColumns./gradlew :iceberg-parquet:spotlessJavaCheckgit diff --checkAI Disclosure