Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4689f8b
netfx, netcore: sync tracing
edwardneal Sep 20, 2025
19163f5
netfx, netcore: whitespace, comment and naming changes
edwardneal Sep 20, 2025
69099ac
netfx, netcore: merge TNIR handling
edwardneal Sep 20, 2025
a5f114f
netfx: sync DNS caching
edwardneal Sep 20, 2025
96ef625
netfx, netcore: merge CER mopup
edwardneal Sep 20, 2025
f2de25f
netfx, netcore: merge debug assertions
edwardneal Sep 20, 2025
83f112b
netfx: sync SNI-specific and endian-specific logic
edwardneal Sep 20, 2025
b2e4fed
netcore: merge netfx synthesis of default column name from operand
edwardneal Sep 20, 2025
d937f90
netfx: ensure disposal of ConstrainedTextWriter and XmlWriter
edwardneal Sep 20, 2025
1c03e7c
netfx, netcore: sync handling of SqlError generation
edwardneal Sep 20, 2025
13f7a22
netfx: port #232
edwardneal Sep 20, 2025
894f8ca
netfx: port TryRunSetupSpinWaitContinuation
edwardneal Sep 20, 2025
b73d240
netcore: sync _resetConnectionEvent.WaitOne
edwardneal Sep 20, 2025
4eb8697
netfx: port skipping read of fields from SqlLoginAck and SqlReturnValue
edwardneal Sep 20, 2025
5c00879
netcore: supporting infrastructure for CER cleanup
edwardneal Sep 20, 2025
70a622f
netfx: sync GetCodePage
edwardneal Sep 20, 2025
aeab751
netcore, netfx: sync SqlGuid handling
edwardneal Sep 20, 2025
b2cb0fe
netcore, netfx: sync SqlBinary handling
edwardneal Sep 20, 2025
844ad1e
netcore: sync date/time handling
edwardneal Sep 20, 2025
3249a81
netcore, netfx: sync decimal handling
edwardneal Sep 20, 2025
1d1e925
netfx, netcore: sync minor cleanup of if conditions
edwardneal Sep 20, 2025
52dd551
netfx, netcore: sync creation of LocalDB instances
edwardneal Sep 20, 2025
7880b5f
netcore: run ApplyFeatureExData in a checked context
edwardneal Sep 20, 2025
143de69
netcore, netfx: sync creation of a TryEventScope
edwardneal Sep 20, 2025
c9585a3
netfx: sync order of variable assignment
edwardneal Sep 20, 2025
5a21361
netcore: merge static constructor
edwardneal Sep 20, 2025
ec02267
Merge branch 'main' into merge/tdsparser-complete
edwardneal Sep 24, 2025
e2d846b
Merge conditional compilation of netfx-only features
edwardneal Sep 24, 2025
af79e6b
Port TryReadByteArray usage from netcore to netfx
edwardneal Sep 24, 2025
69c81be
Rename existing shared TdsParser.cs to TdsParser.SSPI.cs
edwardneal Sep 24, 2025
6bfb6ef
Final merge of TdsParser.cs and redirection of references
edwardneal Sep 24, 2025
0839219
Code review response
edwardneal Sep 26, 2025
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 @@ -1457,8 +1457,6 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
#if DEBUG
// There is an exception here for MARS as its possible that another thread has closed the connection just as we see an error
Debug.Assert(SniContext.Undefined != stateObj.DebugOnlyCopyOfSniContext || ((_fMARS) && ((_state == TdsParserState.Closed) || (_state == TdsParserState.Broken))), "SniContext must not be None");
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.ProcessSNIError|ERR> SNIContext must not be None = {0}, _fMARS = {1}, TDS Parser State = {2}", stateObj.DebugOnlyCopyOfSniContext, _fMARS, _state);

#endif
TdsParserStateObject.SniErrorDetails details = stateObj.GetErrorDetails();

Expand Down Expand Up @@ -1487,7 +1485,6 @@ 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);

/* Format SNI errors and add Context Information
*
Expand All @@ -1502,15 +1499,17 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
* !=null | == 0 | replace text left of errorMessage
*/

#if NET
if (LocalAppContextSwitches.UseManagedNetworking)
{
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);
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > Error message received from SNI. Error Message = {0}, SNI Error Number ={1}", details.ErrorMessage, details.SniErrorNumber);
}
else
#endif
{
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);
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > Error message received from SNI. Error Message = {0}", details.ErrorMessage);
}

string sqlContextInfo = StringsHelper.GetResourceString(stateObj.SniContext.ToString());
Expand Down Expand Up @@ -4702,8 +4701,9 @@ internal int GetCodePage(SqlCollation collation, TdsParserStateObject stateObj)
// we actually MUST use the code page (i.e. don't error if no ANSI data is sent).
success = true;
}
catch (ArgumentException)
catch (ArgumentException e)
{
ADP.TraceExceptionWithoutRethrow(e);
}

