Skip to content

Commit 875c9f7

Browse files
OssianEPPlusswmal
andauthored
Bug/s884 (#2041)
* Added previous work and made bug fixes * Remove cache attempt * Fixed bugs in Sort,SumIFs and Left * Added more xlookup tests * Fixed AnchorArray when only returning one cell issue * Cleanup and bugfix * Minor bugfixes * Cleaned up comments * missed cleanup --------- Co-authored-by: Mats Alm <897655+swmal@users.noreply.github.com>
1 parent 53b4820 commit 875c9f7

14 files changed

Lines changed: 286 additions & 36 deletions

File tree

src/EPPlus/FormulaParsing/Excel/Functions/MathFunctions/RangeCriteriaFunction.cs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Date Author Change
1717
using OfficeOpenXml.FormulaParsing.ExcelUtilities;
1818
using OfficeOpenXml.FormulaParsing.FormulaExpressions;
1919
using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
20+
using OfficeOpenXml.FormulaParsing.Ranges;
2021
using OfficeOpenXml.FormulaParsing.Utilities;
2122
using OfficeOpenXml.Sorting.Internal;
2223
using OfficeOpenXml.Utils;
@@ -159,15 +160,37 @@ protected List<int> GetMatchIndexes(RangeOrValue rangeOrValue, object searched,
159160
for (var col = address.FromCol; col <= address.ToCol; col++)
160161
{
161162
var candidate = rangeInfo.GetValue(row, col);
162-
if (searched != null && Evaluate(candidate, searched, ctx, convertNumericString))
163+
164+
if (searched != null)
163165
{
164-
result.Add(internalIndex);
166+
if (searched is RangeOrValue critRange)
167+
{
168+
if (critRange.Range != null)
169+
{
170+
foreach (var cell in critRange.Range)
171+
{
172+
if (Evaluate(candidate, cell.Value, ctx, convertNumericString))
173+
{
174+
result.Add(internalIndex);
175+
}
176+
}
177+
}
178+
else if(critRange.Value != null && Evaluate(candidate, critRange.Value, ctx, convertNumericString))
179+
{
180+
result.Add(internalIndex);
181+
}
182+
}
183+
else if (Evaluate(candidate, searched, ctx, convertNumericString))
184+
{
185+
result.Add(internalIndex);
186+
}
165187
}
188+
166189
internalIndex++;
167190
}
168191
}
169192
}
170-
else if(Evaluate(rangeOrValue.Value, searched, ctx, convertNumericString))
193+
else if (Evaluate(rangeOrValue.Value, searched, ctx, convertNumericString))
171194
{
172195
result.Add(internalIndex);
173196
}
@@ -236,7 +259,15 @@ protected IEnumerable<int> GetMatchingIndicesFromArguments(int argStartIx, IList
236259
{
237260
argRanges.Add(new RangeOrValue { Value = arg.ResultValue });
238261
}
239-
criteria.Add(args[ix + 1].ResultValue);
262+
263+
if (args[ix + 1].Result is IRangeInfo critInfo)
264+
{
265+
criteria.Add(new RangeOrValue { Range = critInfo });
266+
}
267+
else
268+
{
269+
criteria.Add(new RangeOrValue { Value = args[ix + 1].ResultValue });
270+
}
240271
}
241272
IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criteria[0], null);
242273
var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList();

src/EPPlus/FormulaParsing/Excel/Functions/MathFunctions/SumIfs.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ Date Author Change
1313
using System;
1414
using System.Collections.Generic;
1515
using System.Linq;
16-
using System.Text;
1716
using OfficeOpenXml.FormulaParsing.Excel.Functions.Metadata;
18-
using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
1917
using OfficeOpenXml.FormulaParsing.Excel.Operators;
2018
using OfficeOpenXml.FormulaParsing.ExcelUtilities;
2119
using OfficeOpenXml.FormulaParsing.FormulaExpressions;

src/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/AnchorArray.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
4949
var ri = new RangeInfo(rangeAddress);
5050
return new DynamicArrayCompileResult(ri, DataType.ExcelRange, rangeAddress);
5151
}
52+
else if(string.IsNullOrEmpty(f?.ToString()) == false)
53+
{
54+
//Even if the formulas is just on one cell it should return the range
55+
var ri = new RangeInfo(address);
56+
return new DynamicArrayCompileResult(ri, DataType.ExcelRange, address);
57+
}
5258
}
5359
}
5460
return CompileResult.GetDynamicArrayResultError(eErrorType.Ref);

src/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/SortFunction.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
8181
byCol = ArgToBool(arguments, 3, false);
8282
}
8383

84-
//Validate
85-
var maxIndex = byCol ? range.Size.NumberOfCols : range.Size.NumberOfRows;
86-
foreach(var sortIndex in sortIndexes)
84+
//Validate (Excel allows the larger number of sort indicies despite them not being used)
85+
var maxPotentialIndex = Math.Max(range.Size.NumberOfCols, range.Size.NumberOfRows);
86+
foreach (var sortIndex in sortIndexes)
8787
{
88-
if (sortIndex < 1 || sortIndex > maxIndex) return CreateResult(eErrorType.Value);
88+
if (sortIndex < 1 || sortIndex > maxPotentialIndex) return CreateResult(eErrorType.Value);
8989
}
9090

