-
Notifications
You must be signed in to change notification settings - Fork 311
Closed
Labels
Bug! 🐛Issues that are bugs in the drivers we maintain.Issues that are bugs in the drivers we maintain.Triage Done ✔️Issues that are triaged by dev team and are in investigation.Issues that are triaged by dev team and are in investigation.
Milestone
Description
Describe the bug
I tried the new 6.1 PReview1 bits, a few of my tests failed with wrong data output, I tracked it down to sqlDataReader.GetChars apparently ignoring the buffer index. In the GetPooledChars loop below the buffer is always written at bufferIndex 0 ignoring the offset parameter. If you run the same code with 6.0.2 it works.
To reproduce
using System.Buffers;
using System.Data;
using Microsoft.Data.SqlClient;
namespace SqlRepro
{
internal class Program
{
static async Task Main(string[] args)
{
const CommandBehavior commandBehavior = CommandBehavior.SequentialAccess | CommandBehavior.SingleResult;
await using var sqlConnection = new SqlConnection("Server=localhost;Database=DatabaseTests;TrustServerCertificate=True;Trusted_Connection=True;");
await sqlConnection.OpenAsync();
const int length = 32000;
const string sqlCharWithArg = "SELECT CONVERT(BIGINT, 1) AS [Id], CONVERT(NVARCHAR(MAX), @input) AS [Value];";
var input = string.Create(length, length, (span, state) =>
{
for (int i = 0; i < state; i++)
{
span[i] = (char) Random.Shared.Next(0x30, 0x5A);
}
});
await using var sqlCommand = new SqlCommand();
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandTimeout = 0;
sqlCommand.CommandText = sqlCharWithArg;
sqlCommand.Parameters.Add(new SqlParameter("@input", SqlDbType.NVarChar, -1) {Value = input});
await using var sqlReader = await sqlCommand.ExecuteReaderAsync(commandBehavior);
var succ = await sqlReader.ReadAsync();
long id = sqlReader.GetInt64(0);
if (id != 1)
{
Console.WriteLine("Id not 1");
}
var sliced = GetPooledChars(sqlReader, 1);
if (!sliced.SequenceEqual(input.ToCharArray()))
{
Console.WriteLine("sliced != input");
}
}
private static char[] GetPooledChars(SqlDataReader sqlDataReader, int ordinal)
{
var buffer = ArrayPool<char>.Shared.Rent(8192);
int offset = 0;
while (true)
{
var read = (int) sqlDataReader.GetChars(ordinal, offset, buffer, offset, buffer.Length - offset);
// in the second iteration, the buffer is already overwritten from offset 0, bufferIndex ignored?
if (read == 0)
{
break;
}
offset += read;
if (buffer.Length - offset < 128)
{
buffer = Resize(buffer);
}
}
var sliced = buffer.AsSpan(0, offset).ToArray();
ArrayPool<char>.Shared.Return(buffer);
return sliced;
static char[] Resize(char[] buffer)
{
var newBuffer = ArrayPool<char>.Shared.Rent(buffer.Length * 2);
Array.Copy(buffer, newBuffer, buffer.Length);
ArrayPool<char>.Shared.Return(buffer);
return newBuffer;
}
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.0-preview1.25120.4" />
</ItemGroup>
</Project>
Expected behavior
Slice should be the same as input in the repro
Further technical details
Microsoft.Data.SqlClient version: 6.1.0-preview1.25120.4
.NET target: 9.0
SQL Server version: SQL Server 2022
Operating system: Windows 11
viktor-svub
Metadata
Metadata
Assignees
Labels
Bug! 🐛Issues that are bugs in the drivers we maintain.Issues that are bugs in the drivers we maintain.Triage Done ✔️Issues that are triaged by dev team and are in investigation.Issues that are triaged by dev team and are in investigation.