Skip to content

Commit ad90cea

Browse files
author
jaby
authored
This closes qax-os#1469, fix cell resolver caused incorrect calculation result (qax-os#1470)
1 parent 363fa94 commit ad90cea

File tree

2 files changed

+45
-18
lines changed

2 files changed

+45
-18
lines changed

calc.go

+27-17
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,10 @@ var (
197197
// calcContext defines the formula execution context.
198198
type calcContext struct {
199199
sync.Mutex
200-
entry string
201-
iterations map[string]uint
200+
entry string
201+
maxCalcIterations uint
202+
iterations map[string]uint
203+
iterationsCache map[string]formulaArg
202204
}
203205

204206
// cellRef defines the structure of a cell reference.
@@ -774,8 +776,10 @@ func (f *File) CalcCellValue(sheet, cell string, opts ...Options) (result string
774776
token formulaArg
775777
)
776778
if token, err = f.calcCellValue(&calcContext{
777-
entry: fmt.Sprintf("%s!%s", sheet, cell),
778-
iterations: make(map[string]uint),
779+
entry: fmt.Sprintf("%s!%s", sheet, cell),
780+
maxCalcIterations: getOptions(opts...).MaxCalcIterations,
781+
iterations: make(map[string]uint),
782+
iterationsCache: make(map[string]formulaArg),
779783
}, sheet, cell); err != nil {
780784
return
781785
}
@@ -1527,17 +1531,6 @@ func (f *File) cellResolver(ctx *calcContext, sheet, cell string) (formulaArg, e
15271531
value string
15281532
err error
15291533
)
1530-
ref := fmt.Sprintf("%s!%s", sheet, cell)
1531-
if formula, _ := f.GetCellFormula(sheet, cell); len(formula) != 0 {
1532-
ctx.Lock()
1533-
if ctx.entry != ref && ctx.iterations[ref] <= f.options.MaxCalcIterations {
1534-
ctx.iterations[ref]++
1535-
ctx.Unlock()
1536-
arg, _ = f.calcCellValue(ctx, sheet, cell)
1537-
return arg, nil
1538-
}
1539-
ctx.Unlock()
1540-
}
15411534
if value, err = f.GetCellValue(sheet, cell, Options{RawCellValue: true}); err != nil {
15421535
return arg, err
15431536
}
@@ -1551,8 +1544,25 @@ func (f *File) cellResolver(ctx *calcContext, sheet, cell string) (formulaArg, e
15511544
return newEmptyFormulaArg(), err
15521545
}
15531546
return arg.ToNumber(), err
1554-
default:
1547+
case CellTypeInlineString, CellTypeSharedString:
15551548
return arg, err
1549+
case CellTypeFormula:
1550+
ref := fmt.Sprintf("%s!%s", sheet, cell)
1551+
if ctx.entry != ref {
1552+
ctx.Lock()
1553+
if ctx.iterations[ref] <= ctx.maxCalcIterations {
1554+
ctx.iterations[ref]++
1555+
ctx.Unlock()
1556+
arg, _ = f.calcCellValue(ctx, sheet, cell)
1557+
ctx.iterationsCache[ref] = arg
1558+
return arg, nil
1559+
}
1560+
ctx.Unlock()
1561+
return ctx.iterationsCache[ref], nil
1562+
}
1563+
fallthrough
1564+
default:
1565+
return newEmptyFormulaArg(), err
15561566
}
15571567
}
15581568

@@ -7746,7 +7756,7 @@ func (fn *formulaFuncs) COUNTBLANK(argsList *list.List) formulaArg {
77467756
}
77477757
var count float64
77487758
for _, cell := range argsList.Front().Value.(formulaArg).ToList() {
7749-
if cell.Value() == "" {
7759+
if cell.Type == ArgEmpty {
77507760
count++
77517761
}
77527762
}

calc_test.go

+18-1
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ func TestCalcCellValue(t *testing.T) {
10231023
"=COUNTBLANK(MUNIT(1))": "0",
10241024
"=COUNTBLANK(1)": "0",
10251025
"=COUNTBLANK(B1:C1)": "1",
1026-
"=COUNTBLANK(C1)": "1",
1026+
"=COUNTBLANK(C1)": "0",
10271027
// COUNTIF
10281028
"=COUNTIF(D1:D9,\"Jan\")": "4",
10291029
"=COUNTIF(D1:D9,\"<>Jan\")": "5",
@@ -5871,3 +5871,20 @@ func TestCalcColRowQRDecomposition(t *testing.T) {
58715871
assert.False(t, calcRowQRDecomposition([][]float64{{0, 0}, {0, 0}}, []float64{0, 0}, 1, 0))
58725872
assert.False(t, calcColQRDecomposition([][]float64{{0, 0}, {0, 0}}, []float64{0, 0}, 1, 0))
58735873
}
5874+
5875+
func TestCalcCellResolver(t *testing.T) {
5876+
f := NewFile()
5877+
// Test reference a cell multiple times in a formula
5878+
assert.NoError(t, f.SetCellValue("Sheet1", "A1", "VALUE1"))
5879+
assert.NoError(t, f.SetCellFormula("Sheet1", "A2", "=A1"))
5880+
for formula, expected := range map[string]string{
5881+
"=CONCATENATE(A1,\"_\",A1)": "VALUE1_VALUE1",
5882+
"=CONCATENATE(A1,\"_\",A2)": "VALUE1_VALUE1",
5883+
"=CONCATENATE(A2,\"_\",A2)": "VALUE1_VALUE1",
5884+
} {
5885+
assert.NoError(t, f.SetCellFormula("Sheet1", "A3", formula))
5886+
result, err := f.CalcCellValue("Sheet1", "A3")
5887+
assert.NoError(t, err, formula)
5888+
assert.Equal(t, expected, result, formula)
5889+
}
5890+
}

0 commit comments

Comments
 (0)