Repository navigation
Conversation
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
@priyankatiwari08 Can you please review this pull request to see if we can finally fix this long standing issue? Thanks! |
|
@jscarle This pull request has been marked as Author attention needed. When you have addressed the reviewer feedback and are ready for another review, please post a comment with |
|
Not sure what my next action is? The github action mentions that I need to address feedback, but I see none? |
Use the negotiated connection encoding for ANSI parameter byte lengths in SQL declarations, RPC metadata, and Always Encrypted type_info. Bound ANSI payload sizes by the characters remaining after Offset and invalidate the cached size when the offset changes. Include the complete fix and its unit and SQL Server regression coverage directly on main. Adapt the tests to the parser namespace introduced by the current main branch. Fixes dotnet#2035 Co-authored-by: Jens Theisen <jens.theisen-external@tuv.com>
5fec81d to
671d5bd
Compare
|
@paulmedynski I resolved the conflicts and recommitted as a single commit to make the fact that this does not depend on the prior pull request clearer. |
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. |
|
@paulmedynski looks like the milestone needs to be updated from 8.0.0 to 8.0.0-preview1. I also fixed an error in tests. |
|
@mdaigle Can you please review this so we can finally put this long standing issue to bed? |
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. |
|
/triage |
There was a problem hiding this comment.
🟡 Changes recommended
A critical prepared-command reuse issue can truncate UTF-8 parameter values when byte-length promotion requires MAX, so declaration changes must trigger reprepare and a boundary-crossing regression test is needed.
1 open issue
What changed in this PR
This PR addresses #2035 by using encoded byte lengths when sizing ANSI parameters, aligning SQL declarations, RPC metadata, and Always Encrypted metadata while preserving character-based SqlParameter.Size semantics.
Changes:
- Share connection-aware byte counting and promote oversized ANSI values to MAX.
- Account for
Offsetwhen calculating transmitted lengths and invalidate cached lengths when it changes. - Add unit and synchronous/asynchronous SQL Server regression coverage. Build-dependent tests and round trips have not completed successfully.
| File | Description |
|---|---|
src/Microsoft.Data.SqlClient/tests/UnitTests/SqlCommandAnsiParameterTests.cs |
Adds byte-boundary, offset, encoding, and metadata regression cases. |
src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Utf8SupportTest/Utf8ParameterTests.cs |
Adds UTF-8 round trips across command modes and command reuse. |
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs |
Centralizes byte sizing, handles offsets, and preserves MAX metadata. |
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.cs |
Uses connection-aware sizing for declarations and RPC validation. |
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Parser/TdsParser.cs |
Supplies parser context to encrypted and SMI metadata generation. |
Review effort: Balanced
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4906 +/- ##
==========================================
- Coverage 67.94% 66.26% -1.68%
==========================================
Files 311 305 -6
Lines 45399 68295 +22896
==========================================
+ Hits 30845 45258 +14413
- Misses 14554 23037 +8483
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@paulmedynski I pushed a fix and additional unit tests and coverage to address the identified issues. |
|
Thanks for picking this up @jscarle. Clearly, when size is inferred, we need to calculate based on byte count, not character count. That looks good to me. But I want to push back a bit on the idea of automatic promotion to varchar(MAX) outside of the inferred case. At the end of the day, we need to convert a varchar SqlParameter to a SQL varchar(n). Reinforcing the SqlParameter.Size interpretation as character count rather than byte count breaks the, effectively, direct mapping we perform today. It seems easier to me to always reason about Size as byte count. Consider inserting a SqlParameter(SqlDbType.VarChar, 8000) into a varchar(8000) column. Outwardly, this would seem to truncate the parameter value to match the capacity of the column and keep us protected. However, if we supply 4001 multibyte characters, we would now promote to varchar(max) and transmit 8002 bytes resulting in a truncation error on the server. I'm thinking that if we reinforce SqlParameter.Size as byte count, it makes it very easy to know that what you're doing with a parameter applies directly to the server-side types. The only downside is that you now need to be aware of multibyte characters and be careful not to split them if you do want to preserve whole characters. Do you agree with this, or are there any issues you can see in my thinking? I'm trying to dig through the existing code and understand it as best as possible, but there's some very tricky logic in here with all kinds of backwards compatibility traps... |
|
@mdaigle I agree that treating an explicitly specified The reason I preserved it here is that the existing implementation already limits ANSI strings by character count and then expands the SQL declaration to accommodate the encoded bytes. For example, under UTF-8, This PR addresses the mismatch between that selected value and the metadata used to transmit it, including reusing a prepared declaration that is too small. The new regression tests reproduce silent truncation on the previous code and verify that the corrected paths preserve the selected value. Your I propose we take this as the metadata/prepared-reuse fix and track explicit That follow-up would address the |
|
@jscarle I can support that approach. We'll want to be very careful with any changes to Size interpretation, so I'm fine to decouple it from this. |
There was a problem hiding this comment.
🟡 Changes recommended
The ANSI length adjustment causes SqlDbType.Variant parameters with an offset to advertise fewer bytes than the writer emits, producing malformed RPC payloads.
1 open issue
1 resolved since last review
Review effort: Balanced
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. |
|
@mdaigle I handled the variant type parameter case that Copilot mentioned and added additional regression tests / coverage. |
There was a problem hiding this comment.
🔵 Needs a closer look
RPC framing, Always Encrypted metadata, and prepared-handle lifecycle changes lack a successful build and executed SQL Server regressions, leaving wire compatibility and failure/reuse behavior unverified.
No open issues 🎉
1 resolved since last review
Review effort: Balanced
|
@mdaigle Added. |
|
/azp run |
|
Azure Pipelines: Successfully started running 2 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. |
There was a problem hiding this comment.
🔵 Needs a closer look
RPC/Always Encrypted metadata and prepared-handle recovery changes lack successful build and SQL Server runtime validation, requiring maintainer verification of wire metadata and command lifecycle behavior.
No open issues 🎉
Review effort: Balanced


