Skip to content

Commit ad8918b

Browse files
committed
Move logic for converting to DuckDBValue to a separate class.
1 parent dff83f5 commit ad8918b

File tree

7 files changed

+112
-127
lines changed

7 files changed

+112
-127
lines changed

DuckDB.NET.Bindings/DuckDBWrapperObjects.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,21 @@ protected override bool ReleaseHandle()
9191

9292
public class DuckDBValue() : SafeHandleZeroOrMinusOneIsInvalid(true)
9393
{
94+
private DuckDBValue[] childValues = [];
95+
9496
protected override bool ReleaseHandle()
9597
{
98+
foreach (var value in childValues)
99+
{
100+
value.Dispose();
101+
}
102+
96103
NativeMethods.Value.DuckDBDestroyValue(out handle);
97104
return true;
98105
}
106+
107+
internal void SetChildValues(DuckDBValue[] values)
108+
{
109+
childValues = values;
110+
}
99111
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Linq;
23
using System.Runtime.InteropServices;
34

45
namespace DuckDB.NET.Native;
@@ -72,5 +73,14 @@ public static class Value
7273

7374
[DllImport(DuckDbLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "duckdb_create_list_value")]
7475
public static extern DuckDBValue DuckDBCreateListValue(DuckDBLogicalType logicalType, IntPtr[] values, long count);
76+
77+
public static DuckDBValue DuckDBCreateListValue(DuckDBLogicalType logicalType, DuckDBValue[] values, int count)
78+
{
79+
var duckDBValue = DuckDBCreateListValue(logicalType, values.Select(item => item.DangerousGetHandle()).ToArray(), count);
80+
81+
duckDBValue.SetChildValues(values);
82+
83+
return duckDBValue;
84+
}
7585
}
7686
}

DuckDB.NET.Data/DuckDBDbType.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace DuckDB.NET.Data;
2+
3+
public enum DuckDBDbType
4+
{
5+
List
6+
}

DuckDB.NET.Data/DuckDBParameter.cs

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

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

17-
public DuckDBParameterType DuckDBType { get; set; }
17+
public DuckDBDbType DuckDBType { get; set; }
1818

1919
#if NET6_0_OR_GREATER
2020
[AllowNull]
@@ -35,7 +35,6 @@ public override object? Value
3535
}
3636
}
3737

38-
3938
public override ParameterDirection Direction { get; set; }
4039
public override bool IsNullable { get; set; }
4140

@@ -74,11 +73,5 @@ public DuckDBParameter(string name, DbType type, object? value)
7473
SourceColumn = string.Empty;
7574
}
7675

