Skip to content

This closes #2303, support 3D references across sheet ranges#2310

Merged
xuri merged 4 commits into
qax-os:masterfrom
sloppy-org:2303-3d-refs-clean
May 25, 2026
Merged

This closes #2303, support 3D references across sheet ranges#2310
xuri merged 4 commits into
qax-os:masterfrom
sloppy-org:2303-3d-refs-clean

Conversation

@krystophny
Copy link
Copy Markdown
Contributor

@krystophny krystophny commented Apr 23, 2026

Description

Formulas of the shape SUM(Sheet1:SheetN!A1) previously failed with #NAME? invalid reference because parseReference split the reference on : and handed the leading sheet token to parseRef, which treats it as a cell name.

This change teaches parseReference to recognise references of the shape <sheet1>:<sheet2>!<ref>, expand them across the workbook-order sheet range, and evaluate each sheet's cell or range recursively. The resulting matrix is consumed unchanged by the existing aggregates (SUM, AVERAGE, MIN, MAX, COUNT, COUNTA, PRODUCT). Non-ASCII unquoted sheet names work too, e.g. SUM(Jänner:Dezember!$M$40).

The quoted-name form SUM('A':'B'!ref) is mis-tokenised by github.com/xuri/efp upstream of parseReference and is therefore out of scope here; it is tracked separately in #2309.

Related Issue

Partial closer for umbrella #2303; the quoted-form gap is tracked in #2309.

Documentation

Reference-site entries for this PR ship in a companion docs PR: xuri/excelize-doc#31. That PR covers the English version; other language versions follow the project's usual rollout cadence.

Motivation and Context

Workbooks with 3D aggregate totals (e.g. annual summaries across monthly sheets) currently cannot be recalculated through excelize — every such formula resolves to #NAME?. This is the narrowest fix that removes that failure without touching other code paths.

How Has This Been Tested

go test -skip TestZip64 -timeout 10m . passes cleanly. gofmt -s -l . and go vet ./... are clean. ARM cross-builds from .github/workflows/go.yml (GOARM=5|6|7, arm64, android/arm64) all build.

$ go test -run 'TestCalc3DRef$' -timeout 60s -v .
=== RUN   TestCalc3DRef
=== RUN   TestCalc3DRef/non-ascii_sheet_names
--- PASS: TestCalc3DRef (0.01s)
    --- PASS: TestCalc3DRef/non-ascii_sheet_names (0.00s)
PASS
ok  	github.com/xuri/excelize/v2	0.014s

TestCalc3DRef is table-driven and covers single-cell, range, degenerate single-sheet, multi-column, reversed range (#REF!), and missing sheet cases across all seven aggregates listed above. The non-ASCII sub-test covers Jänner:Dezember.

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

Formulas of the shape SUM(Sheet1:SheetN!A1) failed with
#NAME? invalid reference because parseReference split the
reference on ':' and handed the leading sheet token to parseRef,
which treats it as a cell name. No code path recognised the 3D
shape.

Add parse3DRef / split3DRef / readSheetToken / expand3DSheetRange
ahead of parseReference. On a match the reference is expanded
across the workbook-order sheet range and each sheet's cell or
range is evaluated recursively, yielding a matrix that existing
aggregates (SUM, AVERAGE, MIN, MAX, COUNT, COUNTA, PRODUCT)
consume unchanged. Non-ASCII sheet names work unquoted, e.g.
SUM(Jänner:Dezember!M40), matching Excel's behaviour.

The quoted-name form SUM('A':'B'!ref) is mis-tokenised by
github.com/xuri/efp before parseReference sees it, so it is
tracked separately and not handled here.

Signed-off-by: Christopher Albert <albert@tugraz.at>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.60%. Comparing base (7240c79) to head (8f0f428).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2310   +/-   ##
=======================================
  Coverage   99.60%   99.60%           
=======================================
  Files          32       32           
  Lines       26803    26855   +52     
=======================================
+ Hits        26697    26749   +52     
  Misses         55       55           
  Partials       51       51           
Flag Coverage Δ
unittests 99.60% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Member

@xuri xuri left a comment

Choose a reason for hiding this comment

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

Thanks for your PR. Could you grant sloppy-org:2303-3d-refs-cleanbranch push permission for me? So I can made some code review updates based on your branch.

@krystophny
Copy link
Copy Markdown
Contributor Author

@xuri I sent an invite to the fork repo, since this pr based write access doesnt work cross-orga . Cheers!

Comment thread calc.go Outdated
Comment thread calc.go Outdated
Comment thread calc.go Outdated
@xuri xuri linked an issue May 25, 2026 that may be closed by this pull request
1 task
@xuri xuri moved this to Features in Excelize v2.11.0 May 25, 2026
Copy link
Copy Markdown
Member

@xuri xuri left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution.

@xuri xuri merged commit f4a068b into qax-os:master May 25, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

Status: Features

Development

Successfully merging this pull request may close these issues.

Support quoted 3D references of the form SUM('Sheet1':'SheetN'!A1)

2 participants