Unsized varchar output parameters change capacity on command reuse, causing history-dependent truncation
维护者通常 2 天内回复
还没有人认领这个 Issue。
评估
调研方向
Start with the value-based Size inference in src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs and declaration sizing in SqlCommand.cs around lines 2208–2255. Trace how an output parameter's previous value affects the next unprepared execution, then add or locate tests for repeated executions with short, empty, and longer outputs. Done means capacity does not shrink unexpectedly, or the requirement for explicit Size is enforced or documented.
由索引模型根据 Issue 内容生成。
描述
Describe the bug
Reusing an unprepared text command with an unsized VarChar output parameter can silently change its capacity based on the previous execution's result.
A short output reduces the inferred capacity for the next execution, potentially truncating a longer result. An empty output triggers the default 8,000-byte declaration, increasing capacity again. Consequently, the same source value can be returned completely or truncated depending on what a previous execution returned.
This report concerns the existing value-based output-size inference behavior, not a proposed change to input parameter sizing.
Exception message: N/A; the concern is silent truncation.
Stack trace: N/A.
To reproduce
Create a console application referencing Microsoft.Data.SqlClient. Set SQLCLIENT_REPRO_CONNECTION_STRING directly in your environment to a connection string for a database whose default collation is UTF-8. Do not call Prepare().
using System;
using System.Data;
using System.Text;
using Microsoft.Data.SqlClient;
string connectionString =
Environment.GetEnvironmentVariable("SQLCLIENT_REPRO_CONNECTION_STRING")
?? throw new InvalidOperationException(
"Set SQLCLIENT_REPRO_CONNECTION_STRING to a UTF-8 database connection string.");
using var connection = new SqlConnection(connectionString);
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = "SET @output = @source;";
var source = command.Parameters.Add("@source", SqlDbType.NVarChar, -1);
var output = command.Parameters.Add("@output", SqlDbType.VarChar);
output.Direction = ParameterDirection.Output;
// Leave Size unset; the initial value provides inferred capacity.
output.Value = "abcdefgh";
string shortValue = new('\u00e9', 2);
string longValue = new('\u00e9', 4);
int execution = 0;
foreach (string value in new[]
{
shortValue,
longValue,
"",
longValue,
shortValue,
longValue
})
{
source.Value = value;
command.ExecuteNonQuery();
string result = (string)output.Value;
Console.WriteLine(
$"Execution={++execution}, requested characters={value.Length}, " +
$"returned characters={result.Length}, " +
$"returned bytes={Encoding.UTF8.GetByteCount(result)}");
}
The following sequence is predicted by the existing declaration-sizing code. Each é occupies two UTF-8 bytes:
| Execution | Requested value | Inferred SQL capacity | Returned value |
|---|---|---|---|
| 1 | éé |
varchar(8), from initial ASCII value |
éé |
| 2 | éééé |
varchar(4), from previous output |
éé — truncated |
| 3 | Empty string | varchar(4) |
Empty string |
| 4 | éééé |
varchar(8000), from empty-value fallback |
éééé — complete |
| 5 | éé |
varchar(8), from previous output |
éé |
| 6 | éééé |
varchar(4), from previous output |
éé — truncated |
Executions 2, 4, and 6 request the same value but return different results because preceding outputs changed the parameter's capacity. This is not limited to multibyte text: varying ASCII output lengths can produce the same history-dependent behavior.
Expected behavior
Once an output parameter has been accepted with an inferred capacity, returning a shorter value should not silently reduce that capacity for subsequent executions.
If output parameters require explicit capacity for reliable reuse, that requirement should be enforced or clearly documented rather than allowing previous results to redefine it.
Further technical details
Microsoft.Data.SqlClient version: No specific released version has yet been confirmed by executing the complete reproduction. Source analysis used the existing implementation at commit 0666194d36d26c140ded15b2f768e7ba9411a970.
.NET target: The complete console reproduction has not yet been executed. .NET SDK 10.0.403 is available in the investigation environment.
SQL Server version: SQL Server 17.0.1145.4 was used for focused server-contract probes of UTF-8 truncation. The complete reproduction requires a database with a UTF-8 default collation.
Operating system: Windows.
Additional context
With Size unset, SqlParameter.Size derives its value from the current Value, which contains the previous output. For ANSI text, the existing declaration builder expands that inferred character count to the previous value's encoded byte length. The resulting SQL declaration constrains assignments inside the next batch.
This makes output capacity depend on execution history. A previous output is not input to an output-only parameter, but it nevertheless influences the next batch's behavior through its declaration.
Relevant source:
Verification status: This report is based on source analysis and focused SQL Server probes confirming multibyte truncation at smaller byte capacities. The complete repeated-command reproduction has not yet been executed against Microsoft.Data.SqlClient; the sequence above is not presented as captured application output.
Workaround: Set an explicit output Size large enough for the expected encoded data, or use Size = -1 where MAX output is appropriate.
- 主要语言
- C#
- 星标
- 1k
- 派生
- 352
- 平均合并
- 4 天 12 小时
- 30 天内合并 PR
- 86
环境准备
在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
dotnet/SqlClient 的其他 Issue
-
Sync ExecuteReader on an STA thread deadlocks against a StateChange handler that marshals to the UI thread (OpenAsyncRetry path)可能重新可做 @mdaigle 于 43 天前认领,目前没有进行中的 PR。 未关闭External :link:
难度 2/5 1-3 小时 新手友好度 64/100
dotnet/SqlClient#4534 · 2 条评论 · 已指派 1 人 ·
维护者通常 2 天内回复
-
Area\Tests
难度 2/5 1-3 小时 新手友好度 68/100
dotnet/SqlClient#4377 · 2 条评论 ·
维护者通常 2 天内回复
-
难度 4/5 3-5 天 新手友好度 62/100
dotnet/SqlClient#4957 · 2 条评论 ·
维护者通常 2 天内回复
-
Approval Needed Code Health :pill: Common Project 🚮 Design Review Needed Up-for-Grabs :raised_hands:
难度 5/5 一周以上 新手友好度 25/100
dotnet/SqlClient#4940 · 1 条评论 · 1 个 reaction ·
维护者通常 2 天内回复
-
Code Health :pill: Up-for-Grabs :raised_hands:
难度 5/5 一周以上 新手友好度 25/100
dotnet/SqlClient#4937 · 1 条评论 ·
维护者通常 2 天内回复
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 85/100
维护者通常 1 天内回复
-
bug effort:S P3
难度 2/5 1-3 小时 新手友好度 72/100
nightscout/nocturne#3219 ·
维护者通常 1 天内回复
-
good first issue
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 1 天内回复
-
bug P2
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
难度 1/5 1 小时以内 新手友好度 85/100
维护者通常 1 天内回复