Add rename_column support to UpdateSchemaAction
- Dominant language
- Rust
- Stars
- 1.4k
- Forks
- 567
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 93
Description
# Add `rename_column` support to `UpdateSchemaAction`
**Label:** `enhancement`
## Is your feature request related to a problem or challenge?
`UpdateSchemaAction` currently supports `add_column` and `delete_column` (PR #2120), but not `rename_column`. Schema evolution APIs in sibling implementations (PyIceberg, Java) all expose rename as a first-class operation, and downstream Rust users who need parity with those implementations have to fall back to:
The `add_column` / `delete_column` infrastructure already does almost everything rename needs (the rebuild-the-schema-tree pattern, the `AddSchema` + `SetCurrentSchema` emission, the `CurrentSchemaIdMatch` requirement). The gap is just the builder method, the validation, and threading the renames through the rebuild step.
## Describe the solution you'd like
A new builder method on `UpdateSchemaAction` matching the existing add/delete shape:
```rust
let tx = Transaction::new(&table);
let action = tx.update_schema()
.rename_column("old_name", "new_name")
.rename_column("person.name", "fullname"); // nested supported
let tx = action.apply(tx).unwrap();
let table = tx.commit(&catalog).await.unwrap();
```
Semantics modeled on `pyiceberg.table.update.schema.UpdateSchema.rename_column`:
- **Field ID is preserved.** This is Iceberg's invariant — rename is a metadata-only operation on the name; the column ID stays stable so existing data files and snapshots remain valid.
- **`path_from` uses `SCHEMA_NAME_DELIMITER`** (`.`) for nested fields. `new_name` is the unqualified leaf name; rename does not move a field between parent structs.
- **Identifier fields handled transparently.** Iceberg keys `identifier_field_ids` by ID, not name, so the existing `with_identifier_field_ids(base_schema.identifier_field_ids())` step in `commit()` already propagates them correctly across renames.
- **Composes with add/delete in the same action.** A rename frees the old name for re-use by an addition; the renamed field can take a name previously held by a sibling being deleted.
Validation rules (all `PreconditionFailed`):
- `path_from` must exist in the current schema.
- A field cannot be both renamed and deleted in the same action — intent is ambiguous.
- `new_name` cannot contain `SCHEMA_NAME_DELIMITER` — would otherwise silently look like a move-across-structs.
- `new_name` cannot collide with a sibling that is not itself being deleted or renamed away.
- If the same field is renamed multiple times, the last rename wins (matches PyIceberg).
### Scope
This issue covers **only `rename_column`**. PyIceberg's `UpdateSchema` exposes other operations not covered here:
- `update_column` (type promotion / nullability / doc edits)
- `make_column_optional` / `make_column_required`
- `move_first` / `move_before` / `move_after`
- `set_identifier_fields`
Those are out of scope and would be follow-up issues if there's interest.
## Willingness to contribute
I can contribute to this feature independently. I have a working branch with the implementation + 10 new unit tests (matching the style and depth of the existing `test_*_add_column*` / `test_*_delete_column*` tests in `transaction::update_schema::tests`), and a PR ready to open once this issue is filed for reference.
Contributor guide
Research direction
Start with UpdateSchemaAction and the existing add_column/delete_column implementations, then read the transaction::update_schema::tests cases named in the issue. Trace the schema-tree rebuild, AddSchema, SetCurrentSchema, and identifier-field handling. Done means nested and repeated renames work with add/delete composition, all listed PreconditionFailed validations hold, and the new unit tests pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- databases
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100