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 :(