Skip to content

Commit f707b2d

Browse files
author
张涛
authored
This closes qax-os#1484, fix the formula calc result issue (qax-os#1485)
- Optimize variable name for data validation
1 parent 65a53b3 commit f707b2d

File tree

3 files changed

+117
-116
lines changed

3 files changed

+117
-116
lines changed

calc.go

+16-15
Original file line numberDiff line numberDiff line change
@@ -1532,6 +1532,22 @@ func (f *File) cellResolver(ctx *calcContext, sheet, cell string) (formulaArg, e
15321532
value string
15331533
err error
15341534
)
1535+
ref := fmt.Sprintf("%s!%s", sheet, cell)
1536+
if formula, _ := f.GetCellFormula(sheet, cell); len(formula) != 0 {
1537+
ctx.Lock()
1538+
if ctx.entry != ref {
1539+
if ctx.iterations[ref] <= f.options.MaxCalcIterations {
1540+
ctx.iterations[ref]++
1541+
ctx.Unlock()
1542+
arg, _ = f.calcCellValue(ctx, sheet, cell)
1543+
ctx.iterationsCache[ref] = arg
1544+
return arg, nil
1545+
}
1546+
ctx.Unlock()
1547+
return ctx.iterationsCache[ref], nil
1548+
}
1549+
ctx.Unlock()
1550+
}
15351551
if value, err = f.GetCellValue(sheet, cell, Options{RawCellValue: true}); err != nil {
15361552
return arg, err
15371553
}
@@ -1547,21 +1563,6 @@ func (f *File) cellResolver(ctx *calcContext, sheet, cell string) (formulaArg, e
15471563
return arg.ToNumber(), err
15481564
case CellTypeInlineString, CellTypeSharedString:
15491565
return arg, err
1550-
case CellTypeFormula:
1551-
ref := fmt.Sprintf("%s!%s", sheet, cell)
1552-
if ctx.entry != ref {
1553-
ctx.Lock()
1554-
if ctx.iterations[ref] <= ctx.maxCalcIterations {
1555-
ctx.iterations[ref]++
1556-
ctx.Unlock()
1557-
arg, _ = f.calcCellValue(ctx, sheet, cell)
1558-
ctx.iterationsCache[ref] = arg
1559-
return arg, nil
1560-
}
1561-
ctx.Unlock()
1562-
return ctx.iterationsCache[ref], nil
1563-
}
1564-
fallthrough
15651566
default:
15661567
return newEmptyFormulaArg(), err
15671568
}

datavalidation.go

+41-41
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ func NewDataValidation(allowBlank bool) *DataValidation {
8888
}
8989

