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

Giorgi / DuckDB.NET / 21786556530

07 Feb 2026 08:39PM UTC coverage: 89.155% (-0.07%) from 89.223%
21786556530

push

github

Giorgi
Added support for clearing in-progress adapter

Requires DuckDB 1.5

1199 of 1393 branches covered (86.07%)

Branch coverage included in aggregate %.

6 of 8 new or added lines in 1 file covered. (75.0%)

193 existing lines in 43 files now uncovered.

2336 of 2572 relevant lines covered (90.82%)

557295.56 hits per line

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

97.18
/DuckDB.NET.Data/DuckDBDataReader.cs
1
using DuckDB.NET.Data.DataChunk.Reader;
2
using System.IO;
3

4
namespace DuckDB.NET.Data;
5

6
public class DuckDBDataReader : DbDataReader
7
{
8
    private readonly DuckDBCommand command;
9
    private readonly CommandBehavior behavior;
10

11
    private DuckDBResult currentResult;
12
    private DuckDBDataChunk? currentChunk;
13

14
    private int fieldCount;
15

16
    private ulong currentChunkRowCount;
17
    private ulong rowsReadFromCurrentChunk;
18

19
    private bool closed;
20
    private bool hasRows;
21
    private bool streamingResult;
22
    private long currentChunkIndex;
23

24
    private readonly IEnumerator<DuckDBResult> resultEnumerator;
25
    private VectorDataReaderBase[] vectorReaders = [];
39,528✔
26
    private Dictionary<string, int> columnMapping = [];
39,528✔
27

28
    internal DuckDBDataReader(DuckDBCommand command, IEnumerable<DuckDBResult> queryResults, CommandBehavior behavior)
39,528✔
29
    {
30
        this.command = command;
39,528✔
31
        this.behavior = behavior;
39,528✔
32
        resultEnumerator = queryResults.GetEnumerator();
39,528✔
33

34
        InitNextReader();
39,528✔
35
    }
39,504✔
36

37
    private bool InitNextReader()
38
    {
39
        while (resultEnumerator.MoveNext())
39,747✔
40
        {
41
            var result = resultEnumerator.Current;
39,516✔
42
            if (NativeMethods.Query.DuckDBResultReturnType(result) == DuckDBResultType.QueryResult)
39,516✔
43
            {
44
                currentChunkIndex = 0;
39,510✔
45
                currentResult = result;
39,510✔
46

47
                columnMapping = [];
39,510✔
48
                fieldCount = (int)NativeMethods.Query.DuckDBColumnCount(ref currentResult);
39,510✔
49
                streamingResult = NativeMethods.Types.DuckDBResultIsStreaming(currentResult) > 0;
39,510✔
50

51
                hasRows = InitChunkData();
39,510✔
52

53
                return true;
39,510✔
54
            }
55

56
            result.Close();
6✔
57
        }
58

59
        return false;
204✔
60
    }
61

62
    private bool InitChunkData()
63
    {
64
        foreach (var reader in vectorReaders)
82,446✔
65
        {
66
            reader.Dispose();
1,179✔
67
        }
68

69
        currentChunk?.Dispose();
40,044✔
70
        currentChunk = streamingResult ? NativeMethods.StreamingResult.DuckDBStreamFetchChunk(currentResult) : NativeMethods.Types.DuckDBResultGetChunk(currentResult, currentChunkIndex);
40,044✔
71

72
        rowsReadFromCurrentChunk = 0;
40,044✔
73

74
        currentChunkRowCount = NativeMethods.DataChunks.DuckDBDataChunkGetSize(currentChunk);
40,044✔
75

76
        if (vectorReaders.Length != fieldCount)
40,044✔
77
        {
78
            vectorReaders = new VectorDataReaderBase[fieldCount];
39,501✔
79
        }
80

81
        for (int index = 0; index < fieldCount; index++)
180,822✔
82
        {
83
            var vector = NativeMethods.DataChunks.DuckDBDataChunkGetVector(currentChunk, index);
50,367✔
84

85
            using var logicalType = NativeMethods.Query.DuckDBColumnLogicalType(ref currentResult, index);
50,367✔
86

87
            var columnName = vectorReaders[index]?.ColumnName ?? NativeMethods.Query.DuckDBColumnName(ref currentResult, index).ToManagedString(false);
50,367✔
88
            vectorReaders[index] = VectorDataReaderFactory.CreateReader(vector, logicalType, columnName);
50,367✔
89
        }
90

91
        if (columnMapping.Count == 0)
40,044✔
92
        {
93
            for (var i = 0; i < vectorReaders.Length; i++)
177,414✔
94
            {
95
                if (!columnMapping.ContainsKey(vectorReaders[i].ColumnName))
49,197✔
96
                {
97
                    columnMapping.Add(vectorReaders[i].ColumnName, i);
49,194✔
98
                }
99
            }
100
        }
101

102
        return currentChunkRowCount > 0;
40,044✔
103
    }
104

105
    public override bool GetBoolean(int ordinal)
106
    {
107
        return GetFieldValue<bool>(ordinal);
81✔
108
    }
109

110
    public override byte GetByte(int ordinal)
111
    {
112
        return GetFieldValue<byte>(ordinal);
18✔
113
    }
114

115
    public override long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length)
