From 6a662663c496cdef2b08463092be441fc97e8113 Mon Sep 17 00:00:00 2001 From: JRahnama Date: Tue, 14 Mar 2023 01:57:23 -0700 Subject: [PATCH 1/5] commit --- .../netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs | 4 ++++ .../netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs | 4 ++++ 2 files changed, 8 insertions(+) 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 81bfc9084e..d23ea4df84 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 @@ -1414,6 +1414,10 @@ private async Task ReconnectAsync(int timeout) if (attempt == retryCount - 1) { SqlClientEventSource.Log.TryTraceEvent("SqlConnection.ReconnectAsync | Info | Original Client Connection Id {0}, give up reconnection", _originalConnectionId); + if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) + { + InnerConnection.CloseConnection(InnerConnection.Owner, ConnectionFactory); + } throw SQL.CR_AllAttemptsFailed(e, _originalConnectionId); } if (timeout > 0 && ADP.TimerRemaining(commandTimeoutExpiration) < ADP.TimerFromSeconds(ConnectRetryInterval)) 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 04acfcb612..27f66e2b28 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 @@ -1728,6 +1728,10 @@ private async Task ReconnectAsync(int timeout) if (attempt == retryCount - 1) { SqlClientEventSource.Log.TryTraceEvent(" Original ClientConnectionID {0} - give up reconnection", _originalConnectionId); + if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) + { + InnerConnection.CloseConnection(InnerConnection.Owner, ConnectionFactory); + } throw SQL.CR_AllAttemptsFailed(e, _originalConnectionId); } if (timeout > 0 && ADP.TimerRemaining(commandTimeoutExpiration) < ADP.TimerFromSeconds(ConnectRetryInterval)) From 9e4ae4f18978656049c8ff52d268e2ccfc868f73 Mon Sep 17 00:00:00 2001 From: JRahnama Date: Tue, 14 Mar 2023 02:04:15 -0700 Subject: [PATCH 2/5] commit --- .../netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs | 1 + .../netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs | 1 + 2 files changed, 2 insertions(+) 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 d23ea4df84..cd8ec4828c 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 @@ -1416,6 +1416,7 @@ private async Task ReconnectAsync(int timeout) SqlClientEventSource.Log.TryTraceEvent("SqlConnection.ReconnectAsync | Info | Original Client Connection Id {0}, give up reconnection", _originalConnectionId); if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) { + SqlClientEventSource.Log.TryTraceEvent(" Original ClientConnectionID {0} - Fatal Error occured. Error Class: {1}", _originalConnectionId, e.Class); InnerConnection.CloseConnection(InnerConnection.Owner, ConnectionFactory); } throw SQL.CR_AllAttemptsFailed(e, _originalConnectionId); 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 27f66e2b28..c7373843b2 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 @@ -1730,6 +1730,7 @@ private async Task ReconnectAsync(int timeout) SqlClientEventSource.Log.TryTraceEvent(" Original ClientConnectionID {0} - give up reconnection", _originalConnectionId); if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) { + SqlClientEventSource.Log.TryTraceEvent(" Original ClientConnectionID {0} - Fatal Error occured. Error Class: {1}", _originalConnectionId, e.Class); InnerConnection.CloseConnection(InnerConnection.Owner, ConnectionFactory); } throw SQL.CR_AllAttemptsFailed(e, _originalConnectionId); From a2f64329d49d35df08595c9f1ee842027edf9c4b Mon Sep 17 00:00:00 2001 From: Javad Rahnama Date: Wed, 22 Mar 2023 21:50:53 -0700 Subject: [PATCH 3/5] commit --- .../ExceptionTest/ConnectionExceptionTest.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs index 97243d4abd..d5c079ea00 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs @@ -18,6 +18,31 @@ public class ConnectionExceptionTest private const string execReaderFailedMessage = "ExecuteReader requires an open and available Connection. The connection's current state is closed."; private const string orderIdQuery = "select orderid from orders where orderid < 10250"; + [Fact] + public void TestConnectionStateWithErrorClass20() + { + using TestTdsServer server = TestTdsServer.StartTestServer(); + using SqlConnection conn = new(server.ConnectionString); + conn.Open(); + SqlCommand cmd = conn.CreateCommand(); + cmd.CommandText = "SELECT 1"; + int result = cmd.ExecuteNonQuery(); + Assert.Equal(-1, result); + Assert.Equal("Open", conn.State.ToString()); + server.Dispose(); + try + { + int result2 = cmd.ExecuteNonQuery(); + } + catch (SqlException ex) + { + Assert.True(ex.Class >= 20); + // Since the server is not accessible driver can close the close the connection + // It is user responsibilty to maintain the connection. + Assert.Equal("Closed", conn.State.ToString()); + } + } + [Fact] public void ExceptionTests() { From 594dbebbd37debf0a9b9eddae5234917d3111f98 Mon Sep 17 00:00:00 2001 From: Javad Rahnama Date: Thu, 23 Mar 2023 11:11:37 -0700 Subject: [PATCH 4/5] commit --- .../src/Microsoft/Data/SqlClient/SqlConnection.cs | 1 + .../SQL/ExceptionTest/ConnectionExceptionTest.cs | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) 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 cd8ec4828c..0c2330267d 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 @@ -1417,6 +1417,7 @@ private async Task ReconnectAsync(int timeout) if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) { SqlClientEventSource.Log.TryTraceEvent(" Original ClientConnectionID {0} - Fatal Error occured. Error Class: {1}", _originalConnectionId, e.Class); + // Errors 20-25, usuallyterminate the database connection InnerConnection.CloseConnection(InnerConnection.Owner, ConnectionFactory); } throw SQL.CR_AllAttemptsFailed(e, _originalConnectionId); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs index d5c079ea00..42df47a35c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs @@ -23,12 +23,15 @@ public void TestConnectionStateWithErrorClass20() { using TestTdsServer server = TestTdsServer.StartTestServer(); using SqlConnection conn = new(server.ConnectionString); + conn.Open(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "SELECT 1"; int result = cmd.ExecuteNonQuery(); + Assert.Equal(-1, result); - Assert.Equal("Open", conn.State.ToString()); + Assert.Equal(System.Data.ConnectionState.Open, conn.State); + server.Dispose(); try { @@ -36,10 +39,14 @@ public void TestConnectionStateWithErrorClass20() } catch (SqlException ex) { - Assert.True(ex.Class >= 20); + Assert.Equal(11, ex.Class); + Assert.NotNull(ex.InnerException); + SqlException innerEx = Assert.IsType(ex.InnerException); + Assert.Equal(20, innerEx.Class); + Assert.StartsWith("A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible.", innerEx.Message); // Since the server is not accessible driver can close the close the connection // It is user responsibilty to maintain the connection. - Assert.Equal("Closed", conn.State.ToString()); + Assert.Equal(System.Data.ConnectionState.Closed, conn.State); } } From 3f066d98311e566fcde8150e5f8bbce490e8db5a Mon Sep 17 00:00:00 2001 From: Javad Date: Wed, 29 Mar 2023 09:03:27 -0700 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Lawrence Cheung <31262254+lcheunglci@users.noreply.github.com> --- .../netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs | 2 +- .../netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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 0c2330267d..ce310b3f22 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 @@ -1417,7 +1417,7 @@ private async Task ReconnectAsync(int timeout) if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) { SqlClientEventSource.Log.TryTraceEvent(" Original ClientConnectionID {0} - Fatal Error occured. Error Class: {1}", _originalConnectionId, e.Class); - // Errors 20-25, usuallyterminate the database connection + // Error Class: 20-25, usually terminates the database connection InnerConnection.CloseConnection(InnerConnection.Owner, ConnectionFactory); } throw SQL.CR_AllAttemptsFailed(e, _originalConnectionId); 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 c7373843b2..3d335badc3 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 @@ -1731,6 +1731,7 @@ private async Task ReconnectAsync(int timeout) if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) { SqlClientEventSource.Log.TryTraceEvent(" Original ClientConnectionID {0} - Fatal Error occured. Error Class: {1}", _originalConnectionId, e.Class); + // Error Class: 20-25, usually terminates the database connection InnerConnection.CloseConnection(InnerConnection.Owner, ConnectionFactory); } throw SQL.CR_AllAttemptsFailed(e, _originalConnectionId);