• 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

84.44
/DuckDB.NET.Data/DataChunk/Reader/NumericVectorDataReader.cs
1
using System.Buffers;
2
using System.Runtime.CompilerServices;
3

4
namespace DuckDB.NET.Data.DataChunk.Reader;
5

6
internal sealed class NumericVectorDataReader : VectorDataReaderBase
7
{
8
    private const int VarIntHeaderSize = 3;
9

10
    internal unsafe NumericVectorDataReader(void* dataPointer, ulong* validityMaskPointer, DuckDBType columnType, string columnName) : base(dataPointer, validityMaskPointer, columnType, columnName)
44,646✔
11
    {
12
    }
44,646✔
13

14
    protected override T GetValidValue<T>(ulong offset, Type targetType)
15
    {
16
        var isFloatingNumericType = TypeExtensions.IsFloatingNumericType<T>();
4,052,164✔
17
        var isIntegralNumericType = TypeExtensions.IsIntegralNumericType<T>();
4,052,164✔
18

19
        if (!(isIntegralNumericType || isFloatingNumericType))
4,052,164✔
20
        {
21
            return base.GetValidValue<T>(offset, targetType);
18,858✔
22
        }
23

24
        //If T is integral type and column is also integral read the data and use Unsafe.As<> or Convert.ChangeType to change type
25
        //If T is floating and column is floating too, read data and cast to T
26
        //Otherwise use the non-generic path
27
        if (isIntegralNumericType)
4,033,306✔
28
        {
29
            return DuckDBType switch
1,782,584!
30
            {
1,782,584✔
31
                DuckDBType.TinyInt => GetUnmanagedTypeValue<sbyte, T>(offset),
96✔
32
                DuckDBType.SmallInt => GetUnmanagedTypeValue<short, T>(offset),
96✔
33
                DuckDBType.Integer => GetUnmanagedTypeValue<int, T>(offset),
1,342,472✔
34
                DuckDBType.BigInt => GetUnmanagedTypeValue<long, T>(offset),
270,516✔
35
                DuckDBType.UnsignedTinyInt => GetUnmanagedTypeValue<byte, T>(offset),
96✔
36
                DuckDBType.UnsignedSmallInt => GetUnmanagedTypeValue<ushort, T>(offset),
96✔
37
                DuckDBType.UnsignedInteger => GetUnmanagedTypeValue<uint, T>(offset),
96✔
38
                DuckDBType.UnsignedBigInt => GetUnmanagedTypeValue<ulong, T>(offset),
177✔
39
                DuckDBType.HugeInt => GetBigInteger<T>(offset, false),
66✔
40
                DuckDBType.UnsignedHugeInt => GetBigInteger<T>(offset, true),
36✔
41
                DuckDBType.VarInt => GetBigInteger<T>(offset),
168,837✔
42
                _ => base.GetValidValue<T>(offset, targetType)
×
43
            };
1,782,584✔
44
        }
45

46
        return DuckDBType switch
2,250,722!
47
        {
2,250,722✔
48
            DuckDBType.Float => (T)(object)GetFieldData<float>(offset),
1,122,416✔
49
            DuckDBType.Double => (T)(object)GetFieldData<double>(offset),
1,128,306✔
50
            _ => base.GetValidValue<T>(offset, targetType)
×
51
        };
2,250,722✔
52
    }
53

54
    internal override object GetValue(ulong offset, Type targetType)
55
    {
56
        var value = DuckDBType switch
9,619,334!
57
        {
9,619,334✔
58
            DuckDBType.TinyInt => GetFieldData<sbyte>(offset),
1,121,096✔
59
            DuckDBType.SmallInt => GetFieldData<short>(offset),
1,126,857✔
60
            DuckDBType.Integer => GetFieldData<int>(offset),
30,954✔
61
            DuckDBType.BigInt => GetFieldData<long>(offset),
1,314,781✔
62
            DuckDBType.UnsignedTinyInt => GetFieldData<byte>(offset),
1,125,978✔
63
            DuckDBType.UnsignedSmallInt => GetFieldData<ushort>(offset),
1,122,757✔
64
            DuckDBType.UnsignedInteger => GetFieldData<uint>(offset),
1,114,164✔
65
            DuckDBType.UnsignedBigInt => GetFieldData<ulong>(offset),
1,123,681✔
66
            DuckDBType.Float => GetFieldData<float>(offset),
78✔
67
            DuckDBType.Double => GetFieldData<double>(offset),
246✔
68
            DuckDBType.HugeInt => GetBigInteger(offset, false),
750,070✔
69
            DuckDBType.UnsignedHugeInt => GetBigInteger(offset, true),
751,145✔
70
            DuckDBType.VarInt => GetBigInteger<BigInteger>(offset),
37,527✔
71
            _ => base.GetValue(offset, targetType)
×
72
        };
9,619,334✔
73

74
        if (targetType.IsNumeric())
9,619,334✔
75
        {
76
            try
77
            {
78
                return Convert.ChangeType(value, targetType);
9,600,476✔
79
            }
80
            catch (OverflowException)
15✔
81
            {
82
                throw new InvalidCastException($"Cannot cast from {value.GetType().Name} to {targetType.Name} in column {ColumnName}");
15✔
83
            }
84
        }
85

86
        throw new InvalidCastException($"Cannot cast from {value.GetType().Name} to {targetType.Name} in column {ColumnName}");
18,858✔
87
    }
9,600,461✔
88

89
    internal unsafe BigInteger GetBigInteger(ulong offset, bool unsigned)
90
    {
91
        if (unsigned)
2,622,012✔
92
        {
93
            var unsignedHugeInt = (DuckDBUHugeInt*)DataPointer + offset;
751,181✔
94
            return unsignedHugeInt->ToBigInteger();
751,181✔
95
        }
96
        else
97
        {
98
            var hugeInt = (DuckDBHugeInt*)DataPointer + offset;
1,870,831✔
99
            return hugeInt->ToBigInteger();
1,870,831✔
100
        }
101
    }
102

103
    private unsafe T GetBigInteger<T>(ulong offset)
104
    {
105
        var data = (DuckDBString*)DataPointer + offset;
206,364✔
106

107
        if (data->Length < VarIntHeaderSize + 1)
206,364!
108
        {
109
            throw new DuckDBException("Invalid blob size for Varint.");
×
110
        }
111

112
        var buffer = new ReadOnlySpan<byte>(data->Data, data->Length);
206,364✔
113
        var isPositive = (buffer[0] & 0x80) != 0;
206,364✔
114
        var source = buffer.Slice(VarIntHeaderSize);
206,364✔
115

116
        byte[]? rented = null;
206,364✔
117

118
        try
119
        {
120
            if (isPositive) return ConvertNumeric<BigInteger, T>(new BigInteger(source, isUnsigned: true, isBigEndian: true));
310,386✔
121

122
            // Negative values need byte complementing — use stack for small payloads, pool for large.
123
            Span<byte> payload = source.Length <= 128
102,342!
124
                ? stackalloc byte[source.Length]
102,342✔
125
                : (rented = ArrayPool<byte>.Shared.Rent(source.Length)).AsSpan(0, source.Length);
102,342✔
126

127
            for (var i = 0; i < source.Length; i++)
1,144,686✔
128
            {
129
                payload[i] = (byte)~source[i];
470,001✔
130
            }
131

132
            return ConvertNumeric<BigInteger, T>(-new BigInteger(payload, isUnsigned: true, isBigEndian: true));
102,342✔
133
        }
134
        catch (OverflowException)
92,709✔
135
        {
136
            throw new InvalidCastException($"Cannot cast from {nameof(BigInteger)} to {typeof(T).Name} in column {ColumnName}");
92,709✔
137
        }
138
        finally
139
        {
140
            if (rented != null)
206,364!
141
            {
142
                ArrayPool<byte>.Shared.Return(rented);
×
143
            }
144
        }
206,364✔
145
    }
113,655✔
146

147
    private T GetBigInteger<T>(ulong offset, bool unsigned)
148
    {
149
        var bigInteger = GetBigInteger(offset, unsigned);
102✔
150

151
        try
152
        {
153
            return ConvertNumeric<BigInteger, T>(bigInteger);
102✔
154
        }
155
        catch (OverflowException)
×
156
        {
157
            throw new InvalidCastException($"Cannot cast from {nameof(BigInteger)} to {typeof(T).Name} in column {ColumnName}");
×
158
        }
159
    }
102✔
160

161
    private TResult GetUnmanagedTypeValue<TQuery, TResult>(ulong offset) where TQuery : unmanaged, INumberBase<TQuery>
162
    {
163
        var value = GetFieldData<TQuery>(offset);
1,613,645✔
164

165
        try
166
        {
167
            return ConvertNumeric<TQuery, TResult>(value);
1,613,645✔
168
        }
169
        catch (OverflowException)
243✔
170
        {
171
            throw new InvalidCastException($"Cannot cast from {typeof(TQuery).Name} to {typeof(TResult).Name} in column {ColumnName}");
243✔
172
        }
173
    }
1,613,402✔
174

175
    private static TResult ConvertNumeric<TSource, TResult>(TSource value) where TSource : INumberBase<TSource>
176
    {
177
        if (typeof(TSource) == typeof(TResult))
1,820,111✔
178
            return Unsafe.As<TSource, TResult>(ref value);
1,669,322✔
179

180
        if (typeof(TResult) == typeof(byte))       return (TResult)(object)byte.CreateChecked(value);
169,638✔
181
        if (typeof(TResult) == typeof(sbyte))      return (TResult)(object)sbyte.CreateChecked(value);
150,792✔
182
        if (typeof(TResult) == typeof(short))      return (TResult)(object)short.CreateChecked(value);
131,940✔
183
        if (typeof(TResult) == typeof(ushort))     return (TResult)(object)ushort.CreateChecked(value);
113,085✔
184
        if (typeof(TResult) == typeof(int))        return (TResult)(object)int.CreateChecked(value);
94,236✔
185
        if (typeof(TResult) == typeof(uint))       return (TResult)(object)uint.CreateChecked(value);
75,390✔
186
        if (typeof(TResult) == typeof(long))       return (TResult)(object)long.CreateChecked(value);
56,529✔
187
        if (typeof(TResult) == typeof(ulong))      return (TResult)(object)ulong.CreateChecked(value);
37,686!
188
        if (typeof(TResult) == typeof(BigInteger)) return (TResult)(object)BigInteger.CreateChecked(value);
×
189

190
        throw new InvalidCastException($"Cannot convert {typeof(TSource).Name} to {typeof(TResult).Name}");
×
191
    }
192
}
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