diff --git a/DuckDB.NET.Data/DuckDBCommand.cs b/DuckDB.NET.Data/DuckDBCommand.cs index 23620cdf..3401f489 100644 --- a/DuckDB.NET.Data/DuckDBCommand.cs +++ b/DuckDB.NET.Data/DuckDBCommand.cs @@ -1,5 +1,6 @@ using DuckDB.NET.Native; using System; +using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Common; @@ -12,6 +13,8 @@ public class DuckDBCommand : DbCommand { private DuckDBConnection? connection; private readonly DuckDBParameterCollection parameters = new(); + private bool prepared; + private readonly List preparedStatements = new(); protected override DbTransaction? DbTransaction { get; set; } protected override DbParameterCollection DbParameterCollection => parameters; @@ -32,6 +35,8 @@ public class DuckDBCommand : DbCommand /// public bool UseStreamingMode { get; set; } = false; + internal DuckDBDataReader? DataReader { get; set; } + private string commandText = string.Empty; #if NET6_0_OR_GREATER @@ -43,7 +48,13 @@ public override string CommandText get => commandText; set { - // TODO: We shouldn't be able to change the CommandText when the command is in execution (requires CommandState implementation) + if (DataReader != null) + throw new InvalidOperationException("cannot change CommandText while a reader is open"); + + if (commandText == value) + return; + + DisposePreparedStatements(); commandText = value ?? string.Empty; } } @@ -80,14 +91,13 @@ public override int ExecuteNonQuery() { EnsureConnectionOpen(); - var results = PreparedStatement.PreparedStatement.PrepareMultiple(connection!.NativeConnection, CommandText, parameters, UseStreamingMode); - var count = 0; - foreach (var result in results) + foreach (var statement in GetStatements()) { - var current = result; + var current = statement.Execute(); count += (int)NativeMethods.Query.DuckDBRowsChanged(ref current); + current.Dispose(); } return count; @@ -111,15 +121,28 @@ public override int ExecuteNonQuery() return (DuckDBDataReader)base.ExecuteReader(behavior); } + protected override void Dispose(bool disposing) + { + if (disposing) + { + DataReader?.Dispose(); + } + + DisposePreparedStatements(); + + base.Dispose(disposing); + } + protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) { - EnsureConnectionOpen(); + if (DataReader != null) + throw new InvalidOperationException("cannot create a new reader while one is open"); - var results = PreparedStatement.PreparedStatement.PrepareMultiple(connection!.NativeConnection, CommandText, parameters, UseStreamingMode); + EnsureConnectionOpen(); - var reader = new DuckDBDataReader(this, results, behavior); + var closeConnection = behavior.HasFlag(CommandBehavior.CloseConnection); - return reader; + return new DuckDBDataReader(this, GetStatements(), closeConnection); } public override void Prepare() { } @@ -128,6 +151,17 @@ public override void Prepare() { } internal void CloseConnection() => Connection!.Close(); + private void DisposePreparedStatements() + { + foreach (var statement in preparedStatements) + { + statement.Dispose(); + } + + preparedStatements.Clear(); + prepared = false; + } + private void EnsureConnectionOpen([CallerMemberName] string operation = "") { if (Connection is null || Connection.State != ConnectionState.Open) @@ -135,4 +169,54 @@ private void EnsureConnectionOpen([CallerMemberName] string operation = "") throw new InvalidOperationException($"{operation} requires an open connection"); } } + + private IEnumerable GetStatements() + { + foreach (var statement in prepared + ? preparedStatements + : PrepareAndEnumerateStatements()) + { + statement.BindParameters(Parameters); + statement.UseStreamingMode = UseStreamingMode; + yield return statement; + } + } + + private IEnumerable PrepareAndEnumerateStatements() + { + DisposePreparedStatements(); + + using var unmanagedQuery = CommandText.ToUnmanagedString(); + + var statementCount = NativeMethods.ExtractStatements.DuckDBExtractStatements(connection!.NativeConnection, unmanagedQuery, out var extractedStatements); + + using (extractedStatements) + { + if (statementCount <= 0) + { + var error = NativeMethods.ExtractStatements.DuckDBExtractStatementsError(extractedStatements); + throw new DuckDBException(error.ToManagedString(false)); + } + + for (int index = 0; index < statementCount; index++) + { + var status = NativeMethods.ExtractStatements.DuckDBPrepareExtractedStatement(connection!.NativeConnection, extractedStatements, index, out var unmanagedStatement); + + if (status.IsSuccess()) + { + var statement = new PreparedStatement.PreparedStatement(unmanagedStatement); + preparedStatements.Add(statement); + yield return statement; + } + else + { + var errorMessage = NativeMethods.PreparedStatements.DuckDBPrepareError(unmanagedStatement).ToManagedString(false); + + throw new DuckDBException(string.IsNullOrEmpty(errorMessage) ? "DuckDBQuery failed" : errorMessage); + } + } + } + + prepared = true; + } } \ No newline at end of file diff --git a/DuckDB.NET.Data/DuckDBDataReader.cs b/DuckDB.NET.Data/DuckDBDataReader.cs index bada5ad4..eafbf8e2 100644 --- a/DuckDB.NET.Data/DuckDBDataReader.cs +++ b/DuckDB.NET.Data/DuckDBDataReader.cs @@ -12,9 +12,9 @@ namespace DuckDB.NET.Data; public class DuckDBDataReader : DbDataReader { private readonly DuckDBCommand command; - private readonly CommandBehavior behavior; + private readonly bool closeConnection; - private DuckDBResult currentResult; + private DuckDBResult? currentResult; private DuckDBDataChunk? currentChunk; private int fieldCount; @@ -27,35 +27,51 @@ public class DuckDBDataReader : DbDataReader private bool streamingResult; private long currentChunkIndex; - private readonly IEnumerator resultEnumerator; + private readonly IEnumerator statementEnumerator; private VectorDataReaderBase[] vectorReaders = []; private Dictionary columnMapping = []; - internal DuckDBDataReader(DuckDBCommand command, IEnumerable queryResults, CommandBehavior behavior) + internal DuckDBDataReader(DuckDBCommand command, IEnumerable statements, bool closeConnection) { this.command = command; - this.behavior = behavior; - resultEnumerator = queryResults.GetEnumerator(); + this.closeConnection = closeConnection; + statementEnumerator = statements.GetEnumerator(); InitNextReader(); + + // Do not modify the command's state when InitNextReader() throws an exception. + command.DataReader = this; } private bool InitNextReader() { - while (resultEnumerator.MoveNext()) + while (statementEnumerator.MoveNext()) { - if (NativeMethods.Query.DuckDBResultReturnType(resultEnumerator.Current) == DuckDBResultType.QueryResult) + currentResult?.Dispose(); + currentResult = null; // Prevent double disposal. + + try { - currentChunkIndex = 0; - currentResult = resultEnumerator.Current; + var current = statementEnumerator.Current.Execute(); + currentResult = current; - columnMapping = []; - fieldCount = (int)NativeMethods.Query.DuckDBColumnCount(ref currentResult); - streamingResult = NativeMethods.Types.DuckDBResultIsStreaming(currentResult) > 0; + if (NativeMethods.Query.DuckDBResultReturnType(current) == DuckDBResultType.QueryResult) + { + currentChunkIndex = 0; - hasRows = InitChunkData(); + columnMapping = []; + fieldCount = (int)NativeMethods.Query.DuckDBColumnCount(ref current); + streamingResult = NativeMethods.Types.DuckDBResultIsStreaming(current) > 0; - return true; + hasRows = InitChunkData(); + + return true; + } + } + catch + { + Dispose(); + throw; } } @@ -69,8 +85,10 @@ private bool InitChunkData() reader.Dispose(); } + var current = currentResult!.Value; + currentChunk?.Dispose(); - currentChunk = streamingResult ? NativeMethods.StreamingResult.DuckDBStreamFetchChunk(currentResult) : NativeMethods.Types.DuckDBResultGetChunk(currentResult, currentChunkIndex); + currentChunk = streamingResult ? NativeMethods.StreamingResult.DuckDBStreamFetchChunk(current) : NativeMethods.Types.DuckDBResultGetChunk(current, currentChunkIndex); rowsReadFromCurrentChunk = 0; @@ -85,9 +103,9 @@ private bool InitChunkData() { var vector = NativeMethods.DataChunks.DuckDBDataChunkGetVector(currentChunk, index); - using var logicalType = NativeMethods.Query.DuckDBColumnLogicalType(ref currentResult, index); + using var logicalType = NativeMethods.Query.DuckDBColumnLogicalType(ref current, index); - var columnName = vectorReaders[index]?.ColumnName ?? NativeMethods.Query.DuckDBColumnName(ref currentResult, index).ToManagedString(false); + var columnName = vectorReaders[index]?.ColumnName ?? NativeMethods.Query.DuckDBColumnName(ref current, index).ToManagedString(false); vectorReaders[index] = VectorDataReaderFactory.CreateReader(vector, logicalType, columnName); } @@ -291,7 +309,7 @@ public override bool Read() public override IEnumerator GetEnumerator() { - return new DbEnumerator(this, behavior == CommandBehavior.CloseConnection); + return new DbEnumerator(this, closeConnection); } public override DataTable GetSchemaTable() @@ -340,20 +358,39 @@ public override void Close() { if (closed) return; + command.DataReader = null; + foreach (var reader in vectorReaders) { reader.Dispose(); } + currentResult?.Dispose(); + currentResult = null; // Prevent double disposal. + currentChunk?.Dispose(); - if (behavior == CommandBehavior.CloseConnection) + try { - command.CloseConnection(); + // Try to consume the enumerator to ensure that all statements are prepared. + while (statementEnumerator.MoveNext()) + { + // No-op. + } + } + catch + { + // Dispose() must not throw exceptions. } + statementEnumerator.Dispose(); + closed = true; - resultEnumerator.Dispose(); + + if (closeConnection) + { + command.CloseConnection(); + } } private void CheckRowRead() diff --git a/DuckDB.NET.Data/PreparedStatement/PreparedStatement.cs b/DuckDB.NET.Data/PreparedStatement/PreparedStatement.cs index c7245dc8..0adacb07 100644 --- a/DuckDB.NET.Data/PreparedStatement/PreparedStatement.cs +++ b/DuckDB.NET.Data/PreparedStatement/PreparedStatement.cs @@ -1,6 +1,5 @@ using DuckDB.NET.Native; using System; -using System.Collections.Generic; using System.Linq; namespace DuckDB.NET.Data.PreparedStatement; @@ -9,50 +8,16 @@ internal sealed class PreparedStatement : IDisposable { private readonly DuckDBPreparedStatement statement; - private PreparedStatement(DuckDBPreparedStatement statement) - { - this.statement = statement; - } + internal bool UseStreamingMode { get; set; } - public static IEnumerable PrepareMultiple(DuckDBNativeConnection connection, string query, DuckDBParameterCollection parameters, bool useStreamingMode) + internal PreparedStatement(DuckDBPreparedStatement statement) { - using var unmanagedQuery = query.ToUnmanagedString(); - - var statementCount = NativeMethods.ExtractStatements.DuckDBExtractStatements(connection, unmanagedQuery, out var extractedStatements); - - using (extractedStatements) - { - if (statementCount <= 0) - { - var error = NativeMethods.ExtractStatements.DuckDBExtractStatementsError(extractedStatements); - throw new DuckDBException(error.ToManagedString(false)); - } - - for (int index = 0; index < statementCount; index++) - { - var status = NativeMethods.ExtractStatements.DuckDBPrepareExtractedStatement(connection, extractedStatements, index, out var statement); - - if (status.IsSuccess()) - { - using var preparedStatement = new PreparedStatement(statement); - using var result = preparedStatement.Execute(parameters, useStreamingMode); - yield return result; - } - else - { - var errorMessage = NativeMethods.PreparedStatements.DuckDBPrepareError(statement).ToManagedString(false); - - throw new DuckDBException(string.IsNullOrEmpty(errorMessage) ? "DuckDBQuery failed" : errorMessage); - } - } - } + this.statement = statement; } - private DuckDBResult Execute(DuckDBParameterCollection parameterCollection, bool useStreamingMode) + internal DuckDBResult Execute() { - BindParameters(statement, parameterCollection); - - var status = useStreamingMode + var status = UseStreamingMode ? NativeMethods.PreparedStatements.DuckDBExecutePreparedStreaming(statement, out var queryResult) : NativeMethods.PreparedStatements.DuckDBExecutePrepared(statement, out queryResult); @@ -78,9 +43,9 @@ private DuckDBResult Execute(DuckDBParameterCollection parameterCollection, bool return queryResult; } - private static void BindParameters(DuckDBPreparedStatement preparedStatement, DuckDBParameterCollection parameterCollection) + internal void BindParameters(DuckDBParameterCollection parameterCollection) { - var expectedParameters = NativeMethods.PreparedStatements.DuckDBParams(preparedStatement); + var expectedParameters = NativeMethods.PreparedStatements.DuckDBParams(statement); if (parameterCollection.Count < expectedParameters) { throw new InvalidOperationException($"Invalid number of parameters. Expected {expectedParameters}, got {parameterCollection.Count}"); @@ -90,10 +55,10 @@ private static void BindParameters(DuckDBPreparedStatement preparedStatement, Du { foreach (DuckDBParameter param in parameterCollection) { - var state = NativeMethods.PreparedStatements.DuckDBBindParameterIndex(preparedStatement, out var index, param.ParameterName.ToUnmanagedString()); + var state = NativeMethods.PreparedStatements.DuckDBBindParameterIndex(statement, out var index, param.ParameterName.ToUnmanagedString()); if (state.IsSuccess()) { - BindParameter(preparedStatement, index, param); + BindParameter(index, param); } } } @@ -102,23 +67,23 @@ private static void BindParameters(DuckDBPreparedStatement preparedStatement, Du for (var i = 0; i < expectedParameters; ++i) { var param = parameterCollection[i]; - BindParameter(preparedStatement, i + 1, param); + BindParameter(i + 1, param); } } } - private static void BindParameter(DuckDBPreparedStatement preparedStatement, long index, DuckDBParameter parameter) + private void BindParameter(long index, DuckDBParameter parameter) { - using var parameterLogicalType = NativeMethods.PreparedStatements.DuckDBParamLogicalType(preparedStatement, index); + using var parameterLogicalType = NativeMethods.PreparedStatements.DuckDBParamLogicalType(statement, index); var duckDBType = NativeMethods.LogicalType.DuckDBGetTypeId(parameterLogicalType); using var duckDBValue = parameter.Value.ToDuckDBValue(parameterLogicalType, duckDBType); - var result = NativeMethods.PreparedStatements.DuckDBBindValue(preparedStatement, index, duckDBValue); + var result = NativeMethods.PreparedStatements.DuckDBBindValue(statement, index, duckDBValue); if (!result.IsSuccess()) { - var errorMessage = NativeMethods.PreparedStatements.DuckDBPrepareError(preparedStatement).ToManagedString(false); + var errorMessage = NativeMethods.PreparedStatements.DuckDBPrepareError(statement).ToManagedString(false); throw new InvalidOperationException($"Unable to bind parameter {index}: {errorMessage}"); } } diff --git a/DuckDB.NET.Samples/Program.cs b/DuckDB.NET.Samples/Program.cs index b0292a88..898c6276 100644 --- a/DuckDB.NET.Samples/Program.cs +++ b/DuckDB.NET.Samples/Program.cs @@ -73,8 +73,10 @@ private static void AdoNetSamples() var executeScalar = command.ExecuteScalar(); command.CommandText = "SELECT foo, bar FROM integers"; - var reader = command.ExecuteReader(); - PrintQueryResults(reader); + using (var reader = command.ExecuteReader()) + { + PrintQueryResults(reader); + } var results = duckDBConnection.Query("SELECT foo, bar FROM integers"); @@ -144,7 +146,7 @@ private static void PrintQueryResults(DbDataReader queryResult) } Console.WriteLine(); - + while (queryResult.Read()) { for (int ordinal = 0; ordinal < queryResult.FieldCount; ordinal++) diff --git a/DuckDB.NET.Test/DuckDBBitStringReaderTests.cs b/DuckDB.NET.Test/DuckDBBitStringReaderTests.cs index 31b07c5f..22ba4d0a 100644 --- a/DuckDB.NET.Test/DuckDBBitStringReaderTests.cs +++ b/DuckDB.NET.Test/DuckDBBitStringReaderTests.cs @@ -11,7 +11,7 @@ public class DuckDBBitStringReaderTests(DuckDBDatabaseFixture db) : DuckDBTestBa public void ReadBitString() { Command.CommandText = "SELECT bitstring('0101011', 12)"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); reader.GetFieldType(0).Should().Be(typeof(string)); @@ -27,7 +27,7 @@ public void ReadBitString() public void ReadBitStringAsBitArray() { Command.CommandText = "SELECT bitstring('0101011', 12)"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var expected = new BitArray(new bool[] { false, false, false, false, false, false, true, false, true, false, true, true }); diff --git a/DuckDB.NET.Test/DuckDBDataReaderListTests.cs b/DuckDB.NET.Test/DuckDBDataReaderListTests.cs index 9a66df52..22ac75fd 100644 --- a/DuckDB.NET.Test/DuckDBDataReaderListTests.cs +++ b/DuckDB.NET.Test/DuckDBDataReaderListTests.cs @@ -111,24 +111,24 @@ public void ReadMultipleListOfStrings() public void ReadMultipleListOfDecimals() { Command.CommandText = "Select * from ( SELECT [1.1, 2.3456, NULL] Union Select [73.56725, 264387.632673487236]) order by 1"; - var reader = Command.ExecuteReader(); - - reader.Read(); - var list = reader.GetFieldValue>(0); - list.Should().BeEquivalentTo(new List { 1.1m, 2.3456m, null }); + using (var reader = Command.ExecuteReader()) + { + reader.Read(); + var list = reader.GetFieldValue>(0); + list.Should().BeEquivalentTo(new List { 1.1m, 2.3456m, null }); - reader.Read(); - var value = reader.GetValue(0); - value.Should().BeEquivalentTo(new List { 73.56725m, 264387.632673487236m }); - reader.Dispose(); + reader.Read(); + var value = reader.GetValue(0); + value.Should().BeEquivalentTo(new List { 73.56725m, 264387.632673487236m }); + } Command.CommandText = "SELECT [1.1, 2.34] "; - reader = Command.ExecuteReader(); - - reader.Read(); - list = reader.GetFieldValue>(0); - list.Should().BeEquivalentTo(new List { 1.1m, 2.34m }); - reader.Dispose(); + using (var reader = Command.ExecuteReader()) + { + reader.Read(); + var list = reader.GetFieldValue>(0); + list.Should().BeEquivalentTo(new List { 1.1m, 2.34m }); + } } [Fact] diff --git a/DuckDB.NET.Test/DuckDBDataReaderMapTests.cs b/DuckDB.NET.Test/DuckDBDataReaderMapTests.cs index 30c46f14..8999d7e1 100644 --- a/DuckDB.NET.Test/DuckDBDataReaderMapTests.cs +++ b/DuckDB.NET.Test/DuckDBDataReaderMapTests.cs @@ -12,7 +12,7 @@ public class DuckDBDataReaderMapTests(DuckDBDatabaseFixture db) : DuckDBTestBase public void ReadMap() { Command.CommandText = "SELECT MAP { 'key1': 1, 'key2': 5, 'key3': 7 }"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.GetFieldType(0).Should().Be(typeof(Dictionary)); reader.Read(); @@ -28,7 +28,7 @@ public void ReadMap() public void ReadMapTwoRows() { Command.CommandText = "Select * from (SELECT MAP { 'key1': 1, 'key2': 5, 'key3': 7 } Union SELECT MAP { 'key2': 15, 'key24': 7 }) order by 1"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var value = reader.GetValue(0); @@ -50,7 +50,7 @@ public void ReadMapTwoRows() public void ReadMapStronglyTyped() { Command.CommandText = "SELECT MAP { 'key1': 1, 'key2': 5, 'key3': 7 }"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var value = reader.GetFieldValue>(0); @@ -63,7 +63,7 @@ public void ReadMapStronglyTyped() public void ReadMapWithNullInNullableDictionary() { Command.CommandText = "SELECT MAP { 'key1': 1, 'key2': NULL, 'key3': 7 }"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var value = reader.GetFieldValue>(0); @@ -76,7 +76,7 @@ public void ReadMapWithNullInNullableDictionary() public void ReadMapWithNullInReferenceTypeDictionary() { Command.CommandText = "SELECT MAP { 'key1': 'abc', 'key2': NULL, 'key3': 'ghi' }"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var value = reader.GetFieldValue>(0); @@ -89,7 +89,7 @@ public void ReadMapWithNullInReferenceTypeDictionary() public void ReadMapWithNullInNotNullableDictionaryThrowsException() { Command.CommandText = "SELECT MAP { 'key1': 1, 'key2': NULL, 'key3': 7 }"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); reader.Invoking(r => r.GetFieldValue>(0)).Should().Throw(); @@ -99,7 +99,7 @@ public void ReadMapWithNullInNotNullableDictionaryThrowsException() public void ReadMapOfList() { Command.CommandText = "SELECT MAP { ['a', 'b']: [1.1, 2.2], ['c', 'd']: [3.3, 4.4] };"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); @@ -121,7 +121,7 @@ public void ReadMapOfList() public void ReadMapWrongTypeThrowsException() { Command.CommandText = "SELECT MAP { ['a', 'b']: [1.1, 2.2], ['c', 'd']: [3.3, 4.4] };"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); reader.Invoking(r => r.GetFieldValue>>(0)).Should().Throw(); diff --git a/DuckDB.NET.Test/DuckDBDataReaderTests.cs b/DuckDB.NET.Test/DuckDBDataReaderTests.cs index ad3cdd66..e3aff697 100644 --- a/DuckDB.NET.Test/DuckDBDataReaderTests.cs +++ b/DuckDB.NET.Test/DuckDBDataReaderTests.cs @@ -21,7 +21,7 @@ public void GetOrdinalReturnsColumnIndex() Command.CommandText = "select * from GetOrdinalTests"; Command.UseStreamingMode = true; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.GetOrdinal("key").Should().Be(0); reader.GetOrdinal("value").Should().Be(1); @@ -37,7 +37,7 @@ public void GetOrdinalRepeatedColumnReturnsFirstIndex() Command.CommandText = "select value, key, value from GetOrdinalTests"; Command.UseStreamingMode = true; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.GetOrdinal("key").Should().Be(1); reader.GetOrdinal("value").Should().Be(0); @@ -52,7 +52,7 @@ public void CloseConnectionClosesConnection() Command.ExecuteNonQuery(); Command.CommandText = "select * from CloseConnectionTests"; - var reader = Command.ExecuteReader(CommandBehavior.CloseConnection); + using var reader = Command.ExecuteReader(CommandBehavior.CloseConnection); reader.Close(); reader.IsClosed.Should().BeTrue(); @@ -63,7 +63,7 @@ public void CloseConnectionClosesConnection() public void ReadValueBeforeReadThrowsException() { Command.CommandText = "select 24"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Invoking(r => r.IsDBNull(0)).Should().Throw(); reader.Invoking(r => r.GetValue(0)).Should().Throw(); @@ -86,7 +86,7 @@ public void ReaderValues() Command.ExecuteNonQuery(); Command.CommandText = "select * from IndexerValuesTests"; - var reader = Command.ExecuteReader(CommandBehavior.CloseConnection); + using var reader = Command.ExecuteReader(CommandBehavior.CloseConnection); reader.Read(); @@ -138,46 +138,51 @@ public void ReaderEnumerator() public void ReadIntervalValues() { Command.CommandText = "SELECT INTERVAL 1 YEAR;"; + using (var reader = Command.ExecuteReader()) + { + reader.Read(); + reader.GetFieldType(0).Should().Be(typeof(TimeSpan)); + reader.GetDataTypeName(0).Should().Be(DuckDBType.Interval.ToString()); - var reader = Command.ExecuteReader(); - reader.Read(); - reader.GetFieldType(0).Should().Be(typeof(TimeSpan)); - reader.GetDataTypeName(0).Should().Be(DuckDBType.Interval.ToString()); - - var interval = reader.GetFieldValue(0); - reader.Invoking(r => r.GetValue(0)).Should().Throw(); + var interval = reader.GetFieldValue(0); + reader.Invoking(r => r.GetValue(0)).Should().Throw(); - interval.Months.Should().Be(12); + interval.Months.Should().Be(12); + } Command.CommandText = "SELECT INTERVAL '28' DAYS;"; - reader = Command.ExecuteReader(); - reader.Read(); + using (var reader = Command.ExecuteReader()) + { + reader.Read(); - interval = reader.GetFieldValue(0); - var value = (TimeSpan)reader.GetValue(0); + var interval = reader.GetFieldValue(0); + var value = (TimeSpan)reader.GetValue(0); - var timeSpan = reader.GetFieldValue(0); - timeSpan.Days.Should().Be(28); + var timeSpan = reader.GetFieldValue(0); + timeSpan.Days.Should().Be(28); - interval.Days.Should().Be(28); - value.Days.Should().Be(28); + interval.Days.Should().Be(28); + value.Days.Should().Be(28); + } Command.CommandText = "SELECT INTERVAL 30 SECONDS;"; - reader = Command.ExecuteReader(); - reader.Read(); + using (var reader = Command.ExecuteReader()) + { + reader.Read(); - interval = reader.GetFieldValue(0); - timeSpan = (TimeSpan)reader.GetValue(0); + var interval = reader.GetFieldValue(0); + var timeSpan = (TimeSpan)reader.GetValue(0); - interval.Micros.Should().Be(30_000_000); - timeSpan.Should().Be(TimeSpan.FromSeconds(30)); + interval.Micros.Should().Be(30_000_000); + timeSpan.Should().Be(TimeSpan.FromSeconds(30)); + } } [Fact] public void LoadDataTable() { Command.CommandText = "select 1 as num, 'text' as str, TIMESTAMP '1992-09-20 20:38:40' as tme"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); var dt = new DataTable(); dt.Load(reader); dt.Rows.Count.Should().Be(1); @@ -308,7 +313,7 @@ public void ReadPivotStatementResult() Command.ExecuteNonQuery(); Command.CommandText = "PIVOT Cities ON Year USING SUM(Population);"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); reader.HasRows.Should().BeTrue(); @@ -327,7 +332,7 @@ public void ReadInsertReturningClause() SELECT 2 AS i, 3 AS j RETURNING *, i * j AS i_times_j;"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); reader.HasRows.Should().BeTrue(); @@ -339,7 +344,7 @@ public void ReadInsertReturningClause() public void ReadNonQueryAsResult() { Command.CommandText = "CREATE TABLE IndexerValuesTests (key INTEGER, value decimal, State Boolean, ErrorCode Integer, mean Float, stdev double)"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.HasRows.Should().BeFalse(); reader.Invoking(r => r.Close()).Should().NotThrow(); @@ -429,7 +434,7 @@ public void ReadVarint() { Command.CommandText = "SELECT (-1234)::VARINT"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var value = (BigInteger)reader.GetValue(0); } diff --git a/DuckDB.NET.Test/DuckDBManagedAppenderListTests.cs b/DuckDB.NET.Test/DuckDBManagedAppenderListTests.cs index 491fad40..c8b1b125 100644 --- a/DuckDB.NET.Test/DuckDBManagedAppenderListTests.cs +++ b/DuckDB.NET.Test/DuckDBManagedAppenderListTests.cs @@ -51,7 +51,7 @@ public void ListValuesInt() { ListValuesInternal("Integer", faker => faker.Random.Int()); } - + [Fact] public void ListValuesIntNullable() { @@ -256,7 +256,7 @@ public void ListGuidAndGuid() for (var i = 1; i <= 10000; i++) { var id = Guid.NewGuid(); - + appender.CreateRow().AppendValue(id).AppendValue(guids).EndRow(); } } @@ -283,7 +283,7 @@ public void ListDecimalAndGuid() for (var i = 1; i <= 10000; i++) { var id = Guid.NewGuid(); - + appender.CreateRow().AppendValue(id).AppendValue(decimalList).EndRow(); } } @@ -332,7 +332,7 @@ private void ListValuesInternal(string typeName, Func generator, in } Command.CommandText = $"SELECT * FROM {table} order by 1"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); var index = 0; while (reader.Read()) diff --git a/DuckDB.NET.Test/DuckDBManagedAppenderTests.cs b/DuckDB.NET.Test/DuckDBManagedAppenderTests.cs index ce99465a..f3ffb4dc 100644 --- a/DuckDB.NET.Test/DuckDBManagedAppenderTests.cs +++ b/DuckDB.NET.Test/DuckDBManagedAppenderTests.cs @@ -277,7 +277,7 @@ public void TemporalValues() result.Select(tuple => tuple.Item8).Should().BeEquivalentTo(dates.Select(TimeOnly.FromDateTime)); Command.CommandText = "Select i from managedAppenderTemporal"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); int index = -1; while (reader.Read()) @@ -624,7 +624,7 @@ public void AppendDefault() } Command.CommandText = "Select * from tbl"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var i = reader.GetInt32(0); diff --git a/DuckDB.NET.Test/Parameters/BlobParameterTests.cs b/DuckDB.NET.Test/Parameters/BlobParameterTests.cs index 2691b8b3..08072fff 100644 --- a/DuckDB.NET.Test/Parameters/BlobParameterTests.cs +++ b/DuckDB.NET.Test/Parameters/BlobParameterTests.cs @@ -15,50 +15,54 @@ public void SimpleTest() Command.CommandText = "SELECT 'ABCD'::BLOB;"; Command.ExecuteNonQuery(); - var reader = Command.ExecuteReader(); - reader.Read(); - - using (var stream = reader.GetStream(0)) + using (var reader = Command.ExecuteReader()) { - stream.Length.Should().Be(4); - stream.CanWrite.Should().Be(false); + reader.Read(); - using (var streamReader = new StreamReader(stream, leaveOpen: true)) + using (var stream = reader.GetStream(0)) { - var text = streamReader.ReadToEnd(); - text.Should().Be("ABCD"); + stream.Length.Should().Be(4); + stream.CanWrite.Should().Be(false); + + using (var streamReader = new StreamReader(stream, leaveOpen: true)) + { + var text = streamReader.ReadToEnd(); + text.Should().Be("ABCD"); + } } - } - using (var streamItem = (Stream)reader.GetValue(0)) - { - using (var streamReader = new StreamReader(streamItem, leaveOpen: true)) + using (var streamItem = (Stream)reader.GetValue(0)) { - var text = streamReader.ReadToEnd(); - text.Should().Be("ABCD"); + using (var streamReader = new StreamReader(streamItem, leaveOpen: true)) + { + var text = streamReader.ReadToEnd(); + text.Should().Be("ABCD"); + } } } Command.CommandText = "SELECT 'AB\\x0aCD'::BLOB"; Command.ExecuteNonQuery(); - reader = Command.ExecuteReader(); - reader.Read(); - - using (var stream = reader.GetStream(0)) + using (var reader = Command.ExecuteReader()) { - stream.Length.Should().Be(5); - using (var streamReader = new StreamReader(stream, leaveOpen: true)) - { - var text = streamReader.ReadLine(); - text.Should().Be("AB"); + reader.Read(); - text = streamReader.ReadLine(); - text.Should().Be("CD"); + using (var stream = reader.GetStream(0)) + { + stream.Length.Should().Be(5); + using (var streamReader = new StreamReader(stream, leaveOpen: true)) + { + var text = streamReader.ReadLine(); + text.Should().Be("AB"); + + text = streamReader.ReadLine(); + text.Should().Be("CD"); + } } - } - reader.GetFieldType(0).Should().Be(typeof(Stream)); + reader.GetFieldType(0).Should().Be(typeof(Stream)); + } } [Fact] @@ -68,7 +72,7 @@ public void SeekTest() Command.CommandText = $"SELECT '{blobValue}'::BLOB;"; Command.ExecuteNonQuery(); - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); using var stream = reader.GetStream(0); @@ -113,7 +117,7 @@ public void BindValueTest() var command = Connection.CreateCommand(); command.CommandText = "SELECT * from BlobTests;"; - var reader = command.ExecuteReader(); + using var reader = command.ExecuteReader(); reader.Read(); using (var stream = reader.GetStream(1)) diff --git a/DuckDB.NET.Test/Parameters/DateTests.cs b/DuckDB.NET.Test/Parameters/DateTests.cs index 48c82447..ce9a8f4a 100644 --- a/DuckDB.NET.Test/Parameters/DateTests.cs +++ b/DuckDB.NET.Test/Parameters/DateTests.cs @@ -34,7 +34,7 @@ public void QueryScalarTest(int year, int mon, int day) public void BindWithCastTest(int year, int mon, int day) { var expectedValue = new DateTime(year, mon, day); - + Command.CommandText = "SELECT ?::DATE;"; Command.Parameters.Add(new DuckDBParameter((DuckDBDateOnly)expectedValue)); @@ -61,36 +61,39 @@ public void InsertAndQueryTest(int year, byte mon, byte day) Command.CommandText = "INSERT INTO DateOnlyTestTable (a, b) VALUES (42, ?);"; Command.Parameters.Add(new DuckDBParameter(new DuckDBDateOnly (year,mon,day))); Command.ExecuteNonQuery(); - + Command.Parameters.Clear(); Command.CommandText = "SELECT * FROM DateOnlyTestTable LIMIT 1;"; - var reader = Command.ExecuteReader(); - reader.Read(); + using (var reader = Command.ExecuteReader()) + { + reader.Read(); - reader.GetFieldType(1).Should().Be(typeof(DateOnly)); + reader.GetFieldType(1).Should().Be(typeof(DateOnly)); - var dateOnly = reader.GetFieldValue(1); + var dateOnly = reader.GetFieldValue(1); - dateOnly.Year.Should().Be(year); - dateOnly.Month.Should().Be(mon); - dateOnly.Day.Should().Be(day); + dateOnly.Year.Should().Be(year); + dateOnly.Month.Should().Be(mon); + dateOnly.Day.Should().Be(day); - var dateTime = dateOnly.ToDateTime(); - dateTime.Year.Should().Be(year); - dateTime.Month.Should().Be(mon); - dateTime.Day.Should().Be(day); - dateTime.Hour.Should().Be(0); - dateTime.Minute.Should().Be(0); - dateTime.Second.Should().Be(0); + var dateTime = dateOnly.ToDateTime(); + dateTime.Year.Should().Be(year); + dateTime.Month.Should().Be(mon); + dateTime.Day.Should().Be(day); + dateTime.Hour.Should().Be(0); + dateTime.Minute.Should().Be(0); + dateTime.Second.Should().Be(0); - reader.GetFieldValue(1).Should().Be(new DateOnly(year, mon, day)); + reader.GetFieldValue(1).Should().Be(new DateOnly(year, mon, day)); - var convertedValue = (DateTime) dateOnly; - convertedValue.Should().Be(dateTime); + var convertedValue = (DateTime)dateOnly; + convertedValue.Should().Be(dateTime); - reader.GetFieldValue(2).Should().BeNull(); - reader.Invoking(dataReader => dataReader.GetFieldValue(2)).Should().Throw().Where(ex => ex.Message.Contains("nullableDateColumn")); + reader.GetFieldValue(2).Should().BeNull(); + reader.Invoking(dataReader => dataReader.GetFieldValue(2)).Should() + .Throw().Where(ex => ex.Message.Contains("nullableDateColumn")); + } Command.CommandText = "DROP TABLE DateOnlyTestTable;"; Command.ExecuteNonQuery(); diff --git a/DuckDB.NET.Test/Parameters/DecimalParameterTest.cs b/DuckDB.NET.Test/Parameters/DecimalParameterTest.cs index fb0f4d4d..1d38834e 100644 --- a/DuckDB.NET.Test/Parameters/DecimalParameterTest.cs +++ b/DuckDB.NET.Test/Parameters/DecimalParameterTest.cs @@ -24,7 +24,7 @@ public void SimpleTest() var scalar = Command.ExecuteScalar(); scalar.Should().Be(value); - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var receivedValue = reader.GetDecimal(0); receivedValue.Should().Be(value); @@ -41,7 +41,7 @@ public void SimpleTest() var scalar = Command.ExecuteScalar(); scalar.Should().Be(value); - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var receivedValue = reader.GetDecimal(0); receivedValue.Should().Be(value); @@ -96,13 +96,15 @@ void DecimalTests(decimal[] values, int precision, int scale) var scalar = Command.ExecuteScalar(); scalar.Should().Be(value); - var reader = Command.ExecuteReader(); - reader.Read(); + using (var reader = Command.ExecuteReader()) + { + reader.Read(); - var receivedValue = reader.GetDecimal(0); - receivedValue.Should().Be(value); + var receivedValue = reader.GetDecimal(0); + receivedValue.Should().Be(value); - reader.GetFieldType(0).Should().Be(typeof(decimal)); + reader.GetFieldType(0).Should().Be(typeof(decimal)); + } Command.CommandText = "Delete from DecimalValuesTests"; Command.ExecuteNonQuery(); @@ -138,13 +140,15 @@ void DecimalTests(string[] cultures, decimal value, int precision, int scale) var scalar = Command.ExecuteScalar(); scalar.Should().Be(value); - var reader = Command.ExecuteReader(); - reader.Read(); + using (var reader = Command.ExecuteReader()) + { + reader.Read(); - var receivedValue = reader.GetDecimal(0); - receivedValue.Should().Be(value); + var receivedValue = reader.GetDecimal(0); + receivedValue.Should().Be(value); - reader.GetFieldType(0).Should().Be(typeof(decimal)); + reader.GetFieldType(0).Should().Be(typeof(decimal)); + } Command.CommandText = "Delete from DecimalValuesTests"; Command.ExecuteNonQuery(); diff --git a/DuckDB.NET.Test/Parameters/GuidParameterTests.cs b/DuckDB.NET.Test/Parameters/GuidParameterTests.cs index 39ed2412..dfbfd8a8 100644 --- a/DuckDB.NET.Test/Parameters/GuidParameterTests.cs +++ b/DuckDB.NET.Test/Parameters/GuidParameterTests.cs @@ -20,7 +20,7 @@ public void ReadGuid() var scalar = Command.ExecuteScalar(); scalar.Should().Be(guid); - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); reader.GetFieldType(0).Should().Be(typeof(Guid)); @@ -36,7 +36,7 @@ public void ReadGuidNullable() Command.CommandText = "SELECT ?::uuid;"; Command.Parameters.Add(new DuckDBParameter(DbType.Guid, null)); - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var receivedValue = reader.GetFieldValue(0); @@ -58,7 +58,7 @@ public void InsertGuidSelect() Command.ExecuteNonQuery(); Command.CommandText = "SELECT * FROM uuid_test;"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var guid = reader.GetFieldValue(0); @@ -81,7 +81,7 @@ public void BindValueTest() var scalar = Command.ExecuteScalar(); scalar.Should().Be(guid); - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var receivedValue = reader.GetGuid(0); receivedValue.Should().Be(guid); diff --git a/DuckDB.NET.Test/Parameters/HugeIntParameterTests.cs b/DuckDB.NET.Test/Parameters/HugeIntParameterTests.cs index bc965706..0d3c3b9b 100644 --- a/DuckDB.NET.Test/Parameters/HugeIntParameterTests.cs +++ b/DuckDB.NET.Test/Parameters/HugeIntParameterTests.cs @@ -17,7 +17,7 @@ public void SimpleTest() var scalar = Command.ExecuteScalar(); scalar.Should().Be(new BigInteger(125)); - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var receivedValue = reader.GetFieldValue(0); receivedValue.Should().Be(125); @@ -46,7 +46,7 @@ public void BindValueTest() Command.CommandText = "SELECT * from HugeIntTests;"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var receivedValue = reader.GetFieldValue(1); @@ -62,7 +62,7 @@ public void SimpleNegativeHugeIntTest() var scalar = Command.ExecuteScalar(); scalar.Should().Be(DuckDBHugeInt.HugeIntMinValue); - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var receivedValue = reader.GetFieldValue(0); receivedValue.Should().Be(DuckDBHugeInt.HugeIntMinValue); @@ -82,7 +82,7 @@ public void BindNegativeHugeIntValueTest() Command.CommandText = "SELECT * from NegativeHugeIntTests;"; - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var receivedValue = reader.GetFieldValue(1); diff --git a/DuckDB.NET.Test/Parameters/IntegerParametersTests.cs b/DuckDB.NET.Test/Parameters/IntegerParametersTests.cs index 9f09ddce..f2448cac 100644 --- a/DuckDB.NET.Test/Parameters/IntegerParametersTests.cs +++ b/DuckDB.NET.Test/Parameters/IntegerParametersTests.cs @@ -19,7 +19,7 @@ private void TestBind(string duckDbType, TValue expectedValue, DuckDBPar var scalar = Command.ExecuteScalar(); scalar.Should().Be(expectedValue); - var reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); var value = getValue(reader); diff --git a/DuckDB.NET.Test/Parameters/ListParameterTests.cs b/DuckDB.NET.Test/Parameters/ListParameterTests.cs index 4820d554..ff8bc619 100644 --- a/DuckDB.NET.Test/Parameters/ListParameterTests.cs +++ b/DuckDB.NET.Test/Parameters/ListParameterTests.cs @@ -29,17 +29,19 @@ private void TestInsertSelect(string duckDbType, Func generator, in Command.CommandText = "SELECT * FROM ParameterListTest;"; - using var reader = Command.ExecuteReader(); - reader.Read(); + using (var reader = Command.ExecuteReader()) + { + reader.Read(); - var value = reader.GetFieldValue>(0); - value.Should().BeEquivalentTo(list); + var value = reader.GetFieldValue>(0); + value.Should().BeEquivalentTo(list); - var arrayValue = reader.GetFieldValue>(1); - arrayValue.Should().BeEquivalentTo(list.Take(10)); + var arrayValue = reader.GetFieldValue>(1); + arrayValue.Should().BeEquivalentTo(list.Take(10)); - var nestedListValue = reader.GetFieldValue>>(2); - nestedListValue.Should().BeEquivalentTo(nestedList); + var nestedListValue = reader.GetFieldValue>>(2); + nestedListValue.Should().BeEquivalentTo(nestedList); + } Command.CommandText = "DROP TABLE ParameterListTest"; Command.ExecuteNonQuery(); diff --git a/DuckDB.NET.Test/Parameters/TimeTests.cs b/DuckDB.NET.Test/Parameters/TimeTests.cs index 83044368..4b26c7c7 100644 --- a/DuckDB.NET.Test/Parameters/TimeTests.cs +++ b/DuckDB.NET.Test/Parameters/TimeTests.cs @@ -86,32 +86,34 @@ public void InsertAndQueryTest(byte hour, byte minute, byte second, int microsec Command.Parameters.Clear(); Command.CommandText = "SELECT * FROM TimeOnlyTestTable LIMIT 1;"; - var reader = Command.ExecuteReader(); - reader.Read(); + using (var reader = Command.ExecuteReader()) + { + reader.Read(); - reader.GetFieldType(1).Should().Be(typeof(TimeOnly)); + reader.GetFieldType(1).Should().Be(typeof(TimeOnly)); - var duckDBTimeOnly = reader.GetFieldValue(1); + var duckDBTimeOnly = reader.GetFieldValue(1); - duckDBTimeOnly.Hour.Should().Be(hour); - duckDBTimeOnly.Min.Should().Be(minute); - duckDBTimeOnly.Sec.Should().Be(second); - duckDBTimeOnly.Microsecond.Should().Be(microsecond); + duckDBTimeOnly.Hour.Should().Be(hour); + duckDBTimeOnly.Min.Should().Be(minute); + duckDBTimeOnly.Sec.Should().Be(second); + duckDBTimeOnly.Microsecond.Should().Be(microsecond); - var dateTime = duckDBTimeOnly.ToDateTime(); - dateTime.Year.Should().Be(DateTime.MinValue.Year); - dateTime.Month.Should().Be(DateTime.MinValue.Month); - dateTime.Day.Should().Be(DateTime.MinValue.Day); - dateTime.Hour.Should().Be(hour); - dateTime.Minute.Should().Be(minute); - dateTime.Second.Should().Be(second); - dateTime.Millisecond.Should().Be(microsecond / 1000); + var dateTime = duckDBTimeOnly.ToDateTime(); + dateTime.Year.Should().Be(DateTime.MinValue.Year); + dateTime.Month.Should().Be(DateTime.MinValue.Month); + dateTime.Day.Should().Be(DateTime.MinValue.Day); + dateTime.Hour.Should().Be(hour); + dateTime.Minute.Should().Be(minute); + dateTime.Second.Should().Be(second); + dateTime.Millisecond.Should().Be(microsecond / 1000); - var convertedValue = (DateTime)duckDBTimeOnly; - convertedValue.Should().Be(dateTime); + var convertedValue = (DateTime)duckDBTimeOnly; + convertedValue.Should().Be(dateTime); - var timeOnly = reader.GetFieldValue(1); - timeOnly.Should().Be(new TimeOnly(hour, minute, second).Add(TimeSpan.FromTicks(microsecond * 10))); + var timeOnly = reader.GetFieldValue(1); + timeOnly.Should().Be(new TimeOnly(hour, minute, second).Add(TimeSpan.FromTicks(microsecond * 10))); + } Command.CommandText = "DROP TABLE TimeOnlyTestTable;"; Command.ExecuteNonQuery(); @@ -153,10 +155,13 @@ public void QueryTimeTzReaderTest(int hour, int minute, int second, int microsec { Command.CommandText = $"SELECT TIMETZ '{hour}:{minute}:{second}.{microsecond:000000}{offsetHours:00+##;00-##;}:{offsetMinutes:00}';"; - using var dataReader = Command.ExecuteReader(); - dataReader.Read(); + DateTimeOffset dateTimeOffset; + using (var dataReader = Command.ExecuteReader()) + { + dataReader.Read(); - var dateTimeOffset = dataReader.GetFieldValue(0); + dateTimeOffset = dataReader.GetFieldValue(0); + } dateTimeOffset.Hour.Should().Be((byte)hour); dateTimeOffset.Minute.Should().Be((byte)minute); @@ -165,7 +170,7 @@ public void QueryTimeTzReaderTest(int hour, int minute, int second, int microsec var timeSpan = new TimeSpan(offsetHours, offsetHours >= 0 ? offsetMinutes : -offsetMinutes, 0); dateTimeOffset.Offset.Should().Be(timeSpan); - + Command.CommandText = "SELECT ?::TIMETZ"; Command.Parameters.Add(new DuckDBParameter(dateTimeOffset)); @@ -186,7 +191,7 @@ public void QueryTimeTzReaderTest(int hour, int minute, int second, int microsec public void BindTimeOnly(int hour, int minute, int second, int microsecond) { var expectedValue = new TimeOnly(hour, minute, second,0).Add(TimeSpan.FromMicroseconds(microsecond)); - + Command.CommandText = "SELECT ?::TIME;"; Command.Parameters.Add(new DuckDBParameter(expectedValue)); diff --git a/DuckDB.NET.Test/Parameters/TimestampTests.cs b/DuckDB.NET.Test/Parameters/TimestampTests.cs index 53c47adf..4513dcdb 100644 --- a/DuckDB.NET.Test/Parameters/TimestampTests.cs +++ b/DuckDB.NET.Test/Parameters/TimestampTests.cs @@ -113,54 +113,56 @@ private void TestTimestampInsert(string timestampType, DuckDBType duckDBType, Da Command.Parameters.Clear(); Command.CommandText = "SELECT * FROM TimestampTestTable LIMIT 1;"; - var reader = Command.ExecuteReader(); - reader.Read(); + using (var reader = Command.ExecuteReader()) + { + reader.Read(); - reader.GetFieldType(1).Should().Be(typeof(DateTime)); + reader.GetFieldType(1).Should().Be(typeof(DateTime)); - var databaseValue = reader.GetDateTime(1); + var databaseValue = reader.GetDateTime(1); - databaseValue.Year.Should().Be(expectedValue.Year); - databaseValue.Month.Should().Be(expectedValue.Month); - databaseValue.Day.Should().Be(expectedValue.Day); - databaseValue.Hour.Should().Be(expectedValue.Hour); - databaseValue.Minute.Should().Be(expectedValue.Minute); - databaseValue.Second.Should().Be(expectedValue.Second); + databaseValue.Year.Should().Be(expectedValue.Year); + databaseValue.Month.Should().Be(expectedValue.Month); + databaseValue.Day.Should().Be(expectedValue.Day); + databaseValue.Hour.Should().Be(expectedValue.Hour); + databaseValue.Minute.Should().Be(expectedValue.Minute); + databaseValue.Second.Should().Be(expectedValue.Second); - databaseValue.Millisecond.Should().Be(expectedValue.Millisecond); - databaseValue.Microsecond.Should().Be(expectedValue.Microsecond); - databaseValue.Nanosecond.Should().Be(expectedValue.Nanosecond); + databaseValue.Millisecond.Should().Be(expectedValue.Millisecond); + databaseValue.Microsecond.Should().Be(expectedValue.Microsecond); + databaseValue.Nanosecond.Should().Be(expectedValue.Nanosecond); - databaseValue.TimeOfDay.Should().Be(expectedValue.TimeOfDay); + databaseValue.TimeOfDay.Should().Be(expectedValue.TimeOfDay); - var dateTimeNullable = reader.GetFieldValue(1); - databaseValue = dateTimeNullable.Value; + var dateTimeNullable = reader.GetFieldValue(1); + databaseValue = dateTimeNullable.Value; - databaseValue.Year.Should().Be(expectedValue.Year); - databaseValue.Month.Should().Be(expectedValue.Month); - databaseValue.Day.Should().Be(expectedValue.Day); - databaseValue.Hour.Should().Be(expectedValue.Hour); - databaseValue.Minute.Should().Be(expectedValue.Minute); - databaseValue.Second.Should().Be(expectedValue.Second); + databaseValue.Year.Should().Be(expectedValue.Year); + databaseValue.Month.Should().Be(expectedValue.Month); + databaseValue.Day.Should().Be(expectedValue.Day); + databaseValue.Hour.Should().Be(expectedValue.Hour); + databaseValue.Minute.Should().Be(expectedValue.Minute); + databaseValue.Second.Should().Be(expectedValue.Second); - databaseValue.Millisecond.Should().Be(expectedValue.Millisecond); - databaseValue.Microsecond.Should().Be(expectedValue.Microsecond); - databaseValue.Nanosecond.Should().Be(expectedValue.Nanosecond); + databaseValue.Millisecond.Should().Be(expectedValue.Millisecond); + databaseValue.Microsecond.Should().Be(expectedValue.Microsecond); + databaseValue.Nanosecond.Should().Be(expectedValue.Nanosecond); - databaseValue.TimeOfDay.Should().Be(expectedValue.TimeOfDay); + databaseValue.TimeOfDay.Should().Be(expectedValue.TimeOfDay); - var dateTimeOffset = reader.GetFieldValue(1); + var dateTimeOffset = reader.GetFieldValue(1); - dateTimeOffset.Year.Should().Be(expectedValue.Year); - dateTimeOffset.Month.Should().Be(expectedValue.Month); - dateTimeOffset.Day.Should().Be(expectedValue.Day); - dateTimeOffset.Hour.Should().Be(expectedValue.Hour); - dateTimeOffset.Minute.Should().Be(expectedValue.Minute); - dateTimeOffset.Second.Should().Be(expectedValue.Second); + dateTimeOffset.Year.Should().Be(expectedValue.Year); + dateTimeOffset.Month.Should().Be(expectedValue.Month); + dateTimeOffset.Day.Should().Be(expectedValue.Day); + dateTimeOffset.Hour.Should().Be(expectedValue.Hour); + dateTimeOffset.Minute.Should().Be(expectedValue.Minute); + dateTimeOffset.Second.Should().Be(expectedValue.Second); - dateTimeOffset.Millisecond.Should().Be(expectedValue.Millisecond); - dateTimeOffset.Microsecond.Should().Be(expectedValue.Microsecond); - dateTimeOffset.Nanosecond.Should().Be(expectedValue.Nanosecond); + dateTimeOffset.Millisecond.Should().Be(expectedValue.Millisecond); + dateTimeOffset.Microsecond.Should().Be(expectedValue.Microsecond); + dateTimeOffset.Nanosecond.Should().Be(expectedValue.Nanosecond); + } if (duckDBType == DuckDBType.TimestampTz) { @@ -174,10 +176,10 @@ private void TestTimestampInsert(string timestampType, DuckDBType duckDBType, Da Command.Parameters.Clear(); Command.CommandText = "SELECT * FROM TimestampTestTable LIMIT 1;"; - reader = Command.ExecuteReader(); + using var reader = Command.ExecuteReader(); reader.Read(); - dateTimeOffset = reader.GetFieldValue(1); + var dateTimeOffset = reader.GetFieldValue(1); dateTimeOffset.Year.Should().Be(expectedValue.Year); dateTimeOffset.Month.Should().Be(expectedValue.Month); diff --git a/README.md b/README.md index 0f5b1845..e5e38ccd 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ using (var duckDBConnection = new DuckDBConnection("Data Source=file.db")) var executeScalar = command.ExecuteScalar(); command.CommandText = "SELECT foo, bar FROM integers"; - var reader = command.ExecuteReader(); + using var reader = command.ExecuteReader(); PrintQueryResults(reader); }