]> source.dussan.org Git - poi.git/commitdiff
Bug 51448 - Avoid exception when evaluating workbooks with more than 256 sheets
authorYegor Kozlov <yegor@apache.org>
Sat, 2 Jul 2011 09:05:35 +0000 (09:05 +0000)
committerYegor Kozlov <yegor@apache.org>
Sat, 2 Jul 2011 09:05:35 +0000 (09:05 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1142181 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/ss/formula/PlainCellCache.java
src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java
src/testcases/org/apache/poi/ss/formula/TestPlainCellCache.java [new file with mode: 0644]

index 977491cce23d6e15f596917d0532268868d91ed8..c224fd3df12ced9e485c1e95844892a26f948f7b 100644 (file)
@@ -34,6 +34,7 @@
 
     <changes>
         <release version="3.8-beta4" date="2011-??-??">
+           <action dev="poi-developers" type="fix">51448 - Avoid exception when evaluating workbooks with more than 256 sheets </action>
            <action dev="poi-developers" type="fix">51458 - Correct BitField wrapping when setting large values</action>
            <action dev="poi-developers" type="add">51460 - Improve HSSF performance when loading very long rows, by switching the CellValue array to an iterator</action>
            <action dev="poi-developers" type="fix">51444 - Prevent corrupted output when saving files created by LibreOffice 3.3 </action>
index 967824bba69e634cf35f5d4dfd884581ab59c4bc..f422b9604e9396a74f318824bae020ee7a5c4b06 100644 (file)
@@ -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<Loc, PlainValueCellCacheEntry> _plainValueEntriesByLoc;
index 6edd5d13dcef9181d0e9e47022a523ff9f9991a5..1c626dcee144fc2205c42c172f394adb94b91246 100644 (file)
@@ -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 (file)
index 0000000..4ad351c
--- /dev/null
@@ -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();
+                }
+            }
+
+        }
+    }
+}