Skip to content

Commit

Permalink
Read blob from data chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
Giorgi committed Sep 6, 2023
1 parent ec81162 commit 7932f5a
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 32 deletions.
14 changes: 10 additions & 4 deletions DuckDB.NET.Data/DuckDBDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,7 @@ public override string GetString(int ordinal)
return null;
}

var data = NativeMethods.DataChunks.DuckDBVectorGetData(vectors[ordinal]);
data += currentRow * Marshal.SizeOf<DuckDBString>();
var data = NativeMethods.DataChunks.DuckDBVectorGetData(vectors[ordinal]) + currentRow * Marshal.SizeOf<DuckDBString>();

var length = Marshal.ReadInt32(data);

Expand Down Expand Up @@ -310,8 +309,15 @@ public override int GetValues(object[] values)

public override Stream GetStream(int ordinal)
{
var blob = NativeMethods.Types.DuckDBValueBlob(currentResult, ordinal, currentRow);
return new DuckDBStream(blob);
var data = NativeMethods.DataChunks.DuckDBVectorGetData(vectors[ordinal]) + currentRow * Marshal.SizeOf<DuckDBString>();

var length = Marshal.ReadInt32(data);

var blobPointer = length <= InlineStringMaxLength
? data + Marshal.SizeOf<int>()
: Marshal.ReadIntPtr(data + Marshal.SizeOf<int>() * 2);

return new DuckDBStream(blobPointer, length);
}

public override bool IsDBNull(int ordinal)
Expand Down
13 changes: 7 additions & 6 deletions DuckDB.NET.Data/DuckDBStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ namespace DuckDB.NET.Data;

class DuckDBStream : Stream
{
private readonly IntPtr data;

private long position;
private readonly DuckDBBlob blob;

public DuckDBStream(DuckDBBlob blob)
public DuckDBStream(IntPtr data, long length)
{
this.blob = blob;
this.data = data;
Length = length;
}

public override void Flush()
Expand All @@ -27,7 +29,7 @@ public override int Read(byte[] buffer, int offset, int count)
{
unchecked
{
var source = position <= int.MaxValue ? IntPtr.Add(blob.Data, (int)position) : new IntPtr(blob.Data.ToInt64() + position);
var source = position <= int.MaxValue ? IntPtr.Add(data, (int)position) : new IntPtr(data.ToInt64() + position);

Marshal.Copy(source, buffer, offset, bytesToRead);

Expand Down Expand Up @@ -73,7 +75,7 @@ public override void Write(byte[] buffer, int offset, int count)
public override bool CanSeek => true;
public override bool CanWrite => false;

public override long Length => blob.Size;
public override long Length { get; }

public override long Position
{
Expand All @@ -83,6 +85,5 @@ public override long Position

public override void Close()
{
blob.Dispose();
}
}
42 changes: 20 additions & 22 deletions DuckDB.NET.Test/Parameters/BlobParameterTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Numerics;
using DuckDB.NET.Data;
using FluentAssertions;
using Xunit;
Expand Down Expand Up @@ -63,39 +62,38 @@ public void SeekTest()
connection.Open();

var command = connection.CreateCommand();
command.CommandText = "SELECT 'ABCDEFGH'::BLOB;";
var blobValue = "ABCDEFGHIJKLMNOPQR";
command.CommandText = $"SELECT '{blobValue}'::BLOB;";
command.ExecuteNonQuery();

var reader = command.ExecuteReader();
reader.Read();

using (var stream = reader.GetStream(0))
using var stream = reader.GetStream(0);
stream.CanSeek.Should().Be(true);
using (var streamReader = new StreamReader(stream, leaveOpen: true))
{
stream.CanSeek.Should().Be(true);
using (var streamReader = new StreamReader(stream, leaveOpen: true))
{
stream.Seek(2, SeekOrigin.Begin);
var text = streamReader.ReadToEnd();
text.Should().Be("CDEFGH");
stream.Seek(2, SeekOrigin.Begin);
var text = streamReader.ReadToEnd();
text.Should().Be(blobValue.Substring(2));

stream.Seek(-4, SeekOrigin.End);
streamReader.ReadLine().Should().Be("EFGH");
stream.Seek(-4, SeekOrigin.End);
streamReader.ReadLine().Should().Be(blobValue[^4..]);

stream.Seek(-4, SeekOrigin.End);
stream.Seek(2, SeekOrigin.Current);
stream.Seek(-4, SeekOrigin.End);
stream.Seek(2, SeekOrigin.Current);

streamReader.ReadLine().Should().Be("GH");
streamReader.ReadLine().Should().Be(blobValue[^4..][^4..][2..]);

stream.Position = 7;
streamReader.ReadLine().Should().Be("H");
stream.Position = 7;
streamReader.ReadLine().Should().Be(blobValue[7..]);

stream.Seek(0, SeekOrigin.Begin).Should().Be(0);
stream.Seek(0, SeekOrigin.End).Should().Be(stream.Length);
stream.Position = 5;
stream.Seek(0, SeekOrigin.Current).Should().Be(stream.Position);
stream.Seek(0, SeekOrigin.Begin).Should().Be(0);
stream.Seek(0, SeekOrigin.End).Should().Be(stream.Length);
stream.Position = 5;
stream.Seek(0, SeekOrigin.Current).Should().Be(stream.Position);

stream.Invoking(s => s.Seek(stream.Length+1, SeekOrigin.Current)).Should().Throw<InvalidOperationException>();
}
stream.Invoking(s => s.Seek(stream.Length+1, SeekOrigin.Current)).Should().Throw<InvalidOperationException>();
}
}

Expand Down

0 comments on commit 7932f5a

Please sign in to comment.