diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationSheet.java
index 3497539be..0af2c842e 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationSheet.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationSheet.java
@@ -45,4 +45,8 @@ final class HSSFEvaluationSheet implements EvaluationSheet {
}
return new HSSFEvaluationCell(cell, this);
}
+
+ public void clearAllCachedResultValues() {
+ // nothing to do
+ }
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
index 81eef9005..61984497e 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
@@ -64,6 +64,10 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
_iBook = book.getWorkbook();
}
+ public void clearAllCachedResultValues() {
+ // nothing to do
+ }
+
@Override
public HSSFName createName() {
return _uBook.createName();
diff --git a/src/java/org/apache/poi/ss/formula/EvaluationSheet.java b/src/java/org/apache/poi/ss/formula/EvaluationSheet.java
index 5dec3aacd..3cc292dc5 100644
--- a/src/java/org/apache/poi/ss/formula/EvaluationSheet.java
+++ b/src/java/org/apache/poi/ss/formula/EvaluationSheet.java
@@ -30,4 +30,12 @@ public interface EvaluationSheet {
* @return null
if there is no cell at the specified coordinates
*/
EvaluationCell getCell(int rowIndex, int columnIndex);
+
+ /**
+ * Propagated from {@link EvaluationWorkbook#clearAllCachedResultValues()} to clear locally cached data.
+ *
+ * @see WorkbookEvaluator#clearAllCachedResultValues()
+ * @see EvaluationWorkbook#clearAllCachedResultValues()
+ */
+ public void clearAllCachedResultValues();
}
diff --git a/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java b/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
index b0a3c7606..fc4cfb32b 100644
--- a/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
+++ b/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
@@ -73,6 +73,13 @@ public interface EvaluationWorkbook {
String resolveNameXText(NameXPtg ptg);
Ptg[] getFormulaTokens(EvaluationCell cell);
UDFFinder getUDFFinder();
+
+ /**
+ * Propagated from {@link WorkbookEvaluator#clearAllCachedResultValues()} to clear locally cached data.
+ * Implementations must call the same method on all referenced {@link EvaluationSheet} instances, as well as clearing local caches.
+ * @see WorkbookEvaluator#clearAllCachedResultValues()
+ */
+ public void clearAllCachedResultValues();
class ExternalSheet {
private final String _workbookName;
diff --git a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
index d1e7d8b22..4ed054467 100644
--- a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
+++ b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
@@ -208,6 +208,7 @@ public final class WorkbookEvaluator {
public void clearAllCachedResultValues() {
_cache.clear();
_sheetIndexesBySheet.clear();
+ _workbook.clearAllCachedResultValues();
}
/**
diff --git a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java
index 886919fe6..fcf00a488 100644
--- a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java
+++ b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationSheet.java
@@ -101,6 +101,14 @@ final class ForkedEvaluationSheet implements EvaluationSheet {
return mewb.getSheetIndex(_masterSheet);
}
+ /* (non-Javadoc)
+ * leave the map alone, if it needs resetting, reusing this class is probably a bad idea.
+ * @see org.apache.poi.ss.formula.EvaluationSheet#clearAllCachedResultValues()
+ */
+ public void clearAllCachedResultValues() {
+ _masterSheet.clearAllCachedResultValues();
+ }
+
private static final class RowColKey implements Comparable{
private final int _rowIndex;
private final int _columnIndex;
diff --git a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
index b936a5476..5e1da9bdc 100644
--- a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
+++ b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
@@ -136,4 +136,12 @@ final class ForkedEvaluationWorkbook implements EvaluationWorkbook {
public UDFFinder getUDFFinder(){
return _masterBook.getUDFFinder();
}
+
+ /* (non-Javadoc)
+ * leave the map alone, if it needs resetting, reusing this class is probably a bad idea.
+ * @see org.apache.poi.ss.formula.EvaluationSheet#clearAllCachedResultValues()
+ */
+ public void clearAllCachedResultValues() {
+ _masterBook.clearAllCachedResultValues();
+ }
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFEvaluationSheet.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFEvaluationSheet.java
index c5d809cad..f2c11953f 100644
--- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFEvaluationSheet.java
+++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFEvaluationSheet.java
@@ -47,4 +47,8 @@ final class SXSSFEvaluationSheet implements EvaluationSheet {
}
return new SXSSFEvaluationCell(cell, this);
}
+
+ public void clearAllCachedResultValues() {
+ // nothing to do
+ }
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFEvaluationWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFEvaluationWorkbook.java
index 44b182b4d..8f0eac330 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFEvaluationWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/BaseXSSFEvaluationWorkbook.java
@@ -56,6 +56,10 @@ public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWork
_uBook = book;
}
+ public void clearAllCachedResultValues() {
+ _tableCache = null;
+ }
+
private int convertFromExternalSheetIndex(int externSheetIndex) {
return externSheetIndex;
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java
index 0286740e0..78aa8f86c 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java
@@ -41,6 +41,10 @@ final class XSSFEvaluationSheet implements EvaluationSheet {
return _xs;
}
+ public void clearAllCachedResultValues() {
+ _cellCache = null;
+ }
+
public EvaluationCell getCell(int rowIndex, int columnIndex) {
// cache for performance: ~30% speedup due to caching
if (_cellCache == null) {
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
index 1e849b673..60f99676c 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
@@ -40,6 +40,11 @@ public final class XSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook {
super(book);
}
+ public void clearAllCachedResultValues() {
+ super.clearAllCachedResultValues();
+ _sheetCache = null;
+ }
+
@Override
public int getSheetIndex(EvaluationSheet evalSheet) {
XSSFSheet sheet = ((XSSFEvaluationSheet)evalSheet).getXSSFSheet();
diff --git a/src/ooxml/testcases/org/apache/poi/ss/formula/TestStructuredReferences.java b/src/ooxml/testcases/org/apache/poi/ss/formula/TestStructuredReferences.java
index fd598a479..4e176257f 100644
--- a/src/ooxml/testcases/org/apache/poi/ss/formula/TestStructuredReferences.java
+++ b/src/ooxml/testcases/org/apache/poi/ss/formula/TestStructuredReferences.java
@@ -18,17 +18,22 @@
package org.apache.poi.ss.formula;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Table;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFTable;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;
@@ -63,8 +68,40 @@ public class TestStructuredReferences {
try {
final FormulaEvaluator eval = new XSSFFormulaEvaluator(wb);
- confirm(eval, wb.getSheet("Table").getRow(5).getCell(0), 49);
- confirm(eval, wb.getSheet("Formulas").getRow(0).getCell(0), 209);
+ final XSSFSheet tableSheet = wb.getSheet("Table");
+ final XSSFSheet formulaSheet = wb.getSheet("Formulas");
+
+ confirm(eval, tableSheet.getRow(5).getCell(0), 49);
+ confirm(eval, formulaSheet.getRow(0).getCell(0), 209);
+ confirm(eval, formulaSheet.getRow(1).getCell(0), "one");
+
+ // test changing a table value, to see if the caches are properly cleared
+ // Issue 59814
+
+ // this test passes before the fix for 59814
+ tableSheet.getRow(1).getCell(1).setCellValue("ONEA");
+ confirm(eval, formulaSheet.getRow(1).getCell(0), "ONEA");
+
+ // test adding a row to a table, issue 59814
+ Row newRow = tableSheet.getRow(7);
+ if (newRow == null) newRow = tableSheet.createRow(7);
+ newRow.createCell(0, CellType.FORMULA).setCellFormula("\\_Prime.1[[#This Row],[@Number]]*\\_Prime.1[[#This Row],[@Number]]");
+ newRow.createCell(1, CellType.STRING).setCellValue("thirteen");
+ newRow.createCell(2, CellType.NUMERIC).setCellValue(13);
+
+ // update Table
+ final XSSFTable table = wb.getTable("\\_Prime.1");
+ final AreaReference newArea = new AreaReference(table.getStartCellReference(), new CellReference(table.getEndRowIndex() + 1, table.getEndColIndex()));
+ String newAreaStr = newArea.formatAsString();
+ table.getCTTable().setRef(newAreaStr);
+ table.getCTTable().getAutoFilter().setRef(newAreaStr);
+ table.updateHeaders();
+ table.updateReferences();
+
+ // these fail before the fix for 59814
+ confirm(eval, tableSheet.getRow(7).getCell(0), 13*13);
+ confirm(eval, formulaSheet.getRow(0).getCell(0), 209 + 13*13);
+
} finally {
wb.close();
}
@@ -78,4 +115,13 @@ public class TestStructuredReferences {
}
assertEquals(expectedResult, cv.getNumberValue(), 0.0);
}
+
+ private static void confirm(FormulaEvaluator fe, Cell cell, String expectedResult) {
+ fe.clearAllCachedResultValues();
+ CellValue cv = fe.evaluate(cell);
+ if (cv.getCellType() != CellType.STRING) {
+ fail("expected String cell type but got " + cv.formatAsString());
+ }
+ assertEquals(expectedResult, cv.getStringValue());
+ }
}
diff --git a/test-data/spreadsheet/StructuredReferences.xlsx b/test-data/spreadsheet/StructuredReferences.xlsx
index 54cf75234..90a470a93 100644
Binary files a/test-data/spreadsheet/StructuredReferences.xlsx and b/test-data/spreadsheet/StructuredReferences.xlsx differ