Skip to content

feat(spec): add unknown datatype support - #1

Open
manuzhang wants to merge 1 commit into
mainfrom
add-unknown-datatype
Open

feat(spec): add unknown datatype support#1
manuzhang wants to merge 1 commit into
mainfrom
add-unknown-datatype

Conversation

@manuzhang

@manuzhang manuzhang commented May 6, 2026

Copy link
Copy Markdown
Owner

Which issue does this PR close?

No issue is currently linked.

What changes are included in this PR?

This is the first and independently mergeable layer of the Unknown-type work. It now contains only the Iceberg v3 logical type and format conversions:

  • Adds PrimitiveType::Unknown parsing, serialization, schema/default validation, format-version checks, and public API support.
  • Maps Arrow Null and Avro null to the Unknown type and preserves null-only values.
  • Reports Unknown as unsupported in Glue and Hive schema conversion.

This is the root of GitHub stack apache#8:

  1. Logical type and conversions: this PR
  2. Parquet writes: #5
  3. Parquet reads and reconstruction: #6

Are these changes tested?

  • This PR: cargo test -p iceberg --lib (1,588 passed)
  • Full three-PR stack: cargo test -p iceberg --lib (1,610 passed)
  • Full stack: make check-fmt
  • Full stack: make check-clippy
  • git diff --check for every split commit

AI Disclosure

OpenAI Codex was used for implementation, regression-test scaffolding, review-feedback follow-up, and splitting the original change into independently reviewable commits. The resulting changes were reviewed against repository conventions and validated with the test and lint coverage listed above.

@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

ensure_data_valid!(
field.initial_default.is_none() && field.write_default.is_none(),

P2 Badge Reject non-null defaults during unknown-field deserialization

When table metadata JSON contains an unknown field with initial-default or write-default set to a non-null value, this check still lets it through: SerdeNestedField::from parses defaults with Literal::try_from_json(...).ok().and_then(identity), so the parse error for an unknown/non-null default is converted to None before SchemaBuilder::build reaches this validation. That means invalid metadata is silently accepted despite the new rule; the validation needs to inspect/preserve the raw non-null default during deserialization or make default parsing errors fail the schema build.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@manuzhang

Copy link
Copy Markdown
Owner Author

@codex fix test failure

@chatgpt-codex-connector

Copy link
Copy Markdown

Summary

  • Switched NestedField deserialization from lossy From conversion to fallible TryFrom, preserving Literal::try_from_json errors for initial-default and write-default instead of converting invalid defaults to None.
  • Added regression tests that reject a non-null JSON default on an unknown field and accept explicit null defaults.

Testing

  • cargo fmt --check
  • cargo test -p iceberg --lib test_unknown_type

Committed the changes with commit 038908d and created a PR titled fix(spec): reject invalid nested field defaults.

View task →

@manuzhang

manuzhang commented May 7, 2026

Copy link
Copy Markdown
Owner Author

@codex check review comments and fix test failure

@chatgpt-codex-connector

Copy link
Copy Markdown

Summary

  • Stabilized SetExpression formatting by sorting set literals before joining them for IN / NOT IN display output, avoiding nondeterministic FnvHashSet iteration order in tests and diagnostics.
  • Updated predicate binding expectations to assert the new deterministic set literal order.
  • Updated strict projection expectations for deterministic IN / NOT IN output across temporal, bucket, and truncate projections.
  • Updated transform projection test expectations to match deterministic set ordering for bucket, temporal, and truncate projections.

Committed the changes as 32be246 and created a follow-up PR titled fix(tests): stabilize set predicate formatting.

Testing

  • cargo test -p iceberg --lib test_unknown_type -- --nocapture
  • cargo fmt --check
  • cargo test -p iceberg --lib
  • git diff --check

View task →

@manuzhang manuzhang closed this May 7, 2026
@manuzhang manuzhang reopened this May 7, 2026
@manuzhang
manuzhang force-pushed the add-unknown-datatype branch 3 times, most recently from 013362e to 043dbd5 Compare May 7, 2026 15:28
@manuzhang

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 043dbd5bb4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/spec/schema/mod.rs
@manuzhang

Copy link
Copy Markdown
Owner Author

@codex

When this validation passes, Schema::builder() now accepts unknown fields, but TableCreation still defaults to FormatVersion::V2 and TableMetadataBuilder::add_schema has no format-version gate. In the scenario where a caller creates or adds a schema containing an optional unknown field without explicitly upgrading to v3, the library will serialize a v1/v2 table metadata file containing a v3-only type, which other Iceberg readers can reject. Please reject unknown unless the table format is v3, or upgrade the metadata before committing it.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 043dbd5bb4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/spec/schema/mod.rs
@manuzhang
manuzhang force-pushed the add-unknown-datatype branch 2 times, most recently from 3e9e57e to 89e1ac1 Compare July 6, 2026 07:30
@manuzhang
manuzhang requested a review from Copilot July 6, 2026 07:33

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end support for Iceberg’s unknown primitive type across the Rust type system and its integration layers (Arrow, Avro, catalogs), while also tightening format-version validation (notably for v3-only nanosecond timestamps) and stabilizing predicate display ordering for deterministic tests.

Changes:

  • Introduces PrimitiveType::Unknown plus schema-level validation rules (must be optional; defaults must be null/absent) and propagates it through Arrow/Avro conversion paths as null-only.
  • Adds schema/type compatibility validation against table format version during metadata normalization and schema additions; derives a minimum required format version from schema types to set table creation format version when needed.
  • Makes set-predicate stringification deterministic by sorting literal lists (updating many expected strings in transform/projection tests).

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
crates/integrations/datafusion/src/schema.rs Uses schema-derived minimum format version (e.g., timestamp_ns ⇒ v3) when registering tables; adds a regression test for v3 selection.
crates/iceberg/src/transform/truncate.rs Updates expected IN (...) ordering in tests to match deterministic literal ordering.
crates/iceberg/src/transform/temporal.rs Updates expected IN (...) ordering in tests to match deterministic literal ordering across temporal transforms.
crates/iceberg/src/transform/bucket.rs Updates expected IN (...) ordering in tests to match deterministic literal ordering for bucket transforms.
crates/iceberg/src/spec/values/datum.rs Rejects constructing datums from bytes for unknown (feature unsupported).
crates/iceberg/src/spec/table_metadata.rs Validates all schemas are compatible with table format version during normalization; adds tests for v3-only types rejected in v2 metadata/builder flows.
crates/iceberg/src/spec/table_metadata_builder.rs Validates schemas added via builder are compatible with the table format version.
crates/iceberg/src/spec/schema/mod.rs Enforces unknown-field constraints at schema build; adds min-format-version calculation and format-version compatibility validation; adds tests.
crates/iceberg/src/spec/datatypes.rs Adds PrimitiveType::Unknown, format-version requirement helpers, and makes NestedField deserialization fallible to enforce default validation.
crates/iceberg/src/expr/visitors/strict_projection.rs Updates expected predicate strings due to deterministic literal ordering.
crates/iceberg/src/expr/predicate.rs Sorts set-expression literals for deterministic Display; updates tests accordingly.
crates/iceberg/src/avro/schema.rs Maps unknown to Avro null and adjusts optional/union handling to avoid null-of-null; roundtrip tests added.
crates/iceberg/src/arrow/value.rs Converts unknown values to null literals; adds Arrow Null handling for constant array creation.
crates/iceberg/src/arrow/schema.rs Maps Arrow DataType::Null ⇔ Iceberg PrimitiveType::Unknown; adds roundtrip tests.
crates/iceberg/src/arrow/reader/projection.rs Treats unknown as non-leaf (no parquet column read) and compatible with any file primitive type.
crates/iceberg/public-api.txt Records Schema::min_format_version in the public API surface.
crates/catalog/hms/src/schema.rs Rejects Hive schema conversion for unknown (feature unsupported).
crates/catalog/glue/src/schema.rs Rejects Glue schema conversion for unknown (feature unsupported).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/iceberg/src/arrow/value.rs
Comment thread crates/iceberg/src/spec/schema/mod.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.

Comment thread crates/iceberg/src/expr/predicate.rs Outdated
Comment thread crates/iceberg/src/spec/schema/mod.rs Outdated
@manuzhang
manuzhang force-pushed the add-unknown-datatype branch from b062b0e to 073000a Compare July 22, 2026 16:04

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 073000a0a9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/transaction/snapshot.rs
Comment thread crates/iceberg/src/arrow/schema.rs
Comment thread crates/iceberg/src/spec/schema/mod.rs
Comment thread crates/iceberg/src/spec/table_metadata.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bac2002d27

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/spec/datatypes.rs Outdated
Comment thread crates/iceberg/src/arrow/schema.rs Outdated
Comment thread crates/iceberg/src/spec/manifest/writer.rs Outdated
Comment thread crates/iceberg/src/arrow/schema.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0a16bfa828

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/writer/file_writer/parquet_writer.rs Outdated
Comment thread crates/iceberg/src/arrow/schema.rs Outdated
Comment thread crates/iceberg/src/arrow/reader/projection.rs Outdated
@manuzhang
manuzhang force-pushed the add-unknown-datatype branch from 0a16bfa to 0144610 Compare July 23, 2026 11:02

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0144610405

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/arrow/record_batch_transformer.rs Outdated
Comment thread crates/iceberg/src/arrow/reader/projection.rs Outdated
@manuzhang
manuzhang force-pushed the add-unknown-datatype branch from 8f892c3 to 7e87c07 Compare August 18, 2026 10:36

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7e87c076ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +364 to +368
.or_else(|| {
source.fields().iter().position(|source_field| {
source_field.name() == target_field.name()
})
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Honor nested field IDs during unknown reconstruction

When a projected struct contains an unknown child, the new recursive transformer runs for the entire struct; if an old nested field was deleted and a new field later reused its name with a different ID, the ID lookup correctly misses but this unconditional name fallback selects the deleted field's physical column. The scan then returns stale values for the newly added field instead of its initial default/null. Only use name/position fallback when the source nested fields do not carry IDs; when IDs are present, a missing target ID must remain missing.

Useful? React with 👍 / 👎.

@manuzhang
manuzhang force-pushed the add-unknown-datatype branch from 7e87c07 to e379217 Compare August 18, 2026 11:02

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c7985d4a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/spec/schema/mod.rs Outdated
Comment on lines +205 to +206
ensure_data_valid!(
field.initial_default.is_none() && field.write_default.is_none(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate unknown values inside container defaults

When a struct/list/map field has a default containing a non-null value at a nested unknown position, this validator only checks defaults attached directly to the unknown child, so the schema passes validation. Programmatic metadata serialization then reaches the try_into_json(...).expect(...) path in NestedField serialization and panics when that nested value cannot be converted to unknown; inspect enclosing container defaults recursively and reject any non-null unknown value during schema construction.

Useful? React with 👍 / 👎.

let props = WriterProperties::builder()
.set_content_defined_chunking(cdc)
.set_compression(compression)
.set_max_row_group_bytes(Some(table_props.parquet_row_group_size_bytes))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject zero row-group byte limits

When write.parquet.row-group-size-bytes=0, TableProperties::try_from accepts the value as a usize, but this call passes Some(0) to parquet-rs, whose set_max_row_group_bytes contract panics for zero. Thus ordinary table configuration can crash ParquetWriterBuilder::from_table_properties instead of returning its advertised Result; validate the value as positive before invoking the setter.

Useful? React with 👍 / 👎.

Comment on lines +813 to +815
self.client
.get_or_try_init(|| async {
RestClient::init(&self.user_config, self.resolve_auth_manager()?).await

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Scope REST authentication to each session context

In the advertised multi-session use case, callers can pass contexts with different identities or credentials, but every operation ignores that context and resolves this single catalog-wide RestClient and authentication session. Consequently all principals' requests use the same catalog token and configuration, so RestSessionCatalog cannot authenticate or isolate the different sessions it is intended to serve; derive or cache authentication per SessionContext rather than once per catalog.

AGENTS.md reference: AGENTS.md:L25-L30

Useful? React with 👍 / 👎.

let compression = match codec {
CompressionCodec::None => Compression::UNCOMPRESSED,
CompressionCodec::Snappy => Compression::SNAPPY,
CompressionCodec::Lzo => Compression::LZO,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject LZO before constructing the Parquet writer

When write.parquet.compression-codec=lzo, property parsing advertises the value as supported and this branch successfully returns Compression::LZO, but parquet-rs only defines the enum value and has no LZO codec implementation, so the first non-empty write fails with an unsupported-codec error. Reject LZO from from_table_properties with FeatureUnsupported (or implement the codec) rather than returning a writer that cannot write any data.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a53f89acac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +786 to +787
let config = &self.user_config;
let auth_type = Self::auth_type(config);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Re-resolve OAuth after merging server configuration

When the client properties contain no OAuth hints but GET /v1/config supplies rest.auth.type=oauth2, a token, or a credential, this resolves NoopAuthManager from user_config before the handshake. Although the response is subsequently merged, NoopAuthManager::catalog_session ignores those merged authentication properties, so every later catalog request is sent unauthenticated. Resolve the catalog-session manager from the merged configuration while retaining the separately selected init session.

Useful? React with 👍 / 👎.


// If the storage location is within the table prefix, files are already scoped to this
// table so there is no need to add database/table context to avoid collisions.
let context = if storage_location.starts_with(table_location) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require a path boundary for table-local storage

When an external object-storage path merely shares the table location's textual prefix, such as table s3://bucket/db/table with write.object-storage.path=s3://bucket/db/table-data, starts_with incorrectly classifies it as inside the table. The generator then omits the database/table context that external shared locations require, producing a layout that differs from the Java-compatible provider and can collide with another table using the same external location. Compare complete path segments rather than an arbitrary string prefix.

Useful? React with 👍 / 👎.

Comment on lines +1183 to +1187
if fields.is_empty() {
let nulls = arrow_buffer::NullBuffer::new_null(num_rows);
return Ok(Arc::new(StructArray::new_empty_fields(
num_rows,
Some(nulls),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep empty partition structs non-null

When _partition is projected from an unpartitioned table, its unified type has no children and this validity buffer marks the struct null for every row. Iceberg declares _partition as a required struct, so an unpartitioned row should contain a valid empty struct rather than null; the current result changes queries such as _partition IS NULL and contradicts the metadata-column schema. Construct the empty StructArray without an all-null validity buffer and keep the output field non-nullable.

Useful? React with 👍 / 👎.

@manuzhang manuzhang closed this Aug 20, 2026
@manuzhang manuzhang reopened this Aug 20, 2026
@manuzhang manuzhang closed this Aug 20, 2026
@manuzhang manuzhang reopened this Aug 20, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fccee71386

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +473 to +476
sqlx::query(&migration_sql)
.execute(&pool)
.await
.map_err(from_sqlx_error)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Serialize concurrent V0 schema migrations

When multiple catalog instances start concurrently with sql.schema-version=V1 against the same V0 database, they can both detect V0 before either executes this ALTER TABLE; the first succeeds, while the second receives a duplicate-column or schema-lock error and fails catalog initialization. Make the migration atomic/idempotent, or re-detect and accept V1 after the expected concurrent-migration error.

Useful? React with 👍 / 👎.

Comment on lines +80 to +81
match field.field_type.as_ref() {
Type::Primitive(PrimitiveType::Unknown) => {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid full-file reads for unknown-only projections

When a scan projects only an unknown field, this produces no physical leaf IDs, and get_arrow_projection_mask_with_field_ids consequently falls back to ProjectionMask::all() to recover the row count. Because an unknown field is absent from every compliant Parquet file, such a projection unnecessarily decodes every physical column in every file; use a row-count virtual column or another minimal row-count source instead of selecting all leaves.

Useful? React with 👍 / 👎.

Comment on lines +57 to +60
} else {
schema
.field_by_name_case_insensitive(column_name)
.map(|field| field.id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject ambiguous case-insensitive column matches

When a valid schema contains names that differ only by case, such as id and ID, a case-insensitive scan now resolves through lowercase_name_to_id, whose construction silently overwrites one of those entries in nondeterministic HashMap iteration order. Even selecting an exact spelling with with_case_sensitive(false) can therefore read or filter the wrong field; detect multiple case-folded matches and return an ambiguity error instead.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c1a7f5e41

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Ok(ProjectionMask::all())
// All requested columns are new or have no physical representation. An empty
// projection still preserves row counts for RecordBatchTransformer.
Ok(ProjectionMask::none(parquet_schema.num_columns()))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve rows when projecting no physical columns

When a scan requests only fields absent from an older file, or only an unknown field, this now produces a zero-column RecordBatch. RecordBatchTransformer::transform_columns immediately returns an empty vector when columns.is_empty(), so constructing the non-empty target schema fails instead of materializing the requested default/null columns for each source row. Pass the batch's explicit row count through the transformation path rather than relying on columns[0].len().

Useful? React with 👍 / 👎.

));
}

let backoff = Self::build_backoff(table_props)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Prevent removing encryption configuration from live tables

When update_table_properties() removes encryption.key-id from a table that already has encrypted snapshots, this newly permitted commit succeeds and persists the removal. On the next catalog load, EncryptionManager::from_table_metadata returns None, while ManifestListReader requires a manager for every existing snapshot with encryption_key_id, making the table's data unreadable. Reject removal of this property while encrypted snapshots exist, or preserve enough key-manager configuration to decrypt historical snapshots.

Useful? React with 👍 / 👎.

@manuzhang
manuzhang force-pushed the add-unknown-datatype branch from 5c1a7f5 to 223d3f0 Compare August 25, 2026 03:15

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 223d3f0cc7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/arrow/reader/projection.rs Outdated
Comment on lines +33 to +34
pub(crate) fn new(file_io: FileIO) -> Self {
Self { file_io }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Expose a public ManifestReader constructor

When downstream code loads a ManifestFile using a standalone FileIO rather than a Table, this commit removes the public ManifestFile::load_manifest method but makes the replacement reader's only constructor crate-private. Such callers cannot construct ManifestReader at all, so upgrading causes a source break and removes the previously supported ability to read manifests outside a Table; make this constructor public or retain a forwarding load_manifest method.

Useful? React with 👍 / 👎.

@manuzhang
manuzhang force-pushed the add-unknown-datatype branch from 223d3f0 to f551818 Compare August 25, 2026 03:39

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f551818c43

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/arrow/record_batch_transformer.rs Outdated
@manuzhang
manuzhang force-pushed the add-unknown-datatype branch 2 times, most recently from 85b1ed3 to 007a95a Compare August 25, 2026 03:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 007a95a42f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/arrow/reader/projection.rs Outdated
@manuzhang
manuzhang force-pushed the add-unknown-datatype branch from 007a95a to 60872f6 Compare August 25, 2026 04:10

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 60872f6490

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/arrow/record_batch_transformer.rs Outdated
Comment thread crates/iceberg/src/arrow/record_batch_transformer.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11c8ef16c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +652 to +655
let initial_default = parse_default(value.initial_default, &value.field_type)?;
let write_default = parse_default(value.write_default, &value.field_type)?;

Ok(NestedField {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject required unknown fields during deserialization

When a consumer deserializes a NestedField directly with {"required":true,"type":"unknown"}, this conversion succeeds because it validates only defaults; the optionality check exists only in SchemaBuilder::build. Direct NestedField deserialization is explicitly supported and tested in this change, so it can expose an invalid v3 field that contradicts the null-only semantics of unknown. Apply the required/optional validation in this TryFrom path as well.

Useful? React with 👍 / 👎.

@manuzhang
manuzhang force-pushed the add-unknown-datatype branch from 11c8ef1 to 02756bf Compare August 26, 2026 07:26

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 02756bfb89

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/iceberg/src/spec/datatypes.rs Outdated
Co-authored-by: Codex <codex@openai.com>
@manuzhang
manuzhang force-pushed the add-unknown-datatype branch from 02756bf to a7efd92 Compare August 26, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants