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:
parent
3676e8d3c8
commit
3db8deb9e0
@ -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();
|
||||
}
|
||||
|
@ -322,30 +322,45 @@ final class LookupUtils {
|
||||
* <tr><td><blank></td><td> </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");
|
||||
}
|
||||
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
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.
|
||||
}
|
||||
// else - numeric value parses OK
|
||||
}
|
||||
// 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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user