AI Disclaimer
I have also encountered this issue and previously confirmed it in #2035. AI (Codex) helped me prepare this PR, building on #4824 and taking its review feedback into account. The implementation and tests are AI-assisted and need maintainer review. The testing section below describes what was actually validated for this PR.
Description
ANSI parameter values can fit within 8,000 characters while exceeding the 8,000-byte limit in the connection's encoding. For example, 4,001
\u00e9characters occupy 8,002 UTF-8 bytes. Selecting non-MAX metadata from the character count produces an invalid VARCHAR declaration or RPC payload.This continues the work in #4824, retaining Jens Theisen's original commit and addressing the gaps identified in the requested-changes review:
ValidateTypeLengthscall, including the SMI and Always Encryptedtype_infopaths. Preserve the MAX length indicator when byte-based promotion occurs and use encoded lengths for bounded ANSI metadata.Offset, including inferredSizeand an explicit size larger than the remaining value. Invalidate the cached payload length whenOffsetchanges.SqlParameter.Sizeretains its character-based semantics, and there are no public API changes. Byte counting is shared by the declaration and metadata paths so they use the same encoding and transmitted slice.Issues
Fixes #2035.
Related original PR: #4824.
Testing
Added 33 unit regression cases covering UTF-8 byte boundaries, ASCII and single-byte encodings, explicit/inferred/MAX sizes, truncation, offsets, changed offsets, nulls,
SqlString,SqlChars, and the metadata entry point used by Always Encrypted. This includes checking that metadata remains MAX after declaration building has already promoted a parameter.Added 16 SQL Server round-trip cases covering synchronous/asynchronous text, stored-procedure, and prepared commands, command reuse across the byte boundary, and offsets with inferred or explicit sizes. The tests use unique database names and clean up their resources.
Validation performed locally:
git diff --checkpassed.Microsoft.NETFramework.ReferenceAssemblies.net462andSystem.Configuration.ConfigurationManager. No build-dependent tests, SQL Server round trips, or customer-repro execution completed.No SDKs, tools, packages, or containers were installed or downloaded. The test results reported on #4824 belong to that PR and are not claimed as validation of this revision.
Suggested release note: Fixed ANSI parameter metadata for multibyte values that exceed the 8,000-byte limit, including encrypted parameter metadata and values sent with an offset.