From fb31065a7bb00f34b39a0ddd3690d6c181a035a3 Mon Sep 17 00:00:00 2001 From: JRahnama Date: Thu, 19 Sep 2024 11:39:14 -0700 Subject: [PATCH 1/4] Address Routing difference in netcore and netfx --- .../Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index d976bb06fc..47894de727 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -109,6 +109,10 @@ internal sealed class SqlInternalConnectionTds : SqlInternalConnection, IDisposa // CONNECTION AND STATE VARIABLES private readonly SqlConnectionPoolGroupProviderInfo _poolGroupProviderInfo; // will only be null when called for ChangePassword, or creating SSE User Instance private TdsParser _parser; + + // Connection re-route limit + internal const int _maxNumberOfRedirectRoute = 10; + private SqlLoginAck _loginAck; private SqlCredential _credential; private FederatedAuthenticationFeatureExtensionData _fedAuthFeatureExtensionData; @@ -1558,7 +1562,7 @@ private void LoginNoFailover(ServerInfo serverInfo, if (RoutingInfo != null) { SqlClientEventSource.Log.TryTraceEvent(" Routed to {0}", serverInfo.ExtendedServerName); - if (routingAttempts > 0) + if (routingAttempts > _maxNumberOfRedirectRoute) { throw SQL.ROR_RecursiveRoutingNotSupported(this); } From 25d4b66b1e76d3af10493df3dc85a88f0ea1ed9e Mon Sep 17 00:00:00 2001 From: JRahnama Date: Thu, 19 Sep 2024 13:31:00 -0700 Subject: [PATCH 2/4] adding the routing support to LoginWithFailover --- .../SqlClient/SqlInternalConnectionTds.cs | 113 +++++++++++++++--- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 26 ++++ .../SqlClient/SqlInternalConnectionTds.cs | 69 ++++++----- .../Data/SqlClient/SqlInternalConnection.cs | 7 +- .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 4 +- .../src/Resources/Strings.resx | 2 +- 6 files changed, 166 insertions(+), 55 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index 47894de727..377b076dba 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -109,10 +109,10 @@ internal sealed class SqlInternalConnectionTds : SqlInternalConnection, IDisposa // CONNECTION AND STATE VARIABLES private readonly SqlConnectionPoolGroupProviderInfo _poolGroupProviderInfo; // will only be null when called for ChangePassword, or creating SSE User Instance private TdsParser _parser; - + // Connection re-route limit internal const int _maxNumberOfRedirectRoute = 10; - + private SqlLoginAck _loginAck; private SqlCredential _credential; private FederatedAuthenticationFeatureExtensionData _fedAuthFeatureExtensionData; @@ -134,7 +134,7 @@ internal sealed class SqlInternalConnectionTds : SqlInternalConnection, IDisposa // The Federated Authentication returned by TryGetFedAuthTokenLocked or GetFedAuthToken. SqlFedAuthToken _fedAuthToken = null; internal byte[] _accessTokenInBytes; - internal readonly Func> _accessTokenCallback; + internal readonly Func> _accessTokenCallback; private readonly ActiveDirectoryAuthenticationTimeoutRetryHelper _activeDirectoryAuthTimeoutRetryHelper; @@ -1367,6 +1367,12 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword, // The GLOBALTRANSACTIONS, DATACLASSIFICATION, TCE, and UTF8 support features are implicitly requested requestedFeatures |= TdsEnums.FeatureExtension.GlobalTransactions | TdsEnums.FeatureExtension.DataClassification | TdsEnums.FeatureExtension.Tce | TdsEnums.FeatureExtension.UTF8Support; + // The AzureSQLSupport feature is implicitly set for ReadOnly login + if (ConnectionOptions.ApplicationIntent == ApplicationIntent.ReadOnly) + { + requestedFeatures |= TdsEnums.FeatureExtension.AzureSQLSupport; + } + // The SQLDNSCaching feature is implicitly set requestedFeatures |= TdsEnums.FeatureExtension.SQLDNSCaching; #if DEBUG @@ -1446,6 +1452,23 @@ private void OpenLoginEnlist(TimeoutTimer timeout, credential, timeout); } + + if (!IsAzureSQLConnection) + { + // If not a connection to Azure SQL, Readonly with FailoverPartner is not supported + if (ConnectionOptions.ApplicationIntent == ApplicationIntent.ReadOnly) + { + if (!string.IsNullOrEmpty(ConnectionOptions.FailoverPartner)) + { + throw SQL.ROR_FailoverNotSupportedConnString(); + } + + if (ServerProvidedFailOverPartner != null) + { + throw SQL.ROR_FailoverNotSupportedServer(this); + } + } + } _timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PostLogin); } catch (Exception e) @@ -1564,7 +1587,7 @@ private void LoginNoFailover(ServerInfo serverInfo, SqlClientEventSource.Log.TryTraceEvent(" Routed to {0}", serverInfo.ExtendedServerName); if (routingAttempts > _maxNumberOfRedirectRoute) { - throw SQL.ROR_RecursiveRoutingNotSupported(this); + throw SQL.ROR_RecursiveRoutingNotSupported(this, _maxNumberOfRedirectRoute); } if (timeout.IsExpired) @@ -1760,7 +1783,9 @@ TimeoutTimer timeout // Re-allocate parser each time to make sure state is known // RFC 50002652 - if parser was created by previous attempt, dispose it to properly close the socket, if created if (_parser != null) + { _parser.Disconnect(); + } _parser = new TdsParser(ConnectionOptions.MARS, ConnectionOptions.Asynchronous); Debug.Assert(SniContext.Undefined == Parser._physicalStateObj.SniContext, $"SniContext should be Undefined; actual Value: {Parser._physicalStateObj.SniContext}"); @@ -1793,15 +1818,44 @@ TimeoutTimer timeout intervalTimer, withFailover: true ); - - if (RoutingInfo != null) + int routingAttemps = 0; + while (RoutingInfo != null) { - // We are in login with failover scenation and server sent routing information - // If it is read-only routing - we did not supply AppIntent=RO (it should be checked before) - // If it is something else, not known yet (future server) - this client is not designed to support this. - // In any case, server should not have sent the routing info. + if (routingAttemps > _maxNumberOfRedirectRoute) + { + throw SQL.ROR_RecursiveRoutingNotSupported(this, _maxNumberOfRedirectRoute); + } + routingAttemps++; + SqlClientEventSource.Log.TryTraceEvent(" Routed to {0}", RoutingInfo.ServerName); - throw SQL.ROR_UnexpectedRoutingInfo(this); + + if(_parser != null) + { + _parser.Disconnect(); + } + + _parser = new TdsParser(ConnectionOptions.MARS, connectionOptions.Asynchronous); + + Debug.Assert(SniContext.Undefined == Parser._physicalStateObj.SniContext, $"SniContext should be Undefined; actual Value: {Parser._physicalStateObj.SniContext}"); + + currentServerInfo = new ServerInfo(ConnectionOptions, RoutingInfo, currentServerInfo.ResolvedServerName, currentServerInfo.ServerSPN); + _timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.RoutingDestination); + _originalClientConnectionId = _clientConnectionId; + _routingDestination = currentServerInfo.UserServerName; + + // restore properties that could be changed by the environemnt tokens + _currentPacketSize = connectionOptions.PacketSize; + _currentLanguage = _originalLanguage = ConnectionOptions.CurrentLanguage; + CurrentDatabase = _originalDatabase = connectionOptions.InitialCatalog; + _currentFailoverPartner = null; + _instanceName = string.Empty; + + AttemptOneLogin( + currentServerInfo, + newPassword, + newSecurePassword, + intervalTimer, + withFailover: true); } break; // leave the while loop -- we've successfully connected } @@ -1818,7 +1872,7 @@ TimeoutTimer timeout throw; // Caller will call LoginFailure() } - if (IsConnectionDoomed) + if (!ADP.IsAzureSqlServerEndpoint(connectionOptions.DataSource) && IsConnectionDoomed) { throw; } @@ -2749,23 +2803,33 @@ internal void OnFeatureExtAck(int featureId, byte[] data) } break; } - - case TdsEnums.FEATUREEXT_UTF8SUPPORT: + case TdsEnums.FEATUREEXT_AZURESQLSUPPORT: { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Received feature extension acknowledgement for UTF8 support", ObjectID); + SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Received feature extension acknowledgement for AzureSQLSupport", ObjectID); + if (data.Length < 1) { - SqlClientEventSource.Log.TryTraceEvent(" {0}, Unknown value for UTF8 support", ObjectID); - throw SQL.ParsingError(); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); + } + + IsAzureSQLConnection = true; + + // Bit 0 for RO/FP support + if ((data[0] & 1) == 1 && SqlClientEventSource.Log.IsTraceEnabled()) + { + SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, FailoverPartner enabled with Readonly intent for AzureSQL DB", ObjectID); + } break; } case TdsEnums.FEATUREEXT_DATACLASSIFICATION: { SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Received feature extension acknowledgement for DATACLASSIFICATION", ObjectID); + if (data.Length < 1) { SqlClientEventSource.Log.TryTraceEvent(" {0}, Unknown token for DATACLASSIFICATION", ObjectID); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); } byte supportedDataClassificationVersion = data[0]; @@ -2778,12 +2842,25 @@ internal void OnFeatureExtAck(int featureId, byte[] data) if (data.Length != 2) { SqlClientEventSource.Log.TryTraceEvent(" {0}, Unknown token for DATACLASSIFICATION", ObjectID); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); } byte enabled = data[1]; _parser.DataClassificationVersion = (enabled == 0) ? TdsEnums.DATA_CLASSIFICATION_NOT_ENABLED : supportedDataClassificationVersion; break; } + case TdsEnums.FEATUREEXT_UTF8SUPPORT: + { + SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Received feature extension acknowledgement for UTF8 support", ObjectID); + + if (data.Length < 1) + { + SqlClientEventSource.Log.TryTraceEvent(" {0}, Unknown value for UTF8 support", ObjectID); + + throw SQL.ParsingError(); + } + break; + } case TdsEnums.FEATUREEXT_SQLDNSCACHING: { @@ -2828,7 +2905,7 @@ internal void OnFeatureExtAck(int featureId, byte[] data) SqlClientEventSource.Log.TryTraceEvent(" {0}, Unknown token for JSONSUPPORT", ObjectID); throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); } - byte jsonSupportVersion = data[0]; + byte jsonSupportVersion = data[0]; if (jsonSupportVersion == 0 || jsonSupportVersion > TdsEnums.MAX_SUPPORTED_JSON_VERSION) { SqlClientEventSource.Log.TryTraceEvent(" {0}, Invalid version number for JSONSUPPORT", ObjectID); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 2ec05846cf..b639c45b43 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -157,6 +157,10 @@ internal static void Assert(string message) // size of Guid (e.g. _clientConnectionId, ActivityId.Id) private const int GUID_SIZE = 16; + // now data length is 1 byte + // First bit is 1 indicating client support failover partner with readonly intent + private static readonly byte[] s_featureExtDataAzureSQLSupportFeatureRequest = { 0x01 }; + // NOTE: You must take the internal connection's _parserLock before modifying this internal bool _asyncWrite = false; @@ -8375,6 +8379,24 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return len; // size of data written } + internal int WriteAzureSQLSupportFeatureRequest(bool write /* if false just calculates the length */) + { + int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = featureData + + if (write) + { + // Write Feature ID + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_AZURESQLSUPPORT); + + // Feature Data length + WriteInt(s_featureExtDataAzureSQLSupportFeatureRequest.Length, _physicalStateObj); + + _physicalStateObj.WriteByteArray(s_featureExtDataAzureSQLSupportFeatureRequest, s_featureExtDataAzureSQLSupportFeatureRequest.Length, 0); + } + + return len; + } + internal int WriteDataClassificationFeatureRequest(bool write /* if false just calculates the length */) { int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version @@ -8747,6 +8769,10 @@ private int ApplyFeatureExData(TdsEnums.FeatureExtension requestedFeatures, { length += WriteGlobalTransactionsFeatureRequest(write); } + if ((requestedFeatures & TdsEnums.FeatureExtension.AzureSQLSupport) != 0) + { + length += WriteAzureSQLSupportFeatureRequest(write); + } if ((requestedFeatures & TdsEnums.FeatureExtension.DataClassification) != 0) { length += WriteDataClassificationFeatureRequest(write); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index cdb7ba2173..f325ec5104 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -397,11 +397,11 @@ internal bool ThreadMayHaveLock() internal SyncAsyncLock _parserLock = new SyncAsyncLock(); private int _threadIdOwningParserLock = -1; - private SqlConnectionTimeoutErrorInternal timeoutErrorInternal; + private SqlConnectionTimeoutErrorInternal _timeoutErrorInternal; internal SqlConnectionTimeoutErrorInternal TimeoutErrorInternal { - get { return timeoutErrorInternal; } + get { return _timeoutErrorInternal; } } // OTHER STATE VARIABLES AND REFERENCES @@ -517,7 +517,7 @@ internal SqlInternalConnectionTds( _originalLanguage = connectionOptions.CurrentLanguage; } - timeoutErrorInternal = new SqlConnectionTimeoutErrorInternal(); + _timeoutErrorInternal = new SqlConnectionTimeoutErrorInternal(); _credential = credential; _parserLock.Wait(canReleaseFromAnyThread: false); @@ -1683,17 +1683,17 @@ private void OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectio failoverPartner = ConnectionOptions.FailoverPartner; } - timeoutErrorInternal.SetInternalSourceType(useFailoverPartner ? SqlConnectionInternalSourceType.Failover : SqlConnectionInternalSourceType.Principle); + _timeoutErrorInternal.SetInternalSourceType(useFailoverPartner ? SqlConnectionInternalSourceType.Failover : SqlConnectionInternalSourceType.Principle); bool hasFailoverPartner = !ADP.IsEmpty(failoverPartner); // Open the connection and Login try { - timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PreLoginBegin); + _timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PreLoginBegin); if (hasFailoverPartner) { - timeoutErrorInternal.SetFailoverScenario(true); // this is a failover scenario + _timeoutErrorInternal.SetFailoverScenario(true); // this is a failover scenario LoginWithFailover( useFailoverPartner, dataSource, @@ -1707,9 +1707,14 @@ private void OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectio } else { - timeoutErrorInternal.SetFailoverScenario(false); // not a failover scenario - LoginNoFailover(dataSource, newPassword, newSecurePassword, redirectedUserInstance, - connectionOptions, credential, timeout); + _timeoutErrorInternal.SetFailoverScenario(false); // not a failover scenario + LoginNoFailover(dataSource, + newPassword, + newSecurePassword, + redirectedUserInstance, + connectionOptions, + credential, + timeout); } if (!IsAzureSQLConnection) @@ -1717,7 +1722,7 @@ private void OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectio // If not a connection to Azure SQL, Readonly with FailoverPartner is not supported if (ConnectionOptions.ApplicationIntent == ApplicationIntent.ReadOnly) { - if (!String.IsNullOrEmpty(ConnectionOptions.FailoverPartner)) + if (!string.IsNullOrEmpty(ConnectionOptions.FailoverPartner)) { throw SQL.ROR_FailoverNotSupportedConnString(); } @@ -1726,11 +1731,9 @@ private void OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectio { throw SQL.ROR_FailoverNotSupportedServer(this); } - } } - - timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PostLogin); + _timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PostLogin); } catch (Exception e) { @@ -1741,7 +1744,7 @@ private void OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectio } throw; } - timeoutErrorInternal.SetAllCompleteMarker(); + _timeoutErrorInternal.SetAllCompleteMarker(); #if DEBUG _parser._physicalStateObj.InvalidateDebugOnlyCopyOfSniContext(); @@ -1885,7 +1888,7 @@ private void LoginNoFailover(ServerInfo serverInfo, string newPassword, SecureSt if (routingAttempts > _maxNumberOfRedirectRoute) { - throw SQL.ROR_RecursiveRoutingNotSupported(this); + throw SQL.ROR_RecursiveRoutingNotSupported(this, _maxNumberOfRedirectRoute); } if (timeout.IsExpired) @@ -1894,7 +1897,7 @@ private void LoginNoFailover(ServerInfo serverInfo, string newPassword, SecureSt } serverInfo = new ServerInfo(ConnectionOptions, _routingInfo, serverInfo.ResolvedServerName, serverInfo.ServerSPN); - timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.RoutingDestination); + _timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.RoutingDestination); _originalClientConnectionId = _clientConnectionId; _routingDestination = serverInfo.UserServerName; @@ -1951,10 +1954,10 @@ private void LoginNoFailover(ServerInfo serverInfo, string newPassword, SecureSt } Debug.Assert(ConnectionOptions.ApplicationIntent != ApplicationIntent.ReadOnly, "FAILOVER+AppIntent=RO: Should already fail (at LOGSHIPNODE in OnEnvChange)"); - timeoutErrorInternal.ResetAndRestartPhase(); - timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PreLoginBegin); - timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.Failover); - timeoutErrorInternal.SetFailoverScenario(true); // this is a failover scenario + _timeoutErrorInternal.ResetAndRestartPhase(); + _timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PreLoginBegin); + _timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.Failover); + _timeoutErrorInternal.SetFailoverScenario(true); // this is a failover scenario LoginWithFailover( true, // start by using failover partner, since we already failed to connect to the primary serverInfo, @@ -2109,7 +2112,9 @@ TimeoutTimer timeout // Re-allocate parser each time to make sure state is known // RFC 50002652 - if parser was created by previous attempt, dispose it to properly close the socket, if created if (_parser != null) + { _parser.Disconnect(); + } _parser = new TdsParser(ConnectionOptions.MARS, ConnectionOptions.Asynchronous); Debug.Assert(SniContext.Undefined == Parser._physicalStateObj.SniContext, String.Format((IFormatProvider)null, "SniContext should be Undefined; actual Value: {0}", Parser._physicalStateObj.SniContext)); @@ -2130,12 +2135,12 @@ TimeoutTimer timeout failoverServerInfo.SetDerivedNames(protocol, ServerProvidedFailOverPartner); } currentServerInfo = failoverServerInfo; - timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.Failover); + _timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.Failover); } else { currentServerInfo = primaryServerInfo; - timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.Principle); + _timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.Principle); } try @@ -2154,20 +2159,22 @@ TimeoutTimer timeout { if (routingAttempts > _maxNumberOfRedirectRoute) { - throw SQL.ROR_RecursiveRoutingNotSupported(this); + throw SQL.ROR_RecursiveRoutingNotSupported(this, _maxNumberOfRedirectRoute); } routingAttempts++; SqlClientEventSource.Log.TryTraceEvent(" Routed to {0}", _routingInfo.ServerName); if (_parser != null) + { _parser.Disconnect(); + } _parser = new TdsParser(ConnectionOptions.MARS, ConnectionOptions.Asynchronous); Debug.Assert(SniContext.Undefined == Parser._physicalStateObj.SniContext, $"SniContext should be Undefined; actual Value: {Parser._physicalStateObj.SniContext}"); currentServerInfo = new ServerInfo(ConnectionOptions, _routingInfo, currentServerInfo.ResolvedServerName, currentServerInfo.ServerSPN); - timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.RoutingDestination); + _timeoutErrorInternal.SetInternalSourceType(SqlConnectionInternalSourceType.RoutingDestination); _originalClientConnectionId = _clientConnectionId; _routingDestination = currentServerInfo.UserServerName; @@ -2176,7 +2183,7 @@ TimeoutTimer timeout _currentLanguage = _originalLanguage = ConnectionOptions.CurrentLanguage; CurrentDatabase = _originalDatabase = ConnectionOptions.InitialCatalog; _currentFailoverPartner = null; - _instanceName = String.Empty; + _instanceName = string.Empty; AttemptOneLogin( currentServerInfo, @@ -2318,18 +2325,18 @@ private void AttemptOneLogin(ServerInfo serverInfo, string newPassword, SecureSt _originalNetworkAddressInfo != null, disableTnir); - timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.ConsumePreLoginHandshake); - timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.LoginBegin); + _timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.ConsumePreLoginHandshake); + _timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.LoginBegin); _parser._physicalStateObj.SniContext = SniContext.Snix_Login; this.Login(serverInfo, timeout, newPassword, newSecurePassword, ConnectionOptions.Encrypt); - timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth); - timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PostLogin); + _timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth); + _timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PostLogin); CompleteLogin(!ConnectionOptions.Pooling); - timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PostLogin); + _timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PostLogin); } @@ -2795,7 +2802,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo) // Username to use in error messages. string username = null; - var authProvider = _sqlAuthenticationProviderManager.GetProvider(ConnectionOptions.Authentication); + SqlAuthenticationProvider authProvider = SqlAuthenticationProvider.GetProvider(ConnectionOptions.Authentication); if (authProvider == null && _accessTokenCallback == null) throw SQL.CannotFindAuthProvider(ConnectionOptions.Authentication.ToString()); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs index e6fe8eec99..4a5f6189bd 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs @@ -196,19 +196,21 @@ internal bool IsGlobalTransactionsEnabledForServer } } -#if NETFRAMEWORK private bool _isAzureSQLConnection = false; // If connected to Azure SQL +#if NETFRAMEWORK + abstract internal bool Is2000 { get; } + abstract internal bool Is2005OrNewer { get; } - +#endif internal bool IsAzureSQLConnection { get @@ -220,7 +222,6 @@ internal bool IsAzureSQLConnection _isAzureSQLConnection = value; } } -#endif override public DbTransaction BeginTransaction(System.Data.IsolationLevel iso) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs index 8592fd7407..63ecb0adb4 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlUtil.cs @@ -1444,10 +1444,10 @@ internal static Exception ROR_FailoverNotSupportedServer(SqlInternalConnectionTd return exc; } - internal static Exception ROR_RecursiveRoutingNotSupported(SqlInternalConnectionTds internalConnection) + internal static Exception ROR_RecursiveRoutingNotSupported(SqlInternalConnectionTds internalConnection, int maxNumberOfRedirectRoute) { SqlErrorCollection errors = new SqlErrorCollection(); - errors.Add(new SqlError(0, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, null, (StringsHelper.GetString(Strings.SQLROR_RecursiveRoutingNotSupported)), "", 0)); + errors.Add(new SqlError(0, (byte)0x00, TdsEnums.FATAL_ERROR_CLASS, null, (StringsHelper.GetString(Strings.SQLROR_RecursiveRoutingNotSupported, maxNumberOfRedirectRoute)), "", 0)); SqlException exc = SqlException.CreateException(errors, null, internalConnection, innerException: null, batchCommand: null); exc._doNotReconnect = true; return exc; diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx index c2dd68b867..8da8117634 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx @@ -4399,7 +4399,7 @@ Dictionary object containing SQL Server names and their trusted column master key paths. - Two or more redirections have occurred. Only one redirection per login is allowed. + Too many redirections have occurred. Only {0} redirections per login is allowed. Connecting to a mirrored SQL Server instance using the ApplicationIntent ReadOnly connection option is not supported. From d76e75f18141a1a8cfb9691bdcb4ee085076125d Mon Sep 17 00:00:00 2001 From: JRahnama Date: Thu, 19 Sep 2024 16:55:34 -0700 Subject: [PATCH 3/4] trigger pipelines --- .../netcore/src/Microsoft/Data/SqlClient/TdsParser.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index b639c45b43..538a97d636 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -554,7 +554,6 @@ internal void Connect( // On Instance failure re-connect and flush SNI named instance cache. _physicalStateObj.SniContext = SniContext.Snix_Connect; - _physicalStateObj.CreatePhysicalSNIHandle( serverInfo.ExtendedServerName, timeout, out instanceName, From 40f03aad7ff0f90b7de85965548d7375e6f5674f Mon Sep 17 00:00:00 2001 From: JRahnama Date: Fri, 20 Sep 2024 12:56:41 -0700 Subject: [PATCH 4/4] Addressing review comments --- .../Data/SqlClient/SqlInternalConnectionTds.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index f325ec5104..2583dd04e8 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -139,7 +139,6 @@ sealed internal class SqlInternalConnectionTds : SqlInternalConnection, IDisposa internal readonly Func> _accessTokenCallback; private readonly ActiveDirectoryAuthenticationTimeoutRetryHelper _activeDirectoryAuthTimeoutRetryHelper; - private readonly SqlAuthenticationProviderManager _sqlAuthenticationProviderManager; // Certificate auth calbacks. ServerCertificateValidationCallback _serverCallback; @@ -288,7 +287,7 @@ internal SessionData CurrentSessionData private int _asyncCommandCount; // number of async Begins minus number of async Ends. // FOR SSE - private string _instanceName = String.Empty; + private string _instanceName = string.Empty; // FOR NOTIFICATIONS private DbConnectionPoolIdentity _identity; // Used to lookup info for notification matching Start(). @@ -496,7 +495,6 @@ internal SqlInternalConnectionTds( _accessTokenCallback = accessTokenCallback; _activeDirectoryAuthTimeoutRetryHelper = new ActiveDirectoryAuthenticationTimeoutRetryHelper(); - _sqlAuthenticationProviderManager = SqlAuthenticationProviderManager.Instance; _serverCallback = serverCallback; _clientCallback = clientCallback; @@ -504,7 +502,7 @@ internal SqlInternalConnectionTds( _identity = identity; Debug.Assert(newSecurePassword != null || newPassword != null, "cannot have both new secure change password and string based change password to be null"); - Debug.Assert(credential == null || (String.IsNullOrEmpty(connectionOptions.UserID) && String.IsNullOrEmpty(connectionOptions.Password)), "cannot mix the new secure password system and the connection string based password"); + Debug.Assert(credential == null || (string.IsNullOrEmpty(connectionOptions.UserID) && string.IsNullOrEmpty(connectionOptions.Password)), "cannot mix the new secure password system and the connection string based password"); Debug.Assert(credential == null || !connectionOptions.IntegratedSecurity, "Cannot use SqlCredential and Integrated Security"); Debug.Assert(credential == null || !connectionOptions.ContextConnection, "Cannot use SqlCredential with context connection"); @@ -1176,7 +1174,7 @@ override internal void ExecuteTransaction(TransactionRequest transactionRequest, } } - string transactionName = name == null ? String.Empty : name; + string transactionName = name == null ? string.Empty : name; if (!_parser.Is2005OrNewer) { @@ -1856,7 +1854,7 @@ private void LoginNoFailover(ServerInfo serverInfo, string newPassword, SecureSt _parser.Disconnect(); _parser = new TdsParser(ConnectionOptions.MARS, ConnectionOptions.Asynchronous); - Debug.Assert(SniContext.Undefined == Parser._physicalStateObj.SniContext, String.Format((IFormatProvider)null, "SniContext should be Undefined; actual Value: {0}", Parser._physicalStateObj.SniContext)); + Debug.Assert(SniContext.Undefined == Parser._physicalStateObj.SniContext, string.Format((IFormatProvider)null, "SniContext should be Undefined; actual Value: {0}", Parser._physicalStateObj.SniContext)); try { @@ -1906,7 +1904,7 @@ private void LoginNoFailover(ServerInfo serverInfo, string newPassword, SecureSt _currentLanguage = _originalLanguage = ConnectionOptions.CurrentLanguage; CurrentDatabase = _originalDatabase = ConnectionOptions.InitialCatalog; _currentFailoverPartner = null; - _instanceName = String.Empty; + _instanceName = string.Empty; routingAttempts++; @@ -2117,7 +2115,7 @@ TimeoutTimer timeout } _parser = new TdsParser(ConnectionOptions.MARS, ConnectionOptions.Asynchronous); - Debug.Assert(SniContext.Undefined == Parser._physicalStateObj.SniContext, String.Format((IFormatProvider)null, "SniContext should be Undefined; actual Value: {0}", Parser._physicalStateObj.SniContext)); + Debug.Assert(SniContext.Undefined == Parser._physicalStateObj.SniContext, string.Format((IFormatProvider)null, "SniContext should be Undefined; actual Value: {0}", Parser._physicalStateObj.SniContext)); ServerInfo currentServerInfo; if (useFailoverHost)