Skip to content

Commit

Permalink
Clean up PR dotnet#18438 and add some tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bricelam committed Feb 20, 2020
1 parent d72f8f9 commit dcf2776
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 14 deletions.
15 changes: 15 additions & 0 deletions src/Microsoft.Data.Sqlite.Core/SqliteDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,21 @@ public override Stream GetStream(int ordinal)
? throw new InvalidOperationException(Resources.NoData)
: _record.GetStream(ordinal);

/// <summary>
/// Retrieves data as a <see cref="TextReader" />.
/// </summary>
/// <param name="ordinal">The zero-based column ordinal.</param>
/// <returns>The returned object.</returns>
public override TextReader GetTextReader(int ordinal)
{
if (IsDBNull(ordinal))
{
return new StringReader(string.Empty);
}

return new StreamReader(GetStream(ordinal), Encoding.UTF8);
}

/// <summary>
/// Gets the value of the specified column.
/// </summary>
Expand Down
29 changes: 15 additions & 14 deletions src/Microsoft.Data.Sqlite.Core/SqliteDataRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,32 +197,33 @@ public static Type GetFieldType(string type)

public virtual long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
{
var blob = GetStream(ordinal);
using var stream = GetStream(ordinal);

long bytesToRead = blob.Length - dataOffset;
if (buffer != null)
if (buffer == null)
{
bytesToRead = Math.Min(bytesToRead, length);
using (var binaryReader = new BinaryReader(blob))
{
Array.Copy(binaryReader.ReadBytes((int)blob.Length), dataOffset, buffer, bufferOffset, bytesToRead);
}
return stream.Length - dataOffset;
}

return bytesToRead;
stream.Position = dataOffset;

return stream.Read(buffer, bufferOffset, length);
}

public virtual long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length)
{
var textStream = GetStream(ordinal);
long charsToRead = textStream.Length - dataOffset;
using var stream = GetStream(ordinal);
using var reader = new StreamReader(stream, Encoding.UTF8);

using (var streamReader = new StreamReader(textStream, Encoding.UTF8))
for (var position = 0; position < dataOffset; position++)
{
Array.Copy(streamReader.ReadToEnd().ToCharArray(), dataOffset, buffer, bufferOffset, Math.Min(charsToRead, length));
if (reader.Read() == -1)
{
// NB: Message is provided by the framework
throw new ArgumentOutOfRangeException(nameof(dataOffset), dataOffset, message: null);
}
}

return charsToRead;
return reader.Read(buffer, bufferOffset, length);
}

public virtual Stream GetStream(int ordinal)
Expand Down
121 changes: 121 additions & 0 deletions test/Microsoft.Data.Sqlite.Tests/SqliteDataReaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,27 @@ public void GetBytes_works()
}
}

[Fact]
public void GetBytes_works_streaming()
{
using (var connection = new SqliteConnection("Data Source=:memory:"))
{
connection.Open();

connection.ExecuteNonQuery("CREATE TABLE Data (Value); INSERT INTO Data VALUES (x'01020304');");

using (var reader = connection.ExecuteReader("SELECT rowid, Value FROM Data;"))
{
var hasData = reader.Read();
Assert.True(hasData);

var buffer = new byte[2];
reader.GetBytes(1, 1, buffer, 0, buffer.Length);
Assert.Equal(new byte[] { 0x02, 0x03 }, buffer);
}
}
}

[Fact]
public void GetBytes_NullBuffer()
{
Expand Down Expand Up @@ -252,6 +273,26 @@ public void GetChars_works_with_overflow()
}
}

[Fact]
public void GetChars_throws_when_dataOffset_out_of_range()
{
using (var connection = new SqliteConnection("Data Source=:memory:"))
{
connection.Open();

using (var reader = connection.ExecuteReader("SELECT 'test';"))
{
var hasData = reader.Read();
Assert.True(hasData);

var buffer = new char[1];
var ex = Assert.Throws<ArgumentOutOfRangeException>(
() => reader.GetChars(0, 5, buffer, 0, buffer.Length));
Assert.Equal("dataOffset", ex.ParamName);
}
}
}

[Fact]
public void GetChars_throws_when_closed()
{
Expand All @@ -262,6 +303,27 @@ public void GetChars_throws_when_closed()
public void GetChars_throws_when_non_query()
=> X_throws_when_non_query(r => r.GetChars(0, 0, null, 0, 0));

[Fact]
public void GetChars_works_streaming()
{
using (var connection = new SqliteConnection("Data Source=:memory:"))
{
connection.Open();

connection.ExecuteNonQuery("CREATE TABLE Data (Value); INSERT INTO Data VALUES ('test');");

using (var reader = connection.ExecuteReader("SELECT rowid, Value FROM Data;"))
{
var hasData = reader.Read();
Assert.True(hasData);

var buffer = new char[2];
reader.GetChars(1, 1, buffer, 0, buffer.Length);
Assert.Equal(new[] { 'e', 's' }, buffer);
}
}
}

[Fact]
public void GetStream_works()
{
Expand Down Expand Up @@ -388,6 +450,65 @@ public void GetStream_throws_when_closed()
public void GetStream_throws_when_non_query()
=> X_throws_when_non_query(r => r.GetStream(0));

[Fact]
public void GetTextReader_works()
{
using (var connection = new SqliteConnection("Data Source=:memory:"))
{
connection.Open();

using (var reader = connection.ExecuteReader("SELECT 'test';"))
{
var hasData = reader.Read();
Assert.True(hasData);

var textReader = reader.GetTextReader(0);
Assert.IsType<MemoryStream>(Assert.IsType<StreamReader>(textReader).BaseStream);
Assert.Equal("test", textReader.ReadToEnd());
}
}
}

[Fact]
public void GetTextReader_works_when_null()
{
using (var connection = new SqliteConnection("Data Source=:memory:"))
{
connection.Open();

using (var reader = connection.ExecuteReader("SELECT NULL;"))
{
var hasData = reader.Read();
Assert.True(hasData);

var textReader = reader.GetTextReader(0);
Assert.IsType<StringReader>(textReader);
Assert.Empty(textReader.ReadToEnd());
}
}
}

[Fact]
public void GetTextReader_works_streaming()
{
using (var connection = new SqliteConnection("Data Source=:memory:"))
{
connection.Open();

connection.ExecuteNonQuery("CREATE TABLE Data (Value); INSERT INTO Data VALUES ('test');");

using (var reader = connection.ExecuteReader("SELECT rowid, Value FROM Data;"))
{
var hasData = reader.Read();
Assert.True(hasData);

var textReader = reader.GetTextReader(1);
Assert.IsType<SqliteBlob>(Assert.IsType<StreamReader>(textReader).BaseStream);
Assert.Equal("test", textReader.ReadToEnd());
}
}
}

[Fact]
public void GetDateTime_works_with_text()
=> GetX_works(
Expand Down

0 comments on commit dcf2776

Please sign in to comment.