Skip to content

Merge | TdsParser functional changes #3555

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

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

edwardneal
Copy link
Contributor

Description

This should cover all necessary functional changes to TdsParser. With these changes merged, the class as a whole should be ready to merge after TdsParserStateObject is dealt with.

Not all of these changes are functional - some are simply necessary to see the real ones clearly. Possibly impactful commits here are:

  • 878fcd4: when TdsParser was writing ints and there was space in the packet buffer, WriteInt would write the bytes to a stackalloc'd Span<byte> and then copy into the buffer. I've eliminated the unnecessary intermediary span, and we now write directly into the buffer.
  • a8be2f1: netfx had more detailed error messages when the parsing of a TDS stream failed. This ports those messages over to netcore.
  • 01b02db: netfx will currently enforce the validation of a server's SSL certificate if Trust Server Certificate is false and the connection's AccessToken or AccessTokenCallback is set, but netcore doesn't currently check the AccessTokenCallback property. This commit changes the behaviour of netcore to match netfx.

There's also one other commit (6d98357) which looks more impactful than it is. s_xmlMetadataSubstituteSequence and s_jsonMetadataSubstituteSequence are the same length, so there's no runtime impact here.

Issues

Relates to #1261.

Testing

Unit tests passed locally.

netcore: removed a simple WriteInt which did nothing besides call BinaryPrimitives.
netcore: when there's space in the packet buffer, WriteInt will now write to it directly (rather than write to a stack-allocated span and copy.)
This removes the need for TdsParser.netcore.cs.
Messages of the netfx exceptions are more detailed
Added mask to netcore logic.
Also removed mask on _encryptionOption from netfx - this will never be outside the range of EncryptionOptions.OPTIONS_MASK.
… is set and certificate is not automatically trusted
This passed state around, but never passed enough state to remove the state machine. Sync with netcore.
@edwardneal edwardneal requested a review from a team as a code owner August 10, 2025 20:33
@@ -10342,27 +10377,23 @@ private Task TDSExecuteRPCAddParameter(TdsParserStateObject stateObj, SqlParamet
// This is in its own method to avoid always allocating the lambda in TDSExecuteRPCParameter
private void TDSExecuteRPCParameterSetupWriteCompletion(SqlCommand cmd, IList<_SqlRPC> rpcArray, int timeout, bool inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, bool isCommandProc, bool sync, TaskCompletionSource<object> completion, int startRpc, int startParam, Task writeParamTask)
{
AsyncHelper.ContinueTaskWithState(
AsyncHelper.ContinueTask(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we want the state parameter anymore?

Copy link
Contributor Author

@edwardneal edwardneal Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd switched away from using a state parameter because it wasn't doing anything and it wasn't present in netcore. We pass this as the state, cast it back to a TdsParser, then don't use it anywhere in the lambda expression (which closes over another 11 variables); it's used once in the failure path (which closes over another variable, so can't currently be made static either.)

The halfway house doesn't really help anyone, but I'm happy enough to reintroduce the state parameter and use a tuple in both places if you'd prefer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, if it's not used downstream that's fine. The netore version is typically better than the netfx.

@@ -11160,7 +11191,7 @@ internal void WriteBulkCopyMetaData(_SqlMetaDataSet metadataCollection, int coun
stateObj.WriteByte(md.scale);
break;
case SqlDbTypeExtensions.Json:
stateObj.WriteByteArray(s_jsonMetadataSubstituteSequence, s_xmlMetadataSubstituteSequence.Length, 0);
stateObj.WriteByteArray(s_jsonMetadataSubstituteSequence, s_jsonMetadataSubstituteSequence.Length, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

Comment on lines 7344 to 7345
WriteGuid((Guid)value, stateObj);
Debug.Assert(length == 16, "Invalid length for guid type in com+ object");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should probably invert these lines. Generally asserts come before the work they are preconditions for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants