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]);
|
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();
|
||||||
}
|
}
|
||||||
|
@ -322,30 +322,45 @@ final class LookupUtils {
|
|||||||
* <tr><td><blank></td><td> </td><td>#VALUE!</td></tr>
|
* <tr><td><blank></td><td> </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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user