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

Giorgi / DuckDB.NET / 21922970228

11 Feb 2026 09:04PM UTC coverage: 89.265% (+0.02%) from 89.25%
21922970228

push

github

Giorgi
Replace ToManagedString with custom marshallers

Introduce DuckDBOwnedStringMarshaller and
DuckDBCallerOwnedStringMarshaller to handle native string
lifetime semantics at the marshalling layer.

1195 of 1387 branches covered (86.16%)

Branch coverage included in aggregate %.

14 of 17 new or added lines in 10 files covered. (82.35%)

2314 of 2544 relevant lines covered (90.96%)

557359.58 hits per line

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

86.87
/DuckDB.NET.Data/Connection/ConnectionManager.cs
1
using System.Collections.Concurrent;
2
using System.Threading;
3

4
namespace DuckDB.NET.Data.Connection;
5

6
/// <summary>
7
/// Creates, caches, and disconnects ConnectionReferences.
8
/// </summary>
9
internal class ConnectionManager
10
{
11
    public static readonly ConnectionManager Default = new();
3✔
12

13
    private static readonly ConcurrentDictionary<string, FileReference> ConnectionCache = new(StringComparer.OrdinalIgnoreCase);
3✔
14

15
    internal ConnectionReference GetConnectionReference(DuckDBConnectionString connectionString)
16
    {
17
        var filename = connectionString.DataSource;
64,941✔
18

19
        var fileRef = connectionString.InMemory && !connectionString.Shared ? new FileReference("") : null;
64,941✔
20

21
        //need to loop until we have a locked fileRef
22
        //that is also in the cache
23
        while (fileRef == null)
65,146✔
24
        {
25
            fileRef = ConnectionCache.GetOrAdd(filename, fn =>
64,924✔
26
            {
64,924✔
27
                fileRef = new FileReference(filename);
46,448✔
28
                return fileRef;
46,448✔
29
            });
64,924✔
30

31
            Monitor.Enter(fileRef);
64,924✔
32

33
            //Need to make sure what we have locked is still in the cache
34
            var existingFileRef = ConnectionCache.GetOrAdd(filename, fileRef);
64,924✔
35

36
            if (existingFileRef == fileRef)
64,924✔
37
            {
38
                //file in the cache matches what is locked, we are good!
39
                break;
40
            }
41

42
            //exit lock and try the whole thing again
43
            Monitor.Exit(fileRef);
205✔
44
            fileRef = null;
205✔
45
        }
46

47
        //now connect what needs to be connected
48
        try
49
        {
50
            if (fileRef.Database == null)
64,941✔
51
            {
52
                var path = connectionString.InMemory ? null : filename;
51,355✔
53

54
                NativeMethods.Configuration.DuckDBCreateConfig(out var config);
51,355✔
55
                using (config)
51,355✔
56
                {
57
                    foreach (var (option, value) in connectionString.Configuration)
205,492✔
58
                    {
59
                        var state = NativeMethods.Configuration.DuckDBSetConfig(config, option, value);
51,394✔
60

61
                        if (!state.IsSuccess())
51,394✔
62
                        {
63
                            throw new DuckDBException($"Error setting '{option}' to '{value}'");
6✔
64
                        }
65
                    }
66

67
                    var resultOpen = NativeMethods.Startup.DuckDBOpen(path, out var db, config, out var error);
51,349✔
68

69
                    if (!resultOpen.IsSuccess())
51,349!
70
                    {
NEW
71
                        throw new DuckDBException($"DuckDBOpen failed: {error}");
×
72
                    }
73
                    fileRef.Database = db;
51,349✔
74
                }
51,349✔
75
            }
76

77
            var resultConnect = NativeMethods.Startup.DuckDBConnect(fileRef.Database, out var nativeConnection);
64,935✔
78

79
            if (resultConnect.IsSuccess())
64,935!
80
            {
81
                fileRef.Increment();
64,935✔
82
            }
83
            else
84
            {
85
                throw new DuckDBException("DuckDBConnect failed");
×
86
            }
87

88
            return new ConnectionReference(fileRef, nativeConnection);
64,935✔
89
        }
90
        finally
91
        {
92
            if (Monitor.IsEntered(fileRef))
64,941✔
93
            {
94
                Monitor.Exit(fileRef);
64,719✔
95
            }
96
        }
64,941✔
97
    }
64,935✔
98

99
    internal void ReturnConnectionReference(ConnectionReference connectionReference)
100
    {
101
        var fileRef = connectionReference.FileReferenceCounter;
64,932✔
102

103
        lock (fileRef)
64,932✔
104
        {
105
            var nativeConnection = connectionReference.NativeConnection;
64,932✔
106

107
            nativeConnection.Dispose();
64,932✔
108

109
            var current = fileRef.Decrement();
64,932✔
110

111
            if (current < 0)
64,932!
112
            {
113
                throw new InvalidOperationException($"{fileRef.FileName} has been returned too many times");
×
114
            }
115

116
            if (current == 0)
64,932✔
117
            {
118
                fileRef.Database?.Dispose();
51,343!
119
                fileRef.Database = null;
51,343✔
120

121
                if (!string.IsNullOrEmpty(fileRef.FileName) && !ConnectionCache.TryRemove(fileRef.FileName, out _))
51,343!
122
                {
123
                    throw new InvalidOperationException($"Internal Error: tried to remove {fileRef.FileName} from cache but it wasn't there!");
×
124
                }
125
            }
126
        }
64,932✔
127
    }
64,932✔
128

129
    internal ConnectionReference DuplicateConnectionReference(ConnectionReference connectionReference)
130
    {
131
        var fileRef = connectionReference.FileReferenceCounter;
3✔
132

133
        if (fileRef.Database is null)
3!
134
            throw new InvalidOperationException(); //shouldn't happen if we already have a connection reference
×
135

136
        lock (fileRef)
3✔
137
        {
138
            var resultConnect = NativeMethods.Startup.DuckDBConnect(fileRef.Database, out var duplicatedNativeConnection);
3✔
139
            if (resultConnect.IsSuccess())
3!
140
            {
141
                fileRef.Increment();
3✔
142
            }
143
            else
144
            {
145
                throw new DuckDBException("DuckDBConnect failed");
×
146
            }
147
            return new ConnectionReference(fileRef, duplicatedNativeConnection);
3✔
148
        }
149
    }
3✔
150
}
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