• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Giorgi / DuckDB.NET / 10031566917

21 Jul 2024 09:46PM UTC coverage: 90.251%. First build
10031566917

push

github

Giorgi
Merge branch 'develop' into nightly-builds

845 of 963 branches covered (87.75%)

Branch coverage included in aggregate %.

23 of 24 new or added lines in 5 files covered. (95.83%)

1710 of 1868 relevant lines covered (91.54%)

797742.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.86
/DuckDB.NET.Data/Internal/PreparedStatement.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Data;
4
using System.Globalization;
5
using System.Linq;
6
using System.Numerics;
7
using DuckDB.NET.Data.Extensions;
8
using DuckDB.NET.Native;
9

10
namespace DuckDB.NET.Data.Internal;
11

12
internal sealed class PreparedStatement : IDisposable
13
{
14
    private static readonly Dictionary<DbType, Func<DuckDBPreparedStatement, long, object, DuckDBState>> Binders = new()
3✔
15
    {
3✔
16
        { DbType.Guid, BindObject },
3✔
17
        { DbType.Currency, BindObject },
3✔
18
        { DbType.Boolean, BindBoolean },
3✔
19
        { DbType.SByte, BindInt8 },
3✔
20
        { DbType.Int16, BindInt16 },
3✔
21
        { DbType.Int32, BindInt32 },
3✔
22
        { DbType.Int64, BindInt64 },
3✔
23
        { DbType.Byte, BindUInt8 },
3✔
24
        { DbType.UInt16, BindUInt16 },
3✔
25
        { DbType.UInt32, BindUInt32 },
3✔
26
        { DbType.UInt64, BindUInt64 },
3✔
27
        { DbType.Single, BindFloat },
3✔
28
        { DbType.Double, BindDouble },
3✔
29
        { DbType.String, BindString },
3✔
30
        { DbType.VarNumeric, BindHugeInt },
3✔
31
        { DbType.Binary, BindBlob },
3✔
32
        { DbType.Date, BindDateOnly },
3✔
33
        { DbType.Time, BindTimeOnly },
3✔
34
        { DbType.DateTime, BindTimestamp }
3✔
35
    };
3✔
36

37
    private readonly DuckDBPreparedStatement statement;
38

39
    private PreparedStatement(DuckDBPreparedStatement statement)
63,051✔
40
    {
41
        this.statement = statement;
63,051✔
42
    }
63,051✔
43

44
    public static IEnumerable<DuckDBResult> PrepareMultiple(DuckDBNativeConnection connection, string query, DuckDBParameterCollection parameters, bool useStreamingMode)
45
    {
46
        using var unmanagedQuery = query.ToUnmanagedString();
62,946✔
47

48
        var statementCount = NativeMethods.ExtractStatements.DuckDBExtractStatements(connection, unmanagedQuery, out var extractedStatements);
62,946✔
49

50
        using (extractedStatements)
62,946✔
51
        {
52
            if (statementCount <= 0)
62,946✔
53
            {
54
                var error = NativeMethods.ExtractStatements.DuckDBExtractStatementsError(extractedStatements);
3✔
55
                throw new DuckDBException(error.ToManagedString(false));
3✔
56
            }
57

58
            for (int index = 0; index < statementCount; index++)
249,288✔
59
            {
60
                var status = NativeMethods.ExtractStatements.DuckDBPrepareExtractedStatement(connection, extractedStatements, index, out var statement);
63,054✔
61

62
                if (status.IsSuccess())
63,054✔
63
                {
64
                    using var preparedStatement = new PreparedStatement(statement);
63,051✔
65
                    using var result = preparedStatement.Execute(parameters, useStreamingMode);
63,051✔
66
                    yield return result;
63,006✔
67
                }
61,701✔
68
                else
69
                {
70
                    var errorMessage = NativeMethods.PreparedStatements.DuckDBPrepareError(statement).ToManagedString(false);
3✔
71

72
                    throw new DuckDBException(string.IsNullOrEmpty(errorMessage) ? "DuckDBQuery failed" : errorMessage, status);
3!
73
                }
74
            }
75
        }
61,590✔
76
    }
61,590✔
77

78
    public DuckDBResult Execute(DuckDBParameterCollection parameterCollection, bool useStreamingMode)
79
    {
80
        BindParameters(statement, parameterCollection);
63,051✔
81

82
        var status = useStreamingMode
63,033✔
83
            ? NativeMethods.PreparedStatements.DuckDBExecutePreparedStreaming(statement, out var queryResult)
63,033✔
84
            : NativeMethods.PreparedStatements.DuckDBExecutePrepared(statement, out queryResult);
63,033✔
85

86
        if (!status.IsSuccess())
63,033✔
87
        {
88
            var errorMessage = NativeMethods.Query.DuckDBResultError(ref queryResult).ToManagedString(false);
27✔
89
            queryResult.Dispose();
27✔
90

91
            if (string.IsNullOrEmpty(errorMessage))
27!
92
            {
NEW
93
                errorMessage = "DuckDB execution failed";
×
94
            }
95

96
            if (errorMessage.StartsWith("INTERRUPT Error"))
27✔
97
            {
98
                throw new OperationCanceledException();
3✔
99
            }
100

101
            throw new DuckDBException(errorMessage, status);
24✔
102
        }
103

104
        return queryResult;
63,006✔
105
    }
106

107
    private static void BindParameters(DuckDBPreparedStatement preparedStatement, DuckDBParameterCollection parameterCollection)
108
    {
109
        var expectedParameters = NativeMethods.PreparedStatements.DuckDBParams(preparedStatement);
63,051✔
110
        if (parameterCollection.Count < expectedParameters)
63,051✔
111
        {
112
            throw new InvalidOperationException($"Invalid number of parameters. Expected {expectedParameters}, got {parameterCollection.Count}");
18✔
113
        }
114

115
        if (parameterCollection.OfType<DuckDBParameter>().Any(p => !string.IsNullOrEmpty(p.ParameterName)))
63,672✔
116
        {
117
            foreach (DuckDBParameter param in parameterCollection)
612✔
118
            {
119
                var state = NativeMethods.PreparedStatements.DuckDBBindParameterIndex(preparedStatement, out var index, param.ParameterName.ToUnmanagedString());
189✔
120
                if (state.IsSuccess())
189✔
121
                {
122
                    BindParameter(preparedStatement, index, param);
159✔
123
                }
124
            }
125
        }
126
        else
127
        {
128
            for (var i = 0; i < expectedParameters; ++i)
126,582✔
129
            {
130
                var param = parameterCollection[i];
375✔
131
                BindParameter(preparedStatement, i + 1, param);
375✔
132
            }
133
        }
134
    }
63,033✔
135

136
    private static void BindParameter(DuckDBPreparedStatement preparedStatement, long index, DuckDBParameter parameter)
137
    {
138
        if (parameter.Value.IsNull())
534✔
139
        {
140
            NativeMethods.PreparedStatements.DuckDBBindNull(preparedStatement, index);
24✔
141
            return;
24✔
142
        }
143

144
        if (!Binders.TryGetValue(parameter.DbType, out var binder))
510!
145
        {
146
            throw new InvalidOperationException($"Unable to bind value of type {parameter.DbType}.");
×
147
        }
148

149
        var result = binder(preparedStatement, index, parameter.Value!);
510✔
150

151
        if (!result.IsSuccess())
510!
152
        {
153
            var errorMessage = NativeMethods.PreparedStatements.DuckDBPrepareError(preparedStatement).ToManagedString(false);
×
154
            throw new InvalidOperationException($"Unable to bind parameter {index}: {errorMessage}");
×
155
        }
156
    }
510✔
157

158
    private static DuckDBState BindObject(DuckDBPreparedStatement preparedStatement, long index, object value)
159
        => BindString(preparedStatement, index, Convert.ToString(value, CultureInfo.InvariantCulture)!);
69✔
160

161
    private static DuckDBState BindBoolean(DuckDBPreparedStatement preparedStatement, long index, object value)
162
        => NativeMethods.PreparedStatements.DuckDBBindBoolean(preparedStatement, index, (bool)value);
3✔
163

164
    private static DuckDBState BindInt8(DuckDBPreparedStatement preparedStatement, long index, object value)
165
        => NativeMethods.PreparedStatements.DuckDBBindInt8(preparedStatement, index, (sbyte)value);
18✔
166

167
    private static DuckDBState BindInt16(DuckDBPreparedStatement preparedStatement, long index, object value)
168
        => NativeMethods.PreparedStatements.DuckDBBindInt16(preparedStatement, index, (short)value);
18✔
169

170
    private static DuckDBState BindInt32(DuckDBPreparedStatement preparedStatement, long index, object value)
171
        => NativeMethods.PreparedStatements.DuckDBBindInt32(preparedStatement, index, (int)value);
123✔
172

173
    private static DuckDBState BindInt64(DuckDBPreparedStatement preparedStatement, long index, object value)
174
        => NativeMethods.PreparedStatements.DuckDBBindInt64(preparedStatement, index, (long)value);
18✔
175

176
    private static DuckDBState BindUInt8(DuckDBPreparedStatement preparedStatement, long index, object value)
177
        => NativeMethods.PreparedStatements.DuckDBBindUInt8(preparedStatement, index, (byte)value);
18✔
178

179
    private static DuckDBState BindUInt16(DuckDBPreparedStatement preparedStatement, long index, object value)
180
        => NativeMethods.PreparedStatements.DuckDBBindUInt16(preparedStatement, index, (ushort)value);
18✔
181

182
    private static DuckDBState BindUInt32(DuckDBPreparedStatement preparedStatement, long index, object value)
183
        => NativeMethods.PreparedStatements.DuckDBBindUInt32(preparedStatement, index, (uint)value);
18✔
184

185
    private static DuckDBState BindUInt64(DuckDBPreparedStatement preparedStatement, long index, object value)
186
        => NativeMethods.PreparedStatements.DuckDBBindUInt64(preparedStatement, index, (ulong)value);
18✔
187

188

189
    private static DuckDBState BindFloat(DuckDBPreparedStatement preparedStatement, long index, object value)
190
        => NativeMethods.PreparedStatements.DuckDBBindFloat(preparedStatement, index, (float)value);
3✔
191

192
    private static DuckDBState BindDouble(DuckDBPreparedStatement preparedStatement, long index, object value)
193
        => NativeMethods.PreparedStatements.DuckDBBindDouble(preparedStatement, index, (double)value);
3✔
194

195
    private static DuckDBState BindString(DuckDBPreparedStatement preparedStatement, long index, object value)
196
    {
197
        using var unmanagedString = (value as string)?.ToUnmanagedString() ?? throw new ArgumentException(nameof(value));
153!
198
        return NativeMethods.PreparedStatements.DuckDBBindVarchar(preparedStatement, index, unmanagedString);
153✔
199
    }
153✔
200

201
    private static DuckDBState BindHugeInt(DuckDBPreparedStatement preparedStatement, long index, object value) =>
202
        NativeMethods.PreparedStatements.DuckDBBindHugeInt(preparedStatement, index, new((BigInteger)value));
6✔
203

204
    private static DuckDBState BindBlob(DuckDBPreparedStatement preparedStatement, long index, object value)
205
    {
206
        var bytes = (byte[])value;
3✔
207
        return NativeMethods.PreparedStatements.DuckDBBindBlob(preparedStatement, index, bytes, bytes.LongLength);
3✔
208
    }
209

210
    private static DuckDBState BindDateOnly(DuckDBPreparedStatement preparedStatement, long index, object value)
211
    {
212
        var date = NativeMethods.DateTimeHelpers.DuckDBToDate((DuckDBDateOnly)value);
18✔
213
        return NativeMethods.PreparedStatements.DuckDBBindDate(preparedStatement, index, date);
18✔
214
    }
215

216
    private static DuckDBState BindTimeOnly(DuckDBPreparedStatement preparedStatement, long index, object value)
217
    {
218
        var time = NativeMethods.DateTimeHelpers.DuckDBToTime((DuckDBTimeOnly)value);
36✔
219
        return NativeMethods.PreparedStatements.DuckDBBindTime(preparedStatement, index, time);
36✔
220
    }
221

222
    private static DuckDBState BindTimestamp(DuckDBPreparedStatement preparedStatement, long index, object value)
223
    {
224
        var timestamp = DuckDBTimestamp.FromDateTime((DateTime)value);
36✔
225
        var timestampStruct = NativeMethods.DateTimeHelpers.DuckDBToTimestamp(timestamp);
36✔
226
        return NativeMethods.PreparedStatements.DuckDBBindTimestamp(preparedStatement, index, timestampStruct);
36✔
227
    }
228

229
    public void Dispose()
230
    {
231
        statement.Dispose();
62,412✔
232
    }
62,412✔
233
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc