Bug 62993: XSSFEvaluationSheet now retrieves valid last row index from underlying XSSFSheet. Thanks to Axel Howind.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1850212 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Vladislav Galas 2019-01-03 00:08:52 +00:00
parent e501d4015d
commit 3b8055baa0
8 changed files with 142 additions and 19 deletions

View File

@ -28,11 +28,9 @@ import org.apache.poi.util.Internal;
final class HSSFEvaluationSheet implements EvaluationSheet {
private final HSSFSheet _hs;
private int _lastDefinedRow = -1;
public HSSFEvaluationSheet(HSSFSheet hs) {
_hs = hs;
_lastDefinedRow = _hs.getLastRowNum();
}
public HSSFSheet getHSSFSheet() {
@ -45,7 +43,7 @@ final class HSSFEvaluationSheet implements EvaluationSheet {
*/
@Override
public int getLastRowNum() {
return _lastDefinedRow;
return _hs.getLastRowNum();
}
@Override
@ -66,6 +64,5 @@ final class HSSFEvaluationSheet implements EvaluationSheet {
*/
@Override
public void clearAllCachedResultValues() {
_lastDefinedRow = _hs.getLastRowNum();
}
}

View File

@ -27,11 +27,9 @@ import org.apache.poi.util.Internal;
@Internal
final class SXSSFEvaluationSheet implements EvaluationSheet {
private final SXSSFSheet _xs;
private int _lastDefinedRow = -1;
public SXSSFEvaluationSheet(SXSSFSheet sheet) {
_xs = sheet;
_lastDefinedRow = _xs.getLastRowNum();
}
public SXSSFSheet getSXSSFSheet() {
@ -44,7 +42,7 @@ final class SXSSFEvaluationSheet implements EvaluationSheet {
*/
@Override
public int getLastRowNum() {
return _lastDefinedRow;
return _xs.getLastRowNum();
}
@Override
@ -68,6 +66,5 @@ final class SXSSFEvaluationSheet implements EvaluationSheet {
*/
@Override
public void clearAllCachedResultValues() {
_lastDefinedRow = _xs.getLastRowNum();
}
}

View File

@ -34,11 +34,9 @@ final class XSSFEvaluationSheet implements EvaluationSheet {
private final XSSFSheet _xs;
private Map<CellKey, EvaluationCell> _cellCache;
private int _lastDefinedRow = -1;
public XSSFEvaluationSheet(XSSFSheet sheet) {
_xs = sheet;
_lastDefinedRow = _xs.getLastRowNum();
}
public XSSFSheet getXSSFSheet() {
@ -51,7 +49,7 @@ final class XSSFEvaluationSheet implements EvaluationSheet {
*/
@Override
public int getLastRowNum() {
return _lastDefinedRow;
return _xs.getLastRowNum();
}
/* (non-JavaDoc), inherit JavaDoc from EvaluationWorkbook
@ -60,15 +58,16 @@ final class XSSFEvaluationSheet implements EvaluationSheet {
@Override
public void clearAllCachedResultValues() {
_cellCache = null;
_lastDefinedRow = _xs.getLastRowNum();
}
@Override
public EvaluationCell getCell(int rowIndex, int columnIndex) {
// shortcut evaluation if reference is outside the bounds of existing data
// see issue #61841 for impact on VLOOKUP in particular
if (rowIndex > _lastDefinedRow) return null;
if (rowIndex > getLastRowNum()) {
return null;
}
// cache for performance: ~30% speedup due to caching
if (_cellCache == null) {
_cellCache = new HashMap<>(_xs.getLastRowNum() * 3);

View File

@ -27,7 +27,6 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
@ -131,7 +130,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTablePart;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableParts;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheetSource;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
@ -1211,6 +1209,10 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
@Override
public int getLastRowNum() {
// _rows.getLastKey() (O(logN)) or caching last row (O(1))?
// A test with 1_000_000 rows shows that querying getLastRowNum with lastKey() implementation takes ~40 ms,
// and ~1.2 ms with cached implementation. 40 ms is negligible compared to the time of evaluation a million
// cells, and the lastKey implementation is much more elegant and less error prone than caching.
return _rows.isEmpty() ? 0 : _rows.lastKey();
}

View File

@ -0,0 +1,32 @@
/* ====================================================================
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.xssf.streaming;
import org.apache.poi.ss.formula.EvaluationSheet;
import org.apache.poi.ss.usermodel.BaseTestXEvaluationSheet;
import org.apache.poi.ss.usermodel.Sheet;
import java.util.AbstractMap;
import java.util.Map;
public class TestSXSSFEvaluationSheet extends BaseTestXEvaluationSheet {
@Override
protected Map.Entry<Sheet, EvaluationSheet> getInstance() {
SXSSFSheet sheet = new SXSSFWorkbook().createSheet();
return new AbstractMap.SimpleEntry<>(sheet, new SXSSFEvaluationSheet(sheet));
}
}

View File

@ -16,11 +16,19 @@
==================================================================== */
package org.apache.poi.xssf.usermodel;
import org.apache.poi.ss.formula.EvaluationSheet;
import org.apache.poi.ss.usermodel.BaseTestXEvaluationSheet;
import org.apache.poi.ss.usermodel.Sheet;
import org.junit.Test;
import static org.junit.Assert.*;
import java.util.AbstractMap;
import java.util.Map;
public class TestXSSFEvaluationSheet {
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class TestXSSFEvaluationSheet extends BaseTestXEvaluationSheet {
@Test
public void test() throws Exception {
@ -52,4 +60,10 @@ public class TestXSSFEvaluationSheet {
// other things
assertEquals(sheet, evalsheet.getXSSFSheet());
}
}
@Override
protected Map.Entry<Sheet, EvaluationSheet> getInstance() {
XSSFSheet sheet = new XSSFWorkbook().createSheet();
return new AbstractMap.SimpleEntry<>(sheet, new XSSFEvaluationSheet(sheet));
}
}

View File

@ -0,0 +1,33 @@
/* ====================================================================
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.hssf.usermodel;
import org.apache.poi.ss.formula.EvaluationSheet;
import org.apache.poi.ss.usermodel.BaseTestXEvaluationSheet;
import org.apache.poi.ss.usermodel.Sheet;
import java.util.AbstractMap;
import java.util.Map;
public class TestHSSFEvaluationSheet extends BaseTestXEvaluationSheet {
@Override
protected Map.Entry<Sheet, EvaluationSheet> getInstance() {
HSSFSheet sheet = new HSSFWorkbook().createSheet();
return new AbstractMap.SimpleEntry<>(sheet, new HSSFEvaluationSheet(sheet));
}
}

View File

@ -0,0 +1,49 @@
/* ====================================================================
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.usermodel;
import org.apache.poi.ss.formula.EvaluationSheet;
import org.junit.Test;
import java.util.Map;
import static org.junit.Assert.assertEquals;
public abstract class BaseTestXEvaluationSheet {
/**
* Get a pair of underlying sheet and evaluation sheet.
*/
protected abstract Map.Entry<Sheet, EvaluationSheet> getInstance();
@Test
public void lastRowNumIsUpdatedFromUnderlyingSheet_bug62993() {
Map.Entry<Sheet, EvaluationSheet> sheetPair = getInstance();
Sheet underlyingSheet = sheetPair.getKey();
EvaluationSheet instance = sheetPair.getValue();
assertEquals(0, instance.getLastRowNum());
underlyingSheet.createRow(0);
underlyingSheet.createRow(1);
underlyingSheet.createRow(2);
assertEquals(2, instance.getLastRowNum());
underlyingSheet.removeRow(underlyingSheet.getRow(2));
assertEquals(1, instance.getLastRowNum());
}
}