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

Giorgi / DuckDB.NET / 22921736195

10 Mar 2026 07:24PM UTC coverage: 89.526% (+0.08%) from 89.45%
22921736195

push

github

Giorgi
Update global.json

1255 of 1463 branches covered (85.78%)

Branch coverage included in aggregate %.

2651 of 2900 relevant lines covered (91.41%)

447643.55 hits per line

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

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

5
namespace DuckDB.NET.Data;
6

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

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

15
    private int fieldCount;
16

17
    private ulong currentChunkRowCount;
18
    private ulong rowsReadFromCurrentChunk;
19

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

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

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

35
        InitNextReader();
39,807✔
36
    }
39,759✔
37

38
    private bool InitNextReader()
39
    {
40
        foreach (var reader in vectorReaders)
81,780✔
41
        {
42
            reader?.Dispose();
729!
43
        }
44

45
        vectorReaders = [];
40,161✔
46

47
        while (resultEnumerator.MoveNext())
40,167✔
48
        {
49
            var result = resultEnumerator.Current;
39,771✔
50
            if (NativeMethods.Query.DuckDBResultReturnType(result) == DuckDBResultType.QueryResult)
39,771✔
51
            {
52
                currentChunkIndex = 0;
39,765✔
53
                currentResult = result;
39,765✔
54

55
                columnMapping = [];
39,765✔
56
                fieldCount = (int)NativeMethods.Query.DuckDBColumnCount(ref currentResult);
39,765✔
57
                streamingResult = NativeMethods.Types.DuckDBResultIsStreaming(currentResult) > 0;
39,765✔
58

59
                hasRows = InitChunkData();
39,765✔
60

61
                return true;
39,765✔
62
            }
63

64
            result.Close();
6✔
65
        }
66

67
        return false;
345✔
68
    }
69

70
    private bool InitChunkData()
71
    {
72
        var canReuse = vectorReaders.Length > 0;
40,488✔
73

74
        currentChunk?.Dispose();
40,488✔
75
        currentChunk = streamingResult ? NativeMethods.StreamingResult.DuckDBStreamFetchChunk(currentResult) : NativeMethods.Types.DuckDBResultGetChunk(currentResult, currentChunkIndex);
40,488✔
76

77
        rowsReadFromCurrentChunk = 0;
40,488✔
78

79
        currentChunkRowCount = NativeMethods.DataChunks.DuckDBDataChunkGetSize(currentChunk);
40,488✔
80

81
        if (!canReuse)
40,488✔
82
        {
83
            vectorReaders = new VectorDataReaderBase[fieldCount];
39,765✔
84
        }
85

86
        for (int index = 0; index < fieldCount; index++)
182,850✔
87
        {
88
            var vector = NativeMethods.DataChunks.DuckDBDataChunkGetVector(currentChunk, index);
50,937✔
89

90
            if (canReuse)
50,937✔
91
            {
92
                vectorReaders[index].Reset(vector);
1,425✔
93
            }
94
            else
95
            {
96
                using var logicalType = NativeMethods.Query.DuckDBColumnLogicalType(ref currentResult, index);
49,512✔
97

98
                var columnName = NativeMethods.Query.DuckDBColumnName(ref currentResult, index);
49,512✔
99
                vectorReaders[index] = VectorDataReaderFactory.CreateReader(vector, logicalType, columnName);
49,512✔
100
            }
101
        }
102

103
        if (columnMapping.Count == 0)
40,488✔
104
        {
105
            for (var i = 0; i < vectorReaders.Length; i++)
178,554✔
106
            {
107
                columnMapping.TryAdd(vectorReaders[i].ColumnName, i);
49,512✔
108
            }
109
        }
110

111
        return currentChunkRowCount > 0;
40,488✔
112
    }
113

114
    public override bool GetBoolean(int ordinal)
115
    {
116
        return GetFieldValue<bool>(ordinal);
81✔
117
    }
118

119
    public override byte GetByte(int ordinal)
120
    {
121
        return GetFieldValue<byte>(ordinal);
18✔
122
    }