77-
public override void ResetDbType()
78-
=> DbType = DefaultDbType;
79-
}
80-
81-
public enum DuckDBParameterType
82-
{
83-
List
76+
public override void ResetDbType() => DbType = DefaultDbType;
8477
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Numerics;
5+
using DuckDB.NET.Native;
6+
7+
namespace DuckDB.NET.Data.Internal;
8+
9+
internal static class ClrToDuckDBConverter
10+
{
11+
public static DuckDBValue ToDuckDBValue(this object value) =>
12+
value switch
13+
{
14+
bool val => NativeMethods.Value.DuckDBCreateBool(val),
15+
sbyte val => NativeMethods.Value.DuckDBCreateInt8(val),
16+
short val => NativeMethods.Value.DuckDBCreateInt16(val),
17+
int val => NativeMethods.Value.DuckDBCreateInt32(val),
18+
byte val => NativeMethods.Value.DuckDBCreateUInt8(val),
19+
ushort val => NativeMethods.Value.DuckDBCreateUInt16(val),
20+
uint val => NativeMethods.Value.DuckDBCreateUInt32(val),
21+
long val => NativeMethods.Value.DuckDBCreateInt64(val),
22+
ulong val => NativeMethods.Value.DuckDBCreateUInt64(val),
23+
float val => NativeMethods.Value.DuckDBCreateFloat(val),
24+
double val => NativeMethods.Value.DuckDBCreateDouble(val),
25+
string val => StringToDuckDBValue(val),
26+
decimal val => DecimalToDuckDBValue(val),
27+
Guid val => GuidToDuckDBValue(val),
28+
BigInteger val => NativeMethods.Value.DuckDBCreateHugeInt(new DuckDBHugeInt(val)),
29+
byte[] val => NativeMethods.Value.DuckDBCreateBlob(val, val.Length),
30+
DateTime val => NativeMethods.Value.DuckDBCreateTimestamp(NativeMethods.DateTimeHelpers.DuckDBToTimestamp(DuckDBTimestamp.FromDateTime(val))),
31+
DuckDBDateOnly val => NativeMethods.Value.DuckDBCreateDate(NativeMethods.DateTimeHelpers.DuckDBToDate(val)),
32+
#if NET6_0_OR_GREATER
33+
DateOnly val => NativeMethods.Value.DuckDBCreateDate(NativeMethods.DateTimeHelpers.DuckDBToDate(val)),
34+
#endif
35+
DuckDBTimeOnly val => NativeMethods.Value.DuckDBCreateTime(NativeMethods.DateTimeHelpers.DuckDBToTime(val)),
36+
#if NET6_0_OR_GREATER
37+
TimeOnly val => NativeMethods.Value.DuckDBCreateTime(NativeMethods.DateTimeHelpers.DuckDBToTime(val)),
38+
#endif
39+
ICollection<int> val => CreateListValue(DuckDBType.Integer, val),
40+
_ => throw new InvalidCastException($"Cannot convert value of type {value.GetType().FullName} to DuckDBValue.")
41+
};
42+
43+
private static DuckDBValue GuidToDuckDBValue(Guid value)
44+
{
45+
using var handle = value.ToString().ToUnmanagedString();
46+
return NativeMethods.Value.DuckDBCreateVarchar(handle);
47+
}
48+
49+
private static DuckDBValue DecimalToDuckDBValue(decimal value)
50+
{
51+
using var handle = value.ToString(CultureInfo.InvariantCulture).ToUnmanagedString();
52+
return NativeMethods.Value.DuckDBCreateVarchar(handle);
53+
}
54+
55+
private static DuckDBValue StringToDuckDBValue(string value)
56+
{
57+
using var handle = value.ToUnmanagedString();
58+
return NativeMethods.Value.DuckDBCreateVarchar(handle);
59+
}
60+
61+
private static DuckDBValue CreateListValue<T>(DuckDBType duckDBType, ICollection<T> collection)
62+
{
63+
using var logicalType = NativeMethods.LogicalType.DuckDBCreateLogicalType(duckDBType);
64+
65+
var values = new DuckDBValue[collection.Count];
66+
67+
var index = 0;
68+
foreach (var item in collection)
69+
{
70+
var duckDBValue = item.ToDuckDBValue();
71+
values[index] = duckDBValue;
72+
index++;
73+
}
74+
75+
return NativeMethods.Value.DuckDBCreateListValue(logicalType, values, collection.Count);
76+
}
77+
}

DuckDB.NET.Data/Internal/DuckDBTypeMap.cs

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
using DuckDB.NET.Data.Extensions;
2-
using DuckDB.NET.Native;
31
using System;
4-
using System.Collections;
52
using System.Collections.Generic;
63
using System.Data;
7-
using System.Linq;
84
using System.Numerics;
5+
using DuckDB.NET.Data.Extensions;
6+
using DuckDB.NET.Native;
97

108
namespace DuckDB.NET.Data.Internal;
119

@@ -62,7 +60,6 @@ internal static class DuckDBTypeMap
6260
{ typeof(string), DuckDBType.Varchar},
6361
{ typeof(decimal), DuckDBType.Decimal},
6462
{ typeof(object), DuckDBType.Any},
65-
6663
};
6764

6865
public static DbType GetDbTypeForValue(object? value)
@@ -80,7 +77,6 @@ public static DbType GetDbTypeForValue(object? value)
8077
}
8178

8279
return DbType.Object;
83-
throw new InvalidOperationException($"Values of type {type.FullName} are not supported.");
8480
}
8581

8682
public static DuckDBLogicalType GetLogicalType<T>()
@@ -92,37 +88,4 @@ public static DuckDBLogicalType GetLogicalType<T>()
9288

9389
throw new InvalidOperationException($"Cannot map type {typeof(T).FullName} to DuckDBType.");
9490
}
95-
}
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-
}
12891
}

DuckDB.NET.Data/Internal/PreparedStatement.cs

Lines changed: 3 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,13 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Data;
4-
using System.Globalization;
53
using System.Linq;
6-
using System.Numerics;
74
using DuckDB.NET.Data.Extensions;
85
using DuckDB.NET.Native;
96

107
namespace DuckDB.NET.Data.Internal;
118

