diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
index e2c6feedfa..be51c3e62c 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs
@@ -563,7 +563,9 @@ public Guid ClientConnectionId
else
{
Task reconnectTask = _currentReconnectionTask;
- if (reconnectTask != null && !reconnectTask.IsCompleted)
+ // Connection closed but previously open should return the correct ClientConnectionId
+ DbConnectionClosedPreviouslyOpened innerConnectionClosed = (InnerConnection as DbConnectionClosedPreviouslyOpened);
+ if ((reconnectTask != null && !reconnectTask.IsCompleted) || null != innerConnectionClosed)
{
return _originalConnectionId;
}
@@ -856,6 +858,7 @@ private void CloseInnerConnection()
// The SqlInternalConnectionTds is set to OpenBusy during close, once this happens the cast below will fail and
// the command will no longer be cancelable. It might be desirable to be able to cancel the close operation, but this is
// outside of the scope of Whidbey RTM. See (SqlCommand::Cancel) for other lock.
+ _originalConnectionId = ClientConnectionId;
InnerConnection.CloseConnection(this, ConnectionFactory);
}
diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlStatistics.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlStatistics.cs
index da71b7e1b7..32e06b2df0 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlStatistics.cs
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlStatistics.cs
@@ -210,9 +210,9 @@ internal long SafeIncrement(ref long value)
internal void UpdateStatistics()
{
// update connection time
- if (_closeTimestamp >= _openTimestamp)
+ if (_closeTimestamp >= _openTimestamp && long.MaxValue > _closeTimestamp - _openTimestamp)
{
- SafeAdd(ref _connectionTime, _closeTimestamp - _openTimestamp);
+ _connectionTime = _closeTimestamp - _openTimestamp;
}
else
{
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs
index 30e3feb101..f7b88667d6 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs
@@ -792,7 +792,9 @@ public Guid ClientConnectionId
else
{
Task reconnectTask = _currentReconnectionTask;
- if (reconnectTask != null && !reconnectTask.IsCompleted)
+ // Connection closed but previously open should return the correct ClientConnectionId
+ DbConnectionClosedPreviouslyOpened innerConnectionClosed = (InnerConnection as DbConnectionClosedPreviouslyOpened);
+ if ((reconnectTask != null && !reconnectTask.IsCompleted) || null != innerConnectionClosed)
{
return _originalConnectionId;
}
@@ -1253,6 +1255,7 @@ void CloseInnerConnection()
// The SqlInternalConnectionTds is set to OpenBusy during close, once this happens the cast below will fail and
// the command will no longer be cancelable. It might be desirable to be able to cancel the close opperation, but this is
// outside of the scope of Whidbey RTM. See (SqlCommand::Cancel) for other lock.
+ _originalConnectionId = ClientConnectionId;
InnerConnection.CloseConnection(this, ConnectionFactory);
}
diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlStatistics.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlStatistics.cs
index 036b1d99ce..28dfee86f0 100644
--- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlStatistics.cs
+++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlStatistics.cs
@@ -207,9 +207,9 @@ internal long SafeIncrement(ref long value)
internal void UpdateStatistics()
{
// update connection time
- if (_closeTimestamp >= _openTimestamp)
+ if (_closeTimestamp >= _openTimestamp && long.MaxValue > _closeTimestamp - _openTimestamp)
{
- SafeAdd(ref _connectionTime, _closeTimestamp - _openTimestamp);
+ _connectionTime = _closeTimestamp - _openTimestamp;
}
else
{
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
index 7a82bfbf08..f20d1ddccb 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj
@@ -113,6 +113,7 @@
+
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlStatisticsTest/SqlStatisticsTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlStatisticsTest/SqlStatisticsTest.cs
new file mode 100644
index 0000000000..53c71f5ced
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlStatisticsTest/SqlStatisticsTest.cs
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Data;
+using System.Data.Common;
+using System.Collections;
+using Xunit;
+
+namespace Microsoft.Data.SqlClient.ManualTesting.Tests
+{
+ public class SqlStatisticsTest
+ {
+ private static DateTime startTime = new DateTime();
+ private static Guid clientConnectionId = Guid.Empty;
+
+ [CheckConnStrSetupFact]
+ public static void TestRetrieveStatistics()
+ {
+ startTime = DateTime.Now;
+ SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString);
+ string text = "SELECT TOP 2000 * from [dbo].[Order Details]";
+ using (SqlCommand command = new SqlCommand(text))
+ {
+ connection.StatisticsEnabled = true;
+ connection.Open();
+ connection.StateChange += new StateChangeEventHandler(HandleStateChange);
+
+ command.Connection = connection;
+ using (SqlDataReader dr = command.ExecuteReader())
+ {
+ IDictionary stats1 = connection.RetrieveStatistics();
+
+ // Ensure ConnectionTime is within a reasonable range
+ Assert.True((long)stats1["ConnectionTime"] < DateTime.Now.Subtract(startTime).TotalMilliseconds + 1000, "Unexpected ConnectionTime: " + stats1["ConnectionTime"]);
+ clientConnectionId = connection.ClientConnectionId;
+ Assert.True(clientConnectionId != Guid.Empty);
+
+ int row = 0;
+ while (dr.Read())
+ {
+ row++;
+ }
+ }
+ }
+ // Ensure calling RetrieveStatistics multiple times do not affect the ConnectionTime
+ connection.RetrieveStatistics();
+ connection.RetrieveStatistics();
+ connection.RetrieveStatistics();
+ connection.RetrieveStatistics();
+ connection.RetrieveStatistics();
+ connection.RetrieveStatistics();
+ connection.Close();
+ IDictionary stats2 = connection.RetrieveStatistics();
+ Assert.True((long)stats2["ConnectionTime"] < DateTime.Now.Subtract(startTime).TotalMilliseconds + 1000, "Unexpected ConnectionTime: " + stats2["ConnectionTime"]);
+ // Ensure ClientConnectionId remains available even after the connection is closed
+ Assert.True(connection.ClientConnectionId == clientConnectionId);
+ }
+
+ private static void HandleStateChange(object sender, StateChangeEventArgs args)
+ {
+ if (args.CurrentState == ConnectionState.Closed)
+ {
+ System.Collections.IDictionary stats = ((SqlConnection)sender).RetrieveStatistics();
+ Assert.True((long)stats["ConnectionTime"] < DateTime.Now.Subtract(startTime).TotalMilliseconds + 1000, "Unexpected ConnectionTime: " + stats["ConnectionTime"]);
+ Assert.True(((SqlConnection)sender).ClientConnectionId == clientConnectionId);
+ }
+ }
+ }
+}