Skip to content

Commit a01beb1

Browse files
committed
PosgreSql: Cast to decimal(28, x) for some Math operations
This prevents System.OverflowExeptions for results of updated operation on results reading. Npgsql does not provide any ways to get some native numeric value and scale it down to .Net decimal, everything is done internally within client. So we have cast results.
1 parent aedcd10 commit a01beb1

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)