From: Yegor Kozlov Date: Sat, 2 Jul 2011 09:05:35 +0000 (+0000) Subject: Bug 51448 - Avoid exception when evaluating workbooks with more than 256 sheets X-Git-Tag: REL_3_8_BETA4~347 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=16bee58c25f06e3e9bd27d52d22b285202034445;p=poi.git Bug 51448 - Avoid exception when evaluating workbooks with more than 256 sheets git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1142181 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 977491cce2..c224fd3df1 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 51448 - Avoid exception when evaluating workbooks with more than 256 sheets 51458 - Correct BitField wrapping when setting large values 51460 - Improve HSSF performance when loading very long rows, by switching the CellValue array to an iterator 51444 - Prevent corrupted output when saving files created by LibreOffice 3.3 diff --git a/src/java/org/apache/poi/ss/formula/PlainCellCache.java b/src/java/org/apache/poi/ss/formula/PlainCellCache.java index 967824bba6..f422b9604e 100644 --- a/src/java/org/apache/poi/ss/formula/PlainCellCache.java +++ b/src/java/org/apache/poi/ss/formula/PlainCellCache.java @@ -28,7 +28,7 @@ final class PlainCellCache { public static final class Loc { - private final int _bookSheetColumn; + private final long _bookSheetColumn; private final int _rowIndex; @@ -37,18 +37,19 @@ final class PlainCellCache { _rowIndex = rowIndex; } - public static int toBookSheetColumn(int bookIndex, int sheetIndex, int columnIndex) { - return ((bookIndex & 0x00FF) << 24) + ((sheetIndex & 0x00FF) << 16) - + ((columnIndex & 0xFFFF) << 0); + public static long toBookSheetColumn(int bookIndex, int sheetIndex, int columnIndex) { + return ((bookIndex & 0xFFFFl) << 48) + + ((sheetIndex & 0xFFFFl) << 32) + + ((columnIndex & 0xFFFFl) << 0); } - public Loc(int bookSheetColumn, int rowIndex) { + public Loc(long bookSheetColumn, int rowIndex) { _bookSheetColumn = bookSheetColumn; _rowIndex = rowIndex; } public int hashCode() { - return _bookSheetColumn + 17 * _rowIndex; + return (int)(_bookSheetColumn ^ (_bookSheetColumn >>> 32)) + 17 * _rowIndex; } public boolean equals(Object obj) { @@ -60,9 +61,18 @@ final class PlainCellCache { public int getRowIndex() { return _rowIndex; } + public int getColumnIndex() { - return _bookSheetColumn & 0x000FFFF; + return (int)(_bookSheetColumn & 0x000FFFF); } + + public int getSheetIndex() { + return (int)((_bookSheetColumn >> 32) & 0xFFFF); + } + + public int getBookIndex() { + return (int)((_bookSheetColumn >> 48) & 0xFFFF); + } } private Map _plainValueEntriesByLoc; diff --git a/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java b/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java index 6edd5d13dc..1c626dcee1 100644 --- a/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java +++ b/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java @@ -46,7 +46,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.util.CellReference; import org.apache.poi.ss.formula.IEvaluationListener.ICacheEntry; import org.apache.poi.ss.formula.PlainCellCache.Loc; -import org.apache.poi.ss.usermodel.CellValue; +import org.apache.poi.ss.usermodel.*; /** * Tests {@link org.apache.poi.ss.formula.EvaluationCache}. Makes sure that where possible (previously calculated) cached @@ -696,4 +696,82 @@ public class TestEvaluationCache extends TestCase { ps.println('"' + log[i] + "\","); } } + + private static void testPlainValueCache(Workbook wb, int numberOfSheets) { + + Row row; + Cell cell; + + //create summary sheet + Sheet summary = wb.createSheet("summary"); + wb.setActiveSheet(wb.getSheetIndex(summary)); + + //formula referring all sheets created below + row = summary.createRow(0); + Cell summaryCell = row.createCell(0); + summaryCell.setCellFormula("SUM(A2:A" + (numberOfSheets + 2) + ")"); + + + //create sheets with cells having (different) numbers + // and add a row to summary + for (int i = 1; i < numberOfSheets; i++) { + Sheet sheet = wb.createSheet("new" + i); + + row = sheet.createRow(0); + cell = row.createCell(0); + cell.setCellValue(i); + + row = summary.createRow(i); + cell = row.createCell(0); + cell.setCellFormula("new" + i + "!A1"); + + } + + + //calculate + FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); + evaluator.evaluateFormulaCell(summaryCell); + } + + + public void testPlainValueCache() { + + Workbook wb = new HSSFWorkbook(); + int numberOfSheets = 4098; // Bug 51448 reported that Evaluation Cache got messed up after 256 sheets + + Row row; + Cell cell; + + //create summary sheet + Sheet summary = wb.createSheet("summary"); + wb.setActiveSheet(wb.getSheetIndex(summary)); + + //formula referring all sheets created below + row = summary.createRow(0); + Cell summaryCell = row.createCell(0); + summaryCell.setCellFormula("SUM(A2:A" + (numberOfSheets + 2) + ")"); + + + //create sheets with cells having (different) numbers + // and add a row to summary + for (int i = 1; i < numberOfSheets; i++) { + Sheet sheet = wb.createSheet("new" + i); + + row = sheet.createRow(0); + cell = row.createCell(0); + cell.setCellValue(i); + + row = summary.createRow(i); + cell = row.createCell(0); + cell.setCellFormula("new" + i + "!A1"); + + } + + + //calculate + FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); + evaluator.evaluateFormulaCell(summaryCell); + assertEquals(8394753.0, summaryCell.getNumericCellValue()); + } + } diff --git a/src/testcases/org/apache/poi/ss/formula/TestPlainCellCache.java b/src/testcases/org/apache/poi/ss/formula/TestPlainCellCache.java new file mode 100644 index 0000000000..4ad351cbea --- /dev/null +++ b/src/testcases/org/apache/poi/ss/formula/TestPlainCellCache.java @@ -0,0 +1,75 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.apache.poi.ss.formula; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; +import org.apache.poi.hssf.model.HSSFFormulaParser; +import org.apache.poi.hssf.usermodel.*; +import org.apache.poi.hssf.util.CellReference; +import org.apache.poi.ss.formula.IEvaluationListener.ICacheEntry; +import org.apache.poi.ss.formula.PlainCellCache.Loc; +import org.apache.poi.ss.formula.eval.*; +import org.apache.poi.ss.formula.ptg.Ptg; +import org.apache.poi.ss.usermodel.CellValue; + +import java.io.PrintStream; +import java.util.*; + +/** + * @author Yegor Kozlov + */ +public class TestPlainCellCache extends TestCase { + + /** + * + */ + public void testLoc(){ + PlainCellCache cache = new PlainCellCache(); + for (int bookIndex = 0; bookIndex < 0x1000; bookIndex += 0x100) { + for (int sheetIndex = 0; sheetIndex < 0x1000; sheetIndex += 0x100) { + for (int rowIndex = 0; rowIndex < 0x100000; rowIndex += 0x1000) { + for (int columnIndex = 0; columnIndex < 0x4000; columnIndex += 0x100) { + Loc loc = new Loc(bookIndex, sheetIndex, rowIndex, columnIndex); + assertEquals(bookIndex, loc.getBookIndex()); + assertEquals(sheetIndex, loc.getSheetIndex()); + assertEquals(rowIndex, loc.getRowIndex()); + assertEquals(columnIndex, loc.getColumnIndex()); + + Loc sameLoc = new Loc(bookIndex, sheetIndex, rowIndex, columnIndex); + assertEquals(loc.hashCode(), sameLoc.hashCode()); + assertTrue(loc.equals(sameLoc)); + + assertNull(cache.get(loc)); + PlainValueCellCacheEntry entry = new PlainValueCellCacheEntry(new NumberEval(0)); + cache.put(loc, entry); + assertSame(entry, cache.get(loc)); + cache.remove(loc); + assertNull(cache.get(loc)); + + cache.put(loc, entry); + } + cache.clear(); + } + } + + } + } +}