nazq opened a new pull request, #2563:
URL: https://github.com/apache/iceberg-rust/pull/2563
## Which issue does this PR close?
- Closes #2562.
## What changes are included in this PR?
Adds `rename_column` to `UpdateSchemaAction`, completing the
add/delete/rename triad for non-incompatible schema evolution in
`transaction::update_schema`.
### Public API
```rust
let tx = Transaction::new(&table);
let action = tx.update_schema()
.add_column(AddColumn::optional("new_col",
Type::Primitive(PrimitiveType::Int)))
.rename_column("old_name", "new_name")
.rename_column("person.name", "fullname") // nested supported
.delete_column("dead_col");
let tx = action.apply(tx).unwrap();
let table = tx.commit(&catalog).await.unwrap();
```
`rename_column(path_from, new_name)` mirrors the existing `add_column` /
`delete_column` builder shape. Field IDs are preserved across rename — only the
leaf name changes.
### Implementation
A new `renames: Vec<(String, String)>` accumulator on `UpdateSchemaAction`,
plus a new step in `commit()` between deletes and additions:
- **After deletes** so a rename can re-use a name being deleted in the same
action.
- **Before additions** so an addition can re-use a name being renamed away.
The renames are resolved to a `HashMap<i32, String>` keyed by field ID, then
threaded through `rebuild_fields` / `rebuild_field` — same recursive walk that
handles deletes and nested additions. Each rebuild call site that previously
copied `field.name.clone()` now looks up the rename map first and falls back to
the original name. Identifier-field handling falls out for free because Rust
keys `identifier_field_ids` by ID, not name — the existing
`with_identifier_field_ids(base_schema.identifier_field_ids())` step propagates
the set unchanged.
### Semantics
Modeled on `pyiceberg.table.update.schema.UpdateSchema.rename_column`:
- `path_from` must exist in the current schema → otherwise
`PreconditionFailed`.
- A field cannot be both renamed and deleted in the same action →
`PreconditionFailed` (intent is ambiguous; matches PyIceberg).
- `new_name` cannot contain `SCHEMA_NAME_DELIMITER` → `PreconditionFailed`
(the unqualified-name requirement; preventing it from silently looking like a
move-across-structs).
- `new_name` cannot collide with a sibling that is not itself being deleted
or renamed away → `PreconditionFailed`.
- Same field renamed twice → last rename wins (matches PyIceberg's "stack on
prior update" behavior).
### Scope
`rename_column` only. PyIceberg's `UpdateSchema` has other ops
(`update_column`, `make_column_required`, `move_*`, `set_identifier_fields`) —
those are out of scope here and would be follow-up PRs if there's interest.
## Are these changes tested?
Yes — 10 new unit tests in `transaction::update_schema::tests`, matching the
style and depth of the existing `test_*_add_column*` / `test_*_delete_column*`
tests:
| Test | What it covers |
|---|---|
| `test_rename_column` | Simple root-level rename, verifies field ID
preserved |
| `test_rename_nested_column` | Nested rename (`person.name` →
`person.fullname`), preserves sibling fields |
| `test_rename_missing_column_fails` | Missing source field →
`PreconditionFailed` |
| `test_rename_and_delete_same_column_fails` | Rename + delete on same
column → `PreconditionFailed` |
| `test_rename_to_existing_sibling_fails` | Collision with a non-deleted,
non-renamed sibling → `PreconditionFailed` |
| `test_rename_path_with_dot_in_new_name_fails` | Rejects qualified new name
|
| `test_rename_identifier_field_preserves_identifier_ids` | Verifies
`identifier_field_ids` is preserved across rename of an identifier field |
| `test_rename_frees_name_for_addition` | Composition test: rename + add
re-uses the old name |
| `test_rename_same_column_twice_last_wins` | Idempotency / "last wins"
semantics |
| `test_rename_self_is_noop` | Rename to current name produces unchanged
schema |
All 18 existing `transaction::update_schema` tests still pass (no
regressions). Full `iceberg` lib suite: 1306/1306 passing. Clippy + rustfmt
clean.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]