9090
// SetError set error notice.
91-
func (dd *DataValidation) SetError(style DataValidationErrorStyle, title, msg string) {
92-
dd.Error = &msg
93-
dd.ErrorTitle = &title
91+
func (dv *DataValidation) SetError(style DataValidationErrorStyle, title, msg string) {
92+
dv.Error = &msg
93+
dv.ErrorTitle = &title
9494
strStyle := styleStop
9595
switch style {
9696
case DataValidationErrorStyleStop:
@@ -101,31 +101,31 @@ func (dd *DataValidation) SetError(style DataValidationErrorStyle, title, msg st
101101
strStyle = styleInformation
102102

103103
}
104-
dd.ShowErrorMessage = true
105-
dd.ErrorStyle = &strStyle
104+
dv.ShowErrorMessage = true
105+
dv.ErrorStyle = &strStyle
106106
}
107107

108108
// SetInput set prompt notice.
109-
func (dd *DataValidation) SetInput(title, msg string) {
110-
dd.ShowInputMessage = true
111-
dd.PromptTitle = &title
112-
dd.Prompt = &msg
109+
func (dv *DataValidation) SetInput(title, msg string) {
110+
dv.ShowInputMessage = true
111+
dv.PromptTitle = &title
112+
dv.Prompt = &msg
113113
}
114114

115115
// SetDropList data validation list.
116-
func (dd *DataValidation) SetDropList(keys []string) error {
116+
func (dv *DataValidation) SetDropList(keys []string) error {
117117
formula := strings.Join(keys, ",")
118118
if MaxFieldLength < len(utf16.Encode([]rune(formula))) {
119119
return ErrDataValidationFormulaLength
120120
}
121-
dd.Formula1 = fmt.Sprintf(`<formula1>"%s"</formula1>`, formulaEscaper.Replace(formula))
122-
dd.Type = convDataValidationType(typeList)
121+
dv.Formula1 = fmt.Sprintf(`<formula1>"%s"</formula1>`, formulaEscaper.Replace(formula))
122+
dv.Type = convDataValidationType(typeList)
123123
return nil
124124
}
125125

126126
// SetRange provides function to set data validation range in drop list, only
127127
// accepts int, float64, or string data type formula argument.
128-
func (dd *DataValidation) SetRange(f1, f2 interface{}, t DataValidationType, o DataValidationOperator) error {
128+
func (dv *DataValidation) SetRange(f1, f2 interface{}, t DataValidationType, o DataValidationOperator) error {
129129
var formula1, formula2 string
130130
switch v := f1.(type) {
131131
case int:
@@ -153,9 +153,9 @@ func (dd *DataValidation) SetRange(f1, f2 interface{}, t DataValidationType, o D
153153
default:
154154
return ErrParameterInvalid
155155
}
156-
dd.Formula1, dd.Formula2 = formula1, formula2
157-
dd.Type = convDataValidationType(t)
158-
dd.Operator = convDataValidationOperator(o)
156+
dv.Formula1, dv.Formula2 = formula1, formula2
157+
dv.Type = convDataValidationType(t)
158+
dv.Operator = convDataValidationOperator(o)
159159
return nil
160160
}
161161

@@ -166,21 +166,21 @@ func (dd *DataValidation) SetRange(f1, f2 interface{}, t DataValidationType, o D
166166
// Sheet1!A7:B8 with validation criteria source Sheet1!E1:E3 settings, create
167167
// in-cell dropdown by allowing list source:
168168
//
169-
// dvRange := excelize.NewDataValidation(true)
170-
// dvRange.Sqref = "A7:B8"
171-
// dvRange.SetSqrefDropList("$E$1:$E$3")
172-
// f.AddDataValidation("Sheet1", dvRange)
173-
func (dd *DataValidation) SetSqrefDropList(sqref string) {
174-
dd.Formula1 = fmt.Sprintf("<formula1>%s</formula1>", sqref)
175-
dd.Type = convDataValidationType(typeList)
169+
// dv := excelize.NewDataValidation(true)
170+
// dv.Sqref = "A7:B8"
171+
// dv.SetSqrefDropList("$E$1:$E$3")
172+
// err := f.AddDataValidation("Sheet1", dv)
173+
func (dv *DataValidation) SetSqrefDropList(sqref string) {
174+
dv.Formula1 = fmt.Sprintf("<formula1>%s</formula1>", sqref)
175+
dv.Type = convDataValidationType(typeList)
176176
}
177177

178178
// SetSqref provides function to set data validation range in drop list.
179-
func (dd *DataValidation) SetSqref(sqref string) {
180-
if dd.Sqref == "" {
181-
dd.Sqref = sqref
179+
func (dv *DataValidation) SetSqref(sqref string) {
180+
if dv.Sqref == "" {
181+
dv.Sqref = sqref
182182
} else {
183-
dd.Sqref = fmt.Sprintf("%s %s", dd.Sqref, sqref)
183+
dv.Sqref = fmt.Sprintf("%s %s", dv.Sqref, sqref)
184184
}
185185
}
186186

@@ -224,28 +224,28 @@ func convDataValidationOperator(o DataValidationOperator) string {
224224
// settings, show error alert after invalid data is entered with "Stop" style
225225
// and custom title "error body":
226226
//
227-
// dvRange := excelize.NewDataValidation(true)
228-
// dvRange.Sqref = "A1:B2"
229-
// dvRange.SetRange(10, 20, excelize.DataValidationTypeWhole, excelize.DataValidationOperatorBetween)
230-
// dvRange.SetError(excelize.DataValidationErrorStyleStop, "error title", "error body")
231-
// err := f.AddDataValidation("Sheet1", dvRange)
227+
// dv := excelize.NewDataValidation(true)
228+
// dv.Sqref = "A1:B2"
229+
// dv.SetRange(10, 20, excelize.DataValidationTypeWhole, excelize.DataValidationOperatorBetween)
230+
// dv.SetError(excelize.DataValidationErrorStyleStop, "error title", "error body")
231+
// err := f.AddDataValidation("Sheet1", dv)
232232
//
233233
// Example 2, set data validation on Sheet1!A3:B4 with validation criteria
234234
// settings, and show input message when cell is selected:
235235
//
236-
// dvRange = excelize.NewDataValidation(true)
237-
// dvRange.Sqref = "A3:B4"
238-
// dvRange.SetRange(10, 20, excelize.DataValidationTypeWhole, excelize.DataValidationOperatorGreaterThan)
239-
// dvRange.SetInput("input title", "input body")
240-
// err = f.AddDataValidation("Sheet1", dvRange)
236+
// dv = excelize.NewDataValidation(true)
237+
// dv.Sqref = "A3:B4"
238+
// dv.SetRange(10, 20, excelize.DataValidationTypeWhole, excelize.DataValidationOperatorGreaterThan)
239+
// dv.SetInput("input title", "input body")
240+
// err = f.AddDataValidation("Sheet1", dv)
241241
//
242242
// Example 3, set data validation on Sheet1!A5:B6 with validation criteria
243243
// settings, create in-cell dropdown by allowing list source:
244244
//
245-
// dvRange = excelize.NewDataValidation(true)
246-
// dvRange.Sqref = "A5:B6"
247-
// dvRange.SetDropList([]string{"1", "2", "3"})
248-
// err = f.AddDataValidation("Sheet1", dvRange)
245+
// dv = excelize.NewDataValidation(true)
246+
// dv.Sqref = "A5:B6"
247+
// dv.SetDropList([]string{"1", "2", "3"})
248+
// err = f.AddDataValidation("Sheet1", dv)
249249
func (f *File) AddDataValidation(sheet string, dv *DataValidation) error {
250250
ws, err := f.workSheetReader(sheet)
251251
if err != nil {

datavalidation_test.go

+60-60
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,25 @@ func TestDataValidation(t *testing.T) {
2525

2626
f := NewFile()
2727

28-
dvRange := NewDataValidation(true)
29-
dvRange.Sqref = "A1:B2"
30-
assert.NoError(t, dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorBetween))
31-
dvRange.SetError(DataValidationErrorStyleStop, "error title", "error body")
32-
dvRange.SetError(DataValidationErrorStyleWarning, "error title", "error body")
33-
dvRange.SetError(DataValidationErrorStyleInformation, "error title", "error body")
34-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
28+
dv := NewDataValidation(true)
29+
dv.Sqref = "A1:B2"
30+
assert.NoError(t, dv.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorBetween))
31+
dv.SetError(DataValidationErrorStyleStop, "error title", "error body")
32+
dv.SetError(DataValidationErrorStyleWarning, "error title", "error body")
33+
dv.SetError(DataValidationErrorStyleInformation, "error title", "error body")
34+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
3535

3636
dataValidations, err := f.GetDataValidations("Sheet1")
3737
assert.NoError(t, err)
3838
assert.Equal(t, len(dataValidations), 1)
3939

4040
assert.NoError(t, f.SaveAs(resultFile))
4141

42-
dvRange = NewDataValidation(true)
43-
dvRange.Sqref = "A3:B4"
44-
assert.NoError(t, dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan))
45-
dvRange.SetInput("input title", "input body")
46-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
42+
dv = NewDataValidation(true)
43+
dv.Sqref = "A3:B4"
44+
assert.NoError(t, dv.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan))
45+
dv.SetInput("input title", "input body")
46+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
4747

4848
dataValidations, err = f.GetDataValidations("Sheet1")
4949
assert.NoError(t, err)
@@ -55,35 +55,35 @@ func TestDataValidation(t *testing.T) {
5555
assert.NoError(t, err)
5656
assert.NoError(t, f.SetSheetRow("Sheet2", "A2", &[]interface{}{"B2", 1}))
5757
assert.NoError(t, f.SetSheetRow("Sheet2", "A3", &[]interface{}{"B3", 3}))
58-
dvRange = NewDataValidation(true)
59-
dvRange.Sqref = "A1:B1"
60-
assert.NoError(t, dvRange.SetRange("INDIRECT($A$2)", "INDIRECT($A$3)", DataValidationTypeWhole, DataValidationOperatorBetween))
61-
dvRange.SetError(DataValidationErrorStyleStop, "error title", "error body")
62-
assert.NoError(t, f.AddDataValidation("Sheet2", dvRange))
58+
dv = NewDataValidation(true)
59+
dv.Sqref = "A1:B1"
60+
assert.NoError(t, dv.SetRange("INDIRECT($A$2)", "INDIRECT($A$3)", DataValidationTypeWhole, DataValidationOperatorBetween))
61+
dv.SetError(DataValidationErrorStyleStop, "error title", "error body")
62+
assert.NoError(t, f.AddDataValidation("Sheet2", dv))
6363
dataValidations, err = f.GetDataValidations("Sheet1")
6464
assert.NoError(t, err)
6565
assert.Equal(t, len(dataValidations), 2)
6666
dataValidations, err = f.GetDataValidations("Sheet2")
6767
assert.NoError(t, err)
6868
assert.Equal(t, len(dataValidations), 1)
6969

70-
dvRange = NewDataValidation(true)
71-
dvRange.Sqref = "A5:B6"
70+
dv = NewDataValidation(true)
71+
dv.Sqref = "A5:B6"
7272
for _, listValid := range [][]string{
7373
{"1", "2", "3"},
7474
{strings.Repeat("&", MaxFieldLength)},
7575
{strings.Repeat("\u4E00", MaxFieldLength)},
7676
{strings.Repeat("\U0001F600", 100), strings.Repeat("\u4E01", 50), "<&>"},
7777
{`A<`, `B>`, `C"`, "D\t", `E'`, `F`},
7878
} {
79-
dvRange.Formula1 = ""
80-
assert.NoError(t, dvRange.SetDropList(listValid),
79+
dv.Formula1 = ""
80+
assert.NoError(t, dv.SetDropList(listValid),
8181
"SetDropList failed for valid input %v", listValid)
82-
assert.NotEqual(t, "", dvRange.Formula1,
82+
assert.NotEqual(t, "", dv.Formula1,
8383
"Formula1 should not be empty for valid input %v", listValid)
8484
}
85-
assert.Equal(t, `<formula1>"A&lt;,B&gt;,C"",D ,E',F"</formula1>`, dvRange.Formula1)
86-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
85+
assert.Equal(t, `<formula1>"A&lt;,B&gt;,C"",D ,E',F"</formula1>`, dv.Formula1)
86+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
8787

8888
dataValidations, err = f.GetDataValidations("Sheet1")
8989
assert.NoError(t, err)
@@ -113,49 +113,49 @@ func TestDataValidationError(t *testing.T) {
113113
assert.NoError(t, f.SetCellStr("Sheet1", "E2", "E2"))
114114
assert.NoError(t, f.SetCellStr("Sheet1", "E3", "E3"))
115115

116-
dvRange := NewDataValidation(true)
117-
dvRange.SetSqref("A7:B8")
118-
dvRange.SetSqref("A7:B8")
119-
dvRange.SetSqrefDropList("$E$1:$E$3")
116+
dv := NewDataValidation(true)
117+
dv.SetSqref("A7:B8")
118+
dv.SetSqref("A7:B8")
119+
dv.SetSqrefDropList("$E$1:$E$3")
120120

121-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
121+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
122122

123-
dvRange = NewDataValidation(true)
124-
err := dvRange.SetDropList(make([]string, 258))
125-
if dvRange.Formula1 != "" {
123+
dv = NewDataValidation(true)
124+
err := dv.SetDropList(make([]string, 258))
125+
if dv.Formula1 != "" {
126126
t.Errorf("data validation error. Formula1 must be empty!")
127127
return
128128
}
129129
assert.EqualError(t, err, ErrDataValidationFormulaLength.Error())
130-
assert.EqualError(t, dvRange.SetRange(nil, 20, DataValidationTypeWhole, DataValidationOperatorBetween), ErrParameterInvalid.Error())
131-
assert.EqualError(t, dvRange.SetRange(10, nil, DataValidationTypeWhole, DataValidationOperatorBetween), ErrParameterInvalid.Error())
132-
assert.NoError(t, dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan))
133-
dvRange.SetSqref("A9:B10")
130+
assert.EqualError(t, dv.SetRange(nil, 20, DataValidationTypeWhole, DataValidationOperatorBetween), ErrParameterInvalid.Error())
131+
assert.EqualError(t, dv.SetRange(10, nil, DataValidationTypeWhole, DataValidationOperatorBetween), ErrParameterInvalid.Error())
132+
assert.NoError(t, dv.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan))
133+
dv.SetSqref("A9:B10")
134134

135-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
135+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
136136

137137
// Test width invalid data validation formula
138-
prevFormula1 := dvRange.Formula1
138+
prevFormula1 := dv.Formula1
139139
for _, keys := range [][]string{
140140
make([]string, 257),
141141
{strings.Repeat("s", 256)},
142142
{strings.Repeat("\u4E00", 256)},
143143
{strings.Repeat("\U0001F600", 128)},
144144
{strings.Repeat("\U0001F600", 127), "s"},
145145
} {
146-
err = dvRange.SetDropList(keys)
147-
assert.Equal(t, prevFormula1, dvRange.Formula1,
146+
err = dv.SetDropList(keys)
147+
assert.Equal(t, prevFormula1, dv.Formula1,
148148
"Formula1 should be unchanged for invalid input %v", keys)
149149
assert.EqualError(t, err, ErrDataValidationFormulaLength.Error())
150150
}
151-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
152-
assert.NoError(t, dvRange.SetRange(
151+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
152+
assert.NoError(t, dv.SetRange(
153153
-math.MaxFloat32, math.MaxFloat32,
154154
DataValidationTypeWhole, DataValidationOperatorGreaterThan))
155-
assert.EqualError(t, dvRange.SetRange(
155+
assert.EqualError(t, dv.SetRange(
156156
-math.MaxFloat64, math.MaxFloat32,
157157
DataValidationTypeWhole, DataValidationOperatorGreaterThan), ErrDataValidationRange.Error())
158-
assert.EqualError(t, dvRange.SetRange(
158+
assert.EqualError(t, dv.SetRange(
159159
math.SmallestNonzeroFloat64, math.MaxFloat64,
160160
DataValidationTypeWhole, DataValidationOperatorGreaterThan), ErrDataValidationRange.Error())
161161
assert.NoError(t, f.SaveAs(resultFile))
@@ -173,33 +173,33 @@ func TestDeleteDataValidation(t *testing.T) {
173173
f := NewFile()
174174
assert.NoError(t, f.DeleteDataValidation("Sheet1", "A1:B2"))
175175

176-
dvRange := NewDataValidation(true)
177-
dvRange.Sqref = "A1:B2"
178-
assert.NoError(t, dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorBetween))
179-
dvRange.SetInput("input title", "input body")
180-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
176+
dv := NewDataValidation(true)
177+
dv.Sqref = "A1:B2"
178+
assert.NoError(t, dv.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorBetween))
179+
dv.SetInput("input title", "input body")
180+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
181181
assert.NoError(t, f.DeleteDataValidation("Sheet1", "A1:B2"))
182182

183-
dvRange.Sqref = "A1"
184-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
183+
dv.Sqref = "A1"
184+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
185185
assert.NoError(t, f.DeleteDataValidation("Sheet1", "B1"))
186186
assert.NoError(t, f.DeleteDataValidation("Sheet1", "A1"))
187187

188-
dvRange.Sqref = "C2:C5"
189-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
188+
dv.Sqref = "C2:C5"
189+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
190190
assert.NoError(t, f.DeleteDataValidation("Sheet1", "C4"))
191191

192-
dvRange = NewDataValidation(true)
193-
dvRange.Sqref = "D2:D2 D3 D4"
194-
assert.NoError(t, dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorBetween))
195-
dvRange.SetInput("input title", "input body")
196-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
192+
dv = NewDataValidation(true)
193+
dv.Sqref = "D2:D2 D3 D4"
194+
assert.NoError(t, dv.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorBetween))
195+
dv.SetInput("input title", "input body")
196+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
197197
assert.NoError(t, f.DeleteDataValidation("Sheet1", "D3"))
198198

199199
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeleteDataValidation.xlsx")))
200200

201-
dvRange.Sqref = "A"
202-
assert.NoError(t, f.AddDataValidation("Sheet1", dvRange))
201+
dv.Sqref = "A"
202+
assert.NoError(t, f.AddDataValidation("Sheet1", dv))
203203
assert.EqualError(t, f.DeleteDataValidation("Sheet1", "A1"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
204204

205205
assert.EqualError(t, f.DeleteDataValidation("Sheet1", "A1:A"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())

0 commit comments

Comments
 (0)