Skip to content

[6.1] Align SqlException Numbers across platforms #3475

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 16, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,18 @@ private void WaitForSSLHandShakeToComplete(ref uint error, ref int protocolVersi
// No - Op
}

private SNIErrorDetails GetSniErrorDetails()
private TdsParserStateObject.SniErrorDetails GetSniErrorDetails()
{
SNIErrorDetails details;
SniError sniError = SniProxy.Instance.GetLastError();
details.sniErrorNumber = sniError.sniError;
details.errorMessage = sniError.errorMessage;
details.nativeError = sniError.nativeError;
details.provider = (int)sniError.provider;
details.lineNumber = sniError.lineNumber;
details.function = sniError.function;
details.exception = sniError.exception;

return details;
}

return new(
sniError.errorMessage,
sniError.nativeError,
sniError.sniError,
(int)sniError.provider,
sniError.lineNumber,
sniError.function,
sniError.exception);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1450,12 +1450,12 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.ProcessSNIError|ERR> SNIContext must not be None = {0}, _fMARS = {1}, TDS Parser State = {2}", stateObj.DebugOnlyCopyOfSniContext, _fMARS, _state);

#endif
SNIErrorDetails details = GetSniErrorDetails();
TdsParserStateObject.SniErrorDetails details = GetSniErrorDetails();

