Skip to content

fix(xls/xlsb): correct column letters in reconstructed formulas (columns >= AA) - #699

Merged
jmcnamara merged 3 commits into
tafia:masterfrom
gaoflow:fix-xls-formula-column-refs-beyond-z
Aug 14, 2026
Merged

fix(xls/xlsb): correct column letters in reconstructed formulas (columns >= AA)#699
jmcnamara merged 3 commits into
tafia:masterfrom
gaoflow:fix-xls-formula-column-refs-beyond-z

Conversation

@gaoflow

@gaoflow gaoflow commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Problem

utils::push_column converts a 0-based column index to Excel column letters, but it used plain base-26 and dropped the most-significant digit, so every index >= 26 was wrong:

index got Excel
26 A AA
52 A BA
701 AZ ZZ
702 BA AAA

775 of the first 801 indices disagree with Excel; only A..Z (0..25) were correct.

push_column is the renderer behind all ~13 column references emitted by the .xls and .xlsb formula readers, so worksheet_formula returned silently wrong columns for any binary-format formula referencing column AA or beyond, e.g. =SUM(AA1:AA10) came back as =SUM(A1:A10) — a different column, no error. (xlsx/ODS are unaffected; they carry formulas as strings.)

Excel columns are bijective base-26, and the crate already implements this correctly in xlsx::column_number_to_name (with a passing test). push_column just never matched its sibling. The fix mirrors that function; a new test asserts the two are byte-identical across the whole valid column range.

Second bug in the same path

While adding an integration fixture I found the BIFF8 PtgArea branch passed the raw column word — including the fColRel/fRwRel flag bits — straight to push_column and hardcoded $, so SUM(AA1:AA3) rendered as $BTSM$1:$BTSM$3. It now masks the 14-bit column and reads the relative flags, mirroring the adjacent PtgRef branch that already does this.

The 3D-reference branches (PtgRef3d/PtgArea3d) have the same unmasked-column pattern and a pre-existing // TODO: check with relative columns; I left those for a separate change to keep this focused.

Tests

  • push_column_is_bijective_base26 — boundary cases (0->A, 25->Z, 26->AA, 701->ZZ, 702->AAA, 16383->XFD) plus a differential check against xlsx::column_number_to_name over the full column range.
  • xls_formula_columns_beyond_z — a new .xls fixture whose formulas reference columns >= 26 (existing formula fixtures only use single-letter columns, so this path was untested). Renders SUM(AA1:AA3) and AA1+AB1.

Full suite passes.

This PR was written with AI assistance under my direction; I have reviewed it and am accountable for it.

@gaoflow
gaoflow force-pushed the fix-xls-formula-column-refs-beyond-z branch from 7d2e04f to cc036b5 Compare July 29, 2026 02:58
Comment thread src/utils.rs Outdated
Comment thread src/utils.rs
Comment thread src/utils.rs Outdated
Comment thread src/utils.rs Outdated
Comment thread src/utils.rs Outdated
Comment thread src/utils.rs Outdated
Comment thread src/xls.rs
Comment thread tests/test.rs Outdated
Comment thread .typos.toml Outdated
@jmcnamara

Copy link
Copy Markdown
Collaborator

As a general comment for future submissions, fixes for an issue should start with a bug report. This change also contains two separate bugs/PRs.

@jmcnamara jmcnamara self-assigned this Jul 29, 2026
@jmcnamara jmcnamara added the needs work for merge The PR needs some rework or clarification. No suitable for merge, yet. label Jul 29, 2026
gaoflow added 2 commits July 31, 2026 20:12
push_column dropped the most-significant digit for columns after Z
(e.g. index 26 rendered as "B"). Share one digit-fill implementation
with the xlsx converter, without allocating a buffer per call.
PtgArea column fields pack 14-bit column numbers with fColRel/fRwRel
flags; the old code read the raw 16 bits, so columns >= 64 (and the
relative flags) were wrong.
@gaoflow
gaoflow force-pushed the fix-xls-formula-column-refs-beyond-z branch from cc036b5 to 060bed4 Compare July 31, 2026 18:13
@gaoflow

gaoflow commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

All applied: push_column and column_number_to_name now share one allocation-free digit-fill core, comments trimmed, test renamed to test_push_column (BA case and typos entry dropped), and the branch is split into two commits — fix(utils) and fix(xls). Kept them in one PR since the xls fix builds on the column rendering; happy to split into a separate PR if you prefer.

@jmcnamara

Copy link
Copy Markdown
Collaborator

Thank you. Could you also mark the comments as resolved.

@gaoflow

gaoflow commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

All review threads are now marked resolved. Thanks!

@jmcnamara
jmcnamara merged commit 3ebbc24 into tafia:master Aug 14, 2026
6 checks passed
@jmcnamara

Copy link
Copy Markdown
Collaborator

Merged. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs work for merge The PR needs some rework or clarification. No suitable for merge, yet. next_release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants