Skip to content

[7.0] Preserve sequential Unicode source buffers (#4945) - #4962

Merged
cheenamalhotra merged 2 commits into
release/7.0from
dev/cheena/dev/automation/7-0-unicode-backport
Nov 3, 2026
Merged

cheenamalhotra merged 2 commits into
release/7.0from
dev/cheena/dev/automation/7-0-unicode-backport

Conversation

@cheenamalhotra

Copy link
Copy Markdown
Member

Description

Backport #4945 from commit 8dae63509ca17fa5b345596f7f3752bea7a4defd to release/7.0, persisted as 944419b61280237996f4ba4b58cca594380e1c2e.

Fix corrupted sequential nvarchar reads on big-endian platforms: decode raw UTF-16LE code units without mutating consumed or unconsumed source bytes. Preserve offsets, partial reads, zero-capacity conversions, and isolated surrogate code units. The production change is unchanged from the original fix.

Release-specific adaptations:

  • Both active legacy implementation projects (netcore/src and netfx/src) compile the single shared decoder source; no duplicate implementation needs patching.
  • Keep the existing driver targets, dependencies, and project structure unchanged. The unit regression file is identical to the source PR.
  • This branch lacks main's globalization test file. Add only the relevant Unicode round-trip coverage, using the existing database-object fixture, and explicitly register it in manual test set 3. Do not import unrelated UTF-8 tests.
  • This branch has no TESTGUIDE.md; document release-specific commands and the architecture limitation in BUILDGUIDE.md instead.

No public API changes, deprecations, localization changes, or intentional breaking changes. Suggested release note: Fix corrupted Unicode text returned by sequential SqlDataReader.GetTextReader reads on big-endian platforms.

The remote base was refreshed before implementation and again before opening this PR; it remains 0620c4cd441ceef4c83f75f190be4b321c6a2a3d, with no intervening fix. No existing PR matched this head branch.

Issues

Backports #4945. This PR does not close the original issue independently of the source fix.

Testing

Windows x64/little-endian: 44 decoder cases and 16 SQL round-trip cases passed, with no skipped cases in the successful final runs. Both active legacy implementation projects built with zero warnings and errors.

Decoder coverage includes raw code-unit preservation, offsets, capacity limits, odd trailing bytes, flush variants, repeated partial reads, unchanged input bytes, and empty conversion. SQL coverage exercises all four sync/async and buffered/streamed parameter combinations, packet-spanning nvarchar(max), single-character and mixed-size reads, destination sentinels, zero-length reads, and repeated EOF.

Environment: the repository-root invocation initially failed because global.json pins unavailable SDK 10.0.109. Successful commands below were run from C:\Users\cmalhotra\.copilot\session-state\87991f1b-e700-4ad8-a764-6e011c4f4a4f\files, using installed SDK 10.0.403, without modifying the SDK pin.

Exact validation commands and results:

# PASS: 11 matching unit test cases discovered.
dotnet test D:\copilot\copilot-worktrees\SqlClient\dev-cheena-curly-dollop\src\Microsoft.Data.SqlClient\tests\UnitTests\Microsoft.Data.SqlClient.UnitTests.csproj --framework net8.0 --list-tests --filter "FullyQualifiedName~SqlUnicodeEncodingTests" --verbosity quiet

# PASS: 11/11 on EACH net8.0, net9.0, net10.0, net462 (44 passed, 0 skipped).
dotnet test D:\copilot\copilot-worktrees\SqlClient\dev-cheena-curly-dollop\src\Microsoft.Data.SqlClient\tests\UnitTests\Microsoft.Data.SqlClient.UnitTests.csproj --filter "FullyQualifiedName~SqlUnicodeEncodingTests" --blame-hang-timeout 10m --verbosity quiet

# PASS: both builds, 0 warnings and 0 errors.
dotnet build D:\copilot\copilot-worktrees\SqlClient\dev-cheena-curly-dollop\src\Microsoft.Data.SqlClient\netcore\src\Microsoft.Data.SqlClient.csproj --verbosity quiet
dotnet build D:\copilot\copilot-worktrees\SqlClient\dev-cheena-curly-dollop\src\Microsoft.Data.SqlClient\netfx\src\Microsoft.Data.SqlClient.csproj --verbosity quiet

# PASS: target SQL regression discovered; initial run without config skipped the conditional theory.
dotnet test D:\copilot\copilot-worktrees\SqlClient\dev-cheena-curly-dollop\src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTests.csproj --framework net8.0 -p:TestSet=3 --list-tests --filter "FullyQualifiedName~UnicodeParameterAndReaderRoundTrip_PreservesWorldwideText" --verbosity quiet

# All framework builds succeeded; execution FAILED 4/framework opening default Northwind (SQL error 4060).
dotnet test D:\copilot\copilot-worktrees\SqlClient\dev-cheena-curly-dollop\src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTests.csproj -p:TestSet=3 --no-restore --filter "FullyQualifiedName~UnicodeParameterAndReaderRoundTrip_PreservesWorldwideText" --blame-hang-timeout 10m --verbosity quiet

# PASS: isolated existing MDS_TEST_CONFIG override used accessible local tempdb instead of unavailable Northwind.
$env:MDS_TEST_CONFIG = 'C:\Users\cmalhotra\.copilot\session-state\87991f1b-e700-4ad8-a764-6e011c4f4a4f\files\unicode-test-config.json'
# PASS: 4/4 on EACH net8.0, net9.0, net10.0, net462 (16 passed, 0 skipped).
dotnet test D:\copilot\copilot-worktrees\SqlClient\dev-cheena-curly-dollop\src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTests.csproj -p:TestSet=3 --no-build --filter "FullyQualifiedName~UnicodeParameterAndReaderRoundTrip_PreservesWorldwideText" --blame-hang-timeout 10m --verbosity quiet

# PASS: no whitespace errors before commit.
git diff --cached --check

The isolated JSON used Data Source=tcp:localhost;Database=tempdb;Integrated Security=true;Encrypt=false; for TCP, the equivalent np:localhost string for named pipes, SupportsIntegratedSecurity=true, and UseManagedSNIOnWindows=false. It was removed after validation. Transient tables were cleaned by the existing RAII fixture; tracked configuration and server setup were unchanged.

Outstanding coverage: no real big-endian runtime is available. These successful x64 runs validate only the little-endian decoder path; running the client on a real big-endian runtime such as s390x remains required to validate the original platform-specific symptom. Full test suites were not run.

  • Tests added or updated
  • Public API changes documented (not applicable; no API changes)
  • Verified against customer repro (original big-endian platform unavailable)
  • Ensure no breaking changes introduced

Guidelines

Please review the contribution guidelines before submitting a pull request:

Backport #4945 from 8dae635. Decode UTF-16LE code units without mutating consumed or unconsumed source bytes.

Retain the release framework/dependency layout. Add focused Unicode round-trip coverage to manual test set 3 and document release commands in BUILDGUIDE.md instead of importing main's unrelated globalization tests or TESTGUIDE.md.

Validated 11 decoder cases and 4 SQL round-trip cases per framework on net8.0, net9.0, net10.0 and net462, plus active legacy implementation builds. SQL tests used an isolated tempdb config; real big-endian execution remains outstanding.

(cherry picked from commit 8dae635)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@cheenamalhotra
cheenamalhotra requested a review from a team as a code owner November 2, 2026 20:07
Copilot AI balanced review requested due to automatic review settings November 2, 2026 20:07
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board Nov 2, 2026
@cheenamalhotra cheenamalhotra added this to the 7.0.4 milestone Nov 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Runtime validation covers only x64/little-endian, leaving the decoder fix and sync/async SQL sequential-read regressions unverified on a real big-endian client.

No open issues 🎉

What changed in this PR

Backports #4945 to release/7.0, fixing corrupted sequential Unicode reads on big-endian platforms by decoding UTF-16LE code units without modifying source buffers.

Changes:

  • Replaces in-place byte swapping with non-mutating decoding while preserving partial-read behavior.
  • Adds decoder unit tests and sync/async SQL round-trip tests, registered in manual test set 3.
  • Documents regression commands and platform limitations without changing public APIs or driver targets.

Reported validation passed on Windows x64; the big-endian path still requires validation on a real big-endian runtime.

File Description
src/​Microsoft.Data.SqlClient/​tests/​UnitTests/​SqlUnicodeEncodingTests.cs Tests code-unit preservation, partial reads, offsets, and unchanged input buffers.
src/​Microsoft.Data.SqlClient/​tests/​ManualTests/​SQL/​GlobalizationTest/​GlobalizationEncodingTests.cs Adds Unicode round-trip coverage for buffered and streamed sync/async operations.
src/​Microsoft.Data.SqlClient/​tests/​ManualTests/​Microsoft.Data.SqlClient.ManualTests.csproj Registers the integration tests in test set 3.
src/​Microsoft.Data.SqlClient/​src/​Microsoft/​Data/​SqlClient/​SqlSequentialTextReader.cs Decodes consumed UTF-16LE bytes without mutating the source.
BUILDGUIDE.md Documents focused regression commands and the big-endian validation requirement.

Review effort: Balanced

@codecov

codecov Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 62.50000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.30%. Comparing base (0620c4c) to head (6e2bad2).

Files with missing lines Patch % Lines
...icrosoft/Data/SqlClient/SqlSequentialTextReader.cs 62.50% 3 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (0620c4c) and HEAD (6e2bad2). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (0620c4c) HEAD (6e2bad2)
CI-SqlClient 1 0
Additional details and impacted files
@@               Coverage Diff               @@
##           release/7.0    #4962      +/-   ##
===============================================
- Coverage        73.21%   66.30%   -6.91%     
===============================================
  Files              296      291       -5     
  Lines            43453    66316   +22863     
===============================================
+ Hits             31813    43970   +12157     
- Misses           11640    22346   +10706     
Flag Coverage Δ
CI-SqlClient ?
PR-SqlClient-Project 66.30% <62.50%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread BUILDGUIDE.md Resolved
@github-project-automation github-project-automation Bot moved this from To triage to Waiting for customer in SqlClient Board Nov 2, 2026
Address review feedback; retain regression commands and platform validation limitations in the PR description.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings November 2, 2026 21:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The corrected corruption path runs only on big-endian runtimes, while reported validation covered only little-endian x64, leaving the affected branch unverified and requiring maintainer review and real big-endian regression testing.

No open issues 🎉

Review effort: Balanced

@cheenamalhotra cheenamalhotra moved this from Waiting for customer to In review in SqlClient Board Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants