From 3839f5f85aace11eb923b2e1b0828476e91e560f Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Sun, 14 Feb 2021 01:20:03 +0000 Subject: [PATCH 1/6] imrpve perf of SqlDateTimeToDateTime --- .../Data/SqlTypes/SqlTypeWorkarounds.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs index 8a4a491898..63bbfc6b7d 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs @@ -62,20 +62,27 @@ internal static DateTime SqlDateTimeToDateTime(int daypart, int timepart) const int SQLTicksPerHour = SQLTicksPerMinute * 60; const int SQLTicksPerDay = SQLTicksPerHour * 24; const int MinDay = -53690; // Jan 1 1753 - const int MaxDay = 2958463; // Dec 31 9999 is this many days from Jan 1 1900 + const uint MaxDay = 2958463; // Dec 31 9999 is this many days from Jan 1 1900 + const uint MaxTime = SQLTicksPerDay - 1; // = 25919999, 11:59:59:997PM const int MinTime = 0; // 00:00:0:000PM - const int MaxTime = SQLTicksPerDay - 1; // = 25919999, 11:59:59:997PM + const long BaseDateTicks = 599266080000000000L;//new DateTime(1900, 1, 1).Ticks; - if (daypart < MinDay || daypart > MaxDay || timepart < MinTime || timepart > MaxTime) + if ((uint)daypart > MaxDay || (uint)timepart > MaxTime || daypart < MinDay || timepart < MinTime) { - throw new OverflowException(SQLResource.DateTimeOverflowMessage); + ThrowOverflowException(); } - long baseDateTicks = new DateTime(1900, 1, 1).Ticks; long dayticks = daypart * TimeSpan.TicksPerDay; - long timeticks = ((long)(timepart / SQLTicksPerMillisecond + 0.5)) * TimeSpan.TicksPerMillisecond; + double timePartPerMs = timepart / SQLTicksPerMillisecond; + double int1 = timePartPerMs + 0.5; + long timeticks1 = ((long)int1) * TimeSpan.TicksPerMillisecond; + long ticks1 = BaseDateTicks + dayticks + timeticks1; + return new DateTime(ticks1); + } - return new DateTime(baseDateTicks + dayticks + timeticks); + private static void ThrowOverflowException() + { + throw new OverflowException(SQLResource.DateTimeOverflowMessage); } #endregion From 1ebe544faf78bf2392da5f9d599b22be3977adf4 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Tue, 16 Feb 2021 22:15:30 +0000 Subject: [PATCH 2/6] rework range check to be correct and faster --- .../Data/SqlTypes/SqlTypeWorkarounds.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs index 63bbfc6b7d..1825a9fcd8 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs @@ -61,23 +61,25 @@ internal static DateTime SqlDateTimeToDateTime(int daypart, int timepart) const int SQLTicksPerMinute = SQLTicksPerSecond * 60; const int SQLTicksPerHour = SQLTicksPerMinute * 60; const int SQLTicksPerDay = SQLTicksPerHour * 24; - const int MinDay = -53690; // Jan 1 1753 + //const int MinDay = -53690; // Jan 1 1753 + const uint MinDayOffset = 53690; // postive value of MinDay used to pull negative values up to 0 so a single check can be used const uint MaxDay = 2958463; // Dec 31 9999 is this many days from Jan 1 1900 const uint MaxTime = SQLTicksPerDay - 1; // = 25919999, 11:59:59:997PM - const int MinTime = 0; // 00:00:0:000PM const long BaseDateTicks = 599266080000000000L;//new DateTime(1900, 1, 1).Ticks; - if ((uint)daypart > MaxDay || (uint)timepart > MaxTime || daypart < MinDay || timepart < MinTime) + // casting to uint wraps negative values to large positive ones above the valid + // ranges so the lower bound doesn't need to be checked + if ((uint)(daypart + MinDayOffset) > (MaxDay + MinDayOffset) || (uint)timepart > MaxTime) { ThrowOverflowException(); } long dayticks = daypart * TimeSpan.TicksPerDay; double timePartPerMs = timepart / SQLTicksPerMillisecond; - double int1 = timePartPerMs + 0.5; - long timeticks1 = ((long)int1) * TimeSpan.TicksPerMillisecond; - long ticks1 = BaseDateTicks + dayticks + timeticks1; - return new DateTime(ticks1); + timePartPerMs += 0.5; + long timeTicks = ((long)timePartPerMs) * TimeSpan.TicksPerMillisecond; + long totalTicks = BaseDateTicks + dayticks + timeTicks; + return new DateTime(totalTicks); } private static void ThrowOverflowException() From f23c868a13298dfe7b4404fdd089e0a5d5068d34 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Sat, 3 Apr 2021 21:52:14 +0100 Subject: [PATCH 3/6] move exception creation to central location --- .../netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs | 5 +++++ .../src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs index 72e9631a82..b35255db29 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -740,6 +740,11 @@ internal static Exception UDTUnexpectedResult(string exceptionText) return ADP.TypeLoad(System.StringsHelper.GetString(Strings.SQLUDT_Unexpected, exceptionText)); } + internal static Exception DateTimeOverflow() + { + throw new OverflowException(SqlTypes.SQLResource.DateTimeOverflowMessage); + } + // // SQL.SqlDependency // diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs index 1825a9fcd8..a34b044cbd 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs @@ -8,6 +8,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Xml; +using Microsoft.Data.SqlClient; namespace Microsoft.Data.SqlTypes { @@ -82,10 +83,8 @@ internal static DateTime SqlDateTimeToDateTime(int daypart, int timepart) return new DateTime(totalTicks); } - private static void ThrowOverflowException() - { - throw new OverflowException(SQLResource.DateTimeOverflowMessage); - } + private static Exception ThrowOverflowException() => throw SQL.DateTimeOverflow(); + #endregion #region Work around inability to access SqlMoney.ctor(long, int) and SqlMoney.ToSqlInternalRepresentation From a7d1f9c89113e210f75f93bca6ef39ea9dbfb7bc Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Tue, 6 Apr 2021 01:30:38 +0100 Subject: [PATCH 4/6] add NoInlining hint and comment about ThrowOverflowException being extracted from it's caller. --- .../src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs index a34b044cbd..8bf15ead0e 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlTypes/SqlTypeWorkarounds.cs @@ -6,6 +6,7 @@ using System.Data.SqlTypes; using System.Diagnostics; using System.IO; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Xml; using Microsoft.Data.SqlClient; @@ -83,6 +84,10 @@ internal static DateTime SqlDateTimeToDateTime(int daypart, int timepart) return new DateTime(totalTicks); } + // this method is split out of SqlDateTimeToDateTime for performance reasons + // it is faster to make a method call than it is to incorporate the asm for this + // method in the calling method. + [MethodImpl(MethodImplOptions.NoInlining)] private static Exception ThrowOverflowException() => throw SQL.DateTimeOverflow(); #endregion From 57929019e45ca5da9acd61f6e3cbad3d8f8430fc Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Tue, 6 Apr 2021 01:43:10 +0100 Subject: [PATCH 5/6] add exception method to SqlUtil for netfx --- .../netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs index efdbe12778..83d0e48864 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -799,6 +799,11 @@ static internal SysTx.TransactionPromotionException PromotionFailed(Exception in return e; } + internal static Exception DateTimeOverflow() + { + throw new OverflowException(SqlTypes.SQLResource.DateTimeOverflowMessage); + } + // // SQL.SqlDependency // From 622b83705fa147cbe5381228dae823b9b295a9c1 Mon Sep 17 00:00:00 2001 From: Wraith2 Date: Tue, 6 Apr 2021 01:47:12 +0100 Subject: [PATCH 6/6] return exception from Sql type instead of throwing it. --- .../netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs | 2 +- .../netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs index b35255db29..56e91846f2 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -742,7 +742,7 @@ internal static Exception UDTUnexpectedResult(string exceptionText) internal static Exception DateTimeOverflow() { - throw new OverflowException(SqlTypes.SQLResource.DateTimeOverflowMessage); + return new OverflowException(SqlTypes.SQLResource.DateTimeOverflowMessage); } // diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs index 83d0e48864..bdec925681 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -801,7 +801,7 @@ static internal SysTx.TransactionPromotionException PromotionFailed(Exception in internal static Exception DateTimeOverflow() { - throw new OverflowException(SqlTypes.SQLResource.DateTimeOverflowMessage); + return new OverflowException(SqlTypes.SQLResource.DateTimeOverflowMessage); } //