116
    {
UNCOV
117
        throw new NotImplementedException();
×
118
    }
119

120
    public override char GetChar(int ordinal)
121
    {
UNCOV
122
        throw new NotSupportedException();
×
123
    }
124

125
    public override long GetChars(int ordinal, long dataOffset, char[]? buffer, int bufferOffset, int length)
126
    {
UNCOV
127
        throw new NotSupportedException();
×
128
    }
129

130
    public override string GetDataTypeName(int ordinal)
131
    {
132
        return vectorReaders[ordinal].DuckDBType.ToString();
6✔
133
    }
134

135
    public override DateTime GetDateTime(int ordinal)
136
    {
137
        return GetFieldValue<DateTime>(ordinal);
177✔
138
    }
139

140
    public override decimal GetDecimal(int ordinal)
141
    {
142
        return GetFieldValue<decimal>(ordinal);
360✔
143
    }
144

145
    public override double GetDouble(int ordinal)
146
    {
147
        return GetFieldValue<double>(ordinal);
3✔
148
    }
149

150
    public override Type GetFieldType(int ordinal)
151
    {
152
        return vectorReaders[ordinal].ClrType;
19,854✔
153
    }
154

155
    public override Type GetProviderSpecificFieldType(int ordinal)
156
    {
157
        return vectorReaders[ordinal].ProviderSpecificClrType;
123✔
158
    }
159

160
    public override float GetFloat(int ordinal)
161
    {
162
        return GetFieldValue<float>(ordinal);
9✔
163
    }
164

165
    public override Guid GetGuid(int ordinal)
166
    {
167
        return GetFieldValue<Guid>(ordinal);
12✔
168
    }
169

170
    public override short GetInt16(int ordinal)
171
    {
172
        return GetFieldValue<short>(ordinal);
18✔
173
    }
174

175
    public override int GetInt32(int ordinal)
176
    {
177
        return GetFieldValue<int>(ordinal);
30,072✔
178
    }
179

180
    public override long GetInt64(int ordinal)
181
    {
182
        return GetFieldValue<long>(ordinal);
18✔
183
    }
184

185
    public override string GetName(int ordinal)
186
    {
187
        return vectorReaders[ordinal].ColumnName;
966✔
188
    }
189

190
    public override int GetOrdinal(string name)
191
    {
192
        if (columnMapping.TryGetValue(name, out var index))
186✔
193
        {
194
            return index;
180✔
195
        }
196

197
        throw new DuckDBException($"Column with name {name} was not found.");
6✔
198
    }
199

200
    public override string GetString(int ordinal)
201
    {
202
        return GetFieldValue<string>(ordinal);
30,051✔
203
    }
204

205
    public override T GetFieldValue<T>(int ordinal)
206
    {
207
        CheckRowRead();
749,121✔
208

209
        return vectorReaders[ordinal].GetValue<T>(rowsReadFromCurrentChunk - 1);
749,118✔
210
    }
211

212
    public override object GetValue(int ordinal)
213
    {
214
        CheckRowRead();
174,069✔
215

216
        return IsDBNull(ordinal) ? DBNull.Value : vectorReaders[ordinal].GetValue(rowsReadFromCurrentChunk - 1);
174,066✔
217
    }
218

219
    public override object GetProviderSpecificValue(int ordinal)
220
    {
221
        CheckRowRead();
132✔
222

223
        return IsDBNull(ordinal) ? DBNull.Value : vectorReaders[ordinal].GetProviderSpecificValue(rowsReadFromCurrentChunk - 1);
132✔
224
    }
225

226
    public override int GetValues(object[] values)
227
    {
228
        for (var i = 0; i < FieldCount; i++)
3,546✔
229
        {
230
            values[i] = GetValue(i);
1,242✔
231
        }
232

233
        return FieldCount;
531✔
234
    }
