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

Giorgi / DuckDB.NET / 21786556530

07 Feb 2026 08:39PM UTC coverage: 89.155% (-0.07%) from 89.223%
21786556530

push

github

Giorgi
Added support for clearing in-progress adapter

Requires DuckDB 1.5

1199 of 1393 branches covered (86.07%)

Branch coverage included in aggregate %.

6 of 8 new or added lines in 1 file covered. (75.0%)

193 existing lines in 43 files now uncovered.

2336 of 2572 relevant lines covered (90.82%)

557295.56 hits per line

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

93.5
/DuckDB.NET.Data/DuckDBConnection.cs
1
using DuckDB.NET.Data.Connection;
2
using System.ComponentModel;
3
using System.Diagnostics.CodeAnalysis;
4
using System.Runtime.CompilerServices;
5

6
namespace DuckDB.NET.Data;
7

8
public partial class DuckDBConnection : DbConnection
9
{
10
    private readonly ConnectionManager connectionManager = ConnectionManager.Default;
64,896✔
11
    private ConnectionState connectionState = ConnectionState.Closed;
12
    private DuckDBConnectionString? parsedConnection;
13
    private ConnectionReference? connectionReference;
14
    private bool inMemoryDuplication = false;
15
    
16
    private static readonly StateChangeEventArgs FromClosedToOpenEventArgs = new(ConnectionState.Closed, ConnectionState.Open);
3✔
17
    private static readonly StateChangeEventArgs FromOpenToClosedEventArgs = new(ConnectionState.Open, ConnectionState.Closed);
3✔
18

19
    #region Protected Properties
20

UNCOV
21
    protected override DbProviderFactory? DbProviderFactory => DuckDBClientFactory.Instance;
×
22

23
    #endregion
24

25
    internal DuckDBTransaction? Transaction { get; set; }
80,778✔
26

27
    internal DuckDBConnectionString ParsedConnection => parsedConnection ??= DuckDBConnectionStringBuilder.Parse(ConnectionString);
64,968✔
28

29
    public DuckDBConnection()
3✔
30
    {
31
        ConnectionString = string.Empty;
3✔
32
    }
3✔
33

34
    public DuckDBConnection(string connectionString)
64,893✔
35
    {
36
        ConnectionString = connectionString;
64,893✔
37
    }
64,893✔
38

39
    [AllowNull]
40
    [DefaultValue("")]
41
    public override string ConnectionString { get; set; }
190,128✔
42

43
    public override string Database
44
    {
45
        get
46
        {
47
            if (!string.IsNullOrEmpty(ConnectionString))
6✔
48
            {
49
                return ParsedConnection.DataSource;
3✔
50
            }
51

52
            throw new InvalidOperationException("Connection string must be specified.");
3✔
53
        }
54
    }
55

56
    public override string DataSource
57
    {
58
        get
59
        {
60
            if (!string.IsNullOrEmpty(ConnectionString))
6✔
61
            {
62
                return ParsedConnection!.DataSource;
3✔
63
            }
64

65
            throw new InvalidOperationException("Connection string must be specified.");
3✔
66
        }
67
    }
68

69
    /// <summary>
70
    /// Returns the native connection object that can be used to call DuckDB C API functions.
71
    /// </summary>
72
    public DuckDBNativeConnection NativeConnection => connectionReference?.NativeConnection
158,016!
73
                                                      ?? throw new InvalidOperationException("The DuckDBConnection must be open to access the native connection.");
158,016✔
74

UNCOV
75
    public override string ServerVersion => NativeMethods.Startup.DuckDBLibraryVersion().ToManagedString(false);
×
76

77
    public override ConnectionState State => connectionState;
258,057✔
78

79
    public override void ChangeDatabase(string databaseName)
80
    {
UNCOV
81
        throw new NotSupportedException();
×
82
    }
83

84
    public override void Close()
85
    {
86
        if (connectionState == ConnectionState.Closed)
64,938✔
87
        {
88
            throw new InvalidOperationException("Connection is already closed.");
6✔
89
        }
90

91
        if (connectionReference is not null) //Should always be the case
64,932✔
92
        {
93
            connectionManager.ReturnConnectionReference(connectionReference);
64,932✔
94
        }
95

96
        connectionState = ConnectionState.Closed;
64,932✔
97
        OnStateChange(FromOpenToClosedEventArgs);
64,932✔
98
    }
64,932✔
99

100
    public override void Open()
101
    {
102
        if (connectionState == ConnectionState.Open)
64,959✔
103
        {
104
            throw new InvalidOperationException("Connection is already open.");
3✔
105
        }
106

107
        //In case of inMemoryDuplication, we can safely take the hypothesis that connectionReference is already assigned
108
        connectionReference = inMemoryDuplication ? connectionManager.DuplicateConnectionReference(connectionReference!)
64,956✔
109
                                                  : connectionManager.GetConnectionReference(ParsedConnection);
64,956✔
110

111
        connectionState = ConnectionState.Open;
64,938✔
112
        OnStateChange(FromClosedToOpenEventArgs);
64,938✔
113
    }
64,938✔
114

115
    protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
116
    {
117
        return BeginTransaction(isolationLevel);
6✔
118
    }
119

120
    public new DuckDBTransaction BeginTransaction()
121
    {
122
        return BeginTransaction(IsolationLevel.Unspecified);
24✔
123
    }
124

125
    private new DuckDBTransaction BeginTransaction(IsolationLevel isolationLevel)
126
    {
127
        EnsureConnectionOpen();
30✔
128
        if (Transaction != null)
27✔
129
        {
130
            throw new InvalidOperationException("Already in a transaction.");
3✔
131
        }
132

133
        return Transaction = new DuckDBTransaction(this, isolationLevel);
24✔
134
    }
135

136
    protected override DbCommand CreateDbCommand()
137
    {
138
        return CreateCommand();
60,483✔
139
    }
140

141
    public new virtual DuckDBCommand CreateCommand()
142
    {
143
        return new DuckDBCommand
80,709✔
144
        {
80,709✔
145
            Connection = this,
80,709✔
146
            Transaction = Transaction
80,709✔
147
        };
80,709✔
148
    }
149

150
    public DuckDBAppender CreateAppender(string table) => CreateAppender(null, null, table);
177✔
151

152
    public DuckDBAppender CreateAppender(string? schema, string table) => CreateAppender(null, schema, table);
9✔
153

154
    public DuckDBAppender CreateAppender(string? catalog, string? schema, string table)
155
    {
156
        EnsureConnectionOpen();
198✔
157
        using var unmanagedCatalog = catalog.ToUnmanagedString();
198✔
158
        using var unmanagedSchema = schema.ToUnmanagedString();
198✔
159
        using var unmanagedTable = table.ToUnmanagedString();
198✔
160

161
        var appenderState = NativeMethods.Appender.DuckDBAppenderCreateExt(NativeConnection, unmanagedCatalog, unmanagedSchema, unmanagedTable, out var nativeAppender);
198✔
162

163
        if (!appenderState.IsSuccess())
198✔
164
        {
165
            try
166
            {
167
                DuckDBAppender.ThrowLastError(nativeAppender);
3✔
168
            }
169
            finally
170
            {
171
                nativeAppender.Close();
3✔
172
            }
3✔
173
        }
174

175
        return new DuckDBAppender(nativeAppender, GetTableName());
195✔
176

177
        string GetTableName()
178
        {
179
            return string.IsNullOrEmpty(schema) ? table : $"{schema}.{table}";
195✔
180
        }
181
    }
195✔
182

183
    /// <summary>
184
    /// Creates a type-safe appender using an AppenderMap for property-to-column mappings.
185
    /// </summary>
186
    /// <typeparam name="T">The type to append</typeparam>
187
    /// <typeparam name="TMap">The AppenderMap type defining the mappings</typeparam>
188
    /// <param name="table">The table name</param>
189
    /// <returns>A type-safe mapped appender</returns>
190
    public DuckDBMappedAppender<T, TMap> CreateAppender<T, TMap>(string table) 
191
        where TMap : Mapping.DuckDBAppenderMap<T>, new()
192
    {
193
        return CreateAppender<T, TMap>(null, null, table);
9✔
194
    }
195

196
    /// <summary>
197
    /// Creates a type-safe appender using an AppenderMap for property-to-column mappings.
198
    /// </summary>
199
    /// <typeparam name="T">The type to append</typeparam>
200
    /// <typeparam name="TMap">The AppenderMap type defining the mappings</typeparam>
201
    /// <param name="schema">The schema name</param>
202
    /// <param name="table">The table name</param>
203
    /// <returns>A type-safe mapped appender</returns>
204
    public DuckDBMappedAppender<T, TMap> CreateAppender<T, TMap>(string? schema, string table)
205
        where TMap : Mapping.DuckDBAppenderMap<T>, new()
206
    {
UNCOV
207
        return CreateAppender<T, TMap>(null, schema, table);
×
208
    }
209

210
    /// <summary>
211
    /// Creates a type-safe appender using an AppenderMap for property-to-column mappings.
212
    /// </summary>
213
    /// <typeparam name="T">The type to append</typeparam>
214
    /// <typeparam name="TMap">The AppenderMap type defining the mappings</typeparam>
215
    /// <param name="catalog">The catalog name</param>
216
    /// <param name="schema">The schema name</param>
217
    /// <param name="table">The table name</param>
218
    /// <returns>A type-safe mapped appender</returns>
219
    public DuckDBMappedAppender<T, TMap> CreateAppender<T, TMap>(string? catalog, string? schema, string table)
220
        where TMap : Mapping.DuckDBAppenderMap<T>, new()
221
    {
222
        var appender = CreateAppender(catalog, schema, table);
9✔
223
        return new DuckDBMappedAppender<T, TMap>(appender);
9✔
224
    }
225

226
    protected override void Dispose(bool disposing)
227
    {
228
        if (disposing)
64,904✔
229
        {
230
            // this check is to ensure exact same behavior as previous version
231
            // where Close() was calling Dispose(true) instead of the other way around.
232
            if (connectionState == ConnectionState.Open)
64,902✔
233
            {
234
                Close();
64,854✔
235
            }
236
        }
237

238
        base.Dispose(disposing);
64,904✔
239
    }
64,904✔
240

241
    private void EnsureConnectionOpen([CallerMemberName] string operation = "")
242
    {
243
        if (State != ConnectionState.Open)
237✔
244
        {
245
            throw new InvalidOperationException($"{operation} requires an open connection");
6✔
246
        }
247
    }
231✔
248

249
    public DuckDBConnection Duplicate()
250
    {
251
        EnsureConnectionOpen();
9✔
252

253
        // We're sure that the connectionString is not null because we previously checked the connection was open
254
        if (!ParsedConnection!.InMemory)
6✔
255
        {
256
            throw new NotSupportedException("Duplication of the connection is only supported for in-memory connections.");
3✔
257
        }
258

259
        var duplicatedConnection = new DuckDBConnection(ConnectionString)
3✔
260
        {
3✔
261
            parsedConnection = ParsedConnection,
3✔
262
            inMemoryDuplication = true,
3✔
263
            connectionReference = connectionReference,
3✔
264
        };
3✔
265

266
        return duplicatedConnection;
3✔
267
    }
268

269
    public override DataTable GetSchema() =>
270
        GetSchema(DbMetaDataCollectionNames.MetaDataCollections);
3✔
271

272
    public override DataTable GetSchema(string collectionName) =>
273
        GetSchema(collectionName, null);
45✔
274

275
    public override DataTable GetSchema(string collectionName, string?[]? restrictionValues) =>
276
        DuckDBSchema.GetSchema(this, collectionName, restrictionValues);
72✔
277

278
    public DuckDBQueryProgress GetQueryProgress()
279
    {
UNCOV
280
        EnsureConnectionOpen();
×
UNCOV
281
        return NativeMethods.Startup.DuckDBQueryProgress(NativeConnection);
×
282
    }
283
}
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