[#11951] feat(iceberg): map V3 unknown type to Gravitino NullType - #11969
Conversation
Iceberg V3's `unknown` (null-only placeholder) column type previously
loaded through the native API as ExternalType("UNKNOWN"). Map it to
Gravitino's existing NullType instead - the same equivalence Iceberg's
own engine converters use (unknown <-> Spark NullType / Flink NULL /
Arrow null).
- FromIcebergType: unknown -> NullType.
- ToIcebergType / ToIcebergTypeVisitor: NullType -> unknown, via a
dedicated nullType() dispatch hook since NullType is not a
PrimitiveType; reject a required (non-null) unknown column per the
Iceberg spec.
- docs: unified type reference, Iceberg type-mapping table, OpenAPI
primitive-type examples.
- tests: TestConvertUtil (converter + write-path); CatalogIcebergBaseIT
IRC<->native round-trip in both directions.
Builds on the merged variant (apache#11932) and format-version (apache#11954) support.
…nknown-type-3ee7bb # Conflicts: # catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/converter/FromIcebergType.java # catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/converter/TestConvertUtil.java # catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/integration/test/CatalogIcebergBaseIT.java # docs/lakehouse-iceberg-catalog.md # docs/manage-relational-metadata-using-gravitino.md # docs/open-api/datatype.yaml
There was a problem hiding this comment.
Pull request overview
This PR adds native support in the Iceberg catalog for Iceberg V3’s unknown column type by mapping it to Gravitino’s existing Types.NullType, enabling round-trip conversion through both the native metadata API and the Iceberg REST (IRC) surface.
Changes:
- Add Iceberg
unknown⇄ GravitinoNullTypeconversions in the Iceberg type converters, including a dedicated visitor dispatch forNullType. - Enforce Iceberg spec constraints on write: reject required (non-nullable)
unknowncolumns; allow nullableNullTypeto write as Icebergunknown(format-version 3). - Add unit + integration tests and update docs/OpenAPI type references to include
null/unknownmapping.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| docs/open-api/datatype.yaml | Adds null to primitive type examples; adjusts OpenAPI examples for type docs. |
| docs/manage-relational-metadata-using-gravitino.md | Documents NullType semantics and JSON token null. |
| docs/lakehouse-iceberg-catalog.md | Updates Iceberg type mapping table and documents Null ⇄ Iceberg V3 unknown constraints. |
| catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/integration/test/CatalogIcebergBaseIT.java | Adds REST-backend IT coverage for unknown read/write round-trips across native and IRC surfaces. |
| catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/converter/TestConvertUtil.java | Adds unit tests for bidirectional conversion and write-path validation (required unknown rejected). |
| catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/converter/ToIcebergTypeVisitor.java | Adds explicit dispatch hook for Types.NullType (since it is not a PrimitiveType). |
| catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/converter/ToIcebergType.java | Implements NullType → Iceberg UnknownType conversion and enforces optionality for unknown. |
| catalogs/catalog-lakehouse-iceberg/src/main/java/org/apache/gravitino/catalog/lakehouse/iceberg/converter/FromIcebergType.java | Maps Iceberg UNKNOWN to Gravitino Types.NullType. |
Code Coverage Report
Files
|
mchades
left a comment
There was a problem hiding this comment.
please resolve the copilot comment
|
lgtm. please resolve the conflicts |
|
@mchades @roryqi, the conflict with the latest
The refreshed GitHub Actions runs are currently marked |
What changes were proposed in this pull request?
Map Iceberg V3's
unknowntype to Gravitino's existingTypes.NullType, so anunknowncolumn loads through the native metadata API as a first-classnulltype instead of theExternalType("UNKNOWN")stopgap it resolves to today.catalog-lakehouse-iceberg:FromIcebergTypemapsunknown → NullType;ToIcebergType/ToIcebergTypeVisitormapNullType → unknown(via anullType()dispatch hook, sinceNullTypeisn't aPrimitiveType), and reject a required (non-nullable)unknowncolumn per the Iceberg spec.Null typesection), Iceberg type-mapping table, OpenAPI examples.No new
apitype and nocommon/Python serde change —NullTypealready exists, round-trips as the JSON token"null", and is already mapped for Spark, Flink, Lance, and CLI (the Python client decodes"null"toNullTypewith no change).Builds on the merged native
variantsupport (#11932) and format-version-3 support (#11954).Fixes #11951
Why are the changes needed?
Loading an Iceberg V3 table with an
unknowncolumn through the native API resolves it toExternalType("UNKNOWN")— opaque (nothing can branch on it), not writable back, and external types have caused downstream problems (unqueryable via Trino #10957;catalogString()written verbatim into DDL #11805).unknownis the universal null/void column type — Iceberg's own converters map it to each engine's null type (SparkNullType, FlinkNULL, Arrownull) — and Gravitino already models that asNullType, so this is just the missing wiring.Does this PR introduce any user-facing change?
Yes — Iceberg V3 tables with an
unknowncolumn now load through the native API asnull(previouslyexternal(UNKNOWN)), and anull-typed column can be written to a format-version-3 Iceberg table. Other connectors are unchanged. Connector propagation (reject-with-test for engines without a null-type equivalent) is a planned follow-up.How was this patch tested?
TestConvertUtil):testUnknownType(converter both directions) andtestUnknownColumnToIcebergSchema(write path → optionalunknownfield; required column rejected).CatalogIcebergRestIT, passing) — both cross-surface directions between the Iceberg REST (IRC) API and the native metadata API:testV3TypeConversionViaIcebergClient: IRC writes anunknowncolumn → the native API reads it back asNullType.testCreateUnknownColumnWriteRoundTrip: the native API writes aNullTypecolumn at format-version 3 → native reload returnsNullType, and the IRC reads the same table back as Icebergunknown.