From 8c1ea91775b66a97e8210e92cab8f47bdf053baa Mon Sep 17 00:00:00 2001 From: Ivan Date: Wed, 21 Sep 2022 17:12:53 +0400 Subject: [PATCH] Fix null handling --- DuckDB.NET.Data/Extensions/ObjectExtension.cs | 10 ++++++ DuckDB.NET.Data/Internal/DbTypeMap.cs | 5 +-- DuckDB.NET.Data/Internal/PreparedStatement.cs | 3 +- .../Parameters/ParameterCollectionTests.cs | 32 +++++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 DuckDB.NET.Data/Extensions/ObjectExtension.cs diff --git a/DuckDB.NET.Data/Extensions/ObjectExtension.cs b/DuckDB.NET.Data/Extensions/ObjectExtension.cs new file mode 100644 index 0000000..55a67c6 --- /dev/null +++ b/DuckDB.NET.Data/Extensions/ObjectExtension.cs @@ -0,0 +1,10 @@ +#nullable enable +using System; + +namespace DuckDB.NET.Data.Extensions; + +internal static class NullExtension +{ + public static bool IsNull(this object? value) + => value is null or DBNull; +} \ No newline at end of file diff --git a/DuckDB.NET.Data/Internal/DbTypeMap.cs b/DuckDB.NET.Data/Internal/DbTypeMap.cs index efbe71a..be8c3f2 100644 --- a/DuckDB.NET.Data/Internal/DbTypeMap.cs +++ b/DuckDB.NET.Data/Internal/DbTypeMap.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Data; using System.Numerics; +using DuckDB.NET.Data.Extensions; namespace DuckDB.NET.Data.Internal; @@ -33,9 +34,9 @@ internal static class DbTypeMap public static DbType GetDbTypeForValue(object value) { - if (value == null) + if (value.IsNull()) { - throw new ArgumentNullException(nameof(value)); + return DbType.Object; } var type = value.GetType(); diff --git a/DuckDB.NET.Data/Internal/PreparedStatement.cs b/DuckDB.NET.Data/Internal/PreparedStatement.cs index f6ee15c..696a027 100644 --- a/DuckDB.NET.Data/Internal/PreparedStatement.cs +++ b/DuckDB.NET.Data/Internal/PreparedStatement.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Data; using System.Numerics; +using DuckDB.NET.Data.Extensions; namespace DuckDB.NET.Data; @@ -86,7 +87,7 @@ private static void BindParameters(DuckDBPreparedStatement preparedStatement, Du private static void BindParameter(DuckDBPreparedStatement preparedStatement, long index, DuckDBParameter parameter) { - if (parameter.Value == null) + if (parameter.Value.IsNull()) { NativeMethods.PreparedStatements.DuckDBBindNull(preparedStatement, index); return; diff --git a/DuckDB.NET.Test/Parameters/ParameterCollectionTests.cs b/DuckDB.NET.Test/Parameters/ParameterCollectionTests.cs index 1a90436..47d4e67 100644 --- a/DuckDB.NET.Test/Parameters/ParameterCollectionTests.cs +++ b/DuckDB.NET.Test/Parameters/ParameterCollectionTests.cs @@ -27,6 +27,23 @@ public void BindSingleValueTest(string query) var scalar = command.ExecuteScalar(); scalar.Should().Be(42); } + + [Theory] + [InlineData("SELECT ?1;")] + [InlineData("SELECT ?;")] + [InlineData("SELECT $1;")] + public void BindSingleValueNullTest(string query) + { + using var connection = new DuckDBConnection("DataSource=:memory:"); + connection.Open(); + + var command = connection.CreateCommand(); + + command.Parameters.Add(new DuckDBParameter("test", null)); + command.CommandText = query; + var scalar = command.ExecuteScalar(); + scalar.Should().Be(DBNull.Value); + } [Fact] public void BindNullValueTest() @@ -216,6 +233,21 @@ public void BindDapperDynamicParamsOnlyTest(string queryStatement) connection.Execute(queryStatement, dp); } + + [Theory] + [InlineData("SELECT ?1;")] + [InlineData("SELECT ?;")] + [InlineData("SELECT $1;")] + public void BindSingleValueDapperNullTest(string query) + { + using var connection = new DuckDBConnection("DataSource=:memory:"); + connection.Open(); + + var parameters = new DynamicParameters(); + parameters.Add("test", null); + var scalar = connection.QuerySingle(query, parameters); + scalar.Should().BeNull(); + } [Theory] // Dapper does not support such placeholders when using an object :(