123

124
    public override long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length)
125
    {
126
        throw new NotImplementedException();
×
127
    }
128

129
    public override char GetChar(int ordinal)
130
    {
131
        throw new NotSupportedException();
×
132
    }
133

134
    public override long GetChars(int ordinal, long dataOffset, char[]? buffer, int bufferOffset, int length)
135
    {
136
        throw new NotSupportedException();
×
137
    }
138

139
    public override string GetDataTypeName(int ordinal)
140
    {
141
        return vectorReaders[ordinal].DuckDBType.ToString();
6✔
142
    }
143

144
    public override DateTime GetDateTime(int ordinal)
145
    {
146
        return GetFieldValue<DateTime>(ordinal);
177✔
147
    }
148

149
    public override decimal GetDecimal(int ordinal)
150
    {
151
        return GetFieldValue<decimal>(ordinal);
462✔
152
    }
153

154
    public override double GetDouble(int ordinal)
155
    {
156
        return GetFieldValue<double>(ordinal);
3✔
157
    }
158

159
    public override Type GetFieldType(int ordinal)
160
    {
161
        return vectorReaders[ordinal].ClrType;
20,286✔
162
    }
163

164
    public override Type GetProviderSpecificFieldType(int ordinal)
165
    {
166
        return vectorReaders[ordinal].ProviderSpecificClrType;
123✔
167
    }
168

169
    public override float GetFloat(int ordinal)
170
    {
171
        return GetFieldValue<float>(ordinal);
9✔
172
    }
173

174
    public override Guid GetGuid(int ordinal)
175
    {
176
        return GetFieldValue<Guid>(ordinal);
12✔
177
    }
178

179
    public override short GetInt16(int ordinal)
180
    {
181
        return GetFieldValue<short>(ordinal);
18✔
182
    }
183

184
    public override int GetInt32(int ordinal)
185
    {
186
        return GetFieldValue<int>(ordinal);
30,072✔
187
    }
188

189
    public override long GetInt64(int ordinal)
190
    {
191
        return GetFieldValue<long>(ordinal);
18✔
192
    }
193

194
    public override string GetName(int ordinal)
195
    {
196
        return vectorReaders[ordinal].ColumnName;
1,377✔
197
    }
198

199
    public override int GetOrdinal(string name)
200
    {
201
        if (columnMapping.TryGetValue(name, out var index))
186✔
202
        {
203
            return index;
180✔
204
        }
205

206
        throw new DuckDBException($"Column with name {name} was not found.");
6✔
207
    }
208

209
    public override string GetString(int ordinal)
210
    {
211
        return GetFieldValue<string>(ordinal);
30,051✔
212
    }
213

214
    public override T GetFieldValue<T>(int ordinal)
215
    {
216
        CheckRowRead();
749,223✔
217

218
        return vectorReaders[ordinal].GetValueStrict<T>(rowsReadFromCurrentChunk - 1);
749,220✔
219
    }
220

221
    public override object GetValue(int ordinal)
222
    {
223
        CheckRowRead();
309,582✔
224

225
        return IsDBNull(ordinal) ? DBNull.Value : vectorReaders[ordinal].GetValue(rowsReadFromCurrentChunk - 1);
309,579✔
226
    }
227

228
    public override object GetProviderSpecificValue(int ordinal)
229
    {
230
        CheckRowRead();
132✔
231

232
        return IsDBNull(ordinal) ? DBNull.Value : vectorReaders[ordinal].GetProviderSpecificValue(rowsReadFromCurrentChunk - 1);
132✔
233
    }
234

235
    public override int GetValues(object[] values)
236
    {
237
        for (var i = 0; i < FieldCount; i++)
3,546✔
238
        {
239
            values[i] = GetValue(i);
1,242✔
240
        }
241

242
        return FieldCount;
531✔
243
    }
244

245
    public override Stream GetStream(int ordinal)
246
    {
247
        return GetFieldValue<Stream>(ordinal);
27✔
248
    }
249

250
    public override bool IsDBNull(int ordinal)
251
    {
252
        CheckRowRead();
369,945✔
253

254
        return !vectorReaders[ordinal].IsValid(rowsReadFromCurrentChunk - 1);
369,942✔
255
    }
256

257
    public override int FieldCount => fieldCount;
3,360✔
258

259
    public override object this[int ordinal] => GetValue(ordinal);
77,232✔
260

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

263
    public override int RecordsAffected => -1;
×
264

265
    public override bool HasRows => hasRows;
18✔
266

267
    public override bool IsClosed => closed;
81✔
268

269
    public override bool NextResult()
270
    {
271
        return InitNextReader();
354✔
272
    }
273

274
    public override bool Read()
275
    {
276
        if (rowsReadFromCurrentChunk == currentChunkRowCount)
606,744✔
277
        {
278
            currentChunkIndex++;
723✔
279
            var hasData = InitChunkData();
723✔
280

281
            if (hasData)
723✔
282
            {
283
                rowsReadFromCurrentChunk++;
147✔
284
            }
285

286
            return hasData;
723✔
287
        }
288
        else
289
        {
290
            rowsReadFromCurrentChunk++;
606,021✔
291

292
            return true;
606,021✔
293
        }
294
    }
295

296
    public override int Depth { get; }
×
297

298
    public override IEnumerator GetEnumerator()
299
    {
300
        return new DbEnumerator(this, behavior == CommandBehavior.CloseConnection);
3✔
301
    }
302

303
    public override DataTable GetSchemaTable()
304
    {
305
        var table = new DataTable
45✔
306
        {
45✔
307
            Columns =
45✔
308
            {
45✔
309
                { SchemaTableColumn.ColumnName, typeof(string) },
45✔
310
                { SchemaTableColumn.ColumnOrdinal, typeof(int) },
45✔
311
                { SchemaTableColumn.ColumnSize, typeof(int) },
45✔
312
                { SchemaTableColumn.NumericPrecision, typeof(byte)},
45✔
313
                { SchemaTableColumn.NumericScale, typeof(byte) },
45✔
314
                { SchemaTableColumn.DataType, typeof(Type) },
45✔
315
                { SchemaTableColumn.AllowDBNull, typeof(bool)  }
45✔
316
            }
45✔
317
        };
45✔
318

319
        var rowData = new object[7];
45✔
320

321
        for (var i = 0; i < FieldCount; i++)
636✔
322
        {
323
            rowData[0] = GetName(i);
273✔
324
            rowData[1] = i;
273✔
325
            rowData[2] = -1;
273✔
326
            rowData[5] = GetFieldType(i);
273✔
327
            rowData[6] = true;
273✔
328

329
            if (vectorReaders[i] is DecimalVectorDataReader decimalVectorDataReader)
273✔
330
            {
331
                rowData[4] = decimalVectorDataReader.Scale;
6✔
332
                rowData[3] = decimalVectorDataReader.Precision;
6✔
333
            }
334
            else
335
            {
336
                rowData[3] = rowData[4] = DBNull.Value;
267✔
337
            }
338

339
            table.Rows.Add(rowData);
273✔
340
        }
341

342
        return table;
45✔
343
    }
344

345
    public override void Close()
346
    {
347
        if (closed) return;
39,168✔
348

349
        foreach (var reader in vectorReaders)
156,444✔
350
        {
351
            reader.Dispose();
39,132✔
352
        }
353

354
        currentChunk?.Dispose();
39,090✔
355
        currentResult.Close();
39,090✔
356

357
        if (behavior == CommandBehavior.CloseConnection)
39,090✔
358
        {
359
            command.CloseConnection();
6✔
360
        }
361

362
        closed = true;
39,090✔
363
        resultEnumerator.Dispose();
39,090✔
364
    }
39,090✔
365

366
    private void CheckRowRead()
367
    {
368
        if (rowsReadFromCurrentChunk <= 0)
1,428,882✔
369
        {
370
            throw new InvalidOperationException("No row has been read");
9✔
371
        }
372
    }
1,428,873✔
373
}
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