if (details.sniErrorNumber != 0)
if (details.SniErrorNumber != 0)
{
// handle special SNI error codes that are converted into exception which is not a SqlException.
switch (details.sniErrorNumber)
switch (details.SniErrorNumber)
{
case SniErrors.MultiSubnetFailoverWithMoreThan64IPs:
// Connecting with the MultiSubnetFailover connection option to a SQL Server instance configured with more than 64 IP addresses is not supported.
Expand All @@ -1476,8 +1476,8 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
}
// PInvoke code automatically sets the length of the string for us
// So no need to look for \0
string errorMessage = details.errorMessage;
SqlClientEventSource.Log.TryAdvancedTraceEvent("< sc.TdsParser.ProcessSNIError |ERR|ADV > Error message Detail: {0}", details.errorMessage);
string errorMessage = details.ErrorMessage;
SqlClientEventSource.Log.TryAdvancedTraceEvent("< sc.TdsParser.ProcessSNIError |ERR|ADV > Error message Detail: {0}", details.ErrorMessage);

/* Format SNI errors and add Context Information
*
Expand All @@ -1494,23 +1494,23 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)

if (TdsParserStateObjectFactory.UseManagedSNI)
{
Debug.Assert(!string.IsNullOrEmpty(details.errorMessage) || details.sniErrorNumber != 0, "Empty error message received from SNI");
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > Empty error message received from SNI. Error Message = {0}, SNI Error Number ={1}", details.errorMessage, details.sniErrorNumber);
Debug.Assert(!string.IsNullOrEmpty(details.ErrorMessage) || details.SniErrorNumber != 0, "Empty error message received from SNI");
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > Empty error message received from SNI. Error Message = {0}, SNI Error Number ={1}", details.ErrorMessage, details.SniErrorNumber);
}
else
{
Debug.Assert(!string.IsNullOrEmpty(details.errorMessage), "Empty error message received from SNI");
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > Empty error message received from SNI. Error Message = {0}", details.errorMessage);
Debug.Assert(!string.IsNullOrEmpty(details.ErrorMessage), "Empty error message received from SNI");
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > Empty error message received from SNI. Error Message = {0}", details.ErrorMessage);
}

string sqlContextInfo = StringsHelper.GetResourceString(stateObj.SniContext.ToString());
string providerRid = string.Format("SNI_PN{0}", details.provider);
string providerRid = string.Format("SNI_PN{0}", details.Provider);
string providerName = StringsHelper.GetResourceString(providerRid);
Debug.Assert(!string.IsNullOrEmpty(providerName), $"invalid providerResourceId '{providerRid}'");
uint win32ErrorCode = details.nativeError;
int win32ErrorCode = details.NativeError;

SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > SNI Native Error Code = {0}", win32ErrorCode);
if (details.sniErrorNumber == 0)
if (details.SniErrorNumber == 0)
{
// Provider error. The message from provider is preceeded with non-localizable info from SNI
// strip provider info from SNI
Expand Down Expand Up @@ -1544,33 +1544,33 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
if (TdsParserStateObjectFactory.UseManagedSNI)
{
// SNI error. Append additional error message info if available and hasn't been included.
string sniLookupMessage = SQL.GetSNIErrorMessage(details.sniErrorNumber);
string sniLookupMessage = SQL.GetSNIErrorMessage(details.SniErrorNumber);
errorMessage = (string.IsNullOrEmpty(errorMessage) || errorMessage.Contains(sniLookupMessage))
? sniLookupMessage
: (sniLookupMessage + ": " + errorMessage);
}
else
{
// SNI error. Replace the entire message.
errorMessage = SQL.GetSNIErrorMessage(details.sniErrorNumber);
errorMessage = SQL.GetSNIErrorMessage(details.SniErrorNumber);

// If its a LocalDB error, then nativeError actually contains a LocalDB-specific error code, not a win32 error code
if (details.sniErrorNumber == SniErrors.LocalDBErrorCode)
if (details.SniErrorNumber == SniErrors.LocalDBErrorCode)
{
errorMessage += LocalDbApi.GetLocalDbMessage((int)details.nativeError);
errorMessage += LocalDbApi.GetLocalDbMessage(details.NativeError);
win32ErrorCode = 0;
}
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > Extracting the latest exception from native SNI. errorMessage: {0}", errorMessage);
}
}
errorMessage = string.Format("{0} (provider: {1}, error: {2} - {3})",
sqlContextInfo, providerName, (int)details.sniErrorNumber, errorMessage);
sqlContextInfo, providerName, (int)details.SniErrorNumber, errorMessage);

SqlClientEventSource.Log.TryAdvancedTraceErrorEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > SNI Error Message. Native Error = {0}, Line Number ={1}, Function ={2}, Exception ={3}, Server = {4}",
(int)details.nativeError, (int)details.lineNumber, details.function, details.exception, _server);
details.NativeError, (int)details.LineNumber, details.Function, details.Exception, _server);

return new SqlError(infoNumber: (int)details.nativeError, errorState: 0x00, TdsEnums.FATAL_ERROR_CLASS, _server,
errorMessage, details.function, (int)details.lineNumber, win32ErrorCode: details.nativeError, details.exception);
return new SqlError(infoNumber: details.NativeError, errorState: 0x00, TdsEnums.FATAL_ERROR_CLASS, _server,
errorMessage, details.Function, (int)details.LineNumber, win32ErrorCode: details.NativeError, details.Exception);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,6 @@ namespace Microsoft.Data.SqlClient
{
internal sealed partial class TdsParser
{
internal struct SNIErrorDetails
{
public string errorMessage;
public uint nativeError;
public uint sniErrorNumber;
public int provider;
public uint lineNumber;
public string function;
public Exception exception;
}

internal static void FillGuidBytes(Guid guid, Span<byte> buffer) => guid.TryWriteBytes(buffer);

internal static void FillDoubleBytes(double value, Span<byte> buffer) => BinaryPrimitives.TryWriteInt64LittleEndian(buffer, BitConverter.DoubleToInt64Bits(value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1589,7 +1589,7 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
string providerRid = string.Format("SNI_PN{0}", (int)details.provider);
string providerName = StringsHelper.GetString(providerRid);
Debug.Assert(!string.IsNullOrEmpty(providerName), $"invalid providerResourceId '{providerRid}'");
uint win32ErrorCode = details.nativeError;
int win32ErrorCode = details.nativeError;

if (details.sniError == 0)
{
Expand Down Expand Up @@ -1627,14 +1627,14 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
// If its a LocalDB error, then nativeError actually contains a LocalDB-specific error code, not a win32 error code
if (details.sniError == SniErrors.LocalDBErrorCode)
{
errorMessage += LocalDbApi.GetLocalDbMessage((int)details.nativeError);
errorMessage += LocalDbApi.GetLocalDbMessage(details.nativeError);
win32ErrorCode = 0;
}
}
errorMessage = string.Format("{0} (provider: {1}, error: {2} - {3})",
sqlContextInfo, providerName, (int)details.sniError, errorMessage);

return new SqlError((int)details.nativeError, 0x00, TdsEnums.FATAL_ERROR_CLASS,
return new SqlError(details.nativeError, 0x00, TdsEnums.FATAL_ERROR_CLASS,
_server, errorMessage, details.function, (int)details.lineNumber, win32ErrorCode);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal struct SniError
internal Provider provider;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 261)]
internal string errorMessage;
internal uint nativeError;
internal int nativeError;
internal uint sniError;
[MarshalAs(UnmanagedType.LPWStr)]
internal string fileName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ internal static IPAddress[] GetDnsIpAddresses(string serverName)
/// <param name="sniError">SNI error code</param>
/// <param name="errorMessage">Error message</param>
/// <returns></returns>
internal static uint ReportSNIError(SniProviders provider, uint nativeError, uint sniError, string errorMessage)
internal static uint ReportSNIError(SniProviders provider, int nativeError, uint sniError, string errorMessage)
{
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniCommon), EventType.ERR, "Provider = {0}, native Error = {1}, SNI Error = {2}, Error Message = {3}", args0: provider, args1: nativeError, args2: sniError, args3: errorMessage);
return ReportSNIError(new SniError(provider, nativeError, sniError, errorMessage));
Expand All @@ -203,7 +203,7 @@ internal static uint ReportSNIError(SniProviders provider, uint nativeError, uin
/// <param name="sniException">SNI Exception</param>
/// <param name="nativeErrorCode">Native SNI error code</param>
/// <returns></returns>
internal static uint ReportSNIError(SniProviders provider, uint sniError, Exception sniException, uint nativeErrorCode = 0)
internal static uint ReportSNIError(SniProviders provider, uint sniError, Exception sniException, int nativeErrorCode = 0)
{
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniCommon), EventType.ERR, "Provider = {0}, SNI Error = {1}, Exception = {2}", args0: provider, args1: sniError, args2: sniException?.Message);
return ReportSNIError(new SniError(provider, sniError, sniException, nativeErrorCode));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#if NET

using System;
using System.ComponentModel;
using System.Net.Sockets;

namespace Microsoft.Data.SqlClient.ManagedSni
{
Expand All @@ -14,17 +16,18 @@ namespace Microsoft.Data.SqlClient.ManagedSni
internal class SniError
{
// Error numbers from native SNI implementation
internal const uint CertificateValidationErrorCode = 2148074277;
// This is signed int representation of the error code 0x80090325
internal const int CertificateValidationErrorCode = -2146893019;

public readonly SniProviders provider;
public readonly string errorMessage;
public readonly uint nativeError;
public readonly int nativeError;
public readonly uint sniError;
public readonly string function;
public readonly uint lineNumber;
public readonly Exception exception;

public SniError(SniProviders provider, uint nativeError, uint sniErrorCode, string errorMessage)
public SniError(SniProviders provider, int nativeError, uint sniErrorCode, string errorMessage)
{
lineNumber = 0;
function = string.Empty;
Expand All @@ -35,12 +38,25 @@ public SniError(SniProviders provider, uint nativeError, uint sniErrorCode, stri
exception = null;
}

public SniError(SniProviders provider, uint sniErrorCode, Exception sniException, uint nativeErrorCode = 0)
public SniError(SniProviders provider, uint sniErrorCode, Exception sniException, int nativeErrorCode = 0)
{
lineNumber = 0;
function = string.Empty;
this.provider = provider;
nativeError = nativeErrorCode;
if (nativeErrorCode == 0)
{
if (sniException is SocketException socketException)
{
// SocketErrorCode values are cross-plat consistent in .NET (matching native Windows error codes)
// underlying type of SocketErrorCode is int
nativeError = (int)socketException.SocketErrorCode;
}
else if (sniException is Win32Exception win32Exception)
{
nativeError = win32Exception.NativeErrorCode; // Replicates native SNI behavior
}
}
sniError = sniErrorCode;
errorMessage = string.Empty;
exception = sniException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public override uint Receive(out SniPacket packet, int timeout)
packet = null;
var e = new Win32Exception();
SqlClientEventSource.Log.TrySNITraceEvent(nameof(SniNpHandle), EventType.ERR, "Connection Id {0}, Packet length found 0, Win32 exception raised: {1}", args0: _connectionId, args1: e?.Message);
return ReportErrorAndReleasePacket(errorPacket, (uint)e.NativeErrorCode, 0, e.Message);
return ReportErrorAndReleasePacket(errorPacket, e.NativeErrorCode, 0, e.Message);
}
}
catch (ObjectDisposedException ode)
Expand Down Expand Up @@ -413,7 +413,7 @@ private uint ReportErrorAndReleasePacket(SniPacket packet, Exception sniExceptio
return SniCommon.ReportSNIError(SniProviders.NP_PROV, SniCommon.InternalExceptionError, sniException);
}

private uint ReportErrorAndReleasePacket(SniPacket packet, uint nativeError, uint sniError, string errorMessage)
private uint ReportErrorAndReleasePacket(SniPacket packet, int nativeError, uint sniError, string errorMessage)
{
if (packet != null)
{
Expand Down
Loading
Loading