<!-- Don't forget to update status.xml too! -->
<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">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>
<!-- Don't forget to update changes.xml too! -->
<changes>
<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">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>
--- /dev/null
+/* ====================================================================
+ 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() {
+ }
+}
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.MissingArgEval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
// only numbers are counted
return true;
}
+ if(valueEval == MissingArgEval.instance) {
+ // oh yeah, and missing arguments
+ return true;
+ }
// error values and string values not counted
return false;
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.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.NameXEval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
continue;
}
if (ptg instanceof MemErrPtg) { continue; }
- if (ptg instanceof MissingArgPtg) {
- // TODO - might need to push BlankEval or MissingArgEval
- continue;
- }
+
Eval opResult;
if (ptg instanceof OperationPtg) {
OperationPtg optg = (OperationPtg) ptg;
}
// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
opResult = invokeOperation(operation, ops, _workbook, sheetIndex, srcRowNum, srcColNum);
+ if (opResult == MissingArgEval.instance) {
+ opResult = BlankEval.INSTANCE;
+ }
} else {
opResult = getEvalForPtg(ptg, sheetIndex, tracker);
}
if (ptg instanceof ErrPtg) {
return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
}
+ if (ptg instanceof MissingArgPtg) {
+ return MissingArgEval.instance;
+ }
if (ptg instanceof AreaErrPtg ||ptg instanceof RefErrorPtg
|| ptg instanceof DeletedArea3DPtg || ptg instanceof DeletedRef3DPtg) {
return ErrorEval.REF_INVALID;
result.addTestSuite(TestExternalFunction.class);
result.addTestSuite(TestFormulaBugs.class);
result.addTestSuite(TestFormulasFromSpreadsheet.class);
+ result.addTestSuite(TestMissingArgEval.class);
result.addTestSuite(TestPercentEval.class);
result.addTestSuite(TestRangeEval.class);
result.addTestSuite(TestUnaryPlusEval.class);
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}