Skip to content

Commit cc62705

Browse files
committed
5.0.20-5.0.21 changes port
1 parent 3fb57b8 commit cc62705

File tree

10 files changed

+12463
-38
lines changed

10 files changed

+12463
-38
lines changed

Orm/Xtensive.Orm.SqlServer/Orm.Providers.SqlServer/SqlCompiler.cs

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,38 @@ namespace Xtensive.Orm.Providers.SqlServer
1717
{
1818
internal class SqlCompiler : Providers.SqlCompiler
1919
{
20+
private static readonly Type ByteType = typeof(byte);
21+
private static readonly Type Int16Type = typeof(short);
22+
private static readonly Type Int32Type = typeof(int);
23+
private static readonly Type FloatType = typeof(float);
24+
private static readonly Type DecimalType = typeof(decimal);
25+
private static readonly Type StringType = typeof(string);
26+
2027
protected override SqlProvider VisitFreeText(FreeTextProvider provider)
2128
{
2229
SqlFreeTextTable fromTable;
2330
QueryParameterBinding[] bindings;
2431

25-
var stringTypeMapping = Driver.GetTypeMapping(typeof(string));
32+
var stringTypeMapping = Driver.GetTypeMapping(StringType);
2633
var criteriaBinding = new QueryParameterBinding(
2734
stringTypeMapping, provider.SearchCriteria.Invoke, QueryParameterBindingType.Regular);
28-
35+
2936
var index = provider.PrimaryIndex.Resolve(Handlers.Domain.Model);
3037
var table = Mapping[index.ReflectedType];
3138
var columns = provider.Header.Columns.Select(column => column.Name).ToList();
3239

33-
if (provider.TopN==null) {
40+
if (provider.TopN == null) {
3441
fromTable = SqlDml.FreeTextTable(table, criteriaBinding.ParameterReference, columns);
3542
bindings = new[] {criteriaBinding};
3643
}
3744
else {
38-
var intTypeMapping = Driver.GetTypeMapping(typeof(int));
45+
var intTypeMapping = Driver.GetTypeMapping(Int32Type);
3946
var topNBinding = new QueryParameterBinding(intTypeMapping, () => provider.TopN.Invoke(), QueryParameterBindingType.Regular);
4047
fromTable = SqlDml.FreeTextTable(table, criteriaBinding.ParameterReference, columns, topNBinding.ParameterReference);
4148
bindings = new[] { criteriaBinding, topNBinding };
4249
}
4350
var fromTableRef = SqlDml.QueryRef(fromTable);
44-
SqlSelect select = SqlDml.Select(fromTableRef);
51+
var select = SqlDml.Select(fromTableRef);
4552
select.Columns.Add(fromTableRef.Columns[0]);
4653
select.Columns.Add(SqlDml.Cast(fromTableRef.Columns[1], SqlType.Double), "RANK");
4754

@@ -53,7 +60,7 @@ protected override SqlProvider VisitContainsTable(ContainsTableProvider provider
5360
SqlContainsTable fromTable;
5461
QueryParameterBinding[] bindings;
5562

56-
var stringTypeMapping = Driver.GetTypeMapping(typeof(string));
63+
var stringTypeMapping = Driver.GetTypeMapping(StringType);
5764
var criteriaBinding = new QueryParameterBinding(
5865
stringTypeMapping, provider.SearchCriteria.Invoke, QueryParameterBindingType.Regular);
5966

@@ -62,18 +69,18 @@ protected override SqlProvider VisitContainsTable(ContainsTableProvider provider
6269
var columns = provider.Header.Columns.Select(column => column.Name).ToList();
6370

6471
var targetColumnNames = provider.TargetColumns.Select(c => c.Name).ToArray();
65-
if (provider.TopN==null) {
72+
if (provider.TopN == null) {
6673
fromTable = SqlDml.ContainsTable(table, criteriaBinding.ParameterReference, columns, targetColumnNames);
6774
bindings = new[] { criteriaBinding };
6875
}
6976
else {
70-
var intTypeMapping = Driver.GetTypeMapping(typeof(int));
77+
var intTypeMapping = Driver.GetTypeMapping(Int32Type);
7178
var topNBinding = new QueryParameterBinding(intTypeMapping, () => provider.TopN.Invoke(), QueryParameterBindingType.Regular);
7279
fromTable = SqlDml.ContainsTable(table, criteriaBinding.ParameterReference, columns, targetColumnNames, topNBinding.ParameterReference);
7380
bindings = new[] { criteriaBinding, topNBinding };
7481
}
7582
var fromTableRef = SqlDml.QueryRef(fromTable);
76-
SqlSelect select = SqlDml.Select(fromTableRef);
83+
var select = SqlDml.Select(fromTableRef);
7784
select.Columns.Add(fromTableRef.Columns[0]);
7885
select.Columns.Add(SqlDml.Cast(fromTableRef.Columns[1], SqlType.Double), "RANK");
7986

@@ -83,22 +90,65 @@ protected override SqlProvider VisitContainsTable(ContainsTableProvider provider
8390
protected override SqlExpression ProcessAggregate(
8491
SqlProvider source, List<SqlExpression> sourceColumns, AggregateColumn aggregateColumn)
8592
{
86-
var aggregateType = aggregateColumn.Type;
8793
var result = base.ProcessAggregate(source, sourceColumns, aggregateColumn);
88-
if (aggregateColumn.AggregateType==AggregateType.Avg) {
89-
var originType = source.Origin.Header.Columns[aggregateColumn.SourceIndex].Type;
90-
// floats are promoted to doubles, but we need the same type
91-
if (originType==aggregateType && originType!=typeof (float))
94+
var aggregateReturnType = aggregateColumn.Type;
95+
var originCalculateColumn = source.Origin.Header.Columns[aggregateColumn.SourceIndex];
96+
var sqlType = Driver.MapValueType(aggregateReturnType);
97+
98+
if (aggregateColumn.AggregateType == AggregateType.Min
99+
|| aggregateColumn.AggregateType == AggregateType.Max
100+
|| aggregateColumn.AggregateType == AggregateType.Sum) {
101+
if (!IsCalculatedColumn(originCalculateColumn)) {
102+
if (aggregateReturnType == DecimalType) {
103+
return result;
104+
}
105+
else if (ShouldCastDueType(aggregateReturnType)) {
106+
return SqlDml.Cast(result, Driver.MapValueType(aggregateReturnType));
107+
}
108+
}
109+
else if (ShouldCastDueType(aggregateReturnType)) {
110+
return SqlDml.Cast(result, Driver.MapValueType(aggregateReturnType));
111+
}
112+
return result;
113+
}
114+
if (aggregateColumn.AggregateType == AggregateType.Avg) {
115+
//var sqlType = Driver.MapValueType(aggregateReturnType);
116+
if (aggregateReturnType != originCalculateColumn.Type) {
117+
return SqlDml.Cast(SqlDml.Avg(SqlDml.Cast(sourceColumns[aggregateColumn.SourceIndex], sqlType)), sqlType);
118+
}
119+
if (!IsCalculatedColumn(originCalculateColumn)) {
120+
if (aggregateReturnType == DecimalType) {
121+
return result;
122+
}
123+
else if (ShouldCastDueType(aggregateReturnType)) {
124+
return SqlDml.Cast(SqlDml.Avg(SqlDml.Cast(sourceColumns[aggregateColumn.SourceIndex], sqlType)), sqlType);
125+
}
126+
else if (aggregateReturnType != originCalculateColumn.Type) {
127+
return SqlDml.Cast(SqlDml.Avg(SqlDml.Cast(sourceColumns[aggregateColumn.SourceIndex], sqlType)), sqlType);
128+
}
129+
}
130+
else {
131+
if (ShouldCastDueType(aggregateReturnType)) {
132+
return SqlDml.Cast(SqlDml.Avg(SqlDml.Cast(sourceColumns[aggregateColumn.SourceIndex], sqlType)), sqlType);
133+
}
134+
else if (aggregateReturnType != originCalculateColumn.Type) {
135+
return SqlDml.Cast(SqlDml.Avg(SqlDml.Cast(sourceColumns[aggregateColumn.SourceIndex], sqlType)), sqlType);
136+
}
92137
return result;
93-
var sqlType = Driver.MapValueType(aggregateType);
94-
return SqlDml.Cast(SqlDml.Avg(SqlDml.Cast(sourceColumns[aggregateColumn.SourceIndex], sqlType)), sqlType);
138+
}
95139
}
96-
// cast to decimal is dangerous, because 'decimal' defaults to integer type
97-
if (aggregateColumn.AggregateType==AggregateType.Sum && aggregateType!=typeof (decimal))
98-
return SqlDml.Cast(result, Driver.MapValueType(aggregateType));
99140
return result;
100141
}
101142

143+
private bool IsCalculatedColumn(Column column) => column is CalculatedColumn;
144+
145+
private bool ShouldCastDueType(Type type)
146+
{
147+
return type == ByteType
148+
|| type == Int16Type
149+
|| type == DecimalType
150+
|| type == FloatType;
151+
}
102152

103153
// Constructors
104154

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Copyright (C) 2020 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
// Created by: Alexey Kulakov
5+
// Created: 2020.03.26
6+
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Linq;
10+
using System.Text;
11+
using Xtensive.Orm;
12+
using Xtensive.Orm.Configuration;
13+
14+
namespace Xtensive.Orm.Tests.Issues.IssueJira0786_SqlServerAggregatesProblem
15+
{
16+
public abstract class AggregatesProblemTestBase : AutoBuildTest
17+
{
18+
protected const decimal FloatValueAccuracy = 0.000001m;
19+
protected const decimal DoubleValueAccuracy = 0.00000000000001m;
20+
protected const decimal DecimalValueAccuracy = 0.00000000000000001m;
21+
22+
protected override Domain BuildDomain(DomainConfiguration configuration)
23+
{
24+
var firstTryConfig = configuration.Clone();
25+
firstTryConfig.UpgradeMode = DomainUpgradeMode.Validate;
26+
try {
27+
return base.BuildDomain(firstTryConfig);
28+
}
29+
catch (SchemaSynchronizationException) { }
30+
catch (Exception) {
31+
throw;
32+
}
33+
34+
var secondTryConfig = configuration.Clone();
35+
secondTryConfig.UpgradeMode = DomainUpgradeMode.Recreate;
36+
return base.BuildDomain(secondTryConfig);
37+
}
38+
39+
protected override DomainConfiguration BuildConfiguration()
40+
{
41+
var configuration = DomainConfigurationFactory.Create();
42+
configuration.Types.Register(typeof(TestEntity).Assembly, typeof(TestEntity).Namespace);
43+
configuration.UpgradeMode = DomainUpgradeMode.Recreate;
44+
return configuration;
45+
}
46+
47+
protected override void CheckRequirements()
48+
{
49+
Require.ProviderIs(StorageProvider.SqlServer);
50+
}
51+
52+
protected override void PopulateData()
53+
{
54+
using (var session = Domain.OpenSession())
55+
using (var tx = session.OpenTransaction()) {
56+
_ = new TestEntity() {
57+
ByteValue = 2,
58+
SByteValue = 4,
59+
ShortValue = 8,
60+
UShortValue = 9,
61+
IntValue = 10,
62+
UIntValue = 11,
63+
LongValue = 20,
64+
ULongValue = 25,
65+
FloatValue = 0.1f,
66+
DecimalValue = 1.2m,
67+
DoubleValue1 = 2.0,
68+
DoubleValue2 = 3.0,
69+
NullableByteValue = 2,
70+
NullableSByteValue = 4,
71+
NullableShortValue = 8,
72+
NullableUShortValue = 9,
73+
NullableIntValue = 30,
74+
NullableUIntValue = 31,
75+
NullableLongValue = 40,
76+
NullableULongValue = 45,
77+
NullableFloatValue = 0.4f,
78+
NullableDecimalValue = 4.2m,
79+
NullableDoubleValue1 = 5.0,
80+
NullableDoubleValue2 = 6.0
81+
};
82+
_ = new TestEntity() {
83+
ByteValue = 3,
84+
SByteValue = 5,
85+
ShortValue = 9,
86+
UShortValue = 10,
87+
IntValue = 11,
88+
UIntValue = 12,
89+
LongValue = 21,
90+
ULongValue = 26,
91+
FloatValue = 0.2f,
92+
DecimalValue = 1.3m,
93+
DoubleValue1 = 2.1,
94+
DoubleValue2 = 3.1,
95+
NullableByteValue = 3,
96+
NullableSByteValue = 5,
97+
NullableShortValue = 9,
98+
NullableUShortValue = 10,
99+
NullableIntValue = 31,
100+
NullableUIntValue = 32,
101+
NullableLongValue = 41,
102+
NullableULongValue = 46,
103+
NullableFloatValue = 0.5f,
104+
NullableDecimalValue = 4.3m,
105+
NullableDoubleValue1 = 5.1,
106+
NullableDoubleValue2 = 6.1
107+
};
108+
_ = new TestEntity() {
109+
ByteValue = 4,
110+
SByteValue = 6,
111+
ShortValue = 10,
112+
UShortValue = 11,
113+
IntValue = 12,
114+
UIntValue = 13,
115+
LongValue = 22,
116+
ULongValue = 27,
117+
FloatValue = 0.3f,
118+
DecimalValue = 1.4m,
119+
DoubleValue1 = 2.3,
120+
DoubleValue2 = 3.3,
121+
NullableByteValue = 4,
122+
NullableSByteValue = 6,
123+
NullableShortValue = 10,
124+
NullableUShortValue = 11,
125+
NullableIntValue = 32,
126+
NullableUIntValue = 33,
127+
NullableLongValue = 42,
128+
NullableULongValue = 47,
129+
NullableFloatValue = 0.6f,
130+
NullableDecimalValue = 4.4m,
131+
NullableDoubleValue1 = 5.3,
132+
NullableDoubleValue2 = 6.3
133+
};
134+
135+
tx.Complete();
136+
}
137+
}
138+
}
139+
}

0 commit comments

Comments
 (0)