Skip to content

Commit dff83f5

Browse files
GiorgiGiorgi
authored andcommitted
Bind List
1 parent 29bce0c commit dff83f5

File tree

7 files changed

+81
-12
lines changed

7 files changed

+81
-12
lines changed

DuckDB.NET.Bindings/DuckDBNativeObjects.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
using System;
2-
using System.Diagnostics.CodeAnalysis;
3-
using System.Numerics;
42
using System.Runtime.InteropServices;
53

64
namespace DuckDB.NET.Native;

DuckDB.NET.Bindings/NativeMethods/NativeMethods.Value.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ public partial class NativeMethods
77
{
88
public static class Value
99
{
10+
[DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_destroy_value")]
11+
public static extern void DuckDBDestroyValue(out IntPtr config);
12+
1013
[DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_create_varchar")]
1114
public static extern DuckDBValue DuckDBCreateVarchar(SafeUnmanagedMemoryHandle value);
1215

@@ -66,8 +69,8 @@ public static class Value
6669

6770
[DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_create_blob")]
6871
public static extern DuckDBValue DuckDBCreateBlob([In] byte[] value, long length);
69-
70-
[DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_destroy_value")]
71-
public static extern void DuckDBDestroyValue(out IntPtr config);
72+
73+
[DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_create_list_value")]
74+
public static extern DuckDBValue DuckDBCreateListValue(DuckDBLogicalType logicalType, IntPtr[] values, long count);
7275
}
7376
}

DuckDB.NET.Data/DuckDBParameter.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public class DuckDBParameter : DbParameter
1414

1515
public override DbType DbType { get; set; }
1616

17+
public DuckDBParameterType DuckDBType { get; set; }
18+
1719
#if NET6_0_OR_GREATER
1820
[AllowNull]
1921
#endif
@@ -74,4 +76,9 @@ public DuckDBParameter(string name, DbType type, object? value)
7476

7577
public override void ResetDbType()
7678
=> DbType = DefaultDbType;
79+
}
80+
81+
public enum DuckDBParameterType
82+
{
83+
List
7784
}

DuckDB.NET.Data/Internal/DuckDBTypeMap.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using DuckDB.NET.Data.Extensions;
22
using DuckDB.NET.Native;
33
using System;
4+
using System.Collections;
45
using System.Collections.Generic;
56
using System.Data;
7+
using System.Linq;
68
using System.Numerics;
79

810
namespace DuckDB.NET.Data.Internal;
@@ -76,6 +78,8 @@ public static DbType GetDbTypeForValue(object? value)
7678
{
7779
return dbType;
7880
}
81+
82+
return DbType.Object;
7983
throw new InvalidOperationException($"Values of type {type.FullName} are not supported.");
8084
}
8185

@@ -89,3 +93,36 @@ public static DuckDBLogicalType GetLogicalType<T>()
8993
throw new InvalidOperationException($"Cannot map type {typeof(T).FullName} to DuckDBType.");
9094
}
9195
}
96+
97+
internal static class ValueConverter
98+
{
99+
public static DuckDBValue ToDuckDBValue(this object value)
100+
{
101+
return value switch
102+
{
103+
int intValue => NativeMethods.Value.DuckDBCreateInt32(intValue),
104+
long longValue => NativeMethods.Value.DuckDBCreateInt64(longValue),
105+
ICollection<int> ints => CreateListValue(DuckDBType.Integer, ints),
106+
_ => throw new InvalidCastException(
107+
$"Cannot convert value of type {value.GetType().FullName} to DuckDBValue.")
108+
};
109+
}
110+
111+
private static DuckDBValue CreateListValue<T>(DuckDBType duckDBType, ICollection<T> collection)
112+
{
113+
using var logicalType = NativeMethods.LogicalType.DuckDBCreateLogicalType(duckDBType);
114+
115+
var values = new IntPtr[collection.Count];
116+
117+
var index = 0;
118+
foreach (var item in collection)
119+
{
120+
using var duckDBValue = item.ToDuckDBValue();
121+
values[index] = duckDBValue.DangerousGetHandle();
122+
index++;
123+
}
124+
125+
return NativeMethods.Value.DuckDBCreateListValue(logicalType,
126+
collection.Select(i => i.ToDuckDBValue().DangerousGetHandle()).ToArray(), collection.Count);
127+
}
128+
}

DuckDB.NET.Data/Internal/PreparedStatement.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,15 @@ private static void BindParameter(DuckDBPreparedStatement preparedStatement, lon
186186
return;
187187
}
188188

189-
if (!ValueCreators.TryGetValue(parameter.DbType, out var func))
190-
{
191-
throw new InvalidOperationException($"Unable to bind value of type {parameter.DbType}.");
192-
}
189+
// if (!ValueCreators.TryGetValue(parameter.DbType, out var func))
190+
// {
191+
// throw new InvalidOperationException($"Unable to bind value of type {parameter.DbType}.");
192+
// }
193+
194+
var duckDBValue2 = parameter.Value!.ToDuckDBValue();
193195

194-
using var duckDBValue = func(parameter.Value!);
195-
var result = NativeMethods.PreparedStatements.DuckDBBindValue(preparedStatement, index, duckDBValue);
196+
//using var duckDBValue = func(parameter.Value!);
197+
var result = NativeMethods.PreparedStatements.DuckDBBindValue(preparedStatement, index, duckDBValue2);
196198

197199
if (!result.IsSuccess())
198200
{

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal sealed unsafe class ListVectorDataWriter : VectorDataWriterBase
1313
private readonly DuckDBLogicalType childType;
1414
private readonly VectorDataWriterBase listItemWriter;
1515

16-
public bool IsList => ColumnType == DuckDBType.List;
16+
private bool IsList => ColumnType == DuckDBType.List;
1717
private ulong vectorReservedSize = DuckDBGlobalData.VectorSize;
1818

1919
public ListVectorDataWriter(IntPtr vector, void* vectorData, DuckDBType columnType, DuckDBLogicalType logicalType) : base(vector, vectorData, columnType)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Collections.Generic;
2+
using DuckDB.NET.Data;
3+
using FluentAssertions;
4+
using Xunit;
5+
6+
namespace DuckDB.NET.Test.Parameters;
7+
8+
public class ListParameterTests(DuckDBDatabaseFixture db) : DuckDBTestBase(db)
9+
{
10+
[Fact]
11+
public void CanBindList()
12+
{
13+
Command.CommandText = "Select ?";
14+
var parameter = new DuckDBParameter(new List<int> {1,2,3});
15+
16+
Command.Parameters.Add(parameter);
17+
18+
using var reader = Command.ExecuteReader();
19+
reader.Read();
20+
reader.GetFieldValue<List<int>>(0).Should().BeEquivalentTo(new List<int>{1,2,3});
21+
}
22+
}

0 commit comments

Comments
 (0)