129
internal sealed class PreparedStatement : IDisposable
1310
{
14-
private static readonly Dictionary<DbType, Func<object, DuckDBValue>> ValueCreators = new()
15-
{
16-
{ DbType.Guid, value =>
17-
{
18-
using var handle = value.ToString().ToUnmanagedString();
19-
return NativeMethods.Value.DuckDBCreateVarchar(handle);
20-
}
21-
},
22-
{ DbType.Currency, value =>
23-
{
24-
using var handle = ((decimal)value).ToString(CultureInfo.InvariantCulture).ToUnmanagedString();
25-
return NativeMethods.Value.DuckDBCreateVarchar(handle);
26-
}
27-
},
28-
{ DbType.Boolean, value => NativeMethods.Value.DuckDBCreateBool((bool)value) },
29-
{ DbType.SByte, value => NativeMethods.Value.DuckDBCreateInt8((sbyte)value) },
30-
{ DbType.Int16, value => NativeMethods.Value.DuckDBCreateInt16((short)value) },
31-
{ DbType.Int32, value => NativeMethods.Value.DuckDBCreateInt32((int)value) },
32-
{ DbType.Int64, value => NativeMethods.Value.DuckDBCreateInt64((long)value) },
33-
{ DbType.Byte, value => NativeMethods.Value.DuckDBCreateUInt8((byte)value) },
34-
{ DbType.UInt16, value => NativeMethods.Value.DuckDBCreateUInt16((ushort)value) },
35-
{ DbType.UInt32, value => NativeMethods.Value.DuckDBCreateUInt32((uint)value) },
36-
{ DbType.UInt64, value => NativeMethods.Value.DuckDBCreateUInt64((ulong)value) },
37-
{ DbType.Single, value => NativeMethods.Value.DuckDBCreateFloat((float)value) },
38-
{ DbType.Double, value => NativeMethods.Value.DuckDBCreateDouble((double)value) },
39-
{ DbType.String, value =>
40-
{
41-
using var handle = ((string)value).ToUnmanagedString();
42-
return NativeMethods.Value.DuckDBCreateVarchar(handle);
43-
}
44-
},
45-
{ DbType.VarNumeric, value => NativeMethods.Value.DuckDBCreateHugeInt(new((BigInteger)value)) },
46-
{ DbType.Binary, value =>
47-
{
48-
var bytes = (byte[])value;
49-
return NativeMethods.Value.DuckDBCreateBlob(bytes, bytes.Length);
50-
}
51-
},
52-
{ DbType.Date, value =>
53-
{
54-
#if NET6_0_OR_GREATER
55-
var date = NativeMethods.DateTimeHelpers.DuckDBToDate(value is DateOnly dateOnly ? (DuckDBDateOnly)dateOnly : (DuckDBDateOnly)value);
56-
#else
57-
var date = NativeMethods.DateTimeHelpers.DuckDBToDate((DuckDBDateOnly)value);
58-
#endif
59-
return NativeMethods.Value.DuckDBCreateDate(date);
60-
}
61-
},
62-
{ DbType.Time, value =>
63-
{
64-
#if NET6_0_OR_GREATER
65-
var time = NativeMethods.DateTimeHelpers.DuckDBToTime(value is TimeOnly timeOnly ? (DuckDBTimeOnly)timeOnly : (DuckDBTimeOnly)value);
66-
#else
67-
var time = NativeMethods.DateTimeHelpers.DuckDBToTime((DuckDBTimeOnly)value);
68-
#endif
69-
return NativeMethods.Value.DuckDBCreateTime(time);
70-
}
71-
},
72-
{ DbType.DateTime, value =>
73-
{
74-
var timestamp = DuckDBTimestamp.FromDateTime((DateTime)value);
75-
var timestampStruct = NativeMethods.DateTimeHelpers.DuckDBToTimestamp(timestamp);
76-
return NativeMethods.Value.DuckDBCreateTimestamp(timestampStruct);
77-
}
78-
},
79-
};
80-
8111
private readonly DuckDBPreparedStatement statement;
8212

8313
private PreparedStatement(DuckDBPreparedStatement statement)
@@ -119,7 +49,7 @@ public static IEnumerable<DuckDBResult> PrepareMultiple(DuckDBNativeConnection c
11949
}
12050
}
12151

122-
public DuckDBResult Execute(DuckDBParameterCollection parameterCollection, bool useStreamingMode)
52+
private DuckDBResult Execute(DuckDBParameterCollection parameterCollection, bool useStreamingMode)
12353
{
12454
BindParameters(statement, parameterCollection);
12555

@@ -186,15 +116,9 @@ private static void BindParameter(DuckDBPreparedStatement preparedStatement, lon
186116
return;
187117
}
188118

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();
119+
using var duckDBValue = parameter.Value!.ToDuckDBValue();
195120

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

199123
if (!result.IsSuccess())
200124
{

0 commit comments

Comments
 (0)