Skip to content

Merge upstream/main: bloom filters, row lineage, new REST auth architecture - #82

Merged
gbrgr merged 75 commits into
mainfrom
gb/merge-upstream-2
Sep 16, 2026
Merged

gbrgr merged 75 commits into
mainfrom
gb/merge-upstream-2

Conversation

@gbrgr

@gbrgr gbrgr commented Sep 16, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Merges apache/iceberg-rust@main into the fork, bringing in ~8 months of upstream changes while preserving all fork-only features (incremental scan, vended credentials, custom REST authenticator, storage-credential refresh, OverwriteAction, binary type promotion).

Notable upstream features adopted:

  • Row lineage (_row_id metadata column), including full support in the incremental-scan reader path
  • Bloom-filter row-group pruning (ArrowReaderBuilder::with_bloom_filter_enabled), also wired into the incremental-scan reader path (IncrementalTableScanBuilder::with_bloom_filter_enabled)
  • Parquet Modular Encryption plumbing through the reader pipeline
  • _partition / _last_updated_sequence_number metadata columns
  • New REST-catalog AuthSession/AuthManager architecture (fork's CustomAuthenticator/vended-credentials support ported onto it)
  • KMS / custom-Runtime wiring, DeleteFileIndexState::Failed fallible delete-index population

Fork-only features carried forward unchanged in behavior, updated only where required to compile against upstream's new APIs:

  • Incremental table scan (crates/iceberg/src/scan/incremental, crates/iceberg/src/arrow/incremental.rs)
  • REST-catalog vended credentials / storage-credential refresh
  • OverwriteAction (this PR also cherry-picks fix(transaction): fix correctness bugs in OverwriteAction #81's outstanding correctness fixes for it — see below)
  • Binary type promotion

Notable fixes made during conflict resolution

  • record_batch_transformer.rs: adopted upstream's _pos metadata-column fix (the original motivation for this merge — a same-type column reorder was being mislabeled instead of reordered).
  • arrow/delete_filter.rs: fixed a latent bug (file_scan_task.deletes → .deletes()) left over from FileScanTask's fields becoming private with accessor methods upstream.
  • delete_file_index.rs: two fork-only methods (get_equality_deletes_for_data_file, all_deletes) were not handling the new DeleteFileIndexState::Failed variant (non-exhaustive match); made both fallible and propagated the error at their two call sites in scan/incremental/mod.rs.
  • arrow/reader/pipeline.rs: preserved the fork's helper-function architecture (shared between the full scan and incremental scan) while folding in bloom-filter support and _row_id synthesis/coalescing, mirroring the existing _last_updated_sequence_number pattern.
  • arrow/incremental.rs: threaded bloom-filter and RowNumber-virtual-column (_row_id positional-fallback) support into the incremental append-task reader, matching the full-scan path.
  • catalog/rest/src/catalog.rs: fixed with_token_authenticator wrapping CustomAuthenticatorManager in an extra Arc that with_auth_manager<M: AuthManager> didn't expect.

Follow-up commits after initial review

  • fix(incremental-scan): expose bloom-filter row-group pruning on IncrementalTableScanBuilder — the incremental reader path threaded bloom_filter_enabled all the way through, but IncrementalTableScan::to_arrow()/to_unzipped_arrow() never called .with_bloom_filter_enabled(), leaving it permanently disabled and unreachable. Added a builder method mirroring TableScanBuilder's, defaulting to disabled.
  • fix(ci): drop crates.io version pin from iceberg-storage-refreshable workspace dep — crates/storage/refreshable is publish = false (fork-only, never published), but the workspace dependency table gave it a version like every published crate, which broke cargo publish --dry-run for iceberg-catalog-rest (its only, dev-only consumer). Dropped the version, matching the existing pattern for iceberg_test_utils.
  • fix(scan): tolerate a dropped partition source column in FileScanTask::validate() — a real regression caught by a post-merge audit: upstream's new FileScanTask::validate() (added in refactor(scan): validate FileScanTask construction apache/iceberg-rust#3131, landed here via an unconflicted auto-merge of scan/task.rs) unconditionally calls partition_spec.partition_type(&schema), which errors for a historical partition spec whose source column has since been dropped — a legitimate v2+ state the fork already tolerates one layer up in PartitionFilterCache::get. During conflict resolution of scan/mod.rs, the corresponding regression test was updated to assert the new error instead of catching the incompatibility. Fixed validate() to mirror PartitionFilterCache::get's tolerance, and restored the test to its original success-path assertions.
  • Cherry-picked fix(transaction): fix correctness bugs in OverwriteAction #81 (fix(transaction): fix correctness bugs in OverwriteAction) into this branch: a resurrection bug where an already-deleted manifest entry could be silently resurrected on a later, unrelated manifest rewrite; wrong schema/partition-spec-id stamped on rewritten manifests (used the table's current schema instead of the manifest's own); manifest naming/location bypassing metadata_location()/commit-uuid convention; and SnapshotProducer::summary() wrongly applying full-table-truncate semantics to OverwriteAction's partial overwrites.

Test plan

  • cargo check --workspace --all-targets --all-features clean
  • cargo test -p iceberg --lib: 1791 passed, 0 failed
  • cargo test --workspace --all-features (excluding python bindings): all unit/doc tests pass; only live-infra integration tests fail locally (S3/minio, HMS thrift, REST catalog — no server running in this sandbox), consistent with existing CI-only test setup
  • cargo clippy --workspace --all-targets --all-features -- -D warnings clean
  • cargo fmt --all -- --check clean
  • cargo machete clean
  • make check-public-api clean (one new public method added and reflected: IncrementalTableScanBuilder::with_bloom_filter_enabled)
  • Two independent post-merge audits done: (1) incremental-scan feature parity vs. the full-scan path, (2) fork-only-feature preservation + a systematic before/after dropped-test check across every file touched by the merge — both findings addressed above
  • CI green (see checks below)

🤖 Generated with Claude Code

anoopj and others added 30 commits August 27, 2026 20:26
…r-row clones (apache#3080)

* perf(arrow): build repeated constant string/binary columns without per-row clones

create_primitive_array_repeated built a throwaway `vec![value.clone(); num_rows]`
for the Utf8/Binary/LargeBinary/FixedSizeBinary arms before handing it to the array
constructor. For strings that clones the value into num_rows separate heap
allocations per batch; the binary arms allocate a throwaway intermediate Vec.

Stream the single value straight into the Arrow buffer via `from_iter_values` with
`std::iter::repeat_n` instead.

Benchmarks (release, throwaway harness, old vs new toggled on this file only):
- leaf create_primitive_array_repeated (Utf8, 8192-row batch): 23.0 -> 4.1 ns/row (5.6x)
- full scan select(x, _partition) over a real manifest + 262k-row parquet file,
  string-partitioned: 20.9 -> 5.7 ns/row (3.7x)

Note that the gain is allocation-counts and scales with how much of the
projection is the string partition column.

Fixes apache#3079

* Feedback
…ield (apache#2826)

* chore(repo): Update Apache Iceberg Rust version options

Updated the version options for Apache Iceberg Rust in the bug report template.

* Replace optional version list with required freeform text
* fix(sql): propagate catalog commit errors

* test(sql): clarify transaction commit coverage

* test(sql): exercise commit errors through catalog API

* test(sql): keep commit regression catalog-focused
* Refs apache#2879

Read-side synthesis of the v3 _row_id metadata column, similar to the _last_updated_sequence_number materialization. We do a per-row coalesce of the physically-stored column against a per-row positional fallback of first_row_id plus the row position, gated on first_row_id (null first_row_id nulls the whole column). The positional fallback consumes the RowNumber virtual column, which is now added whenever _row_id is synthesized.

Added tests

* Fix CI failure

* Fix typo flagged by lint

* Synthesize _row_id in a reader-level stream step

Reject a name-only physical _row_id column unconditionally (it never
threads), fixing a false reject of user columns named _row_id under
positional fallback. Add tests for global position across row groups,
survival through positional deletes, and name collision under fallback.

* Fix pr feedback

* Fix merge collision
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.28 to 0.13.4.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](seanmonstar/reqwest@v0.12.28...v0.13.4)

---
updated-dependencies:
- dependency-name: reqwest
  dependency-version: 0.13.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…e#3115)

Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.86.1 to 2.86.6.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](taiki-e/install-action@288e746...6cd1350)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.86.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the codeql-action group with 2 updates: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.7 to 4.37.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@ff2f1c6...db488dd)

Updates `github/codeql-action/analyze` from 4.37.7 to 4.37.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@ff2f1c6...db488dd)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: codeql-action
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.24.0 to 1.25.0.
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](uuid-rs/uuid@v1.24.0...1.25.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 1.25.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ngs/python (apache#3112)

chore(deps-dev): Bump huggingface-hub in /bindings/python

Bumps [huggingface-hub](https://github.com/huggingface/huggingface_hub) from 1.27.0 to 1.28.0.
- [Release notes](https://github.com/huggingface/huggingface_hub/releases)
- [Commits](huggingface/huggingface_hub@v1.27.0...v1.28.0)

---
updated-dependencies:
- dependency-name: huggingface-hub
  dependency-version: 1.28.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Prune data columns for metadata-only projections

A projection of only metadata columns (e.g. SELECT _row_id) reads no data
columns for their values, since they are synthesized or constant. Without an
independent row-count source, the projection mask fell back to reading every
data column just to recover the row count. Install the RowNumber virtual
column (derived from row-group metadata, no column I/O) as that source for any
metadata-only projection, so the read is pruned to zero data columns. COUNT(*)
(an empty projection) is left unchanged.

Applies to all metadata-only projections: _row_id, _last_updated_sequence_number,
_file, _spec_id, and _partition.

Measured on a 58 MB, 200k-row, 30-column Parquet file, projecting only
_last_updated_sequence_number:

  this change (pruned):        524 KB read,    6 ms
  before (read all columns):  58.6 MB read, 1289 ms

* Incorporate PR feedback
…e#3101)

* refactor(memory): derive catalog configuration from properties

Replace manual catalog property extraction with the shared derive while preserving warehouse validation and forwarding unmodeled properties.

Tracks [apache#3095](apache#3095).

Generated-by: Codex

* refactor(memory): retain typed catalog properties

Remove the redundant config wrapper and catch-all property field, expose the typed properties, and retain the catalog name and typed properties on MemoryCatalog.

Addresses review feedback on [apache#3101](apache#3101).

Generated-by: Codex

* refactor(memory): retain raw catalog properties

* fix(memory): defer missing warehouse validation

* refactor(memory): move raw properties into file io

* fix(memory): restore catalog validation contract

* refactor(memory): retain public catalog properties

* refactor(memory): forward raw catalog properties
* chore: Add LICENSE and NOTICE files for crates missing them in 0.10.0 (apache#2830)

## Which issue does this PR close?

For release: apache#2527

## What changes are included in this PR?

These changes are cherry-picks of apache#2823 and apache#2828. The crates were
missing the LICENSE and NOTICE files required for the distributed source
code.

## Are these changes tested?

Tested using the following script provided by @kevinjqliu. Introducing
this in CI is left as a follow-up
(apache#2827).

```bash
set -Eeuo pipefail

failed=0

while IFS= read -r crate; do
    echo "Checking ${crate}..."
    files="$(cargo package \
    --package "${crate}" \
    --list \
    --locked)"

    for required in LICENSE NOTICE; do
    if ! grep -Fxq "${required}" <<<"${files}"; then
        echo "::error::${crate} package is missing top-level ${required}"
        failed=1
    fi
    done
done < <(
    cargo metadata --no-deps --format-version 1 |
    jq -r '.packages[] | select(.publish != []) | .name'
)

exit "${failed}"
```

---------

Co-authored-by: Andrew Kane <andrew@ankane.org>

* chore: Update changelog for 0.10.0 RC4 (apache#2831)

## Which issue does this PR close?

Follow up for 0.10.0 RC4.

## What changes are included in this PR?

Change log entries for missing changes in 0.10.0 RC4. The changelog is
worded for the original commits to `main`, and not as the squashed
cherry pick in apache#2830.

## Are these changes tested?

N/A

* chore: Update crossbeam-epoch to 0.9.20, pin CI ruff version to 0.15.22 (apache#2911)

## Which issue does this PR close?

Small changes needed for 0.10.1.

## What changes are included in this PR?

First, address advisory in crossbeam-epoch with patch version update.

Second, to address CI, pin Ruff linter for Python to version available
when iceberg-rust 0.10.0 was released.

## Are these changes tested?

Already covered by CI.

* chore: Bump version to 0.10.1, update changelog (apache#2909)

## Which issue does this PR close?

This bumps the crate and pyiceberg-core version to 0.10.1, for the
0.10.1 release.

Additionally, it pins ruff to 0.15.22 which was the version used for
iceberg-rust 0.10.0.

## What changes are included in this PR?

Version bump, updated dependency TSV manifests, updated changelog.

Pins CI version of ruff Python linter.

## Are these changes tested?

N/A

---------

Co-authored-by: Andrew Kane <andrew@ankane.org>
…ICE (apache#3084)

* chore(ci): Fail CI when a publishable crate is missing LICENSE or NOTICE

Missing LICENSE and NOTICE files for newly introduced crates (apache#2823) were
only discovered manually during release preparation, because nothing
asserted their presence.

Add dev/check_license_notice.sh, which lists the packaged files of every
publishable crate with `cargo package --list` and fails when a top-level
LICENSE or NOTICE is absent. Checking the packaged file list rather than
the crate directory also catches files present on disk but excluded from
the published crate. Because `cargo package --list` reports an entry even
when a symlinked target is gone, the file contents are checked separately
so a removed or emptied root copy fails too. Each crate's copy must also
resolve to the repository root file itself, so the license text cannot
drift from one crate to the next.

Run it from the CI lint job so pull requests fail when a crate is missing
either file, and stop excluding the root LICENSE and NOTICE from the
pull_request path filter, since every crate symlinks to those copies and a
PR removing them must still run the job. Also wire it into `make check` so
it can be run locally the same way as the other lint checks.

The check does not pass at this commit. It reports iceberg-property-macro,
which is published but ships neither file, and iceberg-catalog-s3tables,
whose LICENSE and NOTICE are real copies rather than the repository root
files. Both gaps are fixed in the two commits that follow.

Closes apache#2827

* chore: Add missing LICENSE and NOTICE to iceberg-property-macro

iceberg-property-macro is published to crates.io but shipped neither a
LICENSE nor a NOTICE, so the crate was distributed without the files an
Apache release requires. It was missed because the crate was added after
apache#1601, which introduced the files for the crates publishable at the time.

Add the same relative symlinks to the repository root copies that every
other publishable crate uses, which is what the new check in the preceding
commit reports.

* chore: Symlink s3tables LICENSE and NOTICE to the repository root

Every publishable crate references the root LICENSE and NOTICE through a
relative symlink. That convention was established in apache#1601, which added the
files to the crates that were publishable at the time. `iceberg-catalog-s3tables`
was `publish = false` back then so it was skipped, and apache#1916 later added real
copies when the crate was made publishable. Every crate added since has followed
the symlink convention, leaving s3tables as the only outlier.

Replace the copies with symlinks so the root files remain the single source of
truth and per-crate copies cannot drift from them. This is also required for the
check added earlier in this branch to pass, which rejects a per-crate copy that
is not the root file itself: the s3tables copies are byte-identical to the root
files today, but nothing kept them that way.

`cargo package` dereferences the symlinks, so the published crate is unchanged:
LICENSE and NOTICE are still regular files with byte-identical content.

* Update based on PR feedback
* refactor(scan): extract scan planning utilities

* comments

* comments

* remove allocation
* refactor(scan): Validate FileScanTask construction

Make FileScanTask fields private, expose read-only getters, and validate builder output so non-empty partition data always has an associated partition spec.

Generated-by: Codex (GPT-5)

* refactor(scan): Simplify FileScanTask validation

Use typed-builder output conversion for validation instead of coupling the custom build method to generated typestate arguments.

Generated-by: Codex (GPT-5)

* fix(scan): Validate FileScanTask partition data

Validate partition arity and transformed value types while preserving support for historical partition specs whose source columns were dropped. Port the partition coverage from PR apache#3091 to builder regression tests.

Generated-by: Codex (GPT-5)

* fix(scan): Refine partition validation

Enforce symmetric partition/spec presence and tuple arity while avoiding per-value transform validation during task construction. Update the spec-id scan fixture to provide its partition tuple.

Generated-by: Codex (GPT-5)

* fix(scan): Validate partition specs against schema

Preserve historical specs with dropped source columns while validating resolvable partition specs against the task schema. Add regression coverage for an incompatible evolved schema.

Generated-by: Codex (GPT-5)

* fix(scan): Always validate partition specs

Remove the dropped-source shortcut and rely directly on PartitionSpec::partition_type for schema validation. Update dropped-source coverage to assert the resulting planning error.

Generated-by: Codex (GPT-5)
…ache#3022)

* fix(partition): Align DateTime Transform to Java's Implementation

* Add Doc Tests and Update Match Branching

* Adding Spark Equivalence Tests

* Update comments and return early

* Removes requested integration tests

---------

Co-authored-by: Kurtis Wright <kurwrigh@amazon.com>
* feat(scan): carry deletion-vector coordinates on FileScanTaskDeleteFile

Add referenced_data_file, content_offset, and content_size_in_bytes to
FileScanTaskDeleteFile, populated from the delete file's manifest entry.
These locate a deletion-vector blob and scope it to its data file, which
the delete loader needs to read and apply V3 deletion vectors.

Refs apache#2792.

* fix after merging in main

* fix public-api.txt

* fix test name

* update

* apply V3 deletion vectors during scan

* identify deletion vectors by content type and file format

* Fix after merging upstream/main

* Update comment wording.
* bump df to 55.0 (head on main) and arrow to 59.1

* upmerge main after opendal bump

* fix some CI failures

* python version bumps

* bump to branch-55 and rc2 commit. bump to arrow and parquet 59.2

* bump to branch-55 and rc2 commit. bump to arrow and parquet 59.2

* bump to final crates, fix API changes

* update public API

* gate test
…che#3143)

* refactor(python): remove DataFusion integration

Remove the DataFusion table provider export, its tests, and its Rust and Python dependency trees from pyiceberg-core.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* chore(python): leave dependency inventory unchanged

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* docs(python): clarify PyArrow test dependency

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* docs(python): explain PyIceberg core conflict

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…action (apache#3121)

Unify the reserved/metadata column handling behind a single set of transform
actions, per review feedback on apache#3058.

Behavior is unchanged.
…pache#3157)

Bumps [apache/skywalking-eyes/header](https://github.com/apache/skywalking-eyes) from 0.8.0 to 0.9.0.
- [Release notes](https://github.com/apache/skywalking-eyes/releases)
- [Changelog](https://github.com/apache/skywalking-eyes/blob/main/CHANGES.md)
- [Commits](apache/skywalking-eyes@61275cc...a196742)

---
updated-dependencies:
- dependency-name: apache/skywalking-eyes/header
  dependency-version: 0.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…e#3156)

Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.86.6 to 2.87.2.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](taiki-e/install-action@6cd1350...1ed6d7b)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.87.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
kevinjqliu and others added 26 commits September 11, 2026 15:30
)

* ci: check new crates are reserved on crates.io before merge

Trusted publishing can't create a crate, and the release workflow publishes
the whole workspace in one `cargo publish --workspace` run, which cargo
aborts if any crate already exists at the release version. So the existing
"publish the new crate by hand after the workflow fails" instructions no
longer work.

Add a lint step that fails if a publishable crate is missing from
crates.io, and rewrite the release guide appendix around reserving the
crate with a placeholder version when it is added.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: reserve the crate name with a standalone placeholder crate

Overriding the version inside the workspace fails because iceberg depends
on the new crate at the workspace version. Verified with cargo publish
--dry-run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* ci: match the existing publishable-crate filter; document partial publish recovery

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: clarify that reserving a crate needs a token with the publish-new scope

Owning the existing crates does not imply the token in ~/.cargo/credentials.toml
has publish-new, and crates.io reports a missing scope as a generic
authentication failure. Say so, and point at where to create the token.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: fix stale first-publish note, empty placeholder, and owner invitations

- The release steps still said the publish workflow is expected to fail on
  new crates and linked to a heading that no longer exists.
- `cargo new --lib` generates a non-empty lib.rs; use mkdir and touch.
- `cargo owner --add <user>` sends an invitation that must be accepted.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* ci: fail the crates.io check if the crate list is empty

A failed `cargo metadata` inside `for pkg in $(...)` never trips
`bash -e`, so the loop ran zero times and the step passed without
checking anything. Capture the list first and fail if it is empty.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Closes apache#3140.

Mirror apache/iceberg-python#3832: define the required checks in
.asf.yaml, add an ASF-managed Merge Queue ruleset (one-at-a-time squash
merges on main), enable auto-merge, and make every required workflow run
on merge_group without pull_request path or branch filters so its check
always reports. CI and Bindings Python CI gain an always-run aggregate
job (ci-required, bindings-python-ci-required) so matrix job names do
not have to be enumerated as required contexts.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Docker Hub no longer serves the MinIO server and client repositories, preventing integration test containers from starting. Use the corresponding Quay images with the existing release tags.

Generated-by: Codex

Co-authored-by: Kevin Liu <kevinjqliu@users.noreply.github.com>
…e HEAD (apache#3200)

Remove release_ref from create_rc.sh

Co-authored-by: Kevin Liu <kevinjqliu@users.noreply.github.com>
Merge queue checks already validate the final combined change before it lands, so stop rerunning required workflows on main after merge.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* ci: warm shared Rust caches on main

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* ci: restrict cache writes to main

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* ci: refresh Rust caches in main workflows

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* ci: keep cache hydration change focused

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* ci: reuse prior workflow path filters

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.50.0 to 1.50.1.
- [Release notes](https://github.com/crate-ci/typos/releases)
- [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md)
- [Commits](crate-ci/typos@4d9c206...d43b6c0)

---
updated-dependencies:
- dependency-name: crate-ci/typos
  dependency-version: 1.50.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.28 to 0.13.4.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](seanmonstar/reqwest@v0.12.28...v0.13.4)

---
updated-dependencies:
- dependency-name: reqwest
  dependency-version: 0.13.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
)

* refactor(sql): derive catalog configuration from properties

Use the shared property derive for SQL catalog settings while preserving builder precedence, bind-style aliases, schema validation, and forwarded pool properties.

Tracks [apache#3099](apache#3099).

Generated-by: Codex

* refactor(sql): centralize catalog properties

* fix(sql): address catalog property review
…e#3217)

Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.87.2 to 2.87.8.
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](taiki-e/install-action@1ed6d7b...d438492)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.87.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…updates (apache#3209)

Bumps the arrow-parquet group with 2 updates in the / directory: [arrow](https://github.com/apache/arrow-rs) and [parquet](https://github.com/apache/arrow-rs).


Updates `arrow` from 59.2.0 to 59.3.0
- [Release notes](https://github.com/apache/arrow-rs/releases)
- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.0/CHANGELOG.md)
- [Commits](apache/arrow-rs@59.2.0...59.3.0)

Updates `arrow-arith` from 59.2.0 to 59.3.0
- [Release notes](https://github.com/apache/arrow-rs/releases)
- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.0/CHANGELOG.md)
- [Commits](apache/arrow-rs@59.2.0...59.3.0)

Updates `arrow-array` from 59.2.0 to 59.3.0
- [Release notes](https://github.com/apache/arrow-rs/releases)
- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.0/CHANGELOG.md)
- [Commits](apache/arrow-rs@59.2.0...59.3.0)

Updates `arrow-buffer` from 59.2.0 to 59.3.0
- [Release notes](https://github.com/apache/arrow-rs/releases)
- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.0/CHANGELOG.md)
- [Commits](apache/arrow-rs@59.2.0...59.3.0)

Updates `arrow-cast` from 59.2.0 to 59.3.0
- [Release notes](https://github.com/apache/arrow-rs/releases)
- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.0/CHANGELOG.md)
- [Commits](apache/arrow-rs@59.2.0...59.3.0)

Updates `arrow-ord` from 59.2.0 to 59.3.0
- [Release notes](https://github.com/apache/arrow-rs/releases)
- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.0/CHANGELOG.md)
- [Commits](apache/arrow-rs@59.2.0...59.3.0)

Updates `arrow-schema` from 59.2.0 to 59.3.0
- [Release notes](https://github.com/apache/arrow-rs/releases)
- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.0/CHANGELOG.md)
- [Commits](apache/arrow-rs@59.2.0...59.3.0)

Updates `arrow-select` from 59.2.0 to 59.3.0
- [Release notes](https://github.com/apache/arrow-rs/releases)
- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.0/CHANGELOG.md)
- [Commits](apache/arrow-rs@59.2.0...59.3.0)

Updates `arrow-string` from 59.2.0 to 59.3.0
- [Release notes](https://github.com/apache/arrow-rs/releases)
- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.0/CHANGELOG.md)
- [Commits](apache/arrow-rs@59.2.0...59.3.0)

Updates `parquet` from 59.2.0 to 59.3.0
- [Release notes](https://github.com/apache/arrow-rs/releases)
- [Changelog](https://github.com/apache/arrow-rs/blob/59.3.0/CHANGELOG.md)
- [Commits](apache/arrow-rs@59.2.0...59.3.0)

---
updated-dependencies:
- dependency-name: arrow
  dependency-version: 59.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow-parquet
- dependency-name: arrow-arith
  dependency-version: 59.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow-parquet
- dependency-name: arrow-array
  dependency-version: 59.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow-parquet
- dependency-name: arrow-buffer
  dependency-version: 59.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow-parquet
- dependency-name: arrow-cast
  dependency-version: 59.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow-parquet
- dependency-name: arrow-ord
  dependency-version: 59.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow-parquet
- dependency-name: arrow-schema
  dependency-version: 59.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow-parquet
- dependency-name: arrow-select
  dependency-version: 59.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow-parquet
- dependency-name: arrow-string
  dependency-version: 59.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow-parquet
- dependency-name: parquet
  dependency-version: 59.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: arrow-parquet
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…thon (apache#3208)

chore(deps-dev): Bump pyiceberg in /bindings/python

Bumps [pyiceberg](https://github.com/apache/iceberg-python) from 0.11.1 to 0.12.0.
- [Release notes](https://github.com/apache/iceberg-python/releases)
- [Commits](apache/iceberg-python@pyiceberg-0.11.1...pyiceberg-0.12.0)

---
updated-dependencies:
- dependency-name: pyiceberg
  dependency-version: 0.12.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
)

Resolves each data file's sort_order_id against the table's known sort
orders during scan planning and carries the result on FileScanTask as
sort_order (Some only when genuinely sorted; the reserved unsorted
order, id 0, resolves to None) alongside the raw sort_order_id (kept
unresolved so a non-zero id that fails to resolve is still
recoverable as "physically sorted").

PlanContext precomputes a narrow sort-orders map once per scan,
matching the existing unified_partition_type pattern, rather than
carrying the full TableMetadataRef into every ManifestFileContext.
…pache#3204)

The partition splitter built each group's selection mask as a throwaway
`vec![false; num_rows]` and bit-packed it into a `BooleanArray` via
`.into()`, allocating an n-byte `Vec<bool>` plus a full packing pass per
group per batch on every partitioned write. Build the packed buffer
directly with `BooleanBufferBuilder`, setting only the selected bits.
…loning (apache#3214)

`ManifestFilterVisitor::bytes_to_datum` took the field `Type` by value, so
every comparison-leaf call site cloned the field's boxed `Type` to decode a
bound -- and the two in-predicate sites cloned the entire `NestedField`.
`bytes_to_datum` only borrows the type to reach its `PrimitiveType`, so take
`&Type` and pass `&reference.field().field_type` at the call sites, dropping
the per-leaf clones on the manifest-pruning path.
* feat(writer): add PositionDeleteFileWriter

Add PositionDeleteFileWriter and its builder under writer/base_writer. It writes
a position delete file with the two required columns file_path (string, field id
2147483546) and pos (long, 2147483545) and sets DataContentType::PositionDeletes
on close.

position_delete_schema() returns the canonical Iceberg schema, built from the
existing metadata_columns field definitions. write() checks that a batch has
exactly those two required, non-nullable, correctly typed columns before writing,
and rejects a closed writer. close() propagates the partition key and leaves
sort_order_id null.

Position delete files are a v2 construct: v3 replaces them with deletion vectors
and forbids adding new ones, so callers must not route v3 writes here. This base
writer has no format-version gate by design; that gating belongs at the
transaction/commit layer. The writer also does not sort its input, so callers
must supply rows sorted by (file_path, pos) until a higher-level writer enforces
it. Setting referenced_data_file and a higher-level DeltaWriter are follow-ups.

Tested: schema shape, a parquet round trip for single and multiple writes,
partition propagation, that the reserved field ids survive into the written
parquet schema, and the validation cases (wrong column count, wrong/missing/
unparsable field ids, wrong types including LargeUtf8, nullable columns, and
writes after close).

Refs apache#340.

* docs(writer): note the optional row column is unsupported

The position delete spec allows an optional `row` column alongside `file_path`
and `pos` that inlines the deleted row's values. This writer handles only the
two required columns, so say so in the module docs. The batch validator already
rejects a third column with a matching message.

---------

Co-authored-by: Shawn Chang <schang@apache.org>
…che#3194)

The release scripts run each step in a `( trap - ERR; ... )` subshell so a
failure is reported exactly once. bash 3.2 (macOS /bin/bash) does not run
the parent's ERR trap for a failing subshell, so the script still exits on
failure but does not report which step failed. bash 4.0 and later do;
verified against 3.2 through 5.1.

Print a warning at startup on bash older than 4 in the four scripts that
install the trap.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…#3226)

`AesKeySize::from_key_length` and `AesKeySize::from_str` returned
`FeatureUnsupported` for anything outside 128/192/256-bit. AES defines no other
key sizes, so these are invalid input rather than something a later version
could support, and `FeatureUnsupported` here is indistinguishable from the
genuinely unsupported cases such as an unknown key metadata version.

`from_key_length` is reachable from `SecureKey::new`,
`StandardKeyMetadata::try_new` and the `encryption.data-key-length` table
property, all of which now surface `DataInvalid`. Messages change from
"Unsupported ..." to "Invalid ..." to match.
* add standard ket metadata python bindings

* fix

* fix: clarify unsupported key metadata version error

Report the received and supported key metadata versions, matching the wording expected by PyIceberg. Add Rust and Python regression coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* named struct

* improve tests

* tests

---------

Co-authored-by: Kevin Liu <kevin.jq.liu@gmail.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* feat: bloom filter pushdown

* test

* avoid copy

* new name

* fmt

* doc string

* handle type widening

* widen decimals

* pub crate

* full import

* lifetime

* log

* add not supported comment

* make it more safe

* Add tests

* fix

* fmt

* don't read not predicates

* tests

* remove boolean

* doc

* update 0 test

* UUID

* update comment

* update test doc
# Conflicts:
#	Cargo.lock
#	crates/iceberg/src/arrow/delete_filter.rs
#	crates/iceberg/src/arrow/reader/mod.rs
#	crates/iceberg/src/arrow/reader/pipeline.rs
#	crates/iceberg/src/scan/context.rs
…mentalTableScanBuilder

The incremental-scan reader path already threads bloom_filter_enabled through
apply_parquet_filters and both process_incremental_append_task/
process_equality_delete_task, but IncrementalTableScan::to_arrow()/
to_unzipped_arrow() never called ArrowReaderBuilder::with_bloom_filter_enabled,
leaving it permanently disabled. Add a with_bloom_filter_enabled builder method
on IncrementalTableScanBuilder, mirroring TableScanBuilder's, defaulting to
disabled (matching upstream's conservative default given the per-row-group I/O
cost) rather than silently forcing it on.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…workspace dep

crates/storage/refreshable is publish = false (fork-only, never published to
crates.io), but the root workspace dependency table gave it a version like
every other (published) workspace crate. iceberg-catalog-rest depends on it
as a dev-dependency via workspace = true, so cargo publish tried to resolve
"iceberg-storage-refreshable = 0.10.0" from the registry and failed
("no matching package named `iceberg-storage-refreshable` found"). Dropping
the version leaves it path-only, matching the existing pattern used for
iceberg_test_utils (another unpublished dev-only workspace crate), which
cargo correctly omits from the published manifest.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…::validate()

Upstream's new FileScanTask::validate() unconditionally calls
partition_spec.partition_type(&schema), which errors when a historical
partition spec references a source column no longer present in the current
schema -- a legitimate v2+ state the fork already tolerates one layer up in
PartitionFilterCache::get (falls back to an always-true partition filter
rather than erroring). validate() didn't know about that fallback, so it
silently regressed a fork capability: filtered scans over a table that
evolved past a historical spec's source column now hard-failed instead of
falling back gracefully, and the merge's conflict resolution had updated
the regression test to assert the new error rather than catching the
incompatibility.

Mirror PartitionFilterCache::get's own dropped-source-column detection in
validate() and skip the partition_type() check in that case. Restores
scan::mod::test_filtered_scan_with_dropped_partition_source_column to its
original success-path assertions, and updates the new upstream unit test
(scan::task::tests) to expect success instead of rejection for the same
scenario.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Prompted by review comments on the upstream PR our OverwriteAction was
originally built on top of (apache#2185). Checked each
comment against our own implementation; three applied here too:

- Resurrection bug (the serious one): rewrite_manifest's fallback
  branch called add_existing_entry for every entry not newly deleted
  this round, including entries that were already Deleted by a prior
  overwrite -- add_existing_entry unconditionally resets status to
  Existing, silently resurrecting previously-deleted files as live
  data the next time their manifest got rewritten for an unrelated
  reason. Fixed by routing already-non-alive entries through
  add_deleted_entry instead, preserving their original snapshot_id as
  a tombstone. Added test_second_overwrite_does_not_resurrect_deleted_file
  to lock this in.

- Wrong schema-id on rewritten manifests: schema was taken from
  table.metadata().current_schema() (the table's *current* schema)
  rather than the manifest being rewritten's own schema. After any
  schema evolution between the original write and a later overwrite,
  this stamped the wrong schema-id on old entries, which
  schema-id-aware readers (Java, PyIceberg) would misinterpret. Fixed
  by deriving both schema and partition spec directly from the
  manifest's own ManifestMetadata (which already carries fully
  resolved objects, not just IDs) -- this is also simpler than the
  existing partition_spec_by_id table lookup it replaces, and doesn't
  depend on the table still listing that partition spec.

- Manifest naming/location bypassed convention: rewritten manifests
  were written to a hardcoded `{location}/metadata/` path with a
  fresh random UUID per manifest, rather than
  `metadata_location()` (which respects a configured
  write.metadata.path table property, already used correctly
  elsewhere in this same file for the manifest list) and the commit's
  own UUID (shared across every manifest touched by one commit,
  matching SnapshotProducer::new_manifest_writer's own convention).
  Added a commit_uuid() getter on SnapshotProducer and an index
  parameter to rewrite_manifest to keep names unique when a commit
  rewrites more than one manifest.

Also fixed, one level up in shared code: SnapshotProducer::summary()
unconditionally applied "truncate full table" semantics (replace
computed added/removed counts with the previous snapshot's totals)
for any Operation::Overwrite, which is wrong for OverwriteAction's
explicit-file-list partial overwrites -- it already knows exactly
what was added/removed. Added a `truncate_full_table()` method to
SnapshotProduceOperation (default false, only meaningful for an
operation that genuinely replaces the whole table) and had
OverwriteOperation opt out explicitly. Updated
test_delete_only_overwrite_summary, which had documented the old
(wrong) truncated counts as expected behavior, to assert the correct
ones.

Not applicable: the review's manifest-filtering concern (dropping
delete-only manifests) is already handled correctly on our side --
both FastAppendAction and OverwriteAction's existing_manifest() were
confirmed to already keep manifests with has_deleted_files().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gbrgr
gbrgr merged commit ec07ed0 into main Sep 16, 2026
23 checks passed
@gbrgr
gbrgr deleted the gb/merge-upstream-2 branch September 16, 2026 10:41
gbrgr added a commit to RelationalAI/RustyIceberg.jl that referenced this pull request Sep 17, 2026
## Summary
Bumps `iceberg`/`iceberg-catalog-rest` to
`RelationalAI/iceberg-rust@ec07ed0f7` (main, post [PR
#82](RelationalAI/iceberg-rust#82) — the merge
of `apache/iceberg-rust@main`). Brings in row lineage (`_row_id`),
bloom-filter row-group pruning, Parquet Modular Encryption plumbing, and
a new REST-catalog `AuthSession`/`AuthManager` architecture, while our
vended credentials, custom REST authenticator, storage-credential
refresh, and `OverwriteAction` all carry forward unchanged in behavior.

This needed real source changes, not just a rev bump, because that merge
also completed a storage-backend migration on the iceberg-rust side:

- **Storage factory types moved crates.** `iceberg`'s old in-tree
opendal storage module (`OpenDalStorageFactory`,
`OpenDalRoutingStorageFactory`, the `storage-azdls` feature) was removed
in favor of the standalone `iceberg-storage-opendal` crate
(`OpenDalStorageFactory` now lives there; `OpenDalRoutingStorageFactory`
renamed to `OpenDalResolvingStorageFactory`) and
`iceberg-storage-refreshable` (`RefreshableStorageFactory`). Added both
as direct dependencies and updated `catalog.rs`/`table.rs`'s imports and
construction sites.
- **`OpenDalStorageFactory::S3` dropped `configured_scheme`** — it no
longer distinguishes `s3` vs `s3a` — so that field is dropped from the
one call site that set it.
- **`FileScanTask`'s fields all became private with accessor methods.**
Fixed the one remaining field access (`record_count`) and converted
three test-only struct-literal constructions in `full_pipeline.rs` to
the builder API.
- **Bumped `arrow-*`/`parquet` from 58.1 to 59.2** to match
iceberg-rust's new requirement — otherwise cargo resolves two
incompatible versions of the same crates and every type crossing the FFI
boundary fails to unify.

Bumped `iceberg_rust_ffi` and the Julia package version to 0.9.5.

## Test plan
- [x] `cargo check --all-targets` clean (`iceberg_rust_ffi`, against the
new rev)
- [x] `cargo clippy --all-targets -- -D warnings` clean
- [x] `cargo fmt --all -- --check` clean
- [x] CI (Julia test suite, docker-backed integration tests)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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.