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

Giorgi / DuckDB.NET / 21786443631

07 Feb 2026 08:33PM UTC coverage: 89.223% (-0.2%) from 89.45%
21786443631

push

github

Giorgi
Drop netstandard2.0 and net6.0 target frameworks

Update target frameworks to net8.0 and net10.0,
remove all conditional compilation directives for
NET5_0_OR_GREATER, NET6_0_OR_GREATER, and
NET8_0_OR_GREATER. Delete polyfills and shims that
were only needed for older frameworks. Remove
[Experimental] attributes from scalar/table function
APIs.

1197 of 1389 branches covered (86.18%)

Branch coverage included in aggregate %.

12 of 12 new or added lines in 8 files covered. (100.0%)

14 existing lines in 8 files now uncovered.

2330 of 2564 relevant lines covered (90.87%)

557293.59 hits per line

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

90.76
/DuckDB.NET.Data/DataChunk/Reader/NumericVectorDataReader.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Numerics;
4
using System.Runtime.CompilerServices;
5
using DuckDB.NET.Data.Extensions;
6
using DuckDB.NET.Native;
7

8
namespace DuckDB.NET.Data.DataChunk.Reader;
9

10
internal sealed class NumericVectorDataReader : VectorDataReaderBase
11
{
12
    private const int VarIntHeaderSize = 3;
13

14
    internal unsafe NumericVectorDataReader(void* dataPointer, ulong* validityMaskPointer, DuckDBType columnType, string columnName) : base(dataPointer, validityMaskPointer, columnType, columnName)
44,910✔
15
    {
16
    }
44,910✔
17

18
    protected override T GetValidValue<T>(ulong offset, Type targetType)
19
    {
20
        var isFloatingNumericType = TypeExtensions.IsFloatingNumericType<T>();
2,786,873✔
21
        var isIntegralNumericType = TypeExtensions.IsIntegralNumericType<T>();
2,786,873✔
22

23
        if (!(isIntegralNumericType || isFloatingNumericType))
2,786,873✔
24
        {
25
            return base.GetValidValue<T>(offset, targetType);
18,858✔
26
        }
27

28
        //If T is integral type and column is also integral read the data and use Unsafe.As<> or Convert.ChangeType to change type
29
        //If T is floating and column is floating too, read data and cast to T
30
        //Otherwise use the non-generic path
31
        if (isIntegralNumericType)
2,768,015✔
32
        {
33
            return DuckDBType switch
1,276,423!
34
            {
1,276,423✔
35
                DuckDBType.TinyInt => GetUnmanagedTypeValue<sbyte, T>(offset),
96✔
36
                DuckDBType.SmallInt => GetUnmanagedTypeValue<short, T>(offset),
96✔
37
                DuckDBType.Integer => GetUnmanagedTypeValue<int, T>(offset),
956,362✔
38
                DuckDBType.BigInt => GetUnmanagedTypeValue<long, T>(offset),
150,474✔
39
                DuckDBType.UnsignedTinyInt => GetUnmanagedTypeValue<byte, T>(offset),
96✔
40
                DuckDBType.UnsignedSmallInt => GetUnmanagedTypeValue<ushort, T>(offset),
96✔
41
                DuckDBType.UnsignedInteger => GetUnmanagedTypeValue<uint, T>(offset),
96✔
42
                DuckDBType.UnsignedBigInt => GetUnmanagedTypeValue<ulong, T>(offset),
168✔
43
                DuckDBType.HugeInt => GetBigInteger<T>(offset, false),
66✔
44
                DuckDBType.UnsignedHugeInt => GetBigInteger<T>(offset, true),
36✔
45
                DuckDBType.VarInt => GetBigInteger<T>(offset),
168,837✔
46
                _ => base.GetValidValue<T>(offset, targetType)
×
47
            };
1,276,423✔
48
        }
49

50
        return DuckDBType switch
1,491,592!
51
        {
1,491,592✔
52
            DuckDBType.Float => (T)(object)GetFieldData<float>(offset),
746,753✔
53
            DuckDBType.Double => (T)(object)GetFieldData<double>(offset),
744,839✔
54
            _ => base.GetValidValue<T>(offset, targetType)
×
55
        };
1,491,592✔
56
    }
57

58
    internal override object GetValue(ulong offset, Type targetType)
59
    {
60
        var value = DuckDBType switch
10,644,962!
61
        {
10,644,962✔
62
            DuckDBType.TinyInt => GetFieldData<sbyte>(offset),
1,129,143✔
63
            DuckDBType.SmallInt => GetFieldData<short>(offset),
1,131,865✔
64
            DuckDBType.Integer => GetFieldData<int>(offset),
393,138✔
65
            DuckDBType.BigInt => GetFieldData<long>(offset),
1,211,861✔
66
            DuckDBType.UnsignedTinyInt => GetFieldData<byte>(offset),
1,133,817✔
67
            DuckDBType.UnsignedSmallInt => GetFieldData<ushort>(offset),
1,124,660✔
68
            DuckDBType.UnsignedInteger => GetFieldData<uint>(offset),
1,123,094✔
69
            DuckDBType.UnsignedBigInt => GetFieldData<ulong>(offset),
1,115,147✔
70
            DuckDBType.Float => GetFieldData<float>(offset),
372,145✔
71
            DuckDBType.Double => GetFieldData<double>(offset),
373,984✔
72
            DuckDBType.HugeInt => GetBigInteger(offset, false),
744,401✔
73
            DuckDBType.UnsignedHugeInt => GetBigInteger(offset, true),
754,180✔
74
            DuckDBType.VarInt => GetBigInteger<BigInteger>(offset),
37,527✔
75
            _ => base.GetValue(offset, targetType)
×
76
        };
10,644,962✔
77

78
        if (targetType.IsNumeric())
10,644,962✔
79
        {
80
            try
81
            {
82
                return Convert.ChangeType(value, targetType);
10,626,104✔
83
            }
84
            catch (OverflowException)
15✔
85
            {
86
                throw new InvalidCastException($"Cannot cast from {value.GetType().Name} to {targetType.Name} in column {ColumnName}");
15✔
87
            }
88
        }
89

90
        throw new InvalidCastException($"Cannot cast from {value.GetType().Name} to {targetType.Name} in column {ColumnName}");
18,858✔
91
    }
10,626,089✔
92

93
    internal unsafe BigInteger GetBigInteger(ulong offset, bool unsigned)
94
    {
95
        if (unsigned)
2,623,592✔
96
        {
97
            var unsignedHugeInt = (DuckDBUHugeInt*)DataPointer + offset;
754,216✔
98
            return unsignedHugeInt->ToBigInteger();
754,216✔
99
        }
100
        else
101
        {
102
            var hugeInt = (DuckDBHugeInt*)DataPointer + offset;
1,869,376✔
103
            return hugeInt->ToBigInteger();
1,869,376✔
104
        }
105
    }
106

107
    private unsafe T GetBigInteger<T>(ulong offset)
108
    {
109
        var data = (DuckDBString*)DataPointer + offset;
206,364✔
110

111
        if (data->Length < VarIntHeaderSize + 1)
206,364!
112
        {
113
            throw new DuckDBException("Invalid blob size for Varint.");
×
114
        }
115

116
        var buffer = new ReadOnlySpan<byte>(data->Data, data->Length);
206,364✔
117

118
        var isNegative = (buffer[0] & 0x80) == 0;
206,364✔
119

120
        var bytes = new List<byte>(data->Length - VarIntHeaderSize);
206,364✔
121

122
        for (var index = VarIntHeaderSize; index < buffer.Length; index++)
2,345,586✔
123
        {
124
            if (isNegative)
966,429✔
125
            {
126
                bytes.Add((byte)~buffer[index]);
470,001✔
127
            }
128
            else
129
            {
130
                bytes.Add(buffer[index]);
496,428✔
131
            }
132
        }
133

134
        var bigIntegerDigits = new Stack<char>();
206,364✔
135

136
        while (bytes.Count > 0)
2,451,543✔
137
        {
138
            var quotient = new List<char>();
2,245,179✔
139

140
            byte remainder = 0;
2,245,179✔
141

142
            foreach (var @byte in bytes)
21,970,122✔
143
            {
144
                var newValue = remainder * 256 + @byte;
8,739,882✔
145
                quotient.Add(DigitToChar(newValue / 10));
8,739,882✔
146

147
                remainder = (byte)(newValue % 10);
8,739,882✔
148
            }
149

150
            bigIntegerDigits.Push(DigitToChar(remainder));
2,245,179✔
151

152
            // Remove leading zeros from the quotient
153
            bytes.Clear();
2,245,179✔
154

155
            foreach (var digit in quotient)
21,970,122✔
156
            {
157
                if (digit != '0' || bytes.Count > 0)
8,739,882✔
158
                {
159
                    bytes.Add(CharToDigit(digit));
7,773,453✔
160
                }
161
            }
162
        }
163

164
        if (isNegative)
206,364✔
165
        {
166
            bigIntegerDigits.Push('-');
102,342✔
167
        }
168

169
        var integer = BigInteger.Parse(new string(bigIntegerDigits.ToArray()));
206,364✔
170

171
        try
172
        {
173
            return CastTo<T>(integer);
206,364✔
174
        }
175
        catch (OverflowException)
92,709✔
176
        {
177
            throw new InvalidCastException($"Cannot cast from {nameof(BigInteger)} to {typeof(T).Name} in column {ColumnName}");
92,709✔
178
        }
179

180
        char DigitToChar(int c) => (char)(c + '0');
10,985,061✔
181

182
        byte CharToDigit(char digit) => (byte)(digit - '0');
7,773,453✔
183
    }
113,655✔
184

185
    private T GetBigInteger<T>(ulong offset, bool unsigned)
186
    {
187
        var bigInteger = GetBigInteger(offset, unsigned);
102✔
188

189
        try
190
        {
191
            return CastTo<T>(bigInteger);
102✔
192
        }
193
        catch (OverflowException)
×
194
        {
195
            throw new InvalidCastException($"Cannot cast from {nameof(BigInteger)} to {typeof(T).Name} in column {ColumnName}");
×
196
        }
197
    }
102✔
198

199
    private static T CastTo<T>(BigInteger bigInteger)
200
    {
201
        if (typeof(T) == typeof(byte))
206,466✔
202
        {
203
            return (T)(object)(byte)bigInteger;
18,759✔
204
        }
205

206
        if (typeof(T) == typeof(sbyte))
187,707✔
207
        {
208
            return (T)(object)(sbyte)bigInteger;
18,762✔
209
        }
210

211
        if (typeof(T) == typeof(short))
168,945✔
212
        {
213
            return (T)(object)(short)bigInteger;
18,762✔
214
        }
215

216
        if (typeof(T) == typeof(ushort))
150,183✔
217
        {
218
            return (T)(object)(ushort)bigInteger;
18,759✔
219
        }
220

221
        if (typeof(T) == typeof(int))
131,424✔
222
        {
223
            return (T)(object)(int)bigInteger;
18,762✔
224
        }
225

226
        if (typeof(T) == typeof(uint))
112,662✔
227
        {
228
            return (T)(object)(uint)bigInteger;
18,762✔
229
        }
230

231
        if (typeof(T) == typeof(long))
93,900✔
232
        {
233
            return (T)(object)(long)bigInteger;
18,762✔
234
        }
235

236
        if (typeof(T) == typeof(ulong))
75,138✔
237
        {
238
            return (T)(object)(ulong)bigInteger;
18,762✔
239
        }
240

241
        return (T)(object)bigInteger;
56,376✔
242
    }
243

244
    private TResult GetUnmanagedTypeValue<TQuery, TResult>(ulong offset) where TQuery : unmanaged
245
        , INumberBase<TQuery>
246
    {
247
        var resultType = typeof(TResult);
1,107,484✔
248
        var value = GetFieldData<TQuery>(offset);
1,107,484✔
249

250
        if (typeof(TQuery) == resultType)
1,107,484✔
251
        {
252
            return Unsafe.As<TQuery, TResult>(ref value);
1,106,785✔
253
        }
254

255
        try
256
        {
257
            if (resultType == typeof(byte))
699✔
258
            {
259
                return (TResult)(object)byte.CreateChecked(value);
90✔
260
            }
261
            if (resultType == typeof(sbyte))
609✔
262
            {
263
                return (TResult)(object)sbyte.CreateChecked(value);
90✔
264
            }
265
            if (resultType == typeof(short))
519✔
266
            {
267
                return (TResult)(object)short.CreateChecked(value);
90✔
268
            }
269
            if (resultType == typeof(ushort))
429✔
270
            {
271
                return (TResult)(object)ushort.CreateChecked(value);
90✔
272
            }
273
            if (resultType == typeof(int))
339✔
274
            {
275
                return (TResult)(object)int.CreateChecked(value);
87✔
276
            }
277
            if (resultType == typeof(uint))
252✔
278
            {
279
                return (TResult)(object)uint.CreateChecked(value);
90✔
280
            }
281
            if (resultType == typeof(long))
162✔
282
            {
283
                return (TResult)(object)long.CreateChecked(value);
81✔
284
            }
285
            if (resultType == typeof(ulong))
81!
286
            {
287
                return (TResult)(object)ulong.CreateChecked(value);
81✔
288
            }
289

UNCOV
290
            return (TResult)Convert.ChangeType(value, resultType);
×
291
        }
292
        catch (OverflowException)
243✔
293
        {
294
            throw new InvalidCastException($"Cannot cast from {value.GetType().Name} to {resultType.Name} in column {ColumnName}");
243✔
295
        }
296
    }
456✔
297
}
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