Claude posting for Erik Darling
Found while working on #625 (PR #626). This comes from a SqlClient probe and from reading the code. I did not reproduce it in the app.
What happens
Microsoft.Data.SqlClient 7.1.0 does not always report a cancel as OperationCanceledException. A probe against SQL Server 2022 gave these results:
| When the token is cancelled |
What SqlClient throws |
| The server is still running the query |
SqlException: "A severe error occurred on the current command. The results, if any, should be discarded. Operation cancelled by user." |
Rows are streaming through reader.ReadAsync(ct) |
TaskCanceledException |
The first case is the usual one. It happens when a user cancels a slow query, and when a newer fetch replaces an older one. #626 fixed the three plan-capture paths. Their handlers now treat any exception as a cancel when the run's token was cancelled:
catch (Exception ex) when (ex is OperationCanceledException || ct.IsCancellationRequested)
The handlers below still decide by the exception type alone. A cancel that arrives as a SqlException goes to the error branch.
| Where |
On OperationCanceledException |
On any other exception |
QueryStoreGridControl.Fetch.cs:87 (time slicer load) |
status "Cancelled." |
status shows ex.Message |
QueryStoreGridControl.Fetch.cs:140 (plan fetch) |
status "Cancelled." |
status shows ex.Message |
QueryStoreGridControl.Sort.cs:68 |
nothing |
status shows ex.Message |
QueryStoreGridControl.WaitStats.cs:41 |
rethrows |
status shows "Slicer: " and ex.Message |
QueryStoreHistoryControl.Fetch.cs:78 |
status "Cancelled." |
status shows ex.Message |
QueryStoreOverviewControl.axaml.cs:167 and :395 |
nothing |
the "Last refresh failed" badge (ShowRefreshError) |
QueryStoreOverviewControl.axaml.cs:262 |
nothing |
goes to QuerySessionControl.Views.cs:162, which shows it in the status strip or the badge unless a newer load replaced it |
QuerySessionControl.Editor.cs:464 (SetStatusFromException) |
nothing |
red status with ex.Message |
SetStatusFromException has no token. Its callers in QuerySessionControl.QueryStore.cs, QuerySessionControl.Schema.cs and QuerySessionControl.Views.cs must pass one, or check the token themselves.
Two handlers do not have the problem. QueryStoreGridControl.axaml.cs:218 checks the token in its general catch. QuerySessionControl.Connection.cs:226 ignores every exception.
Expected
A cancelled fetch shows "Cancelled." or nothing, the same as an OperationCanceledException does today. A real failure still shows its error.
Probe
A scratch console project that references PlanViewer.Core ran WAITFOR DELAY '00:00:10' against SQL2022 and cancelled the token after 1.5 seconds. A second run cancelled the token while a large result set streamed through ReadAsync.
Claude posting for Erik Darling
Found while working on #625 (PR #626). This comes from a SqlClient probe and from reading the code. I did not reproduce it in the app.
What happens
Microsoft.Data.SqlClient 7.1.0 does not always report a cancel as
OperationCanceledException. A probe against SQL Server 2022 gave these results:SqlException: "A severe error occurred on the current command. The results, if any, should be discarded. Operation cancelled by user."reader.ReadAsync(ct)TaskCanceledExceptionThe first case is the usual one. It happens when a user cancels a slow query, and when a newer fetch replaces an older one. #626 fixed the three plan-capture paths. Their handlers now treat any exception as a cancel when the run's token was cancelled:
The handlers below still decide by the exception type alone. A cancel that arrives as a
SqlExceptiongoes to the error branch.OperationCanceledExceptionQueryStoreGridControl.Fetch.cs:87(time slicer load)ex.MessageQueryStoreGridControl.Fetch.cs:140(plan fetch)ex.MessageQueryStoreGridControl.Sort.cs:68ex.MessageQueryStoreGridControl.WaitStats.cs:41ex.MessageQueryStoreHistoryControl.Fetch.cs:78ex.MessageQueryStoreOverviewControl.axaml.cs:167and:395ShowRefreshError)QueryStoreOverviewControl.axaml.cs:262QuerySessionControl.Views.cs:162, which shows it in the status strip or the badge unless a newer load replaced itQuerySessionControl.Editor.cs:464(SetStatusFromException)ex.MessageSetStatusFromExceptionhas no token. Its callers inQuerySessionControl.QueryStore.cs,QuerySessionControl.Schema.csandQuerySessionControl.Views.csmust pass one, or check the token themselves.Two handlers do not have the problem.
QueryStoreGridControl.axaml.cs:218checks the token in its general catch.QuerySessionControl.Connection.cs:226ignores every exception.Expected
A cancelled fetch shows "Cancelled." or nothing, the same as an
OperationCanceledExceptiondoes today. A real failure still shows its error.Probe
A scratch console project that references
PlanViewer.CoreranWAITFOR DELAY '00:00:10'against SQL2022 and cancelled the token after 1.5 seconds. A second run cancelled the token while a large result set streamed throughReadAsync.