]> source.dussan.org Git - poi.git/commitdiff
Fixes for special cases of lookup functions (test cases added)
authorJosh Micich <josh@apache.org>
Sat, 6 Sep 2008 05:30:31 +0000 (05:30 +0000)
committerJosh Micich <josh@apache.org>
Sat, 6 Sep 2008 05:30:31 +0000 (05:30 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@692612 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java
src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java
src/testcases/org/apache/poi/hssf/data/LookupFunctionsTestCaseData.xls

index e6efaaee4d0e136a92ef64bdd4b21ef1298b9eb5..2bbf6f5cd571bbf9d04c12c259886d656ad1a30e 100644 (file)
@@ -60,8 +60,7 @@ public final class Hlookup implements Function {
                        AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
                        boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
                        int colIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createRowVector(tableArray, 0), isRangeLookup);
-                       ValueEval veRowIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol);
-                       int rowIndex = LookupUtils.resolveRowOrColIndexArg(veRowIndex);
+                       int rowIndex = LookupUtils.resolveRowOrColIndexArg(args[2], srcCellRow, srcCellCol);
                        ValueVector resultCol = createResultColumnVector(tableArray, rowIndex);
                        return resultCol.getItem(colIndex);
                } catch (EvaluationException e) {
@@ -73,12 +72,11 @@ public final class Hlookup implements Function {
        /**
         * Returns one column from an <tt>AreaEval</tt>
         * 
-        * @throws EvaluationException (#VALUE!) if colIndex is negative, (#REF!) if colIndex is too high
+        * @param rowIndex assumed to be non-negative
+        * 
+        * @throws EvaluationException (#REF!) if colIndex is too high
         */
        private ValueVector createResultColumnVector(AreaEval tableArray, int rowIndex) throws EvaluationException {
-               if(rowIndex < 0) {
-                       throw EvaluationException.invalidValue();
-               }
                if(rowIndex >= tableArray.getHeight()) {
                        throw EvaluationException.invalidRef();
                }
index e6a3ec81c2f23edd79186b13d8ccbe0869ba031f..ee67ef8ec59bfe69e5dda72caeb74cf0b046b7a2 100644 (file)
@@ -322,30 +322,45 @@ final class LookupUtils {
         *      <tr><td>&lt;blank&gt;</td><td>&nbsp;</td><td>#VALUE!</td></tr>
         *    </table><br/>
         *
-        *  * Note - out of range errors (both too high and too low) are handled by the caller.
-        * @return column or row index as a zero-based value
-        *
+        * Note - out of range errors (result index too high) are handled by the caller.
+        * @return column or row index as a zero-based value, never negative.
+        * @throws EvaluationException when the specified arg cannot be coerced to a non-negative integer
         */
-       public static int resolveRowOrColIndexArg(ValueEval veRowColIndexArg) throws EvaluationException {
-               if(veRowColIndexArg == null) {
+       public static int resolveRowOrColIndexArg(Eval rowColIndexArg, int srcCellRow, int srcCellCol) throws EvaluationException {
+               if(rowColIndexArg == null) {
                        throw new IllegalArgumentException("argument must not be null");
                }
-               if(veRowColIndexArg instanceof BlankEval) {
-                       throw EvaluationException.invalidValue();
+               
+               ValueEval veRowColIndexArg;
+               try {
+                       veRowColIndexArg = OperandResolver.getSingleValue(rowColIndexArg, srcCellRow, (short)srcCellCol);
+               } catch (EvaluationException e) {
+                       // All errors get translated to #REF!
+                       throw EvaluationException.invalidRef();
                }
-               if(veRowColIndexArg instanceof StringEval) {
-                       StringEval se = (StringEval) veRowColIndexArg;
-                       String strVal = se.getStringValue();
-                       Double dVal = OperandResolver.parseDouble(strVal);
-                       if(dVal == null) {
-                               // String does not resolve to a number. Raise #VALUE! error.
-                               throw EvaluationException.invalidRef();
-                               // This includes text booleans "TRUE" and "FALSE".  They are not valid.
+               int oneBasedIndex;
+               if(veRowColIndexArg instanceof BlankEval) {
+                       oneBasedIndex = 0;
+               } else {
+                       if(veRowColIndexArg instanceof StringEval) {
+                               StringEval se = (StringEval) veRowColIndexArg;
+                               String strVal = se.getStringValue();
+                               Double dVal = OperandResolver.parseDouble(strVal);
+                               if(dVal == null) {
+                                       // String does not resolve to a number. Raise #REF! error.
+                                       throw EvaluationException.invalidRef();
+                                       // This includes text booleans "TRUE" and "FALSE".  They are not valid.
+                               }
+                               // else - numeric value parses OK
                        }
-                       // else - numeric value parses OK
+                       // actual BoolEval values get interpreted as FALSE->0 and TRUE->1
+                       oneBasedIndex = OperandResolver.coerceValueToInt(veRowColIndexArg);
+               }
+               if (oneBasedIndex < 1) {
+                       // note this is asymmetric with the errors when the index is too large (#REF!)  
+                       throw EvaluationException.invalidValue();
                }
-               // actual BoolEval values get interpreted as FALSE->0 and TRUE->1
-               return OperandResolver.coerceValueToInt(veRowColIndexArg) - 1;
+               return oneBasedIndex - 1; // convert to zero based
        }
 
 
@@ -583,11 +598,13 @@ final class LookupUtils {
                return maxIx - 1;
        }
 
-       public static LookupValueComparer createLookupComparer(ValueEval lookupValue) throws EvaluationException {
+       public static LookupValueComparer createLookupComparer(ValueEval lookupValue) {
 
-               if (lookupValue instanceof BlankEval) {
-                       // blank eval can never be found in a lookup array
-                       throw new EvaluationException(ErrorEval.NA);
+               if (lookupValue == BlankEval.INSTANCE) {
+                       // blank eval translates to zero
+                       // Note - a blank eval in the lookup column/row never matches anything
+                       // empty string in the lookup column/row can only be matched by explicit emtpty string
+                       return new NumberLookupComparer(NumberEval.ZERO);
                }
                if (lookupValue instanceof StringEval) {
                        return new StringLookupComparer((StringEval) lookupValue);
index 54f7d465e5de77d75946c61fec8dae63d2a93610..28923c0f374eea8c09707a1589807a41b6b1f459 100644 (file)
@@ -60,8 +60,7 @@ public final class Vlookup implements Function {
                        AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
                        boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
                        int rowIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createColumnVector(tableArray, 0), isRangeLookup);
-                       ValueEval veColIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol);
-                       int colIndex = LookupUtils.resolveRowOrColIndexArg(veColIndex);
+                       int colIndex = LookupUtils.resolveRowOrColIndexArg(args[2], srcCellRow, srcCellCol);
                        ValueVector resultCol = createResultColumnVector(tableArray, colIndex);
                        return resultCol.getItem(rowIndex);
                } catch (EvaluationException e) {
@@ -73,12 +72,11 @@ public final class Vlookup implements Function {
        /**
         * Returns one column from an <tt>AreaEval</tt>
         * 
-        * @throws EvaluationException (#VALUE!) if colIndex is negative, (#REF!) if colIndex is too high
+        * @param colIndex assumed to be non-negative
+        * 
+        * @throws EvaluationException (#REF!) if colIndex is too high
         */
        private ValueVector createResultColumnVector(AreaEval tableArray, int colIndex) throws EvaluationException {
-               if(colIndex < 0) {
-                       throw EvaluationException.invalidValue();
-               }
                if(colIndex >= tableArray.getWidth()) {
                        throw EvaluationException.invalidRef();
                }
index f4b35fb93504540b85455ff37341318cbcd74e1e..94f16e9840536697981a8c31ce59900625c6236f 100755 (executable)
Binary files a/src/testcases/org/apache/poi/hssf/data/LookupFunctionsTestCaseData.xls and b/src/testcases/org/apache/poi/hssf/data/LookupFunctionsTestCaseData.xls differ