ASF Bugzilla – Attachment 36356 Details for
Bug 62904
Simple Excel Array Formula Fails in POI
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch to fix evaluation of IF with array arguments
62904.diff (text/plain), 10.16 KB, created by
Yegor Kozlov
on 2019-01-01 17:27:41 UTC
(
hide
)
Description:
patch to fix evaluation of IF with array arguments
Filename:
MIME Type:
Creator:
Yegor Kozlov
Created:
2019-01-01 17:27:41 UTC
Size:
10.16 KB
patch
obsolete
>Index: src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java >=================================================================== >--- src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java (revision 1850028) >+++ src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java (working copy) >@@ -453,15 +453,24 @@ > // nothing to skip - true param follows > } else { > int dist = attrPtg.getData(); >+ Ptg currPtg = ptgs[i+1]; > i+= countTokensToBeSkipped(ptgs, i, dist); > Ptg nextPtg = ptgs[i+1]; >- if (ptgs[i] instanceof AttrPtg && nextPtg instanceof FuncVarPtg && >- // in order to verify that there is no third param, we need to check >+ >+ if (ptgs[i] instanceof AttrPtg && nextPtg instanceof FuncVarPtg && >+ // in order to verify that there is no third param, we need to check > // if we really have the IF next or some other FuncVarPtg as third param, e.g. ROW()/COLUMN()! > ((FuncVarPtg)nextPtg).getFunctionIndex() == FunctionMetadataRegistry.FUNCTION_INDEX_IF) { > // this is an if statement without a false param (as opposed to MissingArgPtg as the false param) >- i++; >- stack.push(BoolEval.FALSE); >+ //i++; >+ stack.push(arg0); >+ if(currPtg instanceof AreaPtg){ >+ // IF in array mode. See Bug 62904 >+ ValueEval currEval = getEvalForPtg(currPtg, ec); >+ stack.push(currEval); >+ } else { >+ stack.push(BoolEval.FALSE); >+ } > } > } > continue; >Index: src/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java >=================================================================== >--- src/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java (revision 1850028) >+++ src/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java (working copy) >@@ -75,83 +75,12 @@ > } > > public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) { >- ValueEval arg0 = args[0]; >- ValueEval arg1 = args[1]; >+ return evaluateArray(args, srcRowIndex, srcColumnIndex, (vA, vB) -> { >+ int cmpResult = doCompare(vA, vB); >+ boolean result = convertComparisonResult(cmpResult); >+ return BoolEval.valueOf(result); >+ }); > >- int w1, w2, h1, h2; >- int a1FirstCol = 0, a1FirstRow = 0; >- if (arg0 instanceof AreaEval) { >- AreaEval ae = (AreaEval)arg0; >- w1 = ae.getWidth(); >- h1 = ae.getHeight(); >- a1FirstCol = ae.getFirstColumn(); >- a1FirstRow = ae.getFirstRow(); >- } else if (arg0 instanceof RefEval){ >- RefEval ref = (RefEval)arg0; >- w1 = 1; >- h1 = 1; >- a1FirstCol = ref.getColumn(); >- a1FirstRow = ref.getRow(); >- } else { >- w1 = 1; >- h1 = 1; >- } >- int a2FirstCol = 0, a2FirstRow = 0; >- if (arg1 instanceof AreaEval) { >- AreaEval ae = (AreaEval)arg1; >- w2 = ae.getWidth(); >- h2 = ae.getHeight(); >- a2FirstCol = ae.getFirstColumn(); >- a2FirstRow = ae.getFirstRow(); >- } else if (arg1 instanceof RefEval){ >- RefEval ref = (RefEval)arg1; >- w2 = 1; >- h2 = 1; >- a2FirstCol = ref.getColumn(); >- a2FirstRow = ref.getRow(); >- } else { >- w2 = 1; >- h2 = 1; >- } >- >- int width = Math.max(w1, w2); >- int height = Math.max(h1, h2); >- >- ValueEval[] vals = new ValueEval[height * width]; >- >- int idx = 0; >- for(int i = 0; i < height; i++){ >- for(int j = 0; j < width; j++){ >- ValueEval vA; >- try { >- vA = OperandResolver.getSingleValue(arg0, a1FirstRow + i, a1FirstCol + j); >- } catch (EvaluationException e) { >- vA = e.getErrorEval(); >- } >- ValueEval vB; >- try { >- vB = OperandResolver.getSingleValue(arg1, a2FirstRow + i, a2FirstCol + j); >- } catch (EvaluationException e) { >- vB = e.getErrorEval(); >- } >- if(vA instanceof ErrorEval){ >- vals[idx++] = vA; >- } else if (vB instanceof ErrorEval) { >- vals[idx++] = vB; >- } else { >- int cmpResult = doCompare(vA, vB); >- boolean result = convertComparisonResult(cmpResult); >- vals[idx++] = BoolEval.valueOf(result); >- } >- >- } >- } >- >- if (vals.length == 1) { >- return vals[0]; >- } >- >- return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals); > } > > private static int doCompare(ValueEval va, ValueEval vb) { >Index: src/java/org/apache/poi/ss/formula/functions/ArrayFunction.java >=================================================================== >--- src/java/org/apache/poi/ss/formula/functions/ArrayFunction.java (revision 1850028) >+++ src/java/org/apache/poi/ss/formula/functions/ArrayFunction.java (working copy) >@@ -17,11 +17,11 @@ > > package org.apache.poi.ss.formula.functions; > >-import org.apache.poi.ss.formula.eval.BlankEval; >-import org.apache.poi.ss.formula.eval.ErrorEval; >-import org.apache.poi.ss.formula.eval.MissingArgEval; >-import org.apache.poi.ss.formula.eval.ValueEval; >+import org.apache.poi.ss.formula.CacheAreaEval; >+import org.apache.poi.ss.formula.eval.*; > >+import java.util.function.BiFunction; >+ > /** > * @author Robert Hulbert > * Common Interface for any excel built-in function that has implemented array formula functionality. >@@ -41,4 +41,92 @@ > */ > > ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex); >+ >+ /** >+ * >+ * @param args >+ * @param srcRowIndex >+ * @param srcColumnIndex >+ * @param evalFunc >+ * @return >+ */ >+ default ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex, >+ BiFunction<ValueEval, ValueEval, ValueEval> evalFunc) { >+ ValueEval arg0 = args[0]; >+ ValueEval arg1 = args[1]; >+ >+ int w1, w2, h1, h2; >+ int a1FirstCol = 0, a1FirstRow = 0; >+ if (arg0 instanceof AreaEval) { >+ AreaEval ae = (AreaEval)arg0; >+ w1 = ae.getWidth(); >+ h1 = ae.getHeight(); >+ a1FirstCol = ae.getFirstColumn(); >+ a1FirstRow = ae.getFirstRow(); >+ } else if (arg0 instanceof RefEval){ >+ RefEval ref = (RefEval)arg0; >+ w1 = 1; >+ h1 = 1; >+ a1FirstCol = ref.getColumn(); >+ a1FirstRow = ref.getRow(); >+ } else { >+ w1 = 1; >+ h1 = 1; >+ } >+ int a2FirstCol = 0, a2FirstRow = 0; >+ if (arg1 instanceof AreaEval) { >+ AreaEval ae = (AreaEval)arg1; >+ w2 = ae.getWidth(); >+ h2 = ae.getHeight(); >+ a2FirstCol = ae.getFirstColumn(); >+ a2FirstRow = ae.getFirstRow(); >+ } else if (arg1 instanceof RefEval){ >+ RefEval ref = (RefEval)arg1; >+ w2 = 1; >+ h2 = 1; >+ a2FirstCol = ref.getColumn(); >+ a2FirstRow = ref.getRow(); >+ } else { >+ w2 = 1; >+ h2 = 1; >+ } >+ >+ int width = Math.max(w1, w2); >+ int height = Math.max(h1, h2); >+ >+ ValueEval[] vals = new ValueEval[height * width]; >+ >+ int idx = 0; >+ for(int i = 0; i < height; i++){ >+ for(int j = 0; j < width; j++){ >+ ValueEval vA; >+ try { >+ vA = OperandResolver.getSingleValue(arg0, a1FirstRow + i, a1FirstCol + j); >+ } catch (EvaluationException e) { >+ vA = e.getErrorEval(); >+ } >+ ValueEval vB; >+ try { >+ vB = OperandResolver.getSingleValue(arg1, a2FirstRow + i, a2FirstCol + j); >+ } catch (EvaluationException e) { >+ vB = e.getErrorEval(); >+ } >+ if(vA instanceof ErrorEval){ >+ vals[idx++] = vA; >+ } else if (vB instanceof ErrorEval) { >+ vals[idx++] = vB; >+ } else { >+ vals[idx++] = evalFunc.apply(vA, vB); >+ } >+ >+ } >+ } >+ >+ if (vals.length == 1) { >+ return vals[0]; >+ } >+ >+ return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals); >+ } >+ > } >Index: src/java/org/apache/poi/ss/formula/functions/IfFunc.java >=================================================================== >--- src/java/org/apache/poi/ss/formula/functions/IfFunc.java (revision 1850028) >+++ src/java/org/apache/poi/ss/formula/functions/IfFunc.java (working copy) >@@ -17,12 +17,8 @@ > > package org.apache.poi.ss.formula.functions; > >-import org.apache.poi.ss.formula.eval.BlankEval; >-import org.apache.poi.ss.formula.eval.BoolEval; >-import org.apache.poi.ss.formula.eval.EvaluationException; >-import org.apache.poi.ss.formula.eval.MissingArgEval; >-import org.apache.poi.ss.formula.eval.OperandResolver; >-import org.apache.poi.ss.formula.eval.ValueEval; >+import org.apache.poi.ss.formula.CacheAreaEval; >+import org.apache.poi.ss.formula.eval.*; > import org.apache.poi.ss.formula.ptg.Ptg; > import org.apache.poi.ss.formula.ptg.RefPtg; > >@@ -36,8 +32,9 @@ > * See bug numbers #55324 and #55747 for the full details on this. > * TODO Fix this... > */ >-public final class IfFunc extends Var2or3ArgFunction { >+public final class IfFunc extends Var2or3ArgFunction implements ArrayFunction { > >+ @Override > public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) { > boolean b; > try { >@@ -54,6 +51,7 @@ > return BoolEval.FALSE; > } > >+ @Override > public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, > ValueEval arg2) { > boolean b; >@@ -83,4 +81,13 @@ > } > return b.booleanValue(); > } >+ >+ >+ @Override >+ public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) { >+ return evaluateArray(args, srcRowIndex, srcColumnIndex, >+ (vA, vB) -> evaluate(srcRowIndex, srcColumnIndex, vA, vB) >+ ); >+ } >+ > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 62904
:
36259
| 36356