mirror of https://github.com/apache/poi.git
Fix for 43354 - made the formula evaluator capable of handling missing function arguments
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@702231 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f9adf67cff
commit
3a2feafaa6
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
<!-- Don't forget to update status.xml too! -->
|
<!-- Don't forget to update status.xml too! -->
|
||||||
<release version="3.2-alpha1" date="2008-??-??">
|
<release version="3.2-alpha1" date="2008-??-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">43354 - support for evalating formulas with missing args</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">45912 - fixed ArrayIndexOutOfBoundsException in EmbeddedObjectRefSubRecord</action>
|
<action dev="POI-DEVELOPERS" type="fix">45912 - fixed ArrayIndexOutOfBoundsException in EmbeddedObjectRefSubRecord</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">45889 - fixed ArrayIndexOutOfBoundsException when constructing HSLF Table with a single row </action>
|
<action dev="POI-DEVELOPERS" type="fix">45889 - fixed ArrayIndexOutOfBoundsException when constructing HSLF Table with a single row </action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">Initial support for creating hyperlinks in HSLF</action>
|
<action dev="POI-DEVELOPERS" type="add">Initial support for creating hyperlinks in HSLF</action>
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
<!-- Don't forget to update changes.xml too! -->
|
<!-- Don't forget to update changes.xml too! -->
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.2-alpha1" date="2008-??-??">
|
<release version="3.2-alpha1" date="2008-??-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">43354 - support for evalating formulas with missing args</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">45912 - fixed ArrayIndexOutOfBoundsException in EmbeddedObjectRefSubRecord</action>
|
<action dev="POI-DEVELOPERS" type="fix">45912 - fixed ArrayIndexOutOfBoundsException in EmbeddedObjectRefSubRecord</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">45889 - fixed ArrayIndexOutOfBoundsException when constructing HSLF Table with a single row </action>
|
<action dev="POI-DEVELOPERS" type="fix">45889 - fixed ArrayIndexOutOfBoundsException when constructing HSLF Table with a single row </action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">Initial support for creating hyperlinks in HSLF</action>
|
<action dev="POI-DEVELOPERS" type="add">Initial support for creating hyperlinks in HSLF</action>
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.record.formula.eval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the (intermediate) evaluated result of a missing function argument. In most cases
|
||||||
|
* this can be translated into {@link BlankEval} but there are some notable exceptions. Functions
|
||||||
|
* COUNT and COUNTA <em>do</em> count their missing args. Note - the differences between
|
||||||
|
* {@link MissingArgEval} and {@link BlankEval} have not been investigated fully, so the POI
|
||||||
|
* evaluator may need to be updated to account for these as they are found.
|
||||||
|
*
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
public final class MissingArgEval implements ValueEval {
|
||||||
|
|
||||||
|
public static MissingArgEval instance = new MissingArgEval();
|
||||||
|
|
||||||
|
private MissingArgEval() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ package org.apache.poi.hssf.record.formula.functions;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.MissingArgEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||||
import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
|
import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
|
||||||
|
|
||||||
|
@ -64,6 +65,10 @@ public final class Count implements Function {
|
||||||
// only numbers are counted
|
// only numbers are counted
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if(valueEval == MissingArgEval.instance) {
|
||||||
|
// oh yeah, and missing arguments
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// error values and string values not counted
|
// error values and string values not counted
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.apache.poi.hssf.record.formula.eval.BoolEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.FunctionEval;
|
import org.apache.poi.hssf.record.formula.eval.FunctionEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.MissingArgEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.NameEval;
|
import org.apache.poi.hssf.record.formula.eval.NameEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.NameXEval;
|
import org.apache.poi.hssf.record.formula.eval.NameXEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||||
|
@ -284,10 +285,7 @@ public final class WorkbookEvaluator {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ptg instanceof MemErrPtg) { continue; }
|
if (ptg instanceof MemErrPtg) { continue; }
|
||||||
if (ptg instanceof MissingArgPtg) {
|
|
||||||
// TODO - might need to push BlankEval or MissingArgEval
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Eval opResult;
|
Eval opResult;
|
||||||
if (ptg instanceof OperationPtg) {
|
if (ptg instanceof OperationPtg) {
|
||||||
OperationPtg optg = (OperationPtg) ptg;
|
OperationPtg optg = (OperationPtg) ptg;
|
||||||
|
@ -306,6 +304,9 @@ public final class WorkbookEvaluator {
|
||||||
}
|
}
|
||||||
// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
|
// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
|
||||||
opResult = invokeOperation(operation, ops, _workbook, sheetIndex, srcRowNum, srcColNum);
|
opResult = invokeOperation(operation, ops, _workbook, sheetIndex, srcRowNum, srcColNum);
|
||||||
|
if (opResult == MissingArgEval.instance) {
|
||||||
|
opResult = BlankEval.INSTANCE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
opResult = getEvalForPtg(ptg, sheetIndex, tracker);
|
opResult = getEvalForPtg(ptg, sheetIndex, tracker);
|
||||||
}
|
}
|
||||||
|
@ -424,6 +425,9 @@ public final class WorkbookEvaluator {
|
||||||
if (ptg instanceof ErrPtg) {
|
if (ptg instanceof ErrPtg) {
|
||||||
return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
|
return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
|
||||||
}
|
}
|
||||||
|
if (ptg instanceof MissingArgPtg) {
|
||||||
|
return MissingArgEval.instance;
|
||||||
|
}
|
||||||
if (ptg instanceof AreaErrPtg ||ptg instanceof RefErrorPtg
|
if (ptg instanceof AreaErrPtg ||ptg instanceof RefErrorPtg
|
||||||
|| ptg instanceof DeletedArea3DPtg || ptg instanceof DeletedRef3DPtg) {
|
|| ptg instanceof DeletedArea3DPtg || ptg instanceof DeletedRef3DPtg) {
|
||||||
return ErrorEval.REF_INVALID;
|
return ErrorEval.REF_INVALID;
|
||||||
|
|
|
@ -36,6 +36,7 @@ public class AllFormulaEvalTests {
|
||||||
result.addTestSuite(TestExternalFunction.class);
|
result.addTestSuite(TestExternalFunction.class);
|
||||||
result.addTestSuite(TestFormulaBugs.class);
|
result.addTestSuite(TestFormulaBugs.class);
|
||||||
result.addTestSuite(TestFormulasFromSpreadsheet.class);
|
result.addTestSuite(TestFormulasFromSpreadsheet.class);
|
||||||
|
result.addTestSuite(TestMissingArgEval.class);
|
||||||
result.addTestSuite(TestPercentEval.class);
|
result.addTestSuite(TestPercentEval.class);
|
||||||
result.addTestSuite(TestRangeEval.class);
|
result.addTestSuite(TestRangeEval.class);
|
||||||
result.addTestSuite(TestUnaryPlusEval.class);
|
result.addTestSuite(TestUnaryPlusEval.class);
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.record.formula.eval;
|
||||||
|
|
||||||
|
import java.util.EmptyStackException;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link MissingArgEval}
|
||||||
|
*
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
public final class TestMissingArgEval extends TestCase {
|
||||||
|
|
||||||
|
public void testEvaluateMissingArgs() {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
|
||||||
|
HSSFSheet sheet = wb.createSheet("Sheet1");
|
||||||
|
HSSFCell cell = sheet.createRow(0).createCell(0);
|
||||||
|
|
||||||
|
cell.setCellFormula("if(true,)");
|
||||||
|
fe.clearAllCachedResultValues();
|
||||||
|
CellValue cv;
|
||||||
|
try {
|
||||||
|
cv = fe.evaluate(cell);
|
||||||
|
} catch (EmptyStackException e) {
|
||||||
|
throw new AssertionFailedError("Missing args evaluation not implemented (bug 43354");
|
||||||
|
}
|
||||||
|
// MissingArg -> BlankEval -> zero (as formula result)
|
||||||
|
assertEquals(0.0, cv.getNumberValue(), 0.0);
|
||||||
|
|
||||||
|
// MissingArg -> BlankEval -> empty string (in concatenation)
|
||||||
|
cell.setCellFormula("\"abc\"&if(true,)");
|
||||||
|
fe.clearAllCachedResultValues();
|
||||||
|
assertEquals("abc", fe.evaluate(cell).getStringValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCountFuncs() {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
|
||||||
|
HSSFSheet sheet = wb.createSheet("Sheet1");
|
||||||
|
HSSFCell cell = sheet.createRow(0).createCell(0);
|
||||||
|
|
||||||
|
cell.setCellFormula("COUNT(C5,,,,)"); // 4 missing args, C5 is blank
|
||||||
|
assertEquals(4.0, fe.evaluate(cell).getNumberValue(), 0.0);
|
||||||
|
|
||||||
|
cell.setCellFormula("COUNTA(C5,,)"); // 2 missing args, C5 is blank
|
||||||
|
fe.clearAllCachedResultValues();
|
||||||
|
assertEquals(2.0, fe.evaluate(cell).getNumberValue(), 0.0);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue