Skip to content

Commit ea1926f

Browse files
authored
Merge pull request #128 from DataObjects-NET/6.0-pgsql-decimals-round
PosgreSql: Cast to decimal(28, x) for some Math operations
2 parents aedcd10 + a01beb1 commit ea1926f

File tree

1 file changed

+43
-13
lines changed

1 file changed

+43
-13
lines changed

Orm/Xtensive.Orm/Orm/Providers/Expressions/MemberCompilers/MathCompilers.cs

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Denis Krjuchkov
55
// Created: 2009.02.14
66

@@ -130,7 +130,7 @@ public static SqlExpression MathSignFloat(
130130
private static SqlExpression Min(SqlExpression left, SqlExpression right)
131131
{
132132
var result = SqlDml.Case();
133-
result.Add(left < right, left);
133+
_ = result.Add(left < right, left);
134134
result.Else = right;
135135
return result;
136136
}
@@ -230,7 +230,7 @@ public static SqlExpression MathMinDecimal(
230230
private static SqlExpression Max(SqlExpression left, SqlExpression right)
231231
{
232232
var result = SqlDml.Case();
233-
result.Add(left > right, left);
233+
_ = result.Add(left > right, left);
234234
result.Else = right;
235235
return result;
236236
}
@@ -373,7 +373,7 @@ public static SqlExpression MathCeilingDouble(
373373
public static SqlExpression MathCeilingDecimal(
374374
[Type(typeof(decimal))] SqlExpression d)
375375
{
376-
return SqlDml.Ceiling(d);
376+
return TryCastToDecimalPS(SqlDml.Ceiling(d), 28, 0);
377377
}
378378

379379
[Compiler(typeof(Math), "Cos", TargetKind.Static | TargetKind.Method)]
@@ -408,7 +408,7 @@ public static SqlExpression MathFloorDouble(
408408
public static SqlExpression MathFloorDecimal(
409409
[Type(typeof(decimal))] SqlExpression d)
410410
{
411-
return SqlDml.Floor(d);
411+
return TryCastToDecimalPS(SqlDml.Floor(d), 28, 0);
412412
}
413413

414414
[Compiler(typeof(Math), "Log", TargetKind.Static | TargetKind.Method)]
@@ -560,28 +560,58 @@ public static SqlExpression MathTruncateDouble(
560560
public static SqlExpression MathTruncateDecimal(
561561
[Type(typeof(decimal))] SqlExpression d)
562562
{
563-
return SqlDml.Truncate(d);
563+
return TryCastToDecimalPS(SqlDml.Truncate(d), 28, 0);
564564
}
565565

566566
#region Round helpers
567567

568568
private static SqlExpression GenericRound(SqlExpression value, SqlExpression digits, bool isDecimal, SqlExpression mode)
569569
{
570-
if (mode.NodeType!=SqlNodeType.Container)
570+
if (mode.NodeType != SqlNodeType.Container) {
571571
throw new NotSupportedException();
572+
}
573+
572574
var container = (SqlContainer) mode;
573-
if (!(container.Value is MidpointRounding))
575+
if (!(container.Value is MidpointRounding midpointRounding)) {
576+
throw new NotSupportedException();
577+
}
578+
if (!isDecimal) {
579+
return SqlDml.Round(value, digits, TypeCode.Double, midpointRounding);
580+
}
581+
if (digits == null) {
582+
return TryCastToDecimalPS(SqlDml.Round(value, digits, TypeCode.Decimal, midpointRounding), 28, 0);
583+
}
584+
if (!(digits is SqlLiteral<int> scale)) {
574585
throw new NotSupportedException();
575-
return SqlDml.Round(value, digits,
576-
isDecimal ? TypeCode.Decimal : TypeCode.Double,
577-
(MidpointRounding) container.Value);
586+
}
587+
return TryCastToDecimalPS(SqlDml.Round(value, digits, TypeCode.Decimal, midpointRounding), 28, Convert.ToInt16(scale.Value));
578588
}
579589

580590
private static SqlExpression BankersRound(SqlExpression value, SqlExpression digits, bool isDecimal)
581591
{
582-
return SqlDml.Round(value, digits, isDecimal ? TypeCode.Decimal : TypeCode.Double, MidpointRounding.ToEven);
592+
if (!isDecimal) {
593+
return SqlDml.Round(value, digits, TypeCode.Double, MidpointRounding.ToEven);
594+
}
595+
if (digits == null) {
596+
return TryCastToDecimalPS(SqlDml.Round(value, digits, TypeCode.Decimal, MidpointRounding.ToEven), 28, 0);
597+
}
598+
if (!(digits is SqlLiteral<int> scale)) {
599+
throw new NotSupportedException();
600+
}
601+
return TryCastToDecimalPS(SqlDml.Round(value, digits, TypeCode.Decimal, MidpointRounding.ToEven), 28, Convert.ToInt16(scale.Value));
583602
}
584603

585604
#endregion
605+
606+
private static SqlExpression TryCastToDecimalPS(SqlExpression value, short precision, short scale)
607+
{
608+
var context = ExpressionTranslationContext.Current;
609+
var provider = context.ProviderInfo.ProviderName;
610+
if (provider.Equals(WellKnown.Provider.PostgreSql, StringComparison.Ordinal)) {
611+
// to fit result into .Net decimal since Npgsql client libarary does not provide a way to make in on reading
612+
return SqlDml.Cast(value, SqlType.Decimal, precision, scale);
613+
}
614+
return value;
615+
}
586616
}
587617
}

0 commit comments

Comments
 (0)