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
Offer to put parameter values back when copying a statement out of a plan #467
Out of #466, where @joshdbe copied a statement out of a plan and got @0, @1 … @6 where his literals had been.
That text is correct — it is what SQL Server compiled, because the database has PARAMETERIZATION FORCED — but it is not what anyone wants on the clipboard. You copy a statement out of a plan to run it, and a query full of undeclared @0 will not run.
The values are right there
Forced parameterization keeps every literal in the plan's ParameterList, with both compiled and runtime values. From a local repro of #466:
ShowParameters already parses and displays all of this. Nothing new needs reading — the substitution just is not offered anywhere.
What to add
On the statement context menu, alongside the existing Copy Query Text and Open in Query Editor, a variant that puts the parameter values back:
Substitute ParameterRuntimeValue where present, falling back to ParameterCompiledValue. Values arrive pre-quoted ('123456', (5)) — the parens on numerics need stripping, the quotes on strings do not.
Match on whole tokens. @1 must not match inside @11, and a @0 inside a string literal must be left alone.
Only offer it when the statement actually has parameters. A statement with none should not grow a dead menu item.
Worth considering whether this should be the default behavior of the existing two items rather than a third and fourth item, with the raw form as the variant. The parameterized text is the honest record of what was compiled, but the substituted text is what people want to run, and a context menu with four near-identical entries is its own problem.
This is equally useful for procedure parameters and sp_executesql, not just forced parameterization — any plan whose statement text carries @name and whose ParameterList carries the value.
Note for whoever picks this up
Do not reach for the query editor's buffer as the source of truth. It only holds the original text in the one case where the user just executed it from that tab, and it is wrong for a plan opened from a file, from Query Store, or from another session.
Copy Query Text and Open in Query Editor now put the plan's captured parameter values back into the statement before handing it over — runtime values first, compiled as the fallback — so what lands on your clipboard actually runs. The labels say (with values) whenever that happened, and a Copy Query Text (as parameterized) entry appears alongside for the times you want the exact text that matches the plan cache and Query Store. When the plan carries no values, nothing changes and no extra entries appear.
Grid Ctrl+C produces the same text as the menu entry, because handing those two different statements would just be a new bug report.
Works for anything whose ParameterList carries values — forced parameterization, stored procedure parameters, sp_executesql — and invents nothing for parameters the plan didn't capture (OPTION(RECOMPILE) plans keep their bare names, visibly).
@joshdbe this is yours from #466 — next nightly off dev will have it.
Good catch, and it's the same mistake twice in one day — #447 was me fixing one consumer and leaving the others, and so was this.
Both advice buttons come out of AnalysisResult: Humans through TextFormatter, Robots through the JSON serializer, and both take their text from ResultMapper. #467 substituted at the clipboard and the editor because that's where you'd reported it, and never followed the value down to where the analysis is built.
Same seam feeds a few things you haven't hit yet — the HTML export, plan comparison output, and the MCP tools. That last one is the one that bothers me: handing a model @0 with no values is handing it a question it can't answer.
Tracking it in #482, which is where the fix will land. There's one thing to establish before changing it — whether anything matches statements by their text, since substituting values into two runs of the same query with different parameters could stop them pairing up. That would be a worse bug than the one you reported, so it gets checked before anything moves.
Thanks for going back and testing the rest of it rather than stopping at the part that worked.
Fixed on dev in #483, tracked in #482 — @joshdbe, tonight's nightly will have it.
Advice for Humans, Advice for Robots, the HTML export, the comparison report and the MCP tools all get the values now, because it's done where the analysis is built rather than at each button.
Two things it deliberately does not do, both found while fixing it. SELECT @job_name = name keeps its variable rather than becoming SELECT NULL = name, which would read as a comparison — assignment targets are left alone. And the repro-script tool still gets the parameterized text, because it wraps the statement in sp_executesql with a parameter list from the same plan; handing it inlined literals would declare parameters that appear nowhere in the body.
Same ask as before: tell me if it's right rather than me telling you it is.
Activity
Put parameter values back when copying a statement out of a plan (#467)…
erikdarlingdata commentedon Sep 1, 2026
Merged to
devin #470.Copy Query Text and Open in Query Editor now put the plan's captured parameter values back into the statement before handing it over — runtime values first, compiled as the fallback — so what lands on your clipboard actually runs. The labels say (with values) whenever that happened, and a Copy Query Text (as parameterized) entry appears alongside for the times you want the exact text that matches the plan cache and Query Store. When the plan carries no values, nothing changes and no extra entries appear.
Grid Ctrl+C produces the same text as the menu entry, because handing those two different statements would just be a new bug report.
Works for anything whose ParameterList carries values — forced parameterization, stored procedure parameters,
sp_executesql— and invents nothing for parameters the plan didn't capture (OPTION(RECOMPILE)plans keep their bare names, visibly).@joshdbe this is yours from #466 — next nightly off
devwill have it.joshdbe commentedon Sep 2, 2026
Shows actual values in Copy/Paste and query editor. Still shows parametrized in Human and Robot Advice
erikdarlingdata commentedon Sep 2, 2026
Good catch, and it's the same mistake twice in one day — #447 was me fixing one consumer and leaving the others, and so was this.
Both advice buttons come out of
AnalysisResult: Humans throughTextFormatter, Robots through the JSON serializer, and both take their text fromResultMapper. #467 substituted at the clipboard and the editor because that's where you'd reported it, and never followed the value down to where the analysis is built.Same seam feeds a few things you haven't hit yet — the HTML export, plan comparison output, and the MCP tools. That last one is the one that bothers me: handing a model
@0with no values is handing it a question it can't answer.Tracking it in #482, which is where the fix will land. There's one thing to establish before changing it — whether anything matches statements by their text, since substituting values into two runs of the same query with different parameters could stop them pairing up. That would be a worse bug than the one you reported, so it gets checked before anything moves.
Thanks for going back and testing the rest of it rather than stopping at the part that worked.
Put the parameter values back where the analysis is built, not at two…
erikdarlingdata commentedon Sep 2, 2026
Fixed on
devin #483, tracked in #482 — @joshdbe, tonight's nightly will have it.Advice for Humans, Advice for Robots, the HTML export, the comparison report and the MCP tools all get the values now, because it's done where the analysis is built rather than at each button.
Two things it deliberately does not do, both found while fixing it.
SELECT @job_name = namekeeps its variable rather than becomingSELECT NULL = name, which would read as a comparison — assignment targets are left alone. And the repro-script tool still gets the parameterized text, because it wraps the statement insp_executesqlwith a parameter list from the same plan; handing it inlined literals would declare parameters that appear nowhere in the body.Same ask as before: tell me if it's right rather than me telling you it is.
Count statements the way the grid counts, and leave the parameterized…