Skip to content

Commit 97be747

Browse files
authored
Fix sequential text reader bug and add covering test (#3383)
* fix sequential text reader bug and add covering test * remove additional parens * review feedback
1 parent cc23e04 commit 97be747

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlSequentialTextReader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public override Task<int> ReadAsync(char[] buffer, int index, int count)
172172
byte[] byteBuffer = PrepareByteBuffer(charsNeeded, out int byteBufferUsed);
173173

174174
// Permit a 0 byte read in order to advance the reader to the correct column
175-
if ((byteBufferUsed < byteBuffer.Length) || (byteBuffer.Length == 0))
175+
if (byteBufferUsed <= byteBuffer.Length || byteBuffer.Length == 0)
176176
{
177177
SqlDataReader reader = _reader;
178178
if (reader != null)

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderTest.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,60 @@ integrated into a comprehensive development
605605
}
606606
}
607607

608+
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
609+
public static async Task CanReadSequentialDecreasingChunks()
610+
{
611+
// pattern repeat input allows you to more easily identify if chunks are incorrectly
612+
// related to each other by seeing the start and end of sequential chunks and checking
613+
// if they correctly move to the next char while debugging
614+
// simply repeating a single char can't tell you where in the string it went wrong.
615+
const string baseString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
616+
StringBuilder inputBuilder = new StringBuilder();
617+
while (inputBuilder.Length < (64 * 1024))
618+
{
619+
inputBuilder.Append(baseString);
620+
inputBuilder.Append(' ');
621+
}
622+
623+
string input = inputBuilder.ToString();
624+
625+
StringBuilder resultBuilder = new StringBuilder();
626+
CancellationTokenSource cts = new CancellationTokenSource();
627+
using (var connection = new SqlConnection(DataTestUtility.TCPConnectionString))
628+
{
629+
await connection.OpenAsync(cts.Token);
630+
631+
using (var command = connection.CreateCommand())
632+
{
633+
command.CommandText = "SELECT CONVERT(varchar(max),@str) as a";
634+
command.Parameters.AddWithValue("@str", input);
635+
636+
using (var reader = await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess, cts.Token))
637+
{
638+
if (await reader.ReadAsync(cts.Token))
639+
{
640+
using (var textReader = reader.GetTextReader(0))
641+
{
642+
var buffer = new char[4096];
643+
var charsReadCount = -1;
644+
var start = 0;
645+
while (charsReadCount != 0)
646+
{
647+
charsReadCount = await textReader.ReadAsync(buffer, start, buffer.Length - start);
648+
resultBuilder.Append(buffer, start, charsReadCount);
649+
start++;
650+
}
651+
}
652+
}
653+
}
654+
}
655+
}
656+
657+
string result = resultBuilder.ToString();
658+
659+
Assert.Equal(input, result);
660+
}
661+
608662
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
609663
public static async Task CanReadBinaryData()
610664
{

0 commit comments

Comments
 (0)