Release: dev -> main#292
Merged
erikdarlingdata merged 15 commits intomainfrom Apr 27, 2026
Merged
Conversation
Dependencies: - Avalonia 11.3.12 -> 11.3.14 (DataGrid 11.3.13) - ModelContextProtocol + .AspNetCore 0.7.0-preview.1 -> 1.2.0 (GA) - Microsoft.NET.Test.Sdk 17.8.0 -> 18.4.0 - xunit 2.5.3 -> 2.9.3, xunit.runner.visualstudio 2.5.3 -> 3.1.5, coverlet.collector 6.0.0 -> 10.0.0 - Meziantou.Framework.Win32.CredentialManager 1.7.17 -> 1.7.18 - ScottPlot 5.1.57 -> 5.1.58, SkiaSharp.NativeAssets.Linux 3.119.0 -> 3.119.2 Closes 3 transitive vulnerabilities: Tmds.DBus.Protocol (GHSA-xrw6-gwf8-vvr9), System.Net.Http (GHSA-7jgj-8wvc-jh57), System.Text.RegularExpressions (GHSA-cmhx-cq75-c4mj). Source warnings: - PlanAnalyzer.cs: null-conditional on StatementText and PhysicalOp - QueryStoreHistoryWindow.cs: pattern-match ComboBoxItem; replace obsolete DataGridRow.GetIndex with .Index - WindowsCredentialService: [SupportedOSPlatform("windows5.1.2600")] - CredentialServiceFactory: switch to OperatingSystem.IsWindows/IsMacOS; pragma at the cross-platform bridge - CredentialCommand: explicit OperatingSystem.IsWindows guard + pragma 71/71 tests passing. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Single-package swap. The test project uses only [Fact] + the basic Assert.* surface (no theories, no fixtures, no IAsyncLifetime, no ITestOutputHelper), all of which carry over to v3 unchanged. xunit.runner.visualstudio 3.1.5 already supports v3. 71/71 tests passing. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
) SqlClient: API surface unchanged (codebase already uses Encrypt explicitly, SqlConnectionEncryptOption, async-only patterns). Note: the Microsoft.Data.SqlClient.Extensions.Azure auxiliary package is only published at 1.0.0 and isn't required for ActiveDirectoryInteractive in 7.0.1 — the auth method remains in the core package. ScriptDom: 180.6.0 tracks SQL 2025 grammar. No API surface changes affect SqlObjectResolver, SqlFormattingService, or SqlFormatSettingsService. Sticking with TSql160/170 parsers as today; future work can adopt TSql180Parser when needed. 71/71 tests passing. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mechanical API rename pass — no architectural changes.
- Option<T>(name, description) -> Option<T>(name, ...aliases) { Description = ..., DefaultValueFactory = _ => v, Required = true }
- AddAlias(x) -> ctor params or Aliases.Add(x)
- IsRequired -> Required
- AddCommand(c) -> Subcommands.Add(c)
- SetHandler(async ctx => ...) / SetHandler(binder, opts...) -> SetAction(...)
- ctx.ParseResult.GetValueForOption/Argument(x) -> parseResult.GetValue(x)
- root.InvokeAsync(args) -> root.Parse(args).InvokeAsync()
- Argument<T>(name, description) ctor gone -> single-arg ctor + Description property
Smoke-tested: --help on root, analyze, credential render correctly with
descriptions/defaults/aliases. Functional analyze on a .sqlplan emits the
expected JSON. 71/71 tests passing.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Child namespace has implicit access to the parent — and the using was placed after the namespace declaration, which is unusual style. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…275) * Add rule 38 for standard edition limitation on batch mode when dop=2 * Changes Made 1. Fix Rule 38 edge case (PlanAnalyzer.cs) • Introduced editionKnown variable: !string.IsNullOrEmpty(serverMetadata?.Edition) • If ServerMetadata is non-null but Edition is null/empty (collection failure), the Info branch now fires instead of silently skipping 2. Wire RunLiveAsync(FileInfo?, string, string?, string?, DirectoryInfo?, bool, string?, bool, int, string, bool, bool, ICredentialService?, string?, string?, AnalyzerConfig) (AnalyzeCommand.cs) • Fetches ServerMetadata via FetchServerMetadataAsync(string, bool, CancellationToken) after connection is established • Passes it to PlanAnalyzer.Analyze(plan, analyzerConfig, serverMetadata) • Non-fatal try/catch so analysis continues if metadata collection fails 3. Wire RunAsync(FileInfo?, bool, string, bool, bool, AnalyzerConfig) (QueryStoreCommand.cs) • Same pattern: fetches metadata once before the plan analysis loop • Reuses it for all plans in the batch (same server) 4. Wire McpQueryStoreTools (McpQueryStoreTools.cs) • Fetches metadata before the LINQ Select that parses plans • Passes via named parameter serverMetadata: serverMetadata 5. PlanTestHelper overload (PlanTestHelper.cs) • Added LoadAndAnalyze(string planFileName, ServerMetadata? serverMetadata) overload • Original overload delegates to the new one with null 6. Unit tests (PlanAnalyzerTests.cs) — 4 tests: • Standard + DOP=2 + batch + MAXDOP>2 → Warning ✅ • Standard + DOP=2 + batch + MAXDOP=2 → no warning ✅ • No metadata + DOP=2 + batch → Info ✅ • Metadata with null Edition + DOP=2 + batch → Info ✅ (edge case fix)
* PlanViewerControl.axaml.cs — Added:
• A "minimap" toggle button (top-left, always visible over the plan canvas, very small)
• A minimap panel (300×300 default, with close button "✕", header bar, and a Canvas for rendering)
PlanViewerControl.axaml.cs — Added:
1. State fields: Static _minimapWidth/_minimapHeight (preserved in memory across plans, not on disk), drag/resize state, node mapping for minimap interaction
2. Toggle/Open/Close: MinimapToggle_Click(object?, RoutedEventArgs), OpenMinimapPanel(), CloseMinimapPanel()
3. Rendering (RenderMinimap()):
• Branch areas: Each child subtree of the root gets a transparent colored rectangle (8 distinct colors cycling) behind its nodes
• Edges: Scaled-down elbow connectors
• Nodes: Small colored rectangles (red tint for expensive nodes)
• Viewport box: Semi-transparent blue rectangle showing the visible portion of the plan
4. Interaction:
• Click & drag on minimap to pan the plan viewer
• Single click on a node centers the plan viewer on that node
• Double click on a node zooms to ~1/3 viewport size and selects the node
• Resize grip (bottom-right corner) allows resizing between 200×200 and 500×500
5. Live updates: Viewport box updates on scroll, zoom, pan, and mouse wheel zoom. Minimap re-renders on statement change.
6. Per-plan: Each PlanViewerControl instance has its own minimap state, so multiple open plans each have their own minimap.
* 1. Minimap border: Increased from 1 to 2 px thickness
2. Resize grip: Moved from the canvas (where it got destroyed on every re-render) to a permanent AXAML element — a Border with 3 diagonal lines in the bottom-right corner indicating resizability, wired to the existing resize handlers in the constructor
3. Node borders: Changed from EdgeBrush (dark grey #6B7280) to a new MinimapNodeBorderBrush (#A0A4AB — light grey)
4. Node content: Each minimap node now shows its operator icon (scaled to fit, ~70% of the node size, max 16px)
5. Default size: Changed from 300×300 to 400×400
* 1. Minimap border now matches the tooltip/popup style: background #1A1D23, border #3A3D45, 5px thickness, same for header and canvas background
2. Selected node highlighting: When a node is selected in the plan viewer, the corresponding minimap node gets a blue selection border (SelectionBrush, 2px). The highlight persists through minimap re-renders and resets when a different node is selected.
3. Proportional edge thickness: Minimap edges now use the same logarithmic row-count formula as the plan viewer (Math.Log(rows) capped at 2–12), scaled down by the minimap scale factor, with a minimum of 0.5px.
* remove hardcoded colors
* Fixes
Fixes:
1 _selectedNode cleared Added _selectedNode = null in both Clear() and RenderStatement()
2 Dead field removed Removed _minimapDragStart field and its assignment
3 Handlers wired once Moved MinimapCanvas.PointerPressed/Moved/Released subscriptions to constructor, removed per-render -=/+= cycle
4 Unused constant removed Removed MinimapDefaultSize
5 Guard added RenderMinimap() now returns early with if (!MinimapPanel.IsVisible) return; before doing any work
6 Correct brush restored Deselect now uses _minimapNodeBorderBrushCache (matches creation brush) instead of FindBrushResource("BorderBrush")
7 Branch colors extracted Moved to static readonly Color[] MinimapBranchColors field — no allocation per render
8 Node border brush cached Computed once per render cycle in RenderMinimap() and stored in _minimapNodeBorderBrushCache, reused for all non-expensive nodes
* reverse bug fix (to do in another PR)
* Replace the Parent!.Parent! pattern with an x:Name-resolved field on the outer Grid.
* Hoisted the expensive-node background brush to static readonly MinimapExpensiveNodeBgBrush — no more per-node allocation in the render loop.
* align to main
Cleanup of cosmetic regression from #276: tabs were left on 3 lines around ShowError that don't match the surrounding 4-space-indented file. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rious dirty state (#284) - Show "Keyword Casing" instead of "KeywordCasing" in the Parameter column - Row setters were firing PropertyChanged unconditionally; TwoWay bindings on ToggleSwitch / ComboBox write the bound value back during DataGrid row materialization (post-virtualization), tripping the dirty flag without any user action. Setters now compare and short-circuit when the value is unchanged. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…r Parallelism subtypes (#285) Columnstore: PhysicalOp surfaces as "Clustered Index Scan" / "Index Scan" / "Columnstore Index Scan" with Storage="ColumnStore" on the Object element. The mapper previously only inspected PhysicalOp, leaving the columnstore_* icons unused. PlanIconMapper.GetIconName now takes an optional storageType and routes to the columnstore variant when Storage="ColumnStore". Covers both clustered (CCI) and nonclustered (NCCI) columnstore for scan, delete, insert, update, and merge. Parallelism (Repartition / Distribute / Gather Streams): all three share PhysicalOp="Parallelism" and the same parallelism.png icon. Following the overlay approach used by microsoft/vscode-mssql, render a small R/D/G glyph in the bottom-right corner of the icon to distinguish them at a glance. LogicalOp determines the letter; non-parallelism nodes get no overlay. Closes #283. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
FetchTopPlansAsync applied user filters (--query-id, --plan-id, --query-hash, --query-plan-hash, --module) only in Phase 4, AFTER Phase 3 had already selected TOP N plans by CPU across the entire database. If the user's target query wasn't in the top N by CPU during the time window, it was cut from #top_plans before the filter ever ran — even though Query Store / SSMS / sp_QuickieStore could see it fine. Move the filter into Phase 3's CTE so TOP N is selected from the filtered universe. Conditionally JOIN sys.query_store_query when the filter touches query_hash or object_id (otherwise the join is skipped to avoid penalty in the unfiltered path). Phase 4 filter clause is now redundant and removed. The hash-tree and module-tree methods (FetchByQueryHashTree, FetchByPlanHashTree) already applied filters pre-TOP-N — they're unaffected. Closes #286. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the temporary letter-overlay approach with three real icons contributed by @rferraton (MIT-licensed for the repo): repartition_streams, distribute_streams, and gather_streams (the latter is a horizontal mirror of distribute, which matches SSMS's convention). PlanIconMapper.GetIconName now also takes LogicalOp so the three Parallelism subtypes route to their own icon. The overlay rendering and GetParallelismGlyph helper in PlanViewerControl are removed. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* AppSettings (AppSettingsService.cs) • Added AccuracyRatioDivergenceLimit property (default: 10), persisted as "accuracy_ratio_divergence_limit" in the JSON settings file. PlanViewerControl (PlanViewerControl.axaml.cs) • 6 new link color brushes for dark theme: • Underestimated (more actual than estimated): Blue → Light Blue → Fluo Blue • Overestimated (fewer actual than estimated): Light Orange → Fluo Orange → Fluo Red • GetLinkColorBrush(PlanNode, double) method — maps accuracy ratio to a color band: • [0, 1/(limit×100)) → Fluo Blue • [1/(limit×100), 1/(limit×10)) → Light Blue • [1/(limit×10), 1/limit) → Blue • [1/limit, limit] → Default edge color (neutral) • (limit, limit×10) → Light Orange • [limit×10, limit×100) → Fluo Orange • [limit×100, +∞) → Fluo Red • CreateElbowConnector(PlanNode, PlanNode) now uses GetLinkColorBrush(PlanNode, double) instead of the static EdgeBrush, but only colors links differently for actual plans (estimated plans keep the default). * minimap colored links * Internal Code review and some fixes * AppSettingsService.Load().AccuracyRatioDivergenceLimit is no more done per node but only once
* Update README.md: enhance Query Store section and add minimap feature description with screenshots * Update README.md: add minimap feature for navigation and color-coded links for operator accuracy in the features list Co-authored-by: Copilot <copilot@github.com> * typo --------- Co-authored-by: Copilot <copilot@github.com>
Highlights since v1.8.0: - Minimap for plan navigation (#276) - Colored links by accuracy ratio divergence (#289) - Distinct parallelism subtype icons (#285, #288) - Query Store filter ordering fix (#287) - xunit v2 -> v3 migration (#278) - SqlClient 6 -> 7, ScriptDom 170 -> 180 (#279) - System.CommandLine GA (#280) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Release merge from
devtomain. 14 PRs since v1.8.0.Features
Fixes
Maintenance
using PlanViewer.Cli;in two CLI command files (Drop redundant using in CLI command files #281)Docs
Test plan
devdotnet build -c Releasecleandotnet testpassesv1.9.0after merge