Skip to content

Revert commit with broken Translation; Add a test to reproduce Translation error #325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 3, 2025
Merged
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
52 changes: 52 additions & 0 deletions Orm/Xtensive.Orm.Tests/Issues/TranslationIssue_IndexOutOfRange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using NUnit.Framework;
using Xtensive.Orm.Configuration;
using Xtensive.Orm.Tests.Issues.IssueJira0440_CustomCompilerLoosesImplicitCastToNullableModel;

namespace Xtensive.Orm.Tests.Issues
{
namespace TranslationIssue_IndexOutOfRangeModel
{
[HierarchyRoot]
public class TestEntity1 : Entity
{
[Key, Field]
public long Id { get; private set; }

[Field]
public decimal Split { get; set; }
}

}

[TestFixture]
public class TranslationIssue_IndexOutOfRange : AutoBuildTest
{
protected override DomainConfiguration BuildConfiguration()
{
var configuration = base.BuildConfiguration();
configuration.Types.Register(typeof(TranslationIssue_IndexOutOfRangeModel.TestEntity1));
return configuration;
}

[Test]
public void MainTest()
{
using var session = Domain.OpenSession();
using var tx = session.OpenTransaction();

_ = (
from e in session.Query.All<TranslationIssue_IndexOutOfRangeModel.TestEntity1>()
group new {
Split = e.Split * 0.01M
} by e.Id into g
select g
.Select(x => x.Split)
.Distinct()
.Sum()
).ToList();
}
}
}
63 changes: 2 additions & 61 deletions Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -771,21 +771,11 @@ private Expression VisitAggregate(Expression source, MethodInfo method, LambdaEx
MethodCallExpression expressionPart)
{
var aggregateType = ExtractAggregateType(expressionPart);

var origin = VisitAggregateSource(source, argument, aggregateType, expressionPart);
var originProjection = origin.Item1;
var originColumnIndex = origin.Item2;

var headerColumns = originProjection.ItemProjector.DataSource.Header.Columns;
var aggregatedColumn = headerColumns[originColumnIndex];

// For decimal type we try to guess result precision and scale to avoid
// usage of general values which can create some issues result reading
(sbyte precision, sbyte scale)? aggregateTypeHints = TryGuessDecimalPrecisionAndSclale(aggregatedColumn, headerColumns, context.Model);

var aggregateDescriptor = aggregateTypeHints.HasValue
? new AggregateColumnDescriptor(context.GetNextColumnAlias(), originColumnIndex, aggregateType, aggregateTypeHints.Value)
: new AggregateColumnDescriptor(context.GetNextColumnAlias(), originColumnIndex, aggregateType);
var aggregateDescriptor = new AggregateColumnDescriptor(
context.GetNextColumnAlias(), originColumnIndex, aggregateType);
var originDataSource = originProjection.ItemProjector.DataSource;
var resultDataSource = originDataSource.Aggregate(null, [aggregateDescriptor]);

Expand Down Expand Up @@ -867,55 +857,6 @@ private Expression VisitAggregate(Expression source, MethodInfo method, LambdaEx
return Expression.Convert(result, resultType);
}
return result;


static (sbyte, sbyte)? TryGuessDecimalPrecisionAndSclale(Column aggregatedColumn, Rse.ColumnCollection headerColumns, Orm.Model.DomainModel domainModel)
{
if (aggregatedColumn.Type != WellKnownTypes.Decimal)
return null;

if (aggregatedColumn is MappedColumn mColumn) {
var resolvedColumn = mColumn.ColumnInfoRef.Resolve(domainModel);
if (resolvedColumn.Precision.HasValue && resolvedColumn.Scale.HasValue)
return (resolvedColumn.Precision.Value, resolvedColumn.Scale.Value);
}
else if (aggregatedColumn is CalculatedColumn cColumn) {
var expression = cColumn.Expression;
var usedColumns = new Rse.Transformation.TupleAccessGatherer().Gather(expression);

sbyte maxFloorDigits = -1;
sbyte maxScaleDigits = -1;
foreach (var cIndex in usedColumns.Distinct()) {
var usedColumn = headerColumns[cIndex];
if (usedColumn is MappedColumn mmColumn) {
var resolvedColumn = mmColumn.ColumnInfoRef.Resolve(domainModel);

(sbyte? p, sbyte? s) @params = Type.GetTypeCode(resolvedColumn.ValueType) switch {
TypeCode.Decimal => (resolvedColumn.Precision, resolvedColumn.Scale),
TypeCode.Int32 or TypeCode.UInt32 => (19, 8),
TypeCode.Int64 or TypeCode.UInt64 => (28, 8),
TypeCode.Byte or TypeCode.SByte => (8, 5),
TypeCode.Int16 or TypeCode.UInt16 => (10, 5),
_ => (null, null),
};

if (@params.p.HasValue && @params.s.HasValue) {
if (maxScaleDigits < @params.s.Value)
maxScaleDigits = @params.s.Value;
sbyte floorDigits = (sbyte)(@params.p.Value - @params.s.Value);
if (maxFloorDigits < floorDigits)
maxFloorDigits = floorDigits;
}
}
}
if (maxFloorDigits == -1 || maxScaleDigits == -1)
return null;
if (maxFloorDigits + maxScaleDigits <= 28)
return ((sbyte)(maxFloorDigits + maxScaleDigits), maxScaleDigits);
}

return null;
}
}

private CompilableProvider ChooseSourceForAggregate(CompilableProvider left, CompilableProvider right,
Expand Down
Loading