// If we failed, it is quite possible this is because certain culture id's
Expand Down Expand Up @@ -4734,8 +4734,9 @@ internal int GetCodePage(SqlCollation collation, TdsParserStateObject stateObj)
codePage = new CultureInfo(cultureId).TextInfo.ANSICodePage;
success = true;
}
catch (ArgumentException)
catch (ArgumentException e)
{
ADP.TraceExceptionWithoutRethrow(e);
}
break;
case 0x827: // Mapping Non-supported Lithuanian code page to supported Lithuanian.
Expand All @@ -4744,8 +4745,9 @@ internal int GetCodePage(SqlCollation collation, TdsParserStateObject stateObj)
codePage = new CultureInfo(0x427).TextInfo.ANSICodePage;
success = true;
}
catch (ArgumentException)
catch (ArgumentException e)
{
ADP.TraceExceptionWithoutRethrow(e);
}
break;
case 0x43f:
Expand Down Expand Up @@ -8375,6 +8377,7 @@ private void ProcessAttention(TdsParserStateObject stateObj)

// If an exception occurs - break the connection.
// Attention error will not be thrown in this case by Run(), but other failures may.
ADP.TraceExceptionWithoutRethrow(e);
_state = TdsParserState.Broken;
_connHandler.BreakConnection();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ internal void ProcessPendingAck(TdsParserStateObject stateObj)
{
if (stateObj._attentionSent)
{
SqlClientEventSource.Log.TryTraceEvent("TdsParser.ProcessPendingAck | INFO | Connection Object Id {0}, State Obj Id {1}, Processing Attention.", _connHandler.ObjectID, stateObj.ObjectID);
ProcessAttention(stateObj);
}
}
Expand Down Expand Up @@ -404,48 +405,11 @@ internal void Connect(ServerInfo serverInfo,
{
_authenticationProvider = Connection._sspiContextProvider ?? _physicalStateObj.CreateSspiContextProvider();

SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> SSPI or Active Directory Authentication Library for SQL Server based integrated authentication");
SqlClientEventSource.Log.TryTraceEvent("TdsParser.Connect | SEC | SSPI or Active Directory Authentication Library loaded for SQL Server based integrated authentication");
}
else
{
_authenticationProvider = null;

switch (authType)
{
case SqlAuthenticationMethod.ActiveDirectoryPassword:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> Active Directory Password authentication");
break;
case SqlAuthenticationMethod.ActiveDirectoryIntegrated:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> Active Directory Integrated authentication");
break;
case SqlAuthenticationMethod.ActiveDirectoryInteractive:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> Active Directory Interactive authentication");
break;
case SqlAuthenticationMethod.ActiveDirectoryServicePrincipal:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> Active Directory Service Principal authentication");
break;
case SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> Active Directory Device Code Flow authentication");
break;
case SqlAuthenticationMethod.ActiveDirectoryManagedIdentity:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> Active Directory Managed Identity authentication");
break;
case SqlAuthenticationMethod.ActiveDirectoryMSI:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> Active Directory MSI authentication");
break;
case SqlAuthenticationMethod.ActiveDirectoryDefault:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> Active Directory Default authentication");
break;
case SqlAuthenticationMethod.ActiveDirectoryWorkloadIdentity:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> Active Directory Workload Identity authentication");
break;
case SqlAuthenticationMethod.SqlPassword:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> SQL Password authentication");
break;
default:
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.Connect|SEC> SQL authentication");
break;
}
}

// if Strict encryption (i.e. isTlsFirst) is chosen trust server certificate should always be false.
Expand Down Expand Up @@ -901,7 +865,7 @@ private void SendPreLoginHandshake(
offset += actIdSize;
optionDataSize += actIdSize;

SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.SendPreLoginHandshake|INFO> ClientConnectionID {0}, ActivityID {1}", _connHandler._clientConnectionId, actId);
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.SendPreLoginHandshake|INFO> ClientConnectionID {0}, ActivityID {1}", _connHandler?._clientConnectionId, actId);
break;

case (int)PreLoginOptions.FEDAUTHREQUIRED:
Expand Down Expand Up @@ -1242,7 +1206,7 @@ internal void Deactivate(bool connectionIsDoomed)
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.Deactivate|ADV> {0} deactivating", ObjectID);
if (SqlClientEventSource.Log.IsStateDumpEnabled())
{
SqlClientEventSource.Log.StateDumpEvent("<sc.TdsParser.Deactivate|STATE> {0}, {1}", ObjectID, TraceString());
SqlClientEventSource.Log.StateDumpEvent("<sc.TdsParser.Deactivate|STATE> {0} {1}", ObjectID, TraceString());
}

if (MARSOn)
Expand Down Expand Up @@ -1525,14 +1489,17 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
{
case SniErrors.MultiSubnetFailoverWithMoreThan64IPs:
// Connecting with the MultiSubnetFailover connection option to a SQL Server instance configured with more than 64 IP addresses is not supported.
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError|ERR|ADV> Connecting with the MultiSubnetFailover connection option to a SQL Server instance configured with more than 64 IP addresses is not supported.");
throw SQL.MultiSubnetFailoverWithMoreThan64IPs();

case SniErrors.MultiSubnetFailoverWithInstanceSpecified:
// Connecting to a named SQL Server instance using the MultiSubnetFailover connection option is not supported.
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError|ERR|ADV> Connecting to a named SQL Server instance using the MultiSubnetFailover connection option is not supported.");
throw SQL.MultiSubnetFailoverWithInstanceSpecified();

case SniErrors.MultiSubnetFailoverWithNonTcpProtocol:
// Connecting to a SQL Server instance using the MultiSubnetFailover connection option is only supported when using the TCP protocol.
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError|ERR|ADV> Connecting to a SQL Server instance using the MultiSubnetFailover connection option is only supported when using the TCP protocol.");
throw SQL.MultiSubnetFailoverWithNonTcpProtocol();

// continue building SqlError instance
Expand All @@ -1555,22 +1522,36 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
* !=null | == 0 | replace text left of errorMessage
*/

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

string sqlContextInfo = StringsHelper.GetString(Enum.GetName(typeof(SniContext), stateObj.SniContext));
string providerRid = string.Format("SNI_PN{0}", (int)details.Provider);
string providerName = StringsHelper.GetString(providerRid);
Debug.Assert(!string.IsNullOrEmpty(providerName), $"invalid providerResourceId '{providerRid}'");
int win32ErrorCode = details.NativeError;

SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > SNI Native Error Code = {0}", win32ErrorCode);
if (details.SniErrorNumber == 0)
{
// Provider error. The message from provider is preceeded with non-localizable info from SNI
// strip provider info from SNI
//
int iColon = errorMessage.IndexOf(':');
Debug.Assert(0 <= iColon, "':' character missing in sni errorMessage");
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > ':' character missing in sni errorMessage. Error Message index of ':' = {0}", iColon);
Debug.Assert(errorMessage.Length > iColon + 1 && errorMessage[iColon + 1] == ' ', "Expecting a space after the ':' character");
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.ProcessSNIError |ERR|ADV > Expecting a space after the ':' character. Error Message Length = {0}", errorMessage.Length);

// extract the message excluding the colon and trailing cr/lf chars
if (0 <= iColon)
Expand Down Expand Up @@ -1602,10 +1583,14 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj)
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);

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

return new SqlError(details.NativeError, 0x00, TdsEnums.FATAL_ERROR_CLASS,
_server, errorMessage, details.Function, (int)details.LineNumber, win32ErrorCode);
}
Expand Down Expand Up @@ -2493,8 +2478,7 @@ internal TdsOperationStatus TryRun(RunBehavior runBehavior, SqlCommand cmdHandle
{
_connHandler._federatedAuthenticationInfoReceived = true;
SqlFedAuthInfo info;
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.TryRun|SEC> Received federated authentication info token");


result = TryProcessFedAuthInfo(stateObj, tokenLength, out info);
if (result != TdsOperationStatus.Done)
{
Expand Down Expand Up @@ -4040,7 +4024,7 @@ private TdsOperationStatus TryProcessFedAuthInfo(TdsParserStateObject stateObj,
tokenLen -= sizeof(uint); // remaining length is shortened since we read optCount
if (SqlClientEventSource.Log.IsAdvancedTraceOn())
{
SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.TdsParser.TryProcessFedAuthInfo|ADV> CountOfInfoIDs = {0}", optionsCount.ToString(CultureInfo.InvariantCulture));
SqlClientEventSource.Log.AdvancedTraceEvent("<sc.TdsParser.TryProcessFedAuthInfo|ADV> CountOfInfoIDs = {0}", optionsCount.ToString(CultureInfo.InvariantCulture));
}
if (tokenLen > 0)
{
Expand Down Expand Up @@ -9546,8 +9530,8 @@ internal void FailureCleanup(TdsParserStateObject stateObj, Exception e)
// Reset the ThreadHasParserLock value in case our caller expects it to be set\not set
_connHandler.ThreadHasParserLockForClose = originalThreadHasParserLock;
}
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.FailureCleanup|ERR> Exception rethrown.");
}
SqlClientEventSource.Log.TryTraceEvent("<sc.TdsParser.FailureCleanup|ERR> Exception rethrown.");
}

internal Task TdsExecuteSQLBatch(string text, int timeout, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, bool sync, bool callerHasConnectionLock = false, byte[] enclavePackage = null)
Expand Down