Repro script: keep @0/@1 parameters, check data types by shape (#590) - #592
Merged
Merged
Conversation
Simple and forced parameterization name their parameters @0, @1, ..., and IsValidParameterName required a letter after the @. Those parameters were dropped, so the script ran the statement without declaring them and failed with "Must declare the scalar variable". - IsValidParameterName allows a digit after the @. - The name, type and literal checks use \A...\z instead of ^...$, because $ also matches before a final line break. - IsValidDataType checks the shape of the type (1-3 dot-separated names, then an optional (n), (max), (p,s) or (n,name) suffix) instead of a character list. Same idea as PerformanceMonitor#4567, but it also keeps vector(3,float16), which SQL Server 2025 writes into plans, and it allows only plain spaces, not line breaks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR
- A batch's plan lists each statement's parameters, so a name can appear more than once. Keeping @0/@1 made that common: each auto-parameterized statement numbers its own, and the script declared @1 twice and failed with Msg 134. A parameter that several statements use (for example a shared @id) had the same problem before #590. - Each name is now declared once. - A name that the statements give different types is left out with a warning. Those statements are usually literal text that doesn't use it. - The type check's numbers and the compiled-value check use [0-9], not \d, which also matches other scripts' digits. (max) takes no second part. - Tests for both multi-statement cases, the digit checks, and the omitted warning for a hostile name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR
Review round 2 for #590. A parameter listed by several statements now takes the first compiled value that can go into the script, not the first entry, so a statement compiled without sniffing no longer sets it to ?. When the statements disagree, the script uses the first usable value and says so. When every parameter is left out, the script says to see the warnings instead of claiming the plan cache had none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR
|
Reviewed (post-merge). Traced the three regex changes against the untrusted-plan-XML threat model:
No correctness or injection issues found. One non-blocking observation: |
This was referenced Sep 28, 2026
Merged
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.
What does this PR do?
Fixes #590.
The repro script for an auto-parameterized plan failed with
Must declare the scalar variable "@1". SQL Server names the parameters of simple and forced parameterization@0,@1, and so on.IsValidParameterNamerequired a letter after the@, so it dropped those parameters. The script then ran the statement without declaring them.The changes, all in
ReproScriptBuilder.cs:IsValidParameterNameallows a digit right after the@.\Aand\zinstead of^and$. In .NET,$also matches before a final line break, so a name like"@x\n"passed.IsValidDataTypechecks the shape of the type, not only its characters. A type is one to three names separated by dots, each plain or in brackets. An optional(n),(max),(p,s)or(n,name)can follow. A type with anything else, such asint) SELECT 2, is dropped with the existing warning. Before, it went into the script, and SQL Server refused the declaration.@0and@1made that common, because each auto-parameterized statement numbers its own. A batch of two such statements then declared@1twice, and the script failed withThe variable name '@1' has already been declared.@id, had the same failure before this PR.@1 smallintand@1 tinyint, is left out with a warning. Those statements are usually literal text that does not use the name, so the script runs the batch as it is.\dalso matches digits from other scripts, which T-SQL does not read as numbers.This is the same idea as erikdarlingdata/PerformanceMonitor#4567, with two differences:
(n,name)form keepsvector(3,float16), which SQL Server 2025 writes into plans. The pattern in PerformanceMonitor#4567 drops that parameter.GOon a line of its own.Which component(s) does this affect?
The desktop app's Copy Repro button, the MCP
get_repro_scripttool and the actual-plan runner all use the repro script.How was this tested?
ParameterDataTypefrom the cached plans:xmlparameter shows asxml.ParameterList.sys.geography,sys.hierarchyid,vector(3),vector(3,float16)andjson.@1 tinyint) and a forced-parameterization plan (@0 nvarchar(4000),@1 int).Must declare the scalar variable.vector(3,float16)parameter keeps its declaration. Its value is?with a warning, as before, because the plan writes the vector value without quotes.@1 smallintand@1 tinyintruns as literal text, with the new warning.sp_executesqlbatch that uses@idin both statements declares@idonce and runs. Before this PR, both scripts failed withMsg 134.ReproScriptBuilderSafetyTests:@0and@1are declared and assigned, and the script parses.?.varchar(max,2).@1with two types is left out with the warning.?.Review round 1
@1twice (above). The same fix covers a named parameter that two statements use.\dlet digits from other scripts into a type or a value. Both checks now use[0-9].(max)accepted a second part, as invarchar(max,2).IsValidDataTypenow says where spaces are allowed.Review round 2
?although the other statement had one. The script now uses the first value it can put in the script.No parameters found in plan cache. It now saysNo parameters declared: see the warnings above.@1with two types checks the new comment. Both new tests fail against the round-1 commit.Checklist
--no-incremental)dotnet test)🤖 Generated with Claude Code
https://claude.ai/code/session_01G625JBNh45iTR1hpT4CxNR