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
This commit is contained in:
Josh Micich 2008-09-06 05:30:31 +00:00
parent 3676e8d3c8
commit 3db8deb9e0
4 changed files with 47 additions and 34 deletions

View File

@ -60,8 +60,7 @@ public final class Hlookup implements Function {
AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]); AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol); boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
int colIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createRowVector(tableArray, 0), isRangeLookup); int colIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createRowVector(tableArray, 0), isRangeLookup);
ValueEval veRowIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol); int rowIndex = LookupUtils.resolveRowOrColIndexArg(args[2], srcCellRow, srcCellCol);
int rowIndex = LookupUtils.resolveRowOrColIndexArg(veRowIndex);
ValueVector resultCol = createResultColumnVector(tableArray, rowIndex); ValueVector resultCol = createResultColumnVector(tableArray, rowIndex);
return resultCol.getItem(colIndex); return resultCol.getItem(colIndex);
} catch (EvaluationException e) { } catch (EvaluationException e) {
@ -73,12 +72,11 @@ public final class Hlookup implements Function {
/** /**
* Returns one column from an <tt>AreaEval</tt> * 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 { private ValueVector createResultColumnVector(AreaEval tableArray, int rowIndex) throws EvaluationException {
if(rowIndex < 0) {
throw EvaluationException.invalidValue();
}
if(rowIndex >= tableArray.getHeight()) { if(rowIndex >= tableArray.getHeight()) {
throw EvaluationException.invalidRef(); throw EvaluationException.invalidRef();
} }

View File

@ -322,30 +322,45 @@ final class LookupUtils {
* <tr><td>&lt;blank&gt;</td><td>&nbsp;</td><td>#VALUE!</td></tr> * <tr><td>&lt;blank&gt;</td><td>&nbsp;</td><td>#VALUE!</td></tr>
* </table><br/> * </table><br/>
* *
* * Note - out of range errors (both too high and too low) are handled by the caller. * Note - out of range errors (result index too high) are handled by the caller.
* @return column or row index as a zero-based value * @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 { public static int resolveRowOrColIndexArg(Eval rowColIndexArg, int srcCellRow, int srcCellCol) throws EvaluationException {
if(veRowColIndexArg == null) { if(rowColIndexArg == null) {
throw new IllegalArgumentException("argument must not be null"); throw new IllegalArgumentException("argument must not be null");
} }
ValueEval veRowColIndexArg;
try {
veRowColIndexArg = OperandResolver.getSingleValue(rowColIndexArg, srcCellRow, (short)srcCellCol);
} catch (EvaluationException e) {
// All errors get translated to #REF!
throw EvaluationException.invalidRef();
}
int oneBasedIndex;
if(veRowColIndexArg instanceof BlankEval) { 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
}
// 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(); throw EvaluationException.invalidValue();
} }
if(veRowColIndexArg instanceof StringEval) { return oneBasedIndex - 1; // convert to zero based
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.
}
// else - numeric value parses OK
}
// actual BoolEval values get interpreted as FALSE->0 and TRUE->1
return OperandResolver.coerceValueToInt(veRowColIndexArg) - 1;
} }
@ -583,11 +598,13 @@ final class LookupUtils {
return maxIx - 1; return maxIx - 1;
} }
public static LookupValueComparer createLookupComparer(ValueEval lookupValue) throws EvaluationException { public static LookupValueComparer createLookupComparer(ValueEval lookupValue) {
if (lookupValue instanceof BlankEval) { if (lookupValue == BlankEval.INSTANCE) {
// blank eval can never be found in a lookup array // blank eval translates to zero
throw new EvaluationException(ErrorEval.NA); // 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) { if (lookupValue instanceof StringEval) {
return new StringLookupComparer((StringEval) lookupValue); return new StringLookupComparer((StringEval) lookupValue);

View File

@ -60,8 +60,7 @@ public final class Vlookup implements Function {
AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]); AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol); boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
int rowIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createColumnVector(tableArray, 0), isRangeLookup); int rowIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createColumnVector(tableArray, 0), isRangeLookup);
ValueEval veColIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol); int colIndex = LookupUtils.resolveRowOrColIndexArg(args[2], srcCellRow, srcCellCol);
int colIndex = LookupUtils.resolveRowOrColIndexArg(veColIndex);
ValueVector resultCol = createResultColumnVector(tableArray, colIndex); ValueVector resultCol = createResultColumnVector(tableArray, colIndex);
return resultCol.getItem(rowIndex); return resultCol.getItem(rowIndex);
} catch (EvaluationException e) { } catch (EvaluationException e) {
@ -73,12 +72,11 @@ public final class Vlookup implements Function {
/** /**
* Returns one column from an <tt>AreaEval</tt> * 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 { private ValueVector createResultColumnVector(AreaEval tableArray, int colIndex) throws EvaluationException {
if(colIndex < 0) {
throw EvaluationException.invalidValue();
}
if(colIndex >= tableArray.getWidth()) { if(colIndex >= tableArray.getWidth()) {
throw EvaluationException.invalidRef(); throw EvaluationException.invalidRef();
} }