235

236
    public override Stream GetStream(int ordinal)
237
    {
238
        return GetFieldValue<Stream>(ordinal);
27✔
239
    }
240

241
    public override bool IsDBNull(int ordinal)
242
    {
243
        CheckRowRead();
234,432✔
244

245
        return !vectorReaders[ordinal].IsValid(rowsReadFromCurrentChunk - 1);
234,429✔
246
    }
247

248
    public override int FieldCount => fieldCount;
3,024✔
249

250
    public override object this[int ordinal] => GetValue(ordinal);
46,992✔
251

252
    public override object this[string name] => GetValue(GetOrdinal(name));
3✔
253

UNCOV
254
    public override int RecordsAffected => -1;
×
255

256
    public override bool HasRows => hasRows;
18✔
257

258
    public override bool IsClosed => closed;
81✔
259

260
    public override bool NextResult()
261
    {
262
        return InitNextReader();
213✔
263
    }
264

265
    public override bool Read()
266
    {
267
        if (rowsReadFromCurrentChunk == currentChunkRowCount)
486,126✔
268
        {
269
            currentChunkIndex++;
534✔
270
            var hasData = InitChunkData();
534✔
271

272
            if (hasData)
534✔
273
            {
274
                rowsReadFromCurrentChunk++;
99✔
275
            }
276

277
            return hasData;
534✔
278
        }
279
        else
280
        {
281
            rowsReadFromCurrentChunk++;
485,592✔
282

283
            return true;
485,592✔
284
        }
285
    }
286

UNCOV
287
    public override int Depth { get; }
×
288

289
    public override IEnumerator GetEnumerator()
290
    {
291
        return new DbEnumerator(this, behavior == CommandBehavior.CloseConnection);
3✔
292
    }
293

294
    public override DataTable GetSchemaTable()
295
    {
296
        var table = new DataTable
45✔
297
        {
45✔
298
            Columns =
45✔
299
            {
45✔
300
                { SchemaTableColumn.ColumnName, typeof(string) },
45✔
301
                { SchemaTableColumn.ColumnOrdinal, typeof(int) },
45✔
302
                { SchemaTableColumn.ColumnSize, typeof(int) },
45✔
303
                { SchemaTableColumn.NumericPrecision, typeof(byte)},
45✔
304
                { SchemaTableColumn.NumericScale, typeof(byte) },
45✔
305
                { SchemaTableColumn.DataType, typeof(Type) },
45✔
306
                { SchemaTableColumn.AllowDBNull, typeof(bool)  }
45✔
307
            }
45✔
308
        };
45✔
309

310
        var rowData = new object[7];
45✔
311

312
        for (var i = 0; i < FieldCount; i++)
636✔
313
        {
314
            rowData[0] = GetName(i);
273✔
315
            rowData[1] = i;
273✔
316
            rowData[2] = -1;
273✔
317
            rowData[5] = GetFieldType(i);
273✔
318
            rowData[6] = true;
273✔
319

320
            if (vectorReaders[i] is DecimalVectorDataReader decimalVectorDataReader)
273✔
321
            {
322
                rowData[4] = decimalVectorDataReader.Scale;
6✔
323
                rowData[3] = decimalVectorDataReader.Precision;
6✔
324
            }
325
            else
326
            {
327
                rowData[3] = rowData[4] = DBNull.Value;
267✔
328
            }
329

330
            table.Rows.Add(rowData);
273✔
331
        }
332

333
        return table;
45✔
334
    }
335

336
    public override void Close()
337
    {
338
        if (closed) return;
38,913✔
339

340
        foreach (var reader in vectorReaders)
156,702✔
341
        {
342
            reader.Dispose();
39,516✔
343
        }
344

345
        currentChunk?.Dispose();
38,835✔
346
        currentResult.Close();
38,835✔
347

348
        if (behavior == CommandBehavior.CloseConnection)
38,835✔
349
        {
350
            command.CloseConnection();
6✔
351
        }
352

353
        closed = true;
38,835✔
354
        resultEnumerator.Dispose();
38,835✔
355
    }
38,835✔
356

357
    private void CheckRowRead()
358
    {
359
        if (rowsReadFromCurrentChunk <= 0)
1,157,754✔
360
        {
361
            throw new InvalidOperationException("No row has been read");
9✔
362
        }
363
    }
1,157,745✔
364
}
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

© 2026 Coveralls, Inc