From: Josh Micich Date: Sat, 6 Sep 2008 05:30:31 +0000 (+0000) Subject: Fixes for special cases of lookup functions (test cases added) X-Git-Tag: REL_3_2_FINAL~89 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d1fa09977ae393f91e9bd67ad52589ea89c837c8;p=poi.git Fixes for special cases of lookup functions (test cases added) git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@692612 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java b/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java index e6efaaee4d..2bbf6f5cd5 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java @@ -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 AreaEval * - * @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(); } diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java b/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java index e6a3ec81c2..ee67ef8ec5 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java @@ -322,30 +322,45 @@ final class LookupUtils { * <blank> #VALUE! *
* - * * 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); diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java b/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java index 54f7d465e5..28923c0f37 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java @@ -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 AreaEval * - * @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(); } diff --git a/src/testcases/org/apache/poi/hssf/data/LookupFunctionsTestCaseData.xls b/src/testcases/org/apache/poi/hssf/data/LookupFunctionsTestCaseData.xls index f4b35fb935..94f16e9840 100755 Binary files a/src/testcases/org/apache/poi/hssf/data/LookupFunctionsTestCaseData.xls and b/src/testcases/org/apache/poi/hssf/data/LookupFunctionsTestCaseData.xls differ