Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,11 @@ private bool CheckTypesOrderTableOverload(CheckTypesContext context, TexlNode[]
}

var column = columns.Single();
if (columnType != null && !columnType.Accepts(column.Type, exact: true, useLegacyDateTimeAccepts: false, usePowerFxV1CompatibilityRules: context.Features.PowerFxV1CompatibilityRules))

// Allow numeric coercion between Number (Float) and Decimal for sort order values.
// A Float column can be ordered by a Decimal order table and vice versa.
var isNumericCoercionAllowed = columnType != null && columnType.IsNumeric && column.Type.IsNumeric;
if (columnType != null && !isNumericCoercionAllowed && !columnType.Accepts(column.Type, exact: true, useLegacyDateTimeAccepts: false, usePowerFxV1CompatibilityRules: context.Features.PowerFxV1CompatibilityRules))
{
errors.EnsureError(
DocumentErrorSeverity.Severe,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,11 @@ public static async ValueTask<FormulaValue> SortByColumnsOrderTable(EvalVisitor
return CommonErrors.RuntimeTypeMismatch(irContext);
}

// Normalize numeric types so that Number (double) and Decimal can be compared
// interchangeably. Without this, Float column values would never match Decimal
// order-table values via IndexOf because double != decimal in object.Equals.
primitiveValue = NormalizeNumericPrimitive(primitiveValue);

if (orderTableValues.Contains(primitiveValue))
{
return new ErrorValue(irContext, new ExpressionError()
Expand Down Expand Up @@ -1054,6 +1059,9 @@ public static async ValueTask<FormulaValue> SortByColumnsOrderTable(EvalVisitor
return int.MaxValue;
}

// Normalize numeric types to match the normalization applied to orderTableValues.
primitiveValue = NormalizeNumericPrimitive(primitiveValue);

var indexOnTable = orderTableValues.IndexOf(primitiveValue);
if (indexOnTable < 0)
{
Expand All @@ -1071,6 +1079,18 @@ public static async ValueTask<FormulaValue> SortByColumnsOrderTable(EvalVisitor
return new InMemoryTableValue(irContext, orderedRows);
}

// Normalizes numeric primitive values so that Number (double) and Decimal values
// can be compared interchangeably. Both are represented as double for lookup purposes.
private static object NormalizeNumericPrimitive(object value)
{
if (value is decimal d)
{
return (double)d;
}

return value;
}

private class FormulaValueComparer : IComparer<FormulaValue>
{
private EvalVisitor Runner { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,16 @@ Error({Kind:ErrorKind.Numeric})
{ name: "Team Meeting", Day: "Monday" },
{ name: "Scrum Meeting 2", Day: "Tuesday" }), "Day", ["Monday","Tuesday","Wednesday",Left("Hello", -1),"Friday"])
Error({Kind:ErrorKind.InvalidArgument})


// Mixing Float (Number) column values with Decimal order table - issue #2607
// Sort Float column with string literal column name and decimal order table
>> SortByColumns([{A:Float(1)},{A:Float(3)},{A:Float(2)}], "A", [3,2,1])
Table({A:3},{A:2},{A:1})

// Sort Float column with dynamic string column name and decimal order table
>> SortByColumns([{A:Float(1)},{A:Float(3)},{A:Float(2)}], If(true,"A"), [3,2,1])
Table({A:3},{A:2},{A:1})

// Sort calendar, with error in a column of the source referenced by the order values
>> SortByColumns(Table(
{ name: "Project Meeting 3", Day: "Friday" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,3 +495,8 @@ Error({Kind:ErrorKind.InvalidArgument})
{ name: "Team Meeting", Day: "Monday" },
{ name: "Scrum Meeting 2", Day: "Tuesday" }),Day,["Monday","Tuesday", Blank(), "Monday"])
Error({Kind:ErrorKind.InvalidArgument})

// Mixing Float (Number) column values with Decimal order table - issue #2607
// Sort Float column with identifier column name and decimal order table (V1 + SCNAI mode)
>> SortByColumns([{A:Float(1)},{A:Float(3)},{A:Float(2)}], A, [3,2,1])
Table({A:3},{A:2},{A:1})
Loading