@@ -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
0 commit comments