]> source.dussan.org Git - poi.git/commitdiff
fixed special cases of dereferenceResult method
authorJosh Micich <josh@apache.org>
Wed, 16 Dec 2009 23:16:30 +0000 (23:16 +0000)
committerJosh Micich <josh@apache.org>
Wed, 16 Dec 2009 23:16:30 +0000 (23:16 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@891468 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java
src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java

index f18abce008369e14db5f948d9826b612b3d5c676..0b9116db3ea8886bf2eb20a8d63492eba800c549 100644 (file)
@@ -103,14 +103,8 @@ public final class OperandResolver {
        public static ValueEval chooseSingleElementFromArea(AreaEval ae,
                        int srcCellRow, int srcCellCol) throws EvaluationException {
                ValueEval result = chooseSingleElementFromAreaInternal(ae, srcCellRow, srcCellCol);
-               if(result == null) {
-                       // This seems to be required because AreaEval.values() array may contain nulls.
-                       // perhaps that should not be allowed.
-                       result = BlankEval.instance;
-               }
                if (result instanceof ErrorEval) {
                        throw new EvaluationException((ErrorEval) result);
-
                }
                return result;
        }
index 69e1446d447b17d6d5c16c98b2775c30641bfba3..0e63016250e8412c2b862ee3da31c898981a5f2e 100644 (file)
@@ -57,6 +57,7 @@ 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;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
 import org.apache.poi.hssf.record.formula.eval.RefEval;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
@@ -449,14 +450,7 @@ public final class WorkbookEvaluator {
                if (!stack.isEmpty()) {
                        throw new IllegalStateException("evaluation stack not empty");
                }
-               value = dereferenceValue(value, ec.getRowIndex(), ec.getColumnIndex());
-               if (value == BlankEval.instance) {
-                       // Note Excel behaviour here. A blank final final value is converted to zero.
-                       return NumberEval.ZERO;
-                       // Formulas _never_ evaluate to blank.  If a formula appears to have evaluated to
-                       // blank, the actual value is empty string. This can be verified with ISBLANK().
-               }
-               return value;
+               return dereferenceResult(value, ec.getRowIndex(), ec.getColumnIndex());
        }
 
        /**
@@ -480,31 +474,30 @@ public final class WorkbookEvaluator {
                }
                return index-startIndex;
        }
+
        /**
-        * Dereferences a single value from any AreaEval or RefEval evaluation result.
-        * If the supplied evaluationResult is just a plain value, it is returned as-is.
-        * @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
-        *  <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
+        * Dereferences a single value from any AreaEval or RefEval evaluation
+        * result. If the supplied evaluationResult is just a plain value, it is
+        * returned as-is.
+        *
+        * @return a {@link NumberEval}, {@link StringEval}, {@link BoolEval}, or
+        *         {@link ErrorEval}. Never <code>null</code>. {@link BlankEval} is
+        *         converted to {@link NumberEval#ZERO}
         */
-       private static ValueEval dereferenceValue(ValueEval evaluationResult, int srcRowNum, int srcColNum) {
-               if (evaluationResult instanceof RefEval) {
-                       RefEval rv = (RefEval) evaluationResult;
-                       return rv.getInnerValueEval();
+       public static ValueEval dereferenceResult(ValueEval evaluationResult, int srcRowNum, int srcColNum) {
+               ValueEval value;
+               try {
+                       value = OperandResolver.getSingleValue(evaluationResult, srcRowNum, srcColNum);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
                }
-               if (evaluationResult instanceof AreaEval) {
-                       AreaEval ae = (AreaEval) evaluationResult;
-                       if (ae.isRow()) {
-                               if(ae.isColumn()) {
-                                       return ae.getRelativeValue(0, 0);
-                               }
-                               return ae.getAbsoluteValue(ae.getFirstRow(), srcColNum);
-                       }
-                       if (ae.isColumn()) {
-                               return ae.getAbsoluteValue(srcRowNum, ae.getFirstColumn());
-                       }
-                       return ErrorEval.VALUE_INVALID;
+               if (value == BlankEval.instance) {
+                       // Note Excel behaviour here. A blank final final value is converted to zero.
+                       return NumberEval.ZERO;
+                       // Formulas _never_ evaluate to blank.  If a formula appears to have evaluated to
+                       // blank, the actual value is empty string. This can be verified with ISBLANK().
                }
-               return evaluationResult;
+               return value;
        }
 
 
index 7e9149adfa456ee82a98e276f5b7ec5b23343858..5e59933cf6683a4228e5de581e42483c0e3ea62c 100644 (file)
@@ -38,7 +38,11 @@ import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
 import org.apache.poi.hssf.usermodel.HSSFRow;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.usermodel.ErrorConstants;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Workbook;
 
 /**
  * Tests {@link WorkbookEvaluator}.
@@ -193,7 +197,7 @@ public class TestWorkbookEvaluator extends TestCase {
                assertEquals(HSSFCell.CELL_TYPE_STRING, cv.getCellType());
                // adding blank to "abc" gives "abc"
                assertEquals("abc", cv.getStringValue());
-               
+
                // check CHOOSE()
                cell.setCellFormula("\"abc\"&CHOOSE(2,5,,9)");
                fe.notifySetFormula(cell);
@@ -202,4 +206,33 @@ public class TestWorkbookEvaluator extends TestCase {
                // adding blank to "abc" gives "abc"
                assertEquals("abc", cv.getStringValue());
        }
+
+       /**
+        * Functions like IF, INDIRECT, INDEX, OFFSET etc can return AreaEvals which
+        * should be dereferenced by the evaluator
+        */
+       public void testResultOutsideRange() {
+               Workbook wb = new HSSFWorkbook();
+               Cell cell = wb.createSheet("Sheet1").createRow(0).createCell(0);
+               cell.setCellFormula("D2:D5"); // IF(TRUE,D2:D5,D2) or  OFFSET(D2:D5,0,0) would work too
+               FormulaEvaluator fe = wb.getCreationHelper().createFormulaEvaluator();
+               CellValue cv;
+               try {
+                       cv = fe.evaluate(cell);
+               } catch (IllegalArgumentException e) {
+                       if ("Specified row index (0) is outside the allowed range (1..4)".equals(e.getMessage())) {
+                               throw new AssertionFailedError("Identified bug in result dereferencing");
+                       }
+                       throw new RuntimeException(e);
+               }
+               assertEquals(Cell.CELL_TYPE_ERROR, cv.getCellType());
+               assertEquals(ErrorConstants.ERROR_VALUE, cv.getErrorValue());
+
+               // verify circular refs are still detected properly
+               fe.clearAllCachedResultValues();
+               cell.setCellFormula("OFFSET(A1,0,0)");
+               cv = fe.evaluate(cell);
+               assertEquals(Cell.CELL_TYPE_ERROR, cv.getCellType());
+               assertEquals(ErrorEval.CIRCULAR_REF_ERROR.getErrorCode(), cv.getErrorValue());
+       }
 }