9191
if (sortOrder != -1 && sortOrder != 1) return CreateResult(eErrorType.Value);

src/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/XLookup.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
4545
_stopwatch = new Stopwatch();
4646
_stopwatch.Start();
4747
}
48-
var lookupValue = arguments[0].Value ?? 0; //If Search value is null, we should search for 0 instead
49-
5048
// lookup range
5149
if (!arguments[1].IsExcelRange) return CompileResult.GetDynamicArrayResultError(eErrorType.Value);
5250
var lookupRange = arguments[1].ValueAsRangeInfo;
@@ -81,7 +79,10 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
8179
if (e4 != null) return CompileResult.GetErrorResult(e4.Type);
8280
searchMode = XlookupUtil.GetSearchMode(sm);
8381
}
82+
8483
int ix;
84+
var lookupValue = arguments[0].Value ?? 0; //If Search value is null, we should search for 0 instead
85+
8586
if (searchMode == LookupSearchMode.BinarySearchAscending || searchMode == LookupSearchMode.BinarySearchDescending)
8687
{
8788
var asc = searchMode == LookupSearchMode.BinarySearchAscending;
@@ -97,6 +98,7 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
9798
_stopwatch.Stop();
9899
context.Configuration.Logger.LogFunction("XLOOKUP", _stopwatch.ElapsedMilliseconds);
99100
}
101+
100102
return BuildCompileResult(lookupDirection, returnArray, notFoundText, ix);
101103
}
102104

src/EPPlus/FormulaParsing/Excel/Functions/Text/Left.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,26 @@ namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text
2525
internal class Left : ExcelFunction
2626
{
2727
public override ExcelFunctionArrayBehaviour ArrayBehaviour => ExcelFunctionArrayBehaviour.FirstArgCouldBeARange;
28-
public override int ArgumentMinLength => 2;
28+
//Num_Chars is optional
29+
public override int ArgumentMinLength => 1;
2930
public override CompileResult Execute(IList<FunctionArgument> arguments, ParsingContext context)
3031
{
3132
var str = ArgToString(arguments, 0);
3233
if(str == null)
3334
str = string.Empty;
34-
var length = ArgToInt(arguments, 1, out ExcelErrorValue e1);
35+
36+
int length;
37+
ExcelErrorValue e1 = null;
38+
39+
if (arguments.Count < 2)
40+
{
41+
length = 1;
42+
}
43+
else
44+
{
45+
length = ArgToInt(arguments, 1, out e1);
46+
}
47+
3548
if (e1 != null) return CompileResult.GetErrorResult(e1.Type);
3649
if (length < 0)
3750
{
@@ -41,7 +54,7 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
4154
length = str.Length;
4255
if(context.Configuration.EnableUnicodeAwareStringOperations)
4356
{
44-
return CreateResult(str.UnitcodeSubstring(length), DataType.String);
57+
return CreateResult(str.UnicodeSubstring(length), DataType.String);
4558
}
4659
return CreateResult(str.Substring(0, length), DataType.String);
4760
}

src/EPPlus/FormulaParsing/FormulaExpressions/FunctionCompilers/CustomArrayBehaviourCompiler.cs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,19 @@ public override CompileResult Compile(IEnumerable<CompileResult> children, Parsi
5151
if(cr.DataType == DataType.ExcelRange && Function.ArrayBehaviourConfig.CanBeArrayArg(ix))
5252
{
5353
var range = cr.Result as IRangeInfo;
54-
if(range.GetNCells() > 1)
55-
{
56-
rangeArgs[ix] = range;
57-
}
58-
else
59-
{
60-
otherArgs[ix] = CompileResultFactory.Create(range.GetOffset(0, 0));
61-
}
54+
rangeArgs[ix] = range;
55+
56+
//OLD CODE left below in case otherArgs becomes a problem later. Range args when NCells == 1 is
57+
//neccesary in case of in memory range/dynamic array formulas with a single cell.
58+
59+
//if (range.GetNCells() > 1)
60+
//{
61+
// rangeArgs[ix] = range;
62+
//}
63+
//else
64+
//{
65+
// otherArgs[ix] = CompileResultFactory.Create(range.GetOffset(0, 0));
66+
//}
6267
}
6368
else
6469
{

src/EPPlus/Utils/RemoteCalls/HttpRemoteTask.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public override void DoWork()
4040
}
4141
finally
4242
{
43-
ParsingContext.RemoteCallManager.TaskComplate(this);
43+
ParsingContext.RemoteCallManager.TaskComplete(this);
4444
}
4545
}
4646
}

src/EPPlus/Utils/RemoteCalls/RemoteCallManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public void QueueTask(RemoteTask task)
2525
}
2626
ThreadPool.QueueUserWorkItem(_ => task.DoWork());
2727
}
28-
public void TaskComplate(RemoteTask task)
28+
public void TaskComplete(RemoteTask task)
2929
{
3030
_tasks.Remove(task);
3131
}

src/EPPlus/Utils/StringExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ internal static bool ContainsOnlyCharacter(this string s, char theCharacter, boo
4545
return true;
4646
}
4747

48-
internal static string UnitcodeSubstring(this string s, int length)
48+
internal static string UnicodeSubstring(this string s, int length)
4949
{
5050
return StringUtil.UnicodeSubstring(s, length);
5151
}

0 commit comments

Comments
 (0)