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

Giorgi / DuckDB.NET / 22260401650

21 Feb 2026 04:41PM UTC coverage: 89.769% (+0.02%) from 89.754%
22260401650

push

github

Giorgi
Cache enum dictionary lookups in EnumVectorDataReader

Use a dictionary to avoid repeated P/Invoke calls to
DuckDBEnumDictionaryValue for the same enum index.

1230 of 1427 branches covered (86.19%)

Branch coverage included in aggregate %.

16 of 18 new or added lines in 1 file covered. (88.89%)

2499 of 2727 relevant lines covered (91.64%)

320139.67 hits per line

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

86.21
/DuckDB.NET.Data/DataChunk/Reader/EnumVectorDataReader.cs
1
using System.Runtime.CompilerServices;
2

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

5
internal sealed class EnumVectorDataReader : VectorDataReaderBase
6
{
7
    private readonly DuckDBType enumType;
8
    private readonly DuckDBLogicalType logicalType;
9
    private readonly Dictionary<long, string> cachedNames = new(8);
382✔
10

11
    internal unsafe EnumVectorDataReader(IntPtr vector, void* dataPointer, ulong* validityMaskPointer, DuckDBType columnType, string columnName) : base(dataPointer, validityMaskPointer, columnType, columnName)
382✔
12
    {
13
        logicalType = NativeMethods.Vectors.DuckDBVectorGetColumnType(vector);
382✔
14
        enumType = NativeMethods.LogicalType.DuckDBEnumInternalType(logicalType);
382✔
15
    }
382✔
16

17
    protected override T GetValidValue<T>(ulong offset, Type targetType)
18
    {
19
        if (DuckDBType != DuckDBType.Enum)
24!
20
        {
21
            return base.GetValidValue<T>(offset, targetType);
×
22
        }
23

24
        switch (enumType)
24!
25
        {
26
            case DuckDBType.UnsignedTinyInt:
27
            {
28
                var enumValue = GetFieldData<byte>(offset);
16✔
29
                return ToEnumOrString(enumValue);
16✔
30
            }
31
            case DuckDBType.UnsignedSmallInt:
32
            {
33
                var enumValue = GetFieldData<ushort>(offset);
4✔
34
                return ToEnumOrString(enumValue);
4✔
35
            }
36
            case DuckDBType.UnsignedInteger:
37
            {
38
                var enumValue = GetFieldData<uint>(offset);
4✔
39
                return ToEnumOrString(enumValue);
4✔
40
            }
41
            default:
42
                throw new DuckDBException($"Invalid type {DuckDBType} ({(int)DuckDBType}) for column {ColumnName}");
×
43
        }
44

45
        T ToEnumOrString<TSource>(TSource enumValue) where TSource: IBinaryNumber<TSource>
46
        {
47
            if (typeof(T) == typeof(string))
24✔
48
            {
49
                var index = long.CreateChecked(enumValue);
16✔
50
                if (!cachedNames.TryGetValue(index, out var name))
16✔
51
                {
52
                    cachedNames[index] = name = NativeMethods.LogicalType.DuckDBEnumDictionaryValue(logicalType, index);
2✔
53
                }
54

55
                return (T)(object)name;
16✔
56
            }
57
            return Unsafe.As<TSource, T>(ref enumValue);
8✔
58
        }
59
    }
60

61
    internal override object GetValue(ulong offset, Type targetType)
62
    {
63
        if (DuckDBType == DuckDBType.Enum)
749,647!
64
        {
65
            long enumValue = enumType switch
749,647!
66
            {
749,647✔
67
                DuckDBType.UnsignedTinyInt => GetFieldData<byte>(offset),
749,631✔
68
                DuckDBType.UnsignedSmallInt => GetFieldData<ushort>(offset),
8✔
69
                DuckDBType.UnsignedInteger => GetFieldData<uint>(offset),
8✔
NEW
70
                _ => -1
×
71
            };
749,647✔
72

73
            if (targetType == typeof(string))
749,647✔
74
            {
75
                if (!cachedNames.TryGetValue(enumValue, out var name))
378,085✔
76
                {
77
                    cachedNames[enumValue] = name = NativeMethods.LogicalType.DuckDBEnumDictionaryValue(logicalType, enumValue);
44✔
78
                }
79

80
                return name;
378,085✔
81
            }
82

83
            return Enum.ToObject(targetType, enumValue);
371,562✔
84
        }
85

NEW
86
        return base.GetValue(offset, targetType);
×
87
    }
88

89
    public override void Dispose()
90
    {
91
        logicalType.Dispose();
56✔
92
        base.Dispose();
56✔
93
    }
56✔
94
}
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