Skip to content

Commit bf5c1a6

Browse files
committed
Append list to appender
1 parent 338e0d3 commit bf5c1a6

File tree

6 files changed

+94
-4
lines changed

6 files changed

+94
-4
lines changed

DuckDB.NET.Bindings/DuckDBNativeObjects.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,10 @@ public void Dispose()
159159
}
160160

161161
[StructLayout(LayoutKind.Sequential)]
162-
public readonly struct DuckDBListEntry
162+
public struct DuckDBListEntry(ulong offset, ulong length)
163163
{
164-
public ulong Offset { get; }
165-
public ulong Length { get; }
164+
public ulong Offset { get; private set; } = offset;
165+
public ulong Length { get; private set; } = length;
166166
}
167167

168168
public struct DuckDBString

DuckDB.NET.Data/DuckDBAppenderRow.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using DuckDB.NET.Data.Internal.Writer;
22
using DuckDB.NET.Native;
33
using System;
4+
using System.Collections.Generic;
45
using System.Numerics;
56

67
namespace DuckDB.NET.Data;
@@ -101,6 +102,12 @@ public DuckDBAppenderRow AppendValue(TimeSpan? value)
101102

102103
#endregion
103104

105+
#region Composite Types
106+
107+
public DuckDBAppenderRow AppendValue<T>(IReadOnlyCollection<T>? value) => AppendCollectionValue(value);
108+
109+
#endregion
110+
104111
private DuckDBAppenderRow AppendValueInternal<T>(T? value)
105112
{
106113
CheckColumnAccess();
@@ -112,6 +119,17 @@ private DuckDBAppenderRow AppendValueInternal<T>(T? value)
112119
return this;
113120
}
114121

122+
private DuckDBAppenderRow AppendCollectionValue<T>(IReadOnlyCollection<T>? value)
123+
{
124+
CheckColumnAccess();
125+
126+
vectorWriters[columnIndex].AppendCollection(value, rowIndex);
127+
128+
columnIndex++;
129+
130+
return this;
131+
}
132+
115133
#if NET6_0_OR_GREATER
116134
private unsafe DuckDBAppenderRow AppendSpan(Span<byte> val)
117135
{
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using DuckDB.NET.Native;
4+
5+
namespace DuckDB.NET.Data.Internal.Writer;
6+
7+
internal sealed unsafe class ListVectorDataWriter : VectorDataWriterBase
8+
{
9+
private ulong offset = 0;
10+
private readonly VectorDataWriterBase listDataWriter;
11+
12+
public ListVectorDataWriter(IntPtr vector, void* vectorData, DuckDBType columnType, DuckDBLogicalType logicalType) : base(vector, vectorData, columnType)
13+
{
14+
using var childType = NativeMethods.LogicalType.DuckDBListTypeChildType(logicalType);
15+
var childVector = NativeMethods.Vectors.DuckDBListVectorGetChild(vector);
16+
listDataWriter = VectorDataWriterFactory.CreateWriter(childVector, childType);
17+
}
18+
19+
internal override bool AppendCollection<T>(IReadOnlyCollection<T>? value, int rowIndex)
20+
{
21+
if (value == null)
22+
{
23+
AppendNull(rowIndex);
24+
return true;
25+
}
26+
27+
var index = 0;
28+
29+
foreach (var item in value)
30+
{
31+
listDataWriter.AppendValue(item, index++);
32+
}
33+
34+
return AppendValueInternal(new DuckDBListEntry(offset, (ulong)value.Count), rowIndex);
35+
}
36+
}

DuckDB.NET.Data/Internal/Writer/VectorDataWriterBase.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
24
using System.Numerics;
35
using DuckDB.NET.Native;
46

@@ -93,6 +95,8 @@ public unsafe void AppendValue<T>(T value, int rowIndex)
9395

9496
internal virtual bool AppendBigInteger(BigInteger value, int rowIndex) => ThrowException<BigInteger>();
9597

98+
internal virtual bool AppendCollection<T>(IReadOnlyCollection<T>? value, int rowIndex) => ThrowException<bool>();
99+
96100
private bool ThrowException<T>()
97101
{
98102
throw new InvalidOperationException($"Cannot write {typeof(T).Name} to {columnType} column");

DuckDB.NET.Data/Internal/Writer/VectorDataWriterFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static unsafe VectorDataWriterBase CreateWriter(IntPtr vector, DuckDBLogi
2222
DuckDBType.Boolean => new BooleanVectorDataWriter(vector, dataPointer, columnType),
2323

2424
DuckDBType.Map => throw new NotImplementedException($"Writing {columnType} to data chunk is not yet supported"),
25-
DuckDBType.List => throw new NotImplementedException($"Writing {columnType} to data chunk is not yet supported"),
25+
DuckDBType.List => new ListVectorDataWriter(vector, dataPointer, columnType, logicalType),
2626
DuckDBType.Array => throw new NotImplementedException($"Writing {columnType} to data chunk is not yet supported"),
2727
DuckDBType.Blob => new StringVectorDataWriter(vector, dataPointer, columnType),
2828
DuckDBType.Varchar => new StringVectorDataWriter(vector, dataPointer, columnType),

DuckDB.NET.Test/ManagedAppenderTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,38 @@ public void TemporalValues()
268268
result.Select(tuple => tuple.Item8).Should().BeEquivalentTo(dates.Select(TimeOnly.FromDateTime));
269269
}
270270

271+
[Fact]
272+
public void ListValues()
273+
{
274+
Command.CommandText = "CREATE TABLE managedAppenderLists(a INTEGER, b INTEGER[]" +
275+
//", c INTEGER[][]" +
276+
");";
277+
Command.ExecuteNonQuery();
278+
279+
var rows = 20;
280+
using (var appender = Connection.CreateAppender("managedAppenderLists"))
281+
{
282+
for (int i = 0; i < rows; i++)
283+
{
284+
appender.CreateRow()
285+
.AppendValue(i)
286+
.AppendValue(Enumerable.Range(0, i).ToList())
287+
//.AppendValue(new List<List<int>>{ Enumerable.Range(0, 5).ToList() })
288+
.EndRow();
289+
}
290+
}
291+
292+
Command.CommandText = "SELECT * FROM managedAppenderLists order by 1";
293+
var reader = Command.ExecuteReader();
294+
295+
int index = 0;
296+
while (reader.Read())
297+
{
298+
var ints = reader.GetFieldValue<List<int>>(1);
299+
ints.Should().BeEquivalentTo(Enumerable.Range(0, index++).ToList());
300+
}
301+
}
302+
271303
[Fact]
272304
public void IncompleteRowThrowsException()
273305
{

0 commit comments

Comments
 (0)