You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2022/10/18 09:29:55 UTC

[ignite-3] branch main updated: IGNITE-17840 .NET: Allow null args in SQL and Compute (#1221)

This is an automated email from the ASF dual-hosted git repository.

ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new d7a04885a7 IGNITE-17840 .NET: Allow null args in SQL and Compute (#1221)
d7a04885a7 is described below

commit d7a04885a73e37b7310a93d5889bc794a4478784
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Tue Oct 18 12:29:49 2022 +0300

    IGNITE-17840 .NET: Allow null args in SQL and Compute (#1221)
    
    Change `params object[] args` to `params object?[]? args` in all public APIs.
---
 .../requests/sql/ClientSqlExecuteRequest.java      |  6 ++++
 .../Apache.Ignite.Tests/Compute/ComputeTests.cs    | 12 ++++++--
 .../dotnet/Apache.Ignite.Tests/ListLogger.cs       |  2 +-
 .../dotnet/Apache.Ignite.Tests/Sql/SqlTests.cs     | 35 ++++++++++++++++++++++
 .../dotnet/Apache.Ignite/Compute/ICompute.cs       |  8 ++---
 .../Apache.Ignite/Internal/Compute/Compute.cs      | 12 ++++----
 .../Internal/Proto/MessagePackWriterExtensions.cs  |  2 +-
 .../dotnet/Apache.Ignite/Internal/Sql/Sql.cs       |  4 +--
 .../dotnet/Apache.Ignite/Log/CategoryLogger.cs     |  2 +-
 .../dotnet/Apache.Ignite/Log/ConsoleLogger.cs      |  2 +-
 .../dotnet/Apache.Ignite/Log/IIgniteLogger.cs      |  2 +-
 .../dotnet/Apache.Ignite/Log/LoggerExtensions.cs   | 24 +++++++--------
 modules/platforms/dotnet/Apache.Ignite/Sql/ISql.cs |  4 +--
 .../runner/app/client/ItThinClientComputeTest.java |  6 +++-
 14 files changed, 87 insertions(+), 34 deletions(-)

diff --git a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlExecuteRequest.java b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlExecuteRequest.java
index 98dff81b38..f193d4928a 100644
--- a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlExecuteRequest.java
+++ b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlExecuteRequest.java
@@ -33,6 +33,7 @@ import org.apache.ignite.internal.client.proto.ClientBinaryTupleUtils;
 import org.apache.ignite.internal.client.proto.ClientMessagePacker;
 import org.apache.ignite.internal.client.proto.ClientMessageUnpacker;
 import org.apache.ignite.internal.client.proto.ClientSqlColumnTypeConverter;
+import org.apache.ignite.internal.util.ArrayUtils;
 import org.apache.ignite.lang.IgniteInternalCheckedException;
 import org.apache.ignite.lang.IgniteInternalException;
 import org.apache.ignite.sql.ColumnMetadata;
@@ -67,6 +68,11 @@ public class ClientSqlExecuteRequest {
         Statement statement = readStatement(in, sql);
         Object[] arguments = in.unpackObjectArrayFromBinaryTuple();
 
+        if (arguments == null) {
+            // SQL engine requires non-null arguments, but we don't want to complicate the protocol with this requirement.
+            arguments = ArrayUtils.OBJECT_EMPTY_ARRAY;
+        }
+
         return session
                 .executeAsync(tx, statement, arguments)
                 .thenCompose(asyncResultSet -> writeResultSetAsync(out, resources, asyncResultSet, session));
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/Compute/ComputeTests.cs b/modules/platforms/dotnet/Apache.Ignite.Tests/Compute/ComputeTests.cs
index ee2a9584e0..5a14dcedf7 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/Compute/ComputeTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/Compute/ComputeTests.cs
@@ -130,9 +130,17 @@ namespace Apache.Ignite.Tests.Compute
         [Test]
         public async Task TestExecuteWithArgs()
         {
-            var res = await Client.Compute.ExecuteAsync<string>(await Client.GetClusterNodesAsync(), ConcatJob, 1.1, Guid.Empty, "3");
+            var res = await Client.Compute.ExecuteAsync<string>(await Client.GetClusterNodesAsync(), ConcatJob, 1.1, Guid.Empty, "3", null);
 
-            Assert.AreEqual("1.1_00000000-0000-0000-0000-000000000000_3", res);
+            Assert.AreEqual("1.1_00000000-0000-0000-0000-000000000000_3_null", res);
+        }
+
+        [Test]
+        public async Task TestExecuteWithNullArgs()
+        {
+            var res = await Client.Compute.ExecuteAsync<string>(await Client.GetClusterNodesAsync(), ConcatJob, args: null);
+
+            Assert.IsNull(res);
         }
 
         [Test]
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/ListLogger.cs b/modules/platforms/dotnet/Apache.Ignite.Tests/ListLogger.cs
index dcc09ad53b..b0bff83687 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/ListLogger.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/ListLogger.cs
@@ -90,7 +90,7 @@ namespace Apache.Ignite.Tests
         public void Log(
             LogLevel level,
             string message,
-            object[]? args,
+            object?[]? args,
             IFormatProvider? formatProvider,
             string? category,
             string? nativeErrorInfo,
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/SqlTests.cs b/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/SqlTests.cs
index 6a4626d8bf..aee65835fc 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/SqlTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/SqlTests.cs
@@ -74,6 +74,41 @@ namespace Apache.Ignite.Tests.Sql
             Assert.AreEqual("IgniteTuple { NUM = 1, STR = hello }", rows[0].ToString());
         }
 
+        [Test]
+        public async Task TestNullArgs()
+        {
+            await using IResultSet<IIgniteTuple> resultSet = await Client.Sql.ExecuteAsync(
+                transaction: null,
+                statement: "select 1",
+                args: null);
+
+            var rows = await resultSet.ToListAsync();
+
+            Assert.AreEqual(1, rows.Single()[0]);
+        }
+
+        [Test]
+        public async Task TestNullArg()
+        {
+            await Client.Sql.ExecuteAsync(null, "insert into TEST (ID, VAL) VALUES (-1, NULL)");
+
+            await using IResultSet<IIgniteTuple> resultSet = await Client.Sql.ExecuteAsync(
+                transaction: null,
+                statement: "select ID from TEST where VAL = ?",
+                args: new object?[] { null });
+
+            var rows = await resultSet.ToListAsync();
+
+            await using IResultSet<IIgniteTuple> resultSet2 = await Client.Sql.ExecuteAsync(
+                transaction: null,
+                statement: "select ID from TEST where VAL is null");
+
+            var rows2 = await resultSet2.ToListAsync();
+
+            CollectionAssert.IsEmpty(rows);
+            Assert.AreEqual(1, rows2.Count);
+        }
+
         [Test]
         public async Task TestGetAllMultiplePages()
         {
diff --git a/modules/platforms/dotnet/Apache.Ignite/Compute/ICompute.cs b/modules/platforms/dotnet/Apache.Ignite/Compute/ICompute.cs
index 4e37892e59..30ae11d386 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Compute/ICompute.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Compute/ICompute.cs
@@ -35,7 +35,7 @@ namespace Apache.Ignite.Compute
         /// <param name="args">Job arguments.</param>
         /// <typeparam name="T">Job result type.</typeparam>
         /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
-        Task<T> ExecuteAsync<T>(IEnumerable<IClusterNode> nodes, string jobClassName, params object[] args);
+        Task<T> ExecuteAsync<T>(IEnumerable<IClusterNode> nodes, string jobClassName, params object?[]? args);
 
         /// <summary>
         /// Executes a job represented by the given class on one node where the given key is located.
@@ -46,7 +46,7 @@ namespace Apache.Ignite.Compute
         /// <param name="args">Job arguments.</param>
         /// <typeparam name="T">Job result type.</typeparam>
         /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
-        Task<T> ExecuteColocatedAsync<T>(string tableName, IIgniteTuple key, string jobClassName, params object[] args);
+        Task<T> ExecuteColocatedAsync<T>(string tableName, IIgniteTuple key, string jobClassName, params object?[]? args);
 
         /// <summary>
         /// Executes a job represented by the given class on one node where the given key is located.
@@ -58,7 +58,7 @@ namespace Apache.Ignite.Compute
         /// <typeparam name="T">Job result type.</typeparam>
         /// <typeparam name="TKey">Key type.</typeparam>
         /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
-        Task<T> ExecuteColocatedAsync<T, TKey>(string tableName, TKey key, string jobClassName, params object[] args)
+        Task<T> ExecuteColocatedAsync<T, TKey>(string tableName, TKey key, string jobClassName, params object?[]? args)
             where TKey : notnull;
 
         /// <summary>
@@ -69,6 +69,6 @@ namespace Apache.Ignite.Compute
         /// <param name="args">Job arguments.</param>
         /// <typeparam name="T">Job result type.</typeparam>
         /// <returns>A map of <see cref="Task"/> representing the asynchronous operation for every node.</returns>
-        IDictionary<IClusterNode, Task<T>> BroadcastAsync<T>(IEnumerable<IClusterNode> nodes, string jobClassName, params object[] args);
+        IDictionary<IClusterNode, Task<T>> BroadcastAsync<T>(IEnumerable<IClusterNode> nodes, string jobClassName, params object?[]? args);
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite/Internal/Compute/Compute.cs b/modules/platforms/dotnet/Apache.Ignite/Internal/Compute/Compute.cs
index b3dc4a8b0f..d57e145208 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Internal/Compute/Compute.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/Compute/Compute.cs
@@ -57,7 +57,7 @@ namespace Apache.Ignite.Internal.Compute
         }
 
         /// <inheritdoc/>
-        public async Task<T> ExecuteAsync<T>(IEnumerable<IClusterNode> nodes, string jobClassName, params object[] args)
+        public async Task<T> ExecuteAsync<T>(IEnumerable<IClusterNode> nodes, string jobClassName, params object?[]? args)
         {
             IgniteArgumentCheck.NotNull(nodes, nameof(nodes));
             IgniteArgumentCheck.NotNull(jobClassName, nameof(jobClassName));
@@ -66,7 +66,7 @@ namespace Apache.Ignite.Internal.Compute
         }
 
         /// <inheritdoc/>
-        public async Task<T> ExecuteColocatedAsync<T>(string tableName, IIgniteTuple key, string jobClassName, params object[] args) =>
+        public async Task<T> ExecuteColocatedAsync<T>(string tableName, IIgniteTuple key, string jobClassName, params object?[]? args) =>
             await ExecuteColocatedAsync<T, IIgniteTuple>(
                     tableName,
                     key,
@@ -76,7 +76,7 @@ namespace Apache.Ignite.Internal.Compute
                 .ConfigureAwait(false);
 
         /// <inheritdoc/>
-        public async Task<T> ExecuteColocatedAsync<T, TKey>(string tableName, TKey key, string jobClassName, params object[] args)
+        public async Task<T> ExecuteColocatedAsync<T, TKey>(string tableName, TKey key, string jobClassName, params object?[]? args)
             where TKey : notnull =>
             await ExecuteColocatedAsync<T, TKey>(
                     tableName,
@@ -87,7 +87,7 @@ namespace Apache.Ignite.Internal.Compute
                 .ConfigureAwait(false);
 
         /// <inheritdoc/>
-        public IDictionary<IClusterNode, Task<T>> BroadcastAsync<T>(IEnumerable<IClusterNode> nodes, string jobClassName, params object[] args)
+        public IDictionary<IClusterNode, Task<T>> BroadcastAsync<T>(IEnumerable<IClusterNode> nodes, string jobClassName, params object?[]? args)
         {
             IgniteArgumentCheck.NotNull(nodes, nameof(nodes));
             IgniteArgumentCheck.NotNull(jobClassName, nameof(jobClassName));
@@ -118,7 +118,7 @@ namespace Apache.Ignite.Internal.Compute
         private static ICollection<IClusterNode> GetNodesCollection(IEnumerable<IClusterNode> nodes) =>
             nodes as ICollection<IClusterNode> ?? nodes.ToList();
 
-        private async Task<T> ExecuteOnOneNode<T>(IClusterNode node, string jobClassName, object[] args)
+        private async Task<T> ExecuteOnOneNode<T>(IClusterNode node, string jobClassName, object?[]? args)
         {
             IgniteArgumentCheck.NotNull(node, nameof(node));
 
@@ -198,7 +198,7 @@ namespace Apache.Ignite.Internal.Compute
             TKey key,
             Func<Table, IRecordSerializerHandler<TKey>> serializerHandlerFunc,
             string jobClassName,
-            params object[] args)
+            params object?[]? args)
             where TKey : notnull
         {
             // TODO: IGNITE-16990 - implement partition awareness.
diff --git a/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/MessagePackWriterExtensions.cs b/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/MessagePackWriterExtensions.cs
index 6f99afa322..913b9d4703 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/MessagePackWriterExtensions.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/Proto/MessagePackWriterExtensions.cs
@@ -69,7 +69,7 @@ namespace Apache.Ignite.Internal.Proto
         /// </summary>
         /// <param name="writer">Writer.</param>
         /// <param name="arr">Array.</param>
-        public static void WriteObjectArrayAsBinaryTuple(this ref MessagePackWriter writer, object[]? arr)
+        public static void WriteObjectArrayAsBinaryTuple(this ref MessagePackWriter writer, object?[]? arr)
         {
             if (arr == null)
             {
diff --git a/modules/platforms/dotnet/Apache.Ignite/Internal/Sql/Sql.cs b/modules/platforms/dotnet/Apache.Ignite/Internal/Sql/Sql.cs
index b07e3a22e8..c95c40b8f1 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Internal/Sql/Sql.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/Sql/Sql.cs
@@ -46,7 +46,7 @@ namespace Apache.Ignite.Internal.Sql
         }
 
         /// <inheritdoc/>
-        public async Task<IResultSet<IIgniteTuple>> ExecuteAsync(ITransaction? transaction, SqlStatement statement, params object[] args)
+        public async Task<IResultSet<IIgniteTuple>> ExecuteAsync(ITransaction? transaction, SqlStatement statement, params object?[]? args)
         {
             IgniteArgumentCheck.NotNull(statement, nameof(statement));
 
@@ -90,7 +90,7 @@ namespace Apache.Ignite.Internal.Sql
         }
 
         /// <inheritdoc/>
-        public Task<IResultSet<T>> ExecuteAsync<T>(ITransaction? transaction, SqlStatement statement, params object[] args)
+        public Task<IResultSet<T>> ExecuteAsync<T>(ITransaction? transaction, SqlStatement statement, params object?[]? args)
         {
             // TODO: IGNITE-17333 SQL ResultSet object mapping
             throw new NotSupportedException();
diff --git a/modules/platforms/dotnet/Apache.Ignite/Log/CategoryLogger.cs b/modules/platforms/dotnet/Apache.Ignite/Log/CategoryLogger.cs
index e3c051bc43..bf60ad6bec 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Log/CategoryLogger.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Log/CategoryLogger.cs
@@ -63,7 +63,7 @@ namespace Apache.Ignite.Log
         public void Log(
             LogLevel level,
             string message,
-            object[]? args,
+            object?[]? args,
             IFormatProvider? formatProvider,
             string? category,
             string? nativeErrorInfo,
diff --git a/modules/platforms/dotnet/Apache.Ignite/Log/ConsoleLogger.cs b/modules/platforms/dotnet/Apache.Ignite/Log/ConsoleLogger.cs
index 994771ae85..c3c96e7cc9 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Log/ConsoleLogger.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Log/ConsoleLogger.cs
@@ -63,7 +63,7 @@ namespace Apache.Ignite.Log
         public void Log(
             LogLevel level,
             string message,
-            object[]? args,
+            object?[]? args,
             IFormatProvider? formatProvider,
             string? category,
             string? nativeErrorInfo,
diff --git a/modules/platforms/dotnet/Apache.Ignite/Log/IIgniteLogger.cs b/modules/platforms/dotnet/Apache.Ignite/Log/IIgniteLogger.cs
index 0a1c4c2e07..134c5664d2 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Log/IIgniteLogger.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Log/IIgniteLogger.cs
@@ -41,7 +41,7 @@ namespace Apache.Ignite.Log
         void Log(
             LogLevel level,
             string message,
-            object[]? args,
+            object?[]? args,
             IFormatProvider? formatProvider,
             string? category,
             string? nativeErrorInfo,
diff --git a/modules/platforms/dotnet/Apache.Ignite/Log/LoggerExtensions.cs b/modules/platforms/dotnet/Apache.Ignite/Log/LoggerExtensions.cs
index 30ab20d88d..7bec2eecd0 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Log/LoggerExtensions.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Log/LoggerExtensions.cs
@@ -44,7 +44,7 @@ namespace Apache.Ignite.Log
         /// <param name="logger">The logger.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Trace(this IIgniteLogger logger, string message, params object[] args)
+        public static void Trace(this IIgniteLogger logger, string message, params object?[]? args)
         {
             Log(logger, LogLevel.Trace, message, args);
         }
@@ -67,7 +67,7 @@ namespace Apache.Ignite.Log
         /// <param name="ex">The exception.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Trace(this IIgniteLogger logger, Exception ex, string message, params object[] args)
+        public static void Trace(this IIgniteLogger logger, Exception ex, string message, params object?[]? args)
         {
             Log(logger, LogLevel.Trace, ex, message, args);
         }
@@ -88,7 +88,7 @@ namespace Apache.Ignite.Log
         /// <param name="logger">The logger.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Debug(this IIgniteLogger logger, string message, params object[] args)
+        public static void Debug(this IIgniteLogger logger, string message, params object?[]? args)
         {
             Log(logger, LogLevel.Debug, message, args);
         }
@@ -111,7 +111,7 @@ namespace Apache.Ignite.Log
         /// <param name="ex">The exception.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Debug(this IIgniteLogger logger, Exception ex, string message, params object[] args)
+        public static void Debug(this IIgniteLogger logger, Exception ex, string message, params object?[]? args)
         {
             Log(logger, LogLevel.Debug, ex, message, args);
         }
@@ -132,7 +132,7 @@ namespace Apache.Ignite.Log
         /// <param name="logger">The logger.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Info(this IIgniteLogger logger, string message, params object[] args)
+        public static void Info(this IIgniteLogger logger, string message, params object?[]? args)
         {
             Log(logger, LogLevel.Info, message, args);
         }
@@ -155,7 +155,7 @@ namespace Apache.Ignite.Log
         /// <param name="ex">The exception.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Info(this IIgniteLogger logger, Exception ex, string message, params object[] args)
+        public static void Info(this IIgniteLogger logger, Exception ex, string message, params object?[]? args)
         {
             Log(logger, LogLevel.Info, ex, message, args);
         }
@@ -176,7 +176,7 @@ namespace Apache.Ignite.Log
         /// <param name="logger">The logger.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Warn(this IIgniteLogger logger, string message, params object[] args)
+        public static void Warn(this IIgniteLogger logger, string message, params object?[]? args)
         {
             Log(logger, LogLevel.Warn, message, args);
         }
@@ -199,7 +199,7 @@ namespace Apache.Ignite.Log
         /// <param name="ex">The exception.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Warn(this IIgniteLogger logger, Exception ex, string message, params object[] args)
+        public static void Warn(this IIgniteLogger logger, Exception ex, string message, params object?[]? args)
         {
             Log(logger, LogLevel.Warn, ex, message, args);
         }
@@ -220,7 +220,7 @@ namespace Apache.Ignite.Log
         /// <param name="logger">The logger.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Error(this IIgniteLogger logger, string message, params object[] args)
+        public static void Error(this IIgniteLogger logger, string message, params object?[]? args)
         {
             Log(logger, LogLevel.Error, message, args);
         }
@@ -243,7 +243,7 @@ namespace Apache.Ignite.Log
         /// <param name="ex">The exception.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Error(this IIgniteLogger logger, Exception ex, string message, params object[] args)
+        public static void Error(this IIgniteLogger logger, Exception ex, string message, params object?[]? args)
         {
             Log(logger, LogLevel.Error, ex, message, args);
         }
@@ -268,7 +268,7 @@ namespace Apache.Ignite.Log
         /// <param name="level">The level.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Log(this IIgniteLogger logger, LogLevel level, string message, params object[] args)
+        public static void Log(this IIgniteLogger logger, LogLevel level, string message, params object?[]? args)
         {
             IgniteArgumentCheck.NotNull(logger, "logger");
 
@@ -297,7 +297,7 @@ namespace Apache.Ignite.Log
         /// <param name="ex">The exception.</param>
         /// <param name="message">The message.</param>
         /// <param name="args">The arguments.</param>
-        public static void Log(this IIgniteLogger logger, LogLevel level, Exception ex, string message, params object[] args)
+        public static void Log(this IIgniteLogger logger, LogLevel level, Exception ex, string message, params object?[]? args)
         {
             IgniteArgumentCheck.NotNull(logger, "logger");
 
diff --git a/modules/platforms/dotnet/Apache.Ignite/Sql/ISql.cs b/modules/platforms/dotnet/Apache.Ignite/Sql/ISql.cs
index ab7bbcfdcf..247950b05d 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Sql/ISql.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Sql/ISql.cs
@@ -33,7 +33,7 @@ namespace Apache.Ignite.Sql
         /// <param name="statement">Statement to execute.</param>
         /// <param name="args">Arguments for the statement.</param>
         /// <returns>SQL result set.</returns>
-        Task<IResultSet<IIgniteTuple>> ExecuteAsync(ITransaction? transaction, SqlStatement statement, params object[] args);
+        Task<IResultSet<IIgniteTuple>> ExecuteAsync(ITransaction? transaction, SqlStatement statement, params object?[]? args);
 
         /// <summary>
         /// Executes single SQL statement and returns rows deserialized into the specified user type <typeparamref name="T"/>.
@@ -43,6 +43,6 @@ namespace Apache.Ignite.Sql
         /// <param name="args">Arguments for the statement.</param>
         /// <typeparam name="T">Row type.</typeparam>
         /// <returns>SQL result set.</returns>
-        Task<IResultSet<T>> ExecuteAsync<T>(ITransaction? transaction, SqlStatement statement, params object[] args);
+        Task<IResultSet<T>> ExecuteAsync<T>(ITransaction? transaction, SqlStatement statement, params object?[]? args);
     }
 }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientComputeTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientComputeTest.java
index b0f686290a..95c283034f 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientComputeTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientComputeTest.java
@@ -245,7 +245,11 @@ public class ItThinClientComputeTest extends ItAbstractThinClientTest {
     private static class ConcatJob implements ComputeJob<String> {
         @Override
         public String execute(JobExecutionContext context, Object... args) {
-            return Arrays.stream(args).map(Object::toString).collect(Collectors.joining("_"));
+            if (args == null) {
+                return null;
+            }
+
+            return Arrays.stream(args).map(o -> o == null ? "null" : o.toString()).collect(Collectors.joining("_"));
         }
     }