Update the RefEval method signature to cope with multi-sheet references, and have appropriate functions take advantage of this. For bug #55906

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1613453 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2014-07-25 15:46:05 +00:00
parent d97867e5be
commit 3872e620a7
22 changed files with 227 additions and 82 deletions

View File

@ -26,22 +26,21 @@ import org.apache.poi.ss.util.CellReference;
/** /**
* Provides Lazy Evaluation to a 3D Reference * Provides Lazy Evaluation to a 3D Reference
*
* TODO Provide access to multiple sheets where present
*/ */
final class LazyRefEval extends RefEvalBase { final class LazyRefEval extends RefEvalBase {
private final SheetRangeEvaluator _evaluator; private final SheetRangeEvaluator _evaluator;
public LazyRefEval(int rowIndex, int columnIndex, SheetRangeEvaluator sre) { public LazyRefEval(int rowIndex, int columnIndex, SheetRangeEvaluator sre) {
super(rowIndex, columnIndex); super(sre, rowIndex, columnIndex);
if (sre == null) {
throw new IllegalArgumentException("sre must not be null");
}
_evaluator = sre; _evaluator = sre;
} }
@Deprecated
public ValueEval getInnerValueEval() { public ValueEval getInnerValueEval() {
return _evaluator.getEvalForCell(_evaluator.getFirstSheetIndex(), getRow(), getColumn()); return getInnerValueEval(_evaluator.getFirstSheetIndex());
}
public ValueEval getInnerValueEval(int sheetIndex) {
return _evaluator.getEvalForCell(sheetIndex, getRow(), getColumn());
} }
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) { public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {

View File

@ -0,0 +1,23 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.ss.formula;
public interface SheetRange {
public int getFirstSheetIndex();
public int getLastSheetIndex();
}

View File

@ -22,7 +22,7 @@ import org.apache.poi.ss.formula.eval.ValueEval;
/** /**
* Evaluator for returning cells or sheets for a range of sheets * Evaluator for returning cells or sheets for a range of sheets
*/ */
final class SheetRangeEvaluator { final class SheetRangeEvaluator implements SheetRange {
private final int _firstSheetIndex; private final int _firstSheetIndex;
private final int _lastSheetIndex; private final int _lastSheetIndex;
private SheetRefEvaluator[] _sheetEvaluators; private SheetRefEvaluator[] _sheetEvaluators;

View File

@ -59,7 +59,7 @@ public final class OperandResolver {
throws EvaluationException { throws EvaluationException {
ValueEval result; ValueEval result;
if (arg instanceof RefEval) { if (arg instanceof RefEval) {
result = ((RefEval) arg).getInnerValueEval(); result = chooseSingleElementFromRef((RefEval) arg);
} else if (arg instanceof AreaEval) { } else if (arg instanceof AreaEval) {
result = chooseSingleElementFromArea((AreaEval) arg, srcCellRow, srcCellCol); result = chooseSingleElementFromArea((AreaEval) arg, srcCellRow, srcCellCol);
} else { } else {
@ -175,6 +175,10 @@ public final class OperandResolver {
return ae.getAbsoluteValue(ae.getFirstRow(), srcCellCol); return ae.getAbsoluteValue(ae.getFirstRow(), srcCellCol);
} }
private static ValueEval chooseSingleElementFromRef(RefEval ref) {
return ref.getInnerValueEval( ref.getFirstSheetIndex() );
}
/** /**
* Applies some conversion rules if the supplied value is not already an integer.<br/> * Applies some conversion rules if the supplied value is not already an integer.<br/>
* Value is first coerced to a <tt>double</tt> ( See <tt>coerceValueToDouble()</tt> ). * Value is first coerced to a <tt>double</tt> ( See <tt>coerceValueToDouble()</tt> ).

View File

@ -17,9 +17,9 @@
package org.apache.poi.ss.formula.eval; package org.apache.poi.ss.formula.eval;
import org.apache.poi.ss.formula.SheetRange;
/** /**
* @author Amol S Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
* RefEval is the super interface for Ref2D and Ref3DEval. Basically a RefEval * RefEval is the super interface for Ref2D and Ref3DEval. Basically a RefEval
* impl should contain reference to the original ReferencePtg or Ref3DPtg as * impl should contain reference to the original ReferencePtg or Ref3DPtg as
* well as the final "value" resulting from the evaluation of the cell * well as the final "value" resulting from the evaluation of the cell
@ -27,12 +27,11 @@ package org.apache.poi.ss.formula.eval;
* value object should be of type NumberEval; if cell type is CELL_TYPE_STRING, * value object should be of type NumberEval; if cell type is CELL_TYPE_STRING,
* contained value object should be of type StringEval * contained value object should be of type StringEval
*/ */
public interface RefEval extends ValueEval { public interface RefEval extends ValueEval, SheetRange {
/** /**
* @return the evaluated value of the cell referred to by this RefEval. * @return the evaluated value of the cell referred to by this RefEval on the given sheet
*/ */
ValueEval getInnerValueEval(); ValueEval getInnerValueEval(int sheetIndex);
/** /**
* returns the zero based column index. * returns the zero based column index.
@ -44,6 +43,22 @@ public interface RefEval extends ValueEval {
*/ */
int getRow(); int getRow();
/**
* returns the first sheet index this applies to
*/
int getFirstSheetIndex();
/**
* returns the last sheet index this applies to, which
* will be the same as the first for a 2D and many 3D references
*/
int getLastSheetIndex();
/**
* returns the number of sheets this applies to
*/
int getNumberOfSheets();
/** /**
* Creates an {@link AreaEval} offset by a relative amount from this RefEval * Creates an {@link AreaEval} offset by a relative amount from this RefEval
*/ */

View File

@ -17,19 +17,44 @@
package org.apache.poi.ss.formula.eval; package org.apache.poi.ss.formula.eval;
import org.apache.poi.ss.formula.SheetRange;
/** /**
* Common base class for implementors of {@link RefEval} * Common base class for implementors of {@link RefEval}
*
* @author Josh Micich
*/ */
public abstract class RefEvalBase implements RefEval { public abstract class RefEvalBase implements RefEval {
private final int _firstSheetIndex;
private final int _lastSheetIndex;
private final int _rowIndex; private final int _rowIndex;
private final int _columnIndex; private final int _columnIndex;
protected RefEvalBase(int rowIndex, int columnIndex) { protected RefEvalBase(SheetRange sheetRange, int rowIndex, int columnIndex) {
if (sheetRange == null) {
throw new IllegalArgumentException("sheetRange must not be null");
}
_firstSheetIndex = sheetRange.getFirstSheetIndex();
_lastSheetIndex = sheetRange.getLastSheetIndex();
_rowIndex = rowIndex; _rowIndex = rowIndex;
_columnIndex = columnIndex; _columnIndex = columnIndex;
}
protected RefEvalBase(int firstSheetIndex, int lastSheetIndex, int rowIndex, int columnIndex) {
_firstSheetIndex = firstSheetIndex;
_lastSheetIndex = lastSheetIndex;
_rowIndex = rowIndex;
_columnIndex = columnIndex;
}
protected RefEvalBase(int onlySheetIndex, int rowIndex, int columnIndex) {
this(onlySheetIndex, onlySheetIndex, rowIndex, columnIndex);
}
public int getNumberOfSheets() {
return _lastSheetIndex-_firstSheetIndex+1;
}
public int getFirstSheetIndex() {
return _firstSheetIndex;
}
public int getLastSheetIndex() {
return _lastSheetIndex;
} }
public final int getRow() { public final int getRow() {
return _rowIndex; return _rowIndex;

View File

@ -17,6 +17,7 @@
package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.BoolEval; import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.EvaluationException; import org.apache.poi.ss.formula.eval.EvaluationException;
@ -24,7 +25,6 @@ import org.apache.poi.ss.formula.eval.MissingArgEval;
import org.apache.poi.ss.formula.eval.OperandResolver; import org.apache.poi.ss.formula.eval.OperandResolver;
import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.TwoDEval;
/** /**
* Here are the general rules concerning Boolean functions: * Here are the general rules concerning Boolean functions:
@ -61,6 +61,7 @@ public abstract class BooleanFunction implements Function {
* Note: no short-circuit boolean loop exit because any ErrorEvals will override the result * Note: no short-circuit boolean loop exit because any ErrorEvals will override the result
*/ */
for (int i=0, iSize=args.length; i<iSize; i++) { for (int i=0, iSize=args.length; i<iSize; i++) {
Boolean tempVe;
ValueEval arg = args[i]; ValueEval arg = args[i];
if (arg instanceof TwoDEval) { if (arg instanceof TwoDEval) {
TwoDEval ae = (TwoDEval) arg; TwoDEval ae = (TwoDEval) arg;
@ -69,7 +70,7 @@ public abstract class BooleanFunction implements Function {
for (int rrIx=0; rrIx<height; rrIx++) { for (int rrIx=0; rrIx<height; rrIx++) {
for (int rcIx=0; rcIx<width; rcIx++) { for (int rcIx=0; rcIx<width; rcIx++) {
ValueEval ve = ae.getValue(rrIx, rcIx); ValueEval ve = ae.getValue(rrIx, rcIx);
Boolean tempVe = OperandResolver.coerceValueToBoolean(ve, true); tempVe = OperandResolver.coerceValueToBoolean(ve, true);
if (tempVe != null) { if (tempVe != null) {
result = partialEvaluate(result, tempVe.booleanValue()); result = partialEvaluate(result, tempVe.booleanValue());
atleastOneNonBlank = true; atleastOneNonBlank = true;
@ -78,17 +79,25 @@ public abstract class BooleanFunction implements Function {
} }
continue; continue;
} }
Boolean tempVe;
if (arg instanceof RefEval) { if (arg instanceof RefEval) {
ValueEval ve = ((RefEval) arg).getInnerValueEval(); RefEval re = (RefEval) arg;
for (int sIx = re.getFirstSheetIndex(); sIx <= re.getLastSheetIndex(); sIx++) {
ValueEval ve = re.getInnerValueEval(sIx);
tempVe = OperandResolver.coerceValueToBoolean(ve, true); tempVe = OperandResolver.coerceValueToBoolean(ve, true);
} else if (arg == MissingArgEval.instance) { if (tempVe != null) {
result = partialEvaluate(result, tempVe.booleanValue());
atleastOneNonBlank = true;
}
}
continue;
}
if (arg == MissingArgEval.instance) {
tempVe = null; // you can leave out parameters, they are simply ignored tempVe = null; // you can leave out parameters, they are simply ignored
} else { } else {
tempVe = OperandResolver.coerceValueToBoolean(arg, false); tempVe = OperandResolver.coerceValueToBoolean(arg, false);
} }
if (tempVe != null) { if (tempVe != null) {
result = partialEvaluate(result, tempVe.booleanValue()); result = partialEvaluate(result, tempVe.booleanValue());
atleastOneNonBlank = true; atleastOneNonBlank = true;

View File

@ -17,9 +17,9 @@
package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.TwoDEval;
/** /**
* Common logic for COUNT, COUNTA and COUNTIF * Common logic for COUNT, COUNTA and COUNTIF
@ -67,13 +67,18 @@ final class CountUtils {
return result; return result;
} }
/** /**
* @return 1 if the evaluated cell matches the specified criteria * @return the number of evaluated cells in the range that match the specified criteria
*/ */
public static int countMatchingCell(RefEval refEval, I_MatchPredicate criteriaPredicate) { public static int countMatchingCellsInRef(RefEval refEval, I_MatchPredicate criteriaPredicate) {
if(criteriaPredicate.matches(refEval.getInnerValueEval())) { int result = 0;
return 1;
for (int sIx = refEval.getFirstSheetIndex(); sIx <= refEval.getLastSheetIndex(); sIx++) {
ValueEval ve = refEval.getInnerValueEval(sIx);
if(criteriaPredicate.matches(ve)) {
result++;
} }
return 0; }
return result;
} }
public static int countArg(ValueEval eval, I_MatchPredicate criteriaPredicate) { public static int countArg(ValueEval eval, I_MatchPredicate criteriaPredicate) {
if (eval == null) { if (eval == null) {
@ -83,7 +88,7 @@ final class CountUtils {
return countMatchingCellsInArea((TwoDEval) eval, criteriaPredicate); return countMatchingCellsInArea((TwoDEval) eval, criteriaPredicate);
} }
if (eval instanceof RefEval) { if (eval instanceof RefEval) {
return CountUtils.countMatchingCell((RefEval) eval, criteriaPredicate); return CountUtils.countMatchingCellsInRef((RefEval) eval, criteriaPredicate);
} }
return criteriaPredicate.matches(eval) ? 1 : 0; return criteriaPredicate.matches(eval) ? 1 : 0;
} }

View File

@ -17,12 +17,12 @@
package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.BlankEval; import org.apache.poi.ss.formula.eval.BlankEval;
import org.apache.poi.ss.formula.eval.NumberEval; import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.CountUtils.I_MatchPredicate; import org.apache.poi.ss.formula.functions.CountUtils.I_MatchPredicate;
import org.apache.poi.ss.formula.TwoDEval;
/** /**
* Implementation for the function COUNTBLANK * Implementation for the function COUNTBLANK
@ -41,7 +41,7 @@ public final class Countblank extends Fixed1ArgFunction {
double result; double result;
if (arg0 instanceof RefEval) { if (arg0 instanceof RefEval) {
result = CountUtils.countMatchingCell((RefEval) arg0, predicate); result = CountUtils.countMatchingCellsInRef((RefEval) arg0, predicate);
} else if (arg0 instanceof TwoDEval) { } else if (arg0 instanceof TwoDEval) {
result = CountUtils.countMatchingCellsInArea((TwoDEval) arg0, predicate); result = CountUtils.countMatchingCellsInArea((TwoDEval) arg0, predicate);
} else { } else {

View File

@ -19,6 +19,7 @@ package org.apache.poi.ss.formula.functions;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.BlankEval; import org.apache.poi.ss.formula.eval.BlankEval;
import org.apache.poi.ss.formula.eval.BoolEval; import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
@ -29,7 +30,6 @@ import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.StringEval; import org.apache.poi.ss.formula.eval.StringEval;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.CountUtils.I_MatchPredicate; import org.apache.poi.ss.formula.functions.CountUtils.I_MatchPredicate;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.usermodel.ErrorConstants; import org.apache.poi.ss.usermodel.ErrorConstants;
/** /**
@ -444,7 +444,7 @@ public final class Countif extends Fixed2ArgFunction {
private double countMatchingCellsInArea(ValueEval rangeArg, I_MatchPredicate criteriaPredicate) { private double countMatchingCellsInArea(ValueEval rangeArg, I_MatchPredicate criteriaPredicate) {
if (rangeArg instanceof RefEval) { if (rangeArg instanceof RefEval) {
return CountUtils.countMatchingCell((RefEval) rangeArg, criteriaPredicate); return CountUtils.countMatchingCellsInRef((RefEval) rangeArg, criteriaPredicate);
} else if (rangeArg instanceof TwoDEval) { } else if (rangeArg instanceof TwoDEval) {
return CountUtils.countMatchingCellsInArea((TwoDEval) rangeArg, criteriaPredicate); return CountUtils.countMatchingCellsInArea((TwoDEval) rangeArg, criteriaPredicate);
} else { } else {

View File

@ -17,13 +17,18 @@
package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;
import org.apache.poi.ss.formula.OperationEvaluationContext;
import org.apache.poi.ss.formula.eval.*;
import org.apache.poi.ss.usermodel.DateUtil;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import org.apache.poi.ss.formula.OperationEvaluationContext;
import org.apache.poi.ss.formula.eval.BlankEval;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.usermodel.DateUtil;
/** /**
* Implementation for Excel EDATE () function. * Implementation for Excel EDATE () function.
*/ */
@ -56,7 +61,13 @@ public class EDate implements FreeRefFunction {
return 0; return 0;
} }
if (arg instanceof RefEval) { if (arg instanceof RefEval) {
ValueEval innerValueEval = ((RefEval) arg).getInnerValueEval(); RefEval refEval = (RefEval)arg;
if (refEval.getNumberOfSheets() > 1) {
// Multi-Sheet references are not supported
throw new EvaluationException(ErrorEval.VALUE_INVALID);
}
ValueEval innerValueEval = refEval.getInnerValueEval(refEval.getFirstSheetIndex());
if(innerValueEval instanceof NumberEval) { if(innerValueEval instanceof NumberEval) {
return ((NumberEval) innerValueEval).getNumberValue(); return ((NumberEval) innerValueEval).getNumberValue();
} }

View File

@ -76,13 +76,16 @@ public final class LinearRegressionFunction extends Fixed2ArgFunction {
private static final class RefValueArray extends ValueArray { private static final class RefValueArray extends ValueArray {
private final RefEval _ref; private final RefEval _ref;
private final int _width;
public RefValueArray(RefEval ref) { public RefValueArray(RefEval ref) {
super(1); super(ref.getNumberOfSheets());
_ref = ref; _ref = ref;
_width = ref.getNumberOfSheets();
} }
protected ValueEval getItemInternal(int index) { protected ValueEval getItemInternal(int index) {
return _ref.getInnerValueEval(); int sIx = (index % _width) + _ref.getFirstSheetIndex();
return _ref.getInnerValueEval(sIx);
} }
} }

View File

@ -17,6 +17,10 @@
package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.BlankEval; import org.apache.poi.ss.formula.eval.BlankEval;
import org.apache.poi.ss.formula.eval.BoolEval; import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
@ -27,10 +31,6 @@ import org.apache.poi.ss.formula.eval.OperandResolver;
import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.StringEval; import org.apache.poi.ss.formula.eval.StringEval;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.TwoDEval;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* Common functionality used by VLOOKUP, HLOOKUP, LOOKUP and MATCH * Common functionality used by VLOOKUP, HLOOKUP, LOOKUP and MATCH
@ -104,6 +104,28 @@ final class LookupUtils {
} }
} }
private static final class SheetVector implements ValueVector {
private final RefEval _re;
private final int _size;
public SheetVector(RefEval re) {
_size = re.getNumberOfSheets();
_re = re;
}
public ValueEval getItem(int index) {
if(index >= _size) {
throw new ArrayIndexOutOfBoundsException("Specified index (" + index
+ ") is outside the allowed range (0.." + (_size-1) + ")");
}
int sheetIndex = _re.getFirstSheetIndex() + index;
return _re.getInnerValueEval(sheetIndex);
}
public int getSize() {
return _size;
}
}
public static ValueVector createRowVector(TwoDEval tableArray, int relativeRowIndex) { public static ValueVector createRowVector(TwoDEval tableArray, int relativeRowIndex) {
return new RowVector(tableArray, relativeRowIndex); return new RowVector(tableArray, relativeRowIndex);
} }
@ -123,6 +145,10 @@ final class LookupUtils {
return null; return null;
} }
public static ValueVector createVector(RefEval re) {
return new SheetVector(re);
}
/** /**
* Enumeration to support <b>4</b> valued comparison results.<p/> * Enumeration to support <b>4</b> valued comparison results.<p/>
* Excel lookup functions have complex behaviour in the case where the lookup array has mixed * Excel lookup functions have complex behaviour in the case where the lookup array has mixed

View File

@ -17,6 +17,7 @@
package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.EvaluationException; import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.formula.eval.NumberEval; import org.apache.poi.ss.formula.eval.NumberEval;
@ -28,7 +29,6 @@ import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.LookupUtils.CompareResult; import org.apache.poi.ss.formula.functions.LookupUtils.CompareResult;
import org.apache.poi.ss.formula.functions.LookupUtils.LookupValueComparer; import org.apache.poi.ss.formula.functions.LookupUtils.LookupValueComparer;
import org.apache.poi.ss.formula.functions.LookupUtils.ValueVector; import org.apache.poi.ss.formula.functions.LookupUtils.ValueVector;
import org.apache.poi.ss.formula.TwoDEval;
/** /**
* Implementation for the MATCH() Excel function.<p/> * Implementation for the MATCH() Excel function.<p/>
@ -125,7 +125,11 @@ public final class Match extends Var2or3ArgFunction {
private static ValueVector evaluateLookupRange(ValueEval eval) throws EvaluationException { private static ValueVector evaluateLookupRange(ValueEval eval) throws EvaluationException {
if (eval instanceof RefEval) { if (eval instanceof RefEval) {
RefEval re = (RefEval) eval; RefEval re = (RefEval) eval;
return new SingleValueVector(re.getInnerValueEval()); if (re.getNumberOfSheets() == 1) {
return new SingleValueVector(re.getInnerValueEval(re.getFirstSheetIndex()));
} else {
return LookupUtils.createVector(re);
}
} }
if (eval instanceof TwoDEval) { if (eval instanceof TwoDEval) {
ValueVector result = LookupUtils.createVector((TwoDEval)eval); ValueVector result = LookupUtils.createVector((TwoDEval)eval);

View File

@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.BlankEval; import org.apache.poi.ss.formula.eval.BlankEval;
import org.apache.poi.ss.formula.eval.BoolEval; import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
@ -29,7 +30,6 @@ import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.StringEval; import org.apache.poi.ss.formula.eval.StringEval;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.TwoDEval;
/** /**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
@ -106,7 +106,9 @@ public final class Mode implements Function {
} }
if (arg instanceof RefEval) { if (arg instanceof RefEval) {
RefEval re = (RefEval) arg; RefEval re = (RefEval) arg;
collectValue(re.getInnerValueEval(), temp, true); for (int sIx = re.getFirstSheetIndex(); sIx <= re.getLastSheetIndex(); sIx++) {
collectValue(re.getInnerValueEval(sIx), temp, true);
}
return; return;
} }
collectValue(arg, temp, true); collectValue(arg, temp, true);

View File

@ -17,6 +17,7 @@
package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.BlankEval; import org.apache.poi.ss.formula.eval.BlankEval;
import org.apache.poi.ss.formula.eval.BoolEval; import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
@ -27,7 +28,6 @@ import org.apache.poi.ss.formula.eval.OperandResolver;
import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.StringValueEval; import org.apache.poi.ss.formula.eval.StringValueEval;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.TwoDEval;
/** /**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
@ -157,7 +157,9 @@ public abstract class MultiOperandNumericFunction implements Function {
} }
if (operand instanceof RefEval) { if (operand instanceof RefEval) {
RefEval re = (RefEval) operand; RefEval re = (RefEval) operand;
collectValue(re.getInnerValueEval(), true, temp); for (int sIx = re.getFirstSheetIndex(); sIx <= re.getLastSheetIndex(); sIx++) {
collectValue(re.getInnerValueEval(sIx), true, temp);
}
return; return;
} }
collectValue(operand, false, temp); collectValue(operand, false, temp);

View File

@ -17,6 +17,7 @@
package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.AreaEval; import org.apache.poi.ss.formula.eval.AreaEval;
import org.apache.poi.ss.formula.eval.BlankEval; import org.apache.poi.ss.formula.eval.BlankEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
@ -26,7 +27,6 @@ import org.apache.poi.ss.formula.eval.NumericValueEval;
import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.StringEval; import org.apache.poi.ss.formula.eval.StringEval;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.TwoDEval;
/** /**
@ -99,7 +99,10 @@ public final class Sumproduct implements Function {
ValueEval eval; ValueEval eval;
if (arg instanceof RefEval) { if (arg instanceof RefEval) {
RefEval re = (RefEval) arg; RefEval re = (RefEval) arg;
eval = re.getInnerValueEval(); if (re.getNumberOfSheets() > 1) {
throw new EvaluationException(ErrorEval.VALUE_INVALID);
}
eval = re.getInnerValueEval(re.getFirstSheetIndex());
} else { } else {
eval = arg; eval = arg;
} }

View File

@ -35,7 +35,9 @@ public final class T extends Fixed1ArgFunction {
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) { public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
ValueEval arg = arg0; ValueEval arg = arg0;
if (arg instanceof RefEval) { if (arg instanceof RefEval) {
arg = ((RefEval) arg).getInnerValueEval(); // always use the first sheet
RefEval re = (RefEval)arg;
arg = re.getInnerValueEval(re.getFirstSheetIndex());
} else if (arg instanceof AreaEval) { } else if (arg instanceof AreaEval) {
// when the arg is an area, choose the top left cell // when the arg is an area, choose the top left cell
arg = ((AreaEval) arg).getRelativeValue(0, 0); arg = ((AreaEval) arg).getRelativeValue(0, 0);

View File

@ -17,13 +17,13 @@
package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;
import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.EvaluationException; import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.formula.eval.NumberEval; import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.LookupUtils.ValueVector; import org.apache.poi.ss.formula.functions.LookupUtils.ValueVector;
import org.apache.poi.ss.formula.TwoDEval;
/** /**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
@ -61,12 +61,16 @@ public abstract class XYNumericFunction extends Fixed2ArgFunction {
private static final class RefValueArray extends ValueArray { private static final class RefValueArray extends ValueArray {
private final RefEval _ref; private final RefEval _ref;
private final int _width;
public RefValueArray(RefEval ref) { public RefValueArray(RefEval ref) {
super(1); super(ref.getNumberOfSheets());
_ref = ref; _ref = ref;
_width = ref.getNumberOfSheets();
} }
protected ValueEval getItemInternal(int index) { protected ValueEval getItemInternal(int index) {
return _ref.getInnerValueEval(); int sIx = (index % _width) + _ref.getFirstSheetIndex();
return _ref.getInnerValueEval(sIx);
} }
} }

View File

@ -20,8 +20,6 @@ package org.apache.poi.ss.formula.eval;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.ss.formula.ptg.AreaI;
import org.apache.poi.ss.formula.ptg.AreaI.OffsetArea;
import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFRow;
@ -29,6 +27,8 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.AreaReference; import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.CellReference; import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.ss.formula.TwoDEval; import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.ptg.AreaI;
import org.apache.poi.ss.formula.ptg.AreaI.OffsetArea;
import org.apache.poi.ss.usermodel.CellValue; import org.apache.poi.ss.usermodel.CellValue;
/** /**
@ -71,11 +71,10 @@ public final class TestRangeEval extends TestCase {
} }
private static final class MockRefEval extends RefEvalBase { private static final class MockRefEval extends RefEvalBase {
public MockRefEval(int rowIndex, int columnIndex) { public MockRefEval(int rowIndex, int columnIndex) {
super(rowIndex, columnIndex); super(-1, -1, rowIndex, columnIndex);
} }
public ValueEval getInnerValueEval() { public ValueEval getInnerValueEval(int sheetIndex) {
throw new RuntimeException("not expected to be called during this test"); throw new RuntimeException("not expected to be called during this test");
} }
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx,

View File

@ -17,17 +17,17 @@
package org.apache.poi.ss.formula.functions; package org.apache.poi.ss.formula.functions;
import org.apache.poi.ss.formula.ptg.AreaI; import org.apache.poi.ss.formula.TwoDEval;
import org.apache.poi.ss.formula.ptg.AreaPtg;
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
import org.apache.poi.ss.formula.ptg.RefPtg;
import org.apache.poi.ss.formula.eval.AreaEval; import org.apache.poi.ss.formula.eval.AreaEval;
import org.apache.poi.ss.formula.eval.AreaEvalBase; import org.apache.poi.ss.formula.eval.AreaEvalBase;
import org.apache.poi.ss.formula.eval.NumberEval; import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.RefEvalBase; import org.apache.poi.ss.formula.eval.RefEvalBase;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.TwoDEval; import org.apache.poi.ss.formula.ptg.AreaI;
import org.apache.poi.ss.formula.ptg.AreaPtg;
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
import org.apache.poi.ss.formula.ptg.RefPtg;
/** /**
* Test helper class for creating mock <code>Eval</code> objects * Test helper class for creating mock <code>Eval</code> objects
@ -157,14 +157,14 @@ public final class EvalFactory {
private static final class MockRefEval extends RefEvalBase { private static final class MockRefEval extends RefEvalBase {
private final ValueEval _value; private final ValueEval _value;
public MockRefEval(RefPtg ptg, ValueEval value) { public MockRefEval(RefPtg ptg, ValueEval value) {
super(ptg.getRow(), ptg.getColumn()); super(-1, -1, ptg.getRow(), ptg.getColumn());
_value = value; _value = value;
} }
public MockRefEval(Ref3DPtg ptg, ValueEval value) { public MockRefEval(Ref3DPtg ptg, ValueEval value) {
super(ptg.getRow(), ptg.getColumn()); super(-1, -1, ptg.getRow(), ptg.getColumn());
_value = value; _value = value;
} }
public ValueEval getInnerValueEval() { public ValueEval getInnerValueEval(int sheetIndex) {
return _value; return _value;
} }
public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) { public AreaEval offset(int relFirstRowIx, int relLastRowIx, int relFirstColIx, int relLastColIx) {

View File

@ -46,14 +46,23 @@ public class TestEDate extends TestCase{
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public int getRow() { public ValueEval getInnerValueEval(int sheetIndex) {
throw new UnsupportedOperationException();
}
public ValueEval getInnerValueEval() {
return value; return value;
} }
public int getNumberOfSheets() {
return 1;
}
public int getFirstSheetIndex() {
return 0;
}
public int getLastSheetIndex() {
return 0;
}
public int getRow() {
throw new UnsupportedOperationException();
}
public int getColumn() { public int getColumn() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }