You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add database context reconnection tests and diagnostics - #4130
Adds testing and diagnostic instrumentation for database context behavior during transparent reconnection. This pull request investigates the scenario reported in #4108; it does not fix or close that issue.
Driver behavior is unchanged on every path, and there is no new public API.
After a successful session recovery login, CompleteLogin compares the database captured before the connection dropped with the database the server reported during recovery. When they differ it emits a trace through the existing Microsoft.Data.SqlClient.EventSource provider, carrying the connection's object id plus the expected and reported database names. Recovery itself is deliberately left uncorrected, so the reported failure can be observed without being altered.
The trace is written under the provider's existing Trace keyword (2), so it can be collected with EventListener, PerfView or dotnet-trace using the tooling that ships today. No AppContext switch is needed to turn diagnostics on.
The comparison is ordinal. A case-sensitive server can host databases whose names differ only by case, so a case-insensitive match would treat two distinct recovery targets as equal and miss the mismatch.
Issues
Related to #4108. This pull request adds investigation coverage and diagnostics only; it does not resolve the reported issue.
Testing
Unit tests — 13 simulated-server tests. The mismatch scenarios assert the emitted trace through an EventListener subscribed to the real provider and keyword, with no test-only driver hook. The matching-recovery scenario asserts that no trace is emitted, so a comparison that fires when the databases already agree would be caught. Every reconnection test also asserts that no USE batch reaches the server during recovery, proving the recovery path is untouched.
Integration tests — 11 KILL-based tests covering synchronous and asynchronous reconnection workflows. They require configured live-server test infrastructure and are gated on AreConnStringsSetup, IsNotAzureServer and IsNotAzureSynapse, because they create a database and use KILL.
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds simulated-server coverage and supporting test infrastructure to reproduce #4108 (database context reverting after transparent reconnection), along with internal analysis docs and small repo policy/tooling updates.
Changes:
Added new simulated TDS server unit tests covering USE [db] / ChangeDatabase() and post-disconnect reconnection behavior.
Extended the TDS test server utilities to forcibly disconnect active clients while keeping the listener running.
Added analysis documents under plans/database_context/, updated coding-style guidance, and introduced a markdownlint configuration.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.
MSBuild property PowerShellCommand becomes self-referential here: it’s first set to powershell.exe/pwsh and then overwritten with a value that expands $(PowerShellCommand) ..., which can create a circular property expansion at build time. Consider splitting into two properties (e.g., PowerShellExe + PowerShellArgs/TrimDocsCommand) or use a differently named property for the command line so the executable selection isn’t overwritten.
✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.71%. Comparing base (9162f07) to head (8638119). ⚠️ Report is 8 commits behind head on main.
The reason will be displayed to describe this comment to others. Learn more.
Every new context switch is a public API, and we have historically never added a new API/switch for enabling diagnostics for a specific usecase. And this switch is doing more than just diagnostics as the PR description says, it changes the connection behavior, it sends USE during login and emits no diagnostic event SqlConnectionInternal.cs:2404–2445. That makes it harder to observe the original failure without also changing the outcome.
There is a separate correctness risk at line 2445: assigning CurrentDatabase unconditionally could report success if the corrective batch completes without confirming the expected database change.
Alternative: Keep recovery behavior unchanged and emit a mismatch event through the existing Microsoft.Data.SqlClient.EventSource provider, using SqlClientEventSource.Log.TryTraceEvent at the comparison point. Users can enable its existing Trace keyword (2) with EventListener or tracing tools; no new AppContext switch is needed to turn on diagnostics. Include the connection identifier and expected/reported database names, and add a listener-based test. If corrective USE is desired, name and review that separately as an opt-in recovery behavior—not as the diagnostic mechanism.
Adds testing and diagnostic instrumentation for database context behavior
during transparent reconnection. This investigates the scenario reported in
#4108; it does not fix or close that issue.
Driver behavior is unchanged on every path. After a successful session
recovery login, CompleteLogin now compares the database captured before the
connection dropped with the database the server reported, and traces a
mismatch through the existing Microsoft.Data.SqlClient.EventSource provider.
The trace carries the connection's object id plus the expected and reported
database names, and is emitted under the provider's existing Trace keyword
(2), so it can be collected with EventListener, PerfView or dotnet-trace
without any new API. Recovery is deliberately left uncorrected so the
reported failure can be observed without being altered.
The comparison is ordinal: a case-sensitive server can host databases whose
names differ only by case, so a case-insensitive match would treat two
distinct recovery targets as equal and miss the mismatch.
Changes:
- Simulated TDS server coverage for matching recovery, an incorrect database
ENV_CHANGE, an omitted database ENV_CHANGE, a response differing only by
case, pooled connections, pool reset, and disabled connection retry. The
mismatch cases assert the emitted trace through an EventListener; the
matching case asserts no trace is emitted.
- SQL Server integration tests using KILL to exercise reconnection after USE
and ChangeDatabase, including pooling, MARS, stress, DDL placement,
repeated database switches, repeated reconnects, and async execution.
- Test-server diagnostics for disconnecting active clients, counting Login7
handshakes, recording USE batches, and controlling the database reported
during recovery.
- Markdown lint configuration and coding-style guidance for line wrapping and
region usage.
- Agent tooling updates: allow either a connected MCP server or the gh/az
CLIs for GitHub and Azure DevOps access, and document why prompt links are
written relative to the repository root.
There are no public API changes and no new AppContext switches.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assert the no-USE invariant in the three proper-recovery tests that
claimed it without checking, and document the test helper parameters.
- UseDatabase_ProperRecovery_DatabaseContextPreservedAfterReconnect,
ChangeDatabase_ProperRecovery_DatabaseContextPreservedAfterReconnect and
UseDatabase_ProperRecovery_Pooled_DatabaseContextPreservedAfterReconnect
now snapshot UseDatabaseCount before the disconnect and call
AssertNoRecoveryUse afterwards. The pull request described this invariant
as covered by every reconnection test, but these three only checked the
client-side Database property.
- Add the missing XML <param> and <returns> documentation to the test
helpers in both files, as required by testing.instructions.md.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CurrentDatabase is not always a database the server reported: when the recovery response omits the database ENV_CHANGE, it retains the login's preinitialized catalog, yet this trace says the server reported that value. The new omitted-token tests exercise exactly this case, so the diagnostic can misidentify server behavior. Either track whether a database ENV_CHANGE was received or label this value as the database observed by the client; update the trace assertions accordingly.
The mismatch trace attributed CurrentDatabase to the server even when the
recovery response carried no database ENV_CHANGE at all. In that case the
value is the login's pre-initialized catalog, so the trace named a database
the server never reported.
The two cases cannot be told apart by value: a server may legitimately
report exactly the initial catalog, which is identical to the fallback. Track
whether an ENV_DATABASE token arrived while the login response was parsed,
and report the two server behaviors distinctly, since "reported the wrong
database" and "reported none" are different faults.
The flag is reset immediately before the login response is parsed and read
only while completing that same login, so a later USE cannot leave it stale
and a re-login after routing cannot inherit the previous attempt's value.
Split the test assertion helper to match, and assert that the omitted-token
cases do not claim the server reported anything.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The trace attributed CurrentDatabase to the server even when the recovery response carried no database ENV_CHANGE. In that case the value is the login's pre-initialized catalog, so the trace named a database the server never reported. The omitted-token tests asserted Assert.Null(server.LastLoginResponseDatabase) and, in the same test, that the trace said the server reported initialdb — the tests encoded the contradiction.
I took the first of the two suggested remedies rather than relabelling the value, because the two cases cannot be told apart by value alone: a server may legitimately report exactly the initial catalog, which is byte-identical to the fallback. SendInitialCatalog and OmitDatabaseEnvChange would otherwise produce an identical trace while representing different server faults, and distinguishing those is the point of this investigation.
CompleteLogin now tracks whether an ENV_DATABASE token arrived while the login response was parsed, and reports the two behaviors distinctly:
server reported a different database, or
the recovery response carried no database ENV_CHANGE and the connection fell back.
The flag is reset immediately before that parse and read only while completing the same login, so a later USE cannot leave it stale and a re-login after routing cannot inherit the previous attempt's value.
Mutation-checked: forcing the server-reported branch fails exactly the two omitted-ENV_CHANGE tests and no others. The assertion helper is split so the omitted cases also assert the trace does not claim the server reported anything.
Also in this review: the 13 findings from the previous round are confirmed Resolved since last review, and this review carries no suppressed findings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Public API 🆕Issues/PRs that introduce new APIs to the driver.
6 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds testing and diagnostic instrumentation for database context behavior during transparent reconnection. This pull request investigates the scenario reported in #4108; it does not fix or close that issue.
Driver behavior is unchanged on every path, and there is no new public API.
After a successful session recovery login,
CompleteLogincompares the database captured before the connection dropped with the database the server reported during recovery. When they differ it emits a trace through the existingMicrosoft.Data.SqlClient.EventSourceprovider, carrying the connection's object id plus the expected and reported database names. Recovery itself is deliberately left uncorrected, so the reported failure can be observed without being altered.The trace is written under the provider's existing Trace keyword (
2), so it can be collected withEventListener, PerfView or dotnet-trace using the tooling that ships today. No AppContext switch is needed to turn diagnostics on.The comparison is ordinal. A case-sensitive server can host databases whose names differ only by case, so a case-insensitive match would treat two distinct recovery targets as equal and miss the mismatch.
Issues
Related to #4108. This pull request adds investigation coverage and diagnostics only; it does not resolve the reported issue.
Testing
Unit tests — 13 simulated-server tests. The mismatch scenarios assert the emitted trace through an
EventListenersubscribed to the real provider and keyword, with no test-only driver hook. The matching-recovery scenario asserts that no trace is emitted, so a comparison that fires when the databases already agree would be caught. Every reconnection test also asserts that noUSEbatch reaches the server during recovery, proving the recovery path is untouched.Integration tests — 11
KILL-based tests covering synchronous and asynchronous reconnection workflows. They require configured live-server test infrastructure and are gated onAreConnStringsSetup,IsNotAzureServerandIsNotAzureSynapse, because they create a database and useKILL.