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/06/08 13:57:41 UTC

[ignite-3] branch ignite-3.0.0-alpha5 updated: IGNITE-17057 Implement synchronous SQL API for Java client (#865)

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

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


The following commit(s) were added to refs/heads/ignite-3.0.0-alpha5 by this push:
     new 535523c63 IGNITE-17057 Implement synchronous SQL API for Java client (#865)
535523c63 is described below

commit 535523c6321967735c7662cfb8dd0b000720d729
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Wed Jun 8 16:55:34 2022 +0300

    IGNITE-17057 Implement synchronous SQL API for Java client (#865)
    
    * Move `ResultSetImpl` to `ignite-api` module and reuse to implement sync API on the client.
    * Refactor `ClientSqlExecuteRequest` to use sessions because statements are not fully supported on the server side.
    * Use the same tests for server and client SQL APIs to ensure consistent behavior: `ItSqlClientSynchronousApiTest`, `ItSqlClientAsynchronousApiTest`.
    
    (cherry picked from commit c4588a2b6f78391ac3f71dc317b880ac23f455e2)
---
 .../ignite/example/sql/ItSqlExamplesTest.java      |  2 +-
 .../apache/ignite/internal/sql}/ResultSetImpl.java | 15 ++--
 .../main/java/org/apache/ignite/sql/Session.java   | 25 ++++++-
 .../requests/sql/ClientSqlExecuteRequest.java      | 28 ++++---
 .../apache/ignite/internal/client/ClientUtils.java |  1 +
 .../internal/client/sql/ClientAsyncResultSet.java  |  5 ++
 .../ignite/internal/client/sql/ClientSession.java  | 24 ++----
 .../org/apache/ignite/client/ClientSqlTest.java    | 15 +++-
 .../ignite/client/fakes/FakeAsyncResultSet.java    |  9 +--
 .../apache/ignite/client/fakes/FakeSession.java    | 24 ++----
 .../app/client/ItAbstractThinClientTest.java       | 20 +++--
 .../app/client/ItThinClientConnectionTest.java     |  2 +-
 .../runner/app/client/ItThinClientSqlTest.java     | 85 +++++++++++++++++++++-
 .../internal/sql/api/ItSqlAsynchronousApiTest.java | 48 +++++++-----
 .../sql/api/ItSqlClientAsynchronousApiTest.java    | 73 +++++++++++++++++++
 .../sql/api/ItSqlClientSynchronousApiTest.java     | 60 +++++++++++++++
 .../internal/sql/api/ItSqlSynchronousApiTest.java  | 31 +++++---
 .../ignite/internal/sql/api/SessionImpl.java       | 13 ----
 .../internal/sql/api/StatementBuilderImpl.java     | 44 +++++++++--
 19 files changed, 409 insertions(+), 115 deletions(-)

diff --git a/examples/src/integrationTest/java/org/apache/ignite/example/sql/ItSqlExamplesTest.java b/examples/src/integrationTest/java/org/apache/ignite/example/sql/ItSqlExamplesTest.java
index 9d7662596..1dd8d3281 100644
--- a/examples/src/integrationTest/java/org/apache/ignite/example/sql/ItSqlExamplesTest.java
+++ b/examples/src/integrationTest/java/org/apache/ignite/example/sql/ItSqlExamplesTest.java
@@ -58,7 +58,7 @@ public class ItSqlExamplesTest extends AbstractExamplesTest {
      *
      * @throws Exception If failed.
      */
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-17057")
+    @Disabled("https://issues.apache.org/jira/browse/IGNITE-17059")
     @Test
     public void testSqlApiExample() throws Exception {
         assertConsoleOutputContains(SqlApiExample::main, EMPTY_ARGS,
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/ResultSetImpl.java b/modules/api/src/main/java/org/apache/ignite/internal/sql/ResultSetImpl.java
similarity index 87%
rename from modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/ResultSetImpl.java
rename to modules/api/src/main/java/org/apache/ignite/internal/sql/ResultSetImpl.java
index 17cec1959..28ae4cd4b 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/ResultSetImpl.java
+++ b/modules/api/src/main/java/org/apache/ignite/internal/sql/ResultSetImpl.java
@@ -15,11 +15,12 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.sql.api;
+package org.apache.ignite.internal.sql;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.concurrent.CompletionStage;
+import org.apache.ignite.lang.IgniteException;
 import org.apache.ignite.sql.ResultSet;
 import org.apache.ignite.sql.ResultSetMetadata;
 import org.apache.ignite.sql.SqlRow;
@@ -27,11 +28,13 @@ import org.apache.ignite.sql.async.AsyncResultSet;
 import org.jetbrains.annotations.Nullable;
 
 /**
- * Synchronous result set implementation.
+ * Synchronous wrapper over {@link org.apache.ignite.sql.async.AsyncResultSet}.
  */
 public class ResultSetImpl implements ResultSet {
+    /** Wrapped async result set. */
     private final AsyncResultSet ars;
 
+    /** Iterator. */
     private final IteratorImpl it;
 
     /**
@@ -73,14 +76,14 @@ public class ResultSetImpl implements ResultSet {
     /** {@inheritDoc} */
     @Override
     public void close() {
-        SessionImpl.await(ars.closeAsync().toCompletableFuture());
+        ars.closeAsync().toCompletableFuture().join();
     }
 
     /** {@inheritDoc} */
     @Override
     public boolean hasNext() {
         if (it == null) {
-            throw new IgniteSqlException("There are no results");
+            throw new IgniteException("There are no results");
         }
 
         return it.hasNext();
@@ -90,7 +93,7 @@ public class ResultSetImpl implements ResultSet {
     @Override
     public SqlRow next() {
         if (it == null) {
-            throw new IgniteSqlException("There are no results");
+            throw new IgniteException("There are no results");
         }
 
         return it.next();
@@ -114,7 +117,7 @@ public class ResultSetImpl implements ResultSet {
             if (curPage.hasNext()) {
                 return true;
             } else if (nextPageStage != null) {
-                curRes = SessionImpl.await(nextPageStage);
+                curRes = nextPageStage.toCompletableFuture().join();
 
                 advance();
 
diff --git a/modules/api/src/main/java/org/apache/ignite/sql/Session.java b/modules/api/src/main/java/org/apache/ignite/sql/Session.java
index 315cbb199..fc3753839 100644
--- a/modules/api/src/main/java/org/apache/ignite/sql/Session.java
+++ b/modules/api/src/main/java/org/apache/ignite/sql/Session.java
@@ -17,9 +17,12 @@
 
 package org.apache.ignite.sql;
 
+import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
 import java.util.concurrent.Flow;
 import java.util.concurrent.TimeUnit;
+import org.apache.ignite.internal.sql.ResultSetImpl;
 import org.apache.ignite.sql.async.AsyncResultSet;
 import org.apache.ignite.sql.reactive.ReactiveResultSet;
 import org.apache.ignite.tx.Transaction;
@@ -47,7 +50,16 @@ public interface Session extends AutoCloseable {
      * @return SQL query results set.
      * @throws SqlException If failed.
      */
-    ResultSet execute(@Nullable Transaction transaction, String query, @Nullable Object... arguments);
+    default ResultSet execute(@Nullable Transaction transaction, String query, @Nullable Object... arguments) {
+        Objects.requireNonNull(query);
+
+        // TODO: IGNITE-17135 fix exception handling.
+        try {
+            return new ResultSetImpl(executeAsync(transaction, query, arguments).join());
+        } catch (CompletionException e) {
+            throw new SqlException(e);
+        }
+    }
 
     /**
      * Executes single SQL statement.
@@ -57,7 +69,16 @@ public interface Session extends AutoCloseable {
      * @param arguments Arguments for the statement.
      * @return SQL query results set.
      */
-    ResultSet execute(@Nullable Transaction transaction, Statement statement, @Nullable Object... arguments);
+    default ResultSet execute(@Nullable Transaction transaction, Statement statement, @Nullable Object... arguments) {
+        Objects.requireNonNull(statement);
+
+        // TODO: IGNITE-17135 fix exception handling.
+        try {
+            return new ResultSetImpl(executeAsync(transaction, statement, arguments).join());
+        } catch (CompletionException e) {
+            throw new SqlException(e);
+        }
+    }
 
     /**
      * Executes SQL query in an asynchronous way.
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 9529fce09..f9997e47a 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,8 @@ import org.apache.ignite.lang.IgniteInternalCheckedException;
 import org.apache.ignite.lang.IgniteInternalException;
 import org.apache.ignite.sql.ColumnMetadata;
 import org.apache.ignite.sql.IgniteSql;
+import org.apache.ignite.sql.Session;
+import org.apache.ignite.sql.Session.SessionBuilder;
 import org.apache.ignite.sql.Statement;
 import org.apache.ignite.sql.Statement.StatementBuilder;
 import org.apache.ignite.sql.async.AsyncResultSet;
@@ -55,10 +57,11 @@ public class ClientSqlExecuteRequest {
             IgniteSql sql,
             ClientResourceRegistry resources) {
         var tx = readTx(in, resources);
+        Session session = readSession(in, sql);
         Statement statement = readStatement(in, sql);
         Object[] arguments = readArguments(in);
 
-        return sql.createSession()
+        return session
                 .executeAsync(tx, statement, arguments)
                 .thenCompose(asyncResultSet -> writeResultSetAsync(out, resources, asyncResultSet));
     }
@@ -122,28 +125,33 @@ public class ClientSqlExecuteRequest {
     private static Statement readStatement(ClientMessageUnpacker in, IgniteSql sql) {
         StatementBuilder statementBuilder = sql.statementBuilder();
 
+        statementBuilder.query(in.unpackString());
+        statementBuilder.prepared(in.unpackBoolean());
+
+        return statementBuilder.build();
+    }
+
+    private static Session readSession(ClientMessageUnpacker in, IgniteSql sql) {
+        SessionBuilder sessionBuilder = sql.sessionBuilder();
+
         if (!in.tryUnpackNil()) {
-            statementBuilder.defaultSchema(in.unpackString());
+            sessionBuilder.defaultSchema(in.unpackString());
         }
         if (!in.tryUnpackNil()) {
-            statementBuilder.pageSize(in.unpackInt());
+            sessionBuilder.defaultPageSize(in.unpackInt());
         }
 
-        statementBuilder.query(in.unpackString());
-
         if (!in.tryUnpackNil()) {
-            statementBuilder.queryTimeout(in.unpackLong(), TimeUnit.MILLISECONDS);
+            sessionBuilder.defaultTimeout(in.unpackLong(), TimeUnit.MILLISECONDS);
         }
 
-        statementBuilder.prepared(in.unpackBoolean());
-
         var propCount = in.unpackMapHeader();
 
         for (int i = 0; i < propCount; i++) {
-            statementBuilder.property(in.unpackString(), in.unpackObjectWithType());
+            sessionBuilder.property(in.unpackString(), in.unpackObjectWithType());
         }
 
-        return statementBuilder.build();
+        return sessionBuilder.build();
     }
 
     private static Object[] readArguments(ClientMessageUnpacker in) {
diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/ClientUtils.java b/modules/client/src/main/java/org/apache/ignite/internal/client/ClientUtils.java
index 9825850de..cdf45ba67 100644
--- a/modules/client/src/main/java/org/apache/ignite/internal/client/ClientUtils.java
+++ b/modules/client/src/main/java/org/apache/ignite/internal/client/ClientUtils.java
@@ -55,6 +55,7 @@ public class ClientUtils {
      */
     public static IgniteException convertException(Throwable e) {
         if (e instanceof IgniteException) {
+            // TODO: IGNITE-17135 Fix stack trace loss
             return (IgniteException) e;
         }
 
diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientAsyncResultSet.java b/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientAsyncResultSet.java
index 878a183a3..b643a8cd7 100644
--- a/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientAsyncResultSet.java
+++ b/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientAsyncResultSet.java
@@ -145,6 +145,11 @@ class ClientAsyncResultSet implements AsyncResultSet {
                     readRows(r.in());
                     hasMorePages = r.in().unpackBoolean();
 
+                    if (!hasMorePages) {
+                        // When last page is fetched, server closes the cursor.
+                        closed = true;
+                    }
+
                     return this;
                 });
     }
diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientSession.java b/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientSession.java
index e2782662d..455b9dcb1 100644
--- a/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientSession.java
+++ b/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientSession.java
@@ -30,7 +30,6 @@ import org.apache.ignite.internal.client.PayloadOutputChannel;
 import org.apache.ignite.internal.client.ReliableChannel;
 import org.apache.ignite.internal.client.proto.ClientOp;
 import org.apache.ignite.sql.BatchedArguments;
-import org.apache.ignite.sql.ResultSet;
 import org.apache.ignite.sql.Session;
 import org.apache.ignite.sql.Statement;
 import org.apache.ignite.sql.async.AsyncResultSet;
@@ -79,20 +78,6 @@ public class ClientSession implements Session {
         this.properties = properties;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public ResultSet execute(@Nullable Transaction transaction, String query, @Nullable Object... arguments) {
-        // TODO IGNITE-17057.
-        throw new UnsupportedOperationException("Not implemented yet.");
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public ResultSet execute(@Nullable Transaction transaction, Statement statement, @Nullable Object... arguments) {
-        // TODO IGNITE-17057.
-        throw new UnsupportedOperationException("Not implemented yet.");
-    }
-
     /** {@inheritDoc} */
     @Override
     public CompletableFuture<AsyncResultSet> executeAsync(@Nullable Transaction transaction, String query, @Nullable Object... arguments) {
@@ -122,12 +107,13 @@ public class ClientSession implements Session {
 
             w.out().packObject(oneOf(clientStatement.defaultSchema(), defaultSchema));
             w.out().packObject(oneOf(clientStatement.pageSizeNullable(), defaultPageSize));
-            w.out().packObject(clientStatement.query());
             w.out().packObject(oneOf(clientStatement.queryTimeoutNullable(), defaultTimeout));
-            w.out().packBoolean(clientStatement.prepared());
 
             packProperties(w, clientStatement.properties());
 
+            w.out().packObject(clientStatement.query());
+            w.out().packBoolean(clientStatement.prepared());
+
             if (arguments == null) {
                 w.out().packArrayHeader(0);
             } else {
@@ -245,8 +231,8 @@ public class ClientSession implements Session {
     /** {@inheritDoc} */
     @Override
     public CompletableFuture<Void> closeAsync() {
-        // TODO: Cancel/close all active futures.
-        return null;
+        // TODO IGNITE-17134 Cancel/close all active cursors, queries, futures.
+        return CompletableFuture.completedFuture(null);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/client/src/test/java/org/apache/ignite/client/ClientSqlTest.java b/modules/client/src/test/java/org/apache/ignite/client/ClientSqlTest.java
index de348fdec..30b58fe77 100644
--- a/modules/client/src/test/java/org/apache/ignite/client/ClientSqlTest.java
+++ b/modules/client/src/test/java/org/apache/ignite/client/ClientSqlTest.java
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
+import org.apache.ignite.sql.ResultSet;
 import org.apache.ignite.sql.Session;
 import org.apache.ignite.sql.SqlRow;
 import org.apache.ignite.sql.Statement;
@@ -36,7 +37,7 @@ import org.junit.jupiter.api.Test;
  */
 public class ClientSqlTest extends AbstractClientTableTest {
     @Test
-    public void testExecute() {
+    public void testExecuteAsync() {
         Session session = client.sql().createSession();
         AsyncResultSet resultSet = session.executeAsync(null, "SELECT 1").join();
 
@@ -48,6 +49,18 @@ public class ClientSqlTest extends AbstractClientTableTest {
         assertEquals(1, row.intValue(0));
     }
 
+    @Test
+    public void testExecute() {
+        Session session = client.sql().createSession();
+        ResultSet resultSet = session.execute(null, "SELECT 1");
+
+        assertTrue(resultSet.hasRowSet());
+        assertFalse(resultSet.wasApplied());
+
+        SqlRow row = resultSet.next();
+        assertEquals(1, row.intValue(0));
+    }
+
     @Test
     public void testSessionPropertiesPropagation() {
         Session session = client.sql().sessionBuilder()
diff --git a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeAsyncResultSet.java b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeAsyncResultSet.java
index f903e8c41..4e94b4833 100644
--- a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeAsyncResultSet.java
+++ b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeAsyncResultSet.java
@@ -23,7 +23,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CompletionStage;
 import java.util.concurrent.TimeUnit;
-import org.apache.ignite.internal.client.sql.ClientStatement;
 import org.apache.ignite.sql.ColumnMetadata;
 import org.apache.ignite.sql.ResultSetMetadata;
 import org.apache.ignite.sql.Session;
@@ -72,11 +71,11 @@ public class FakeAsyncResultSet implements AsyncResultSet {
         if ("SELECT PROPS".equals(statement.query())) {
             rows = new ArrayList<>();
 
-            rows.add(getRow("schema", statement.defaultSchema()));
-            rows.add(getRow("timeout", statement.queryTimeout(TimeUnit.MILLISECONDS)));
-            rows.add(getRow("pageSize", statement.pageSize()));
+            rows.add(getRow("schema", session.defaultSchema()));
+            rows.add(getRow("timeout", session.defaultTimeout(TimeUnit.MILLISECONDS)));
+            rows.add(getRow("pageSize", session.defaultPageSize()));
 
-            var props = ((ClientStatement) statement).properties();
+            var props = ((FakeSession) session).properties();
 
             for (var e : props.entrySet()) {
                 rows.add(getRow(e.getKey(), e.getValue()));
diff --git a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeSession.java b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeSession.java
index cabae6555..bed8390a2 100644
--- a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeSession.java
+++ b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeSession.java
@@ -25,7 +25,6 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Flow.Publisher;
 import java.util.concurrent.TimeUnit;
 import org.apache.ignite.sql.BatchedArguments;
-import org.apache.ignite.sql.ResultSet;
 import org.apache.ignite.sql.Session;
 import org.apache.ignite.sql.Statement;
 import org.apache.ignite.sql.async.AsyncResultSet;
@@ -69,18 +68,6 @@ public class FakeSession implements Session {
         this.properties = properties;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public ResultSet execute(@Nullable Transaction transaction, String query, @Nullable Object... arguments) {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public ResultSet execute(@Nullable Transaction transaction, Statement statement, @Nullable Object... arguments) {
-        throw new UnsupportedOperationException();
-    }
-
     /** {@inheritDoc} */
     @Override
     public CompletableFuture<AsyncResultSet> executeAsync(@Nullable Transaction transaction, String query, @Nullable Object... arguments) {
@@ -161,19 +148,19 @@ public class FakeSession implements Session {
     /** {@inheritDoc} */
     @Override
     public long defaultTimeout(TimeUnit timeUnit) {
-        return 0;
+        return defaultTimeout;
     }
 
     /** {@inheritDoc} */
     @Override
     public String defaultSchema() {
-        return null;
+        return defaultSchema;
     }
 
     /** {@inheritDoc} */
     @Override
     public int defaultPageSize() {
-        return 0;
+        return defaultPageSize;
     }
 
     /** {@inheritDoc} */
@@ -205,4 +192,9 @@ public class FakeSession implements Session {
     public SessionBuilder toBuilder() {
         return null;
     }
+
+    public Map<String, Object> properties() {
+        //noinspection AssignmentOrReturnOfFieldWithMutableType
+        return properties;
+    }
 }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItAbstractThinClientTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItAbstractThinClientTest.java
index 23d79099a..b940fcfba 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItAbstractThinClientTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItAbstractThinClientTest.java
@@ -118,7 +118,7 @@ public abstract class ItAbstractThinClientTest extends IgniteAbstractTest {
                         .changePartitions(10)
         );
 
-        client = IgniteClient.builder().addresses(getNodeAddresses().toArray(new String[0])).build();
+        client = IgniteClient.builder().addresses(getClientAddresses().toArray(new String[0])).build();
     }
 
     /**
@@ -138,13 +138,23 @@ public abstract class ItAbstractThinClientTest extends IgniteAbstractTest {
     }
 
     protected String getNodeAddress() {
-        return getNodeAddresses().get(0);
+        return getClientAddresses().get(0);
     }
 
-    protected List<String> getNodeAddresses() {
-        List<String> res = new ArrayList<>(startedNodes.size());
+    protected List<String> getClientAddresses() {
+        return getClientAddresses(startedNodes);
+    }
+
+    /**
+     * Gets client connector addresses for the specified nodes.
+     *
+     * @param nodes Nodes.
+     * @return List of client addresses.
+     */
+    public static List<String> getClientAddresses(List<Ignite> nodes) {
+        List<String> res = new ArrayList<>(nodes.size());
 
-        for (Ignite ignite : startedNodes) {
+        for (Ignite ignite : nodes) {
             int port = ((IgniteImpl) ignite).clientAddress().port();
 
             res.add("127.0.0.1:" + port);
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientConnectionTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientConnectionTest.java
index 4cde0f482..83aaf9bb9 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientConnectionTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientConnectionTest.java
@@ -42,7 +42,7 @@ public class ItThinClientConnectionTest extends ItAbstractThinClientTest {
      */
     @Test
     void testThinClientConnectsToServerNodesAndExecutesBasicTableOperations() throws Exception {
-        for (var addr : getNodeAddresses()) {
+        for (var addr : getClientAddresses()) {
             try (var client = IgniteClient.builder().addresses(addr).build()) {
                 List<Table> tables = client.tables().tables();
                 assertEquals(1, tables.size());
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSqlTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSqlTest.java
index 09b2b6b51..99b15200d 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSqlTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSqlTest.java
@@ -30,6 +30,7 @@ import java.util.concurrent.CompletionException;
 import org.apache.ignite.client.IgniteClientException;
 import org.apache.ignite.sql.ColumnMetadata;
 import org.apache.ignite.sql.NoRowSetExpectedException;
+import org.apache.ignite.sql.ResultSet;
 import org.apache.ignite.sql.Session;
 import org.apache.ignite.sql.SqlRow;
 import org.apache.ignite.sql.Statement;
@@ -66,6 +67,26 @@ public class ItThinClientSqlTest extends ItAbstractThinClientTest {
         assertEquals("STR", columns.get(1).name());
     }
 
+    @Test
+    void testExecuteSimpleSelect() {
+        ResultSet resultSet = client().sql()
+                .createSession()
+                .execute(null, "select 1 as num, 'hello' as str");
+
+        assertTrue(resultSet.hasRowSet());
+        assertFalse(resultSet.wasApplied());
+        assertEquals(-1, resultSet.affectedRows());
+
+        SqlRow row = resultSet.next();
+        assertEquals(1, row.intValue(0));
+        assertEquals("hello", row.stringValue(1));
+
+        List<ColumnMetadata> columns = resultSet.metadata().columns();
+        assertEquals(2, columns.size());
+        assertEquals("NUM", columns.get(0).name());
+        assertEquals("STR", columns.get(1).name());
+    }
+
     @Test
     void testExecuteAsyncDdlDml() {
         Session session = client().sql().createSession();
@@ -91,7 +112,7 @@ public class ItThinClientSqlTest extends ItAbstractThinClientTest {
             assertNull(insertRes.metadata());
             assertFalse(insertRes.wasApplied());
             assertEquals(1, insertRes.affectedRows());
-            assertThrows(NoRowSetExpectedException.class, createRes::currentPage);
+            assertThrows(NoRowSetExpectedException.class, insertRes::currentPage);
         }
 
         // Query data.
@@ -135,6 +156,68 @@ public class ItThinClientSqlTest extends ItAbstractThinClientTest {
         assertTrue(deleteRes.wasApplied());
     }
 
+    @Test
+    void testExecuteDdlDml() {
+        Session session = client().sql().createSession();
+
+        // Create table.
+        ResultSet createRes = session
+                .execute(null, "CREATE TABLE testExecuteDdlDml(ID INT PRIMARY KEY, VAL VARCHAR)");
+
+        assertFalse(createRes.hasRowSet());
+        assertNull(createRes.metadata());
+        assertTrue(createRes.wasApplied());
+        assertEquals(-1, createRes.affectedRows());
+
+        // Insert data.
+        for (int i = 0; i < 10; i++) {
+            ResultSet insertRes = session
+                    .execute(null, "INSERT INTO testExecuteDdlDml VALUES (?, ?)", i, "hello " + i);
+
+            assertFalse(insertRes.hasRowSet());
+            assertNull(insertRes.metadata());
+            assertFalse(insertRes.wasApplied());
+            assertEquals(1, insertRes.affectedRows());
+        }
+
+        // Query data.
+        ResultSet selectRes = session
+                .execute(null, "SELECT VAL as MYVALUE, ID, ID + 1 FROM testExecuteDdlDml ORDER BY ID");
+
+        assertTrue(selectRes.hasRowSet());
+        assertFalse(selectRes.wasApplied());
+        assertEquals(-1, selectRes.affectedRows());
+
+        List<ColumnMetadata> columns = selectRes.metadata().columns();
+        assertEquals(3, columns.size());
+        assertEquals("MYVALUE", columns.get(0).name());
+        assertEquals("ID", columns.get(1).name());
+        assertEquals("ID + 1", columns.get(2).name());
+
+        var rows = new ArrayList<SqlRow>();
+        selectRes.forEachRemaining(rows::add);
+
+        assertEquals(10, rows.size());
+        assertEquals("hello 1", rows.get(1).stringValue(0));
+        assertEquals(1, rows.get(1).intValue(1));
+        assertEquals(2, rows.get(1).intValue(2));
+
+        // Update data.
+        ResultSet updateRes = session.execute(null, "UPDATE testExecuteDdlDml SET VAL='upd' WHERE ID < 5");
+
+        assertFalse(updateRes.wasApplied());
+        assertFalse(updateRes.hasRowSet());
+        assertNull(updateRes.metadata());
+        assertEquals(5, updateRes.affectedRows());
+
+        // Delete table.
+        ResultSet deleteRes = session.execute(null, "DROP TABLE testExecuteDdlDml");
+
+        assertFalse(deleteRes.hasRowSet());
+        assertNull(deleteRes.metadata());
+        assertTrue(deleteRes.wasApplied());
+    }
+
     @Test
     @Disabled("IGNITE-16952")
     void testFetchNextPage() {
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlAsynchronousApiTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlAsynchronousApiTest.java
index afac31df6..af0edc6a4 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlAsynchronousApiTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlAsynchronousApiTest.java
@@ -28,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
@@ -64,6 +65,7 @@ import org.junit.jupiter.api.TestInfo;
 /**
  * Tests for asynchronous SQL API.
  */
+@SuppressWarnings("ThrowableNotThrown")
 @Disabled("https://issues.apache.org/jira/browse/IGNITE-15655")
 public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
     private static final int ROW_COUNT = 16;
@@ -81,7 +83,16 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
             sql("DROP TABLE " + t.name());
         }
 
-        super.tearDownBase(testInfo);
+        tearDownBase(testInfo);
+    }
+
+    /**
+     * Gets the SQL API.
+     *
+     * @return SQL API.
+     */
+    protected IgniteSql igniteSql() {
+        return CLUSTER_NODES.get(0).sql();
     }
 
     @Test
@@ -181,7 +192,7 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
             sql("INSERT INTO TEST VALUES (?, ?)", i, i);
         }
 
-        IgniteSql sql = CLUSTER_NODES.get(0).sql();
+        IgniteSql sql = igniteSql();
         Session ses = sql.sessionBuilder().defaultPageSize(ROW_COUNT / 4).build();
 
         TestPageProcessor pageProc = new TestPageProcessor(4);
@@ -203,7 +214,7 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
         sql("CREATE TABLE TEST(COL0 BIGINT PRIMARY KEY, COL1 VARCHAR NOT NULL)");
         sql("INSERT INTO TEST VALUES (?, ?)", 1L, "some string");
 
-        IgniteSql sql = CLUSTER_NODES.get(0).sql();
+        IgniteSql sql = igniteSql();
         Session ses = sql.sessionBuilder().build();
 
         AsyncResultSet rs = ses.executeAsync(null, "SELECT COL1, COL0 FROM TEST").get();
@@ -234,7 +245,7 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
 
     @Test
     public void sqlRow() throws ExecutionException, InterruptedException {
-        IgniteSql sql = CLUSTER_NODES.get(0).sql();
+        IgniteSql sql = igniteSql();
         Session ses = sql.sessionBuilder().build();
 
         AsyncResultSet ars = ses.executeAsync(null, "SELECT 1 as COL_A, 2 as COL_B").get();
@@ -272,7 +283,7 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
             sql("INSERT INTO TEST VALUES (?, ?)", i, i);
         }
 
-        IgniteSql sql = CLUSTER_NODES.get(0).sql();
+        IgniteSql sql = igniteSql();
         Session ses = sql.sessionBuilder().defaultPageSize(1).build();
 
         AsyncResultSet ars0 = ses.executeAsync(null, "SELECT ID FROM TEST ORDER BY ID").get();
@@ -307,31 +318,31 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
 
     @Test
     public void errors() {
-        IgniteSql sql = CLUSTER_NODES.get(0).sql();
+        IgniteSql sql = igniteSql();
         Session ses = sql.sessionBuilder().defaultPageSize(ROW_COUNT / 2).build();
 
         // Parse error.
         {
             CompletableFuture<AsyncResultSet> f = ses.executeAsync(null, "SELECT ID FROM");
-            assertThrowsWithCause(() -> f.get(), IgniteInternalException.class, "Failed to parse query");
+            assertThrowsWithCause(f::get, IgniteInternalException.class, "Failed to parse query");
         }
 
         // Multiple statements error.
         {
             CompletableFuture<AsyncResultSet> f = ses.executeAsync(null, "SELECT 1; SELECT 2");
-            assertThrowsWithCause(() -> f.get(), IgniteSqlException.class, "Multiple statements aren't allowed");
+            assertThrowsWithCause(f::get, IgniteSqlException.class, "Multiple statements aren't allowed");
         }
 
         // Planning error.
         {
             CompletableFuture<AsyncResultSet> f = ses.executeAsync(null, "CREATE TABLE TEST (VAL INT)");
-            assertThrowsWithCause(() -> f.get(), IgniteException.class, "Table without PRIMARY KEY is not supported");
+            assertThrowsWithCause(f::get, IgniteException.class, "Table without PRIMARY KEY is not supported");
         }
 
         // Execute error.
         {
             CompletableFuture<AsyncResultSet> f = ses.executeAsync(null, "SELECT 1 / ?", 0);
-            assertThrowsWithCause(() -> f.get(), ArithmeticException.class, "/ by zero");
+            assertThrowsWithCause(f::get, ArithmeticException.class, "/ by zero");
         }
 
         checkSession(ses);
@@ -344,7 +355,7 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
             sql("INSERT INTO TEST VALUES (?, ?)", i, i);
         }
 
-        IgniteSql sql = CLUSTER_NODES.get(0).sql();
+        IgniteSql sql = igniteSql();
         Session ses = sql.sessionBuilder().defaultPageSize(2).build();
 
         AsyncResultSet ars0 = ses.executeAsync(null, "SELECT ID FROM TEST").get();
@@ -368,7 +379,7 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
         checkSession(ses);
     }
 
-    private void checkDdl(boolean expectedApplied, Session ses, String sql) throws ExecutionException, InterruptedException {
+    private static void checkDdl(boolean expectedApplied, Session ses, String sql) throws ExecutionException, InterruptedException {
         CompletableFuture<AsyncResultSet> fut = ses.executeAsync(
                 null,
                 sql
@@ -386,7 +397,7 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
         asyncRes.closeAsync().toCompletableFuture().get();
     }
 
-    private void checkError(Class<? extends Throwable> expectedException, String msg, Session ses, String sql, Object... args) {
+    private static void checkError(Class<? extends Throwable> expectedException, String msg, Session ses, String sql, Object... args) {
         CompletableFuture<AsyncResultSet> fut = ses.executeAsync(
                 null,
                 sql,
@@ -396,7 +407,7 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
         assertThrowsWithCause(fut::get, expectedException, msg);
     }
 
-    private void checkDml(int expectedAffectedRows, Session ses, String sql, Object... args)
+    private static void checkDml(int expectedAffectedRows, Session ses, String sql, Object... args)
             throws ExecutionException, InterruptedException {
         CompletableFuture<AsyncResultSet> fut = ses.executeAsync(
                 null,
@@ -416,9 +427,11 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
         asyncRes.closeAsync().toCompletableFuture().get();
     }
 
-    private void checkSession(Session s) {
-        assertTrue(((Set<?>) IgniteTestUtils.getFieldValue(s, "futsToClose")).isEmpty());
-        assertTrue(((Set<?>) IgniteTestUtils.getFieldValue(s, "cursToClose")).isEmpty());
+    private static void checkSession(Session s) {
+        if (s instanceof SessionImpl) {
+            assertTrue(((Collection<?>) IgniteTestUtils.getFieldValue(s, "futsToClose")).isEmpty());
+            assertTrue(((Collection<?>) IgniteTestUtils.getFieldValue(s, "cursToClose")).isEmpty());
+        }
     }
 
     static class TestPageProcessor implements
@@ -451,6 +464,7 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
         }
 
         public List<SqlRow> result() {
+            //noinspection AssignmentOrReturnOfFieldWithMutableType
             return res;
         }
     }
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java
new file mode 100644
index 000000000..bf8c5c95b
--- /dev/null
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.sql.api;
+
+import static org.apache.ignite.internal.runner.app.client.ItAbstractThinClientTest.getClientAddresses;
+
+import java.util.concurrent.ExecutionException;
+import org.apache.ignite.client.IgniteClient;
+import org.apache.ignite.sql.IgniteSql;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+
+/**
+ * Tests for asynchronous client SQL API.
+ */
+public class ItSqlClientAsynchronousApiTest extends ItSqlAsynchronousApiTest {
+    private IgniteClient client;
+
+    @BeforeAll
+    public void startClient() {
+        client = IgniteClient.builder().addresses(getClientAddresses(CLUSTER_NODES).get(0)).build();
+    }
+
+    @AfterAll
+    public void stopClient() throws Exception {
+        client.close();
+    }
+
+    @Override
+    protected IgniteSql igniteSql() {
+        return client.sql();
+    }
+
+    @Override
+    @Disabled("IGNITE-17052")
+    public void metadata() throws ExecutionException, InterruptedException {
+        super.metadata();
+    }
+
+    @Override
+    @Disabled("IGNITE-17052")
+    public void sqlRow() throws ExecutionException, InterruptedException {
+        super.sqlRow();
+    }
+
+    @Override
+    @Disabled("IGNITE-17134")
+    public void closeSession() throws ExecutionException, InterruptedException {
+        super.closeSession();
+    }
+
+    @Override
+    @Disabled("IGNITE-17135")
+    public void errors() {
+        super.errors();
+    }
+}
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java
new file mode 100644
index 000000000..dd0b79ea7
--- /dev/null
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.sql.api;
+
+import static org.apache.ignite.internal.runner.app.client.ItAbstractThinClientTest.getClientAddresses;
+
+import org.apache.ignite.client.IgniteClient;
+import org.apache.ignite.sql.IgniteSql;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+
+/**
+ * Tests for synchronous client SQL API.
+ */
+public class ItSqlClientSynchronousApiTest extends ItSqlSynchronousApiTest {
+    private IgniteClient client;
+
+    @BeforeAll
+    public void startClient() {
+        client = IgniteClient.builder().addresses(getClientAddresses(CLUSTER_NODES).get(0)).build();
+    }
+
+    @AfterAll
+    public void stopClient() throws Exception {
+        client.close();
+    }
+
+    @Override
+    protected IgniteSql igniteSql() {
+        return client.sql();
+    }
+
+    @Override
+    @Disabled("IGNITE-17135")
+    public void errors() {
+        super.errors();
+    }
+
+    @Override
+    @Disabled("IGNITE-17135")
+    public void ddl() {
+        super.ddl();
+    }
+}
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlSynchronousApiTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlSynchronousApiTest.java
index 6f4f75c46..082dfc93c 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlSynchronousApiTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlSynchronousApiTest.java
@@ -46,6 +46,7 @@ import org.junit.jupiter.api.TestInfo;
 /**
  * Tests for synchronous SQL API.
  */
+@SuppressWarnings("ThrowableNotThrown")
 @Disabled("https://issues.apache.org/jira/browse/IGNITE-15655")
 public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
     private static final int ROW_COUNT = 16;
@@ -63,12 +64,21 @@ public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
             sql("DROP TABLE " + t.name());
         }
 
-        super.tearDownBase(testInfo);
+        tearDownBase(testInfo);
+    }
+
+    /**
+     * Gets the SQL API.
+     *
+     * @return SQL API.
+     */
+    protected IgniteSql igniteSql() {
+        return CLUSTER_NODES.get(0).sql();
     }
 
     @Test
-    public void ddl() throws ExecutionException, InterruptedException {
-        IgniteSql sql = CLUSTER_NODES.get(0).sql();
+    public void ddl() {
+        IgniteSql sql = igniteSql();
         Session ses = sql.createSession();
 
         // CREATE TABLE
@@ -137,10 +147,10 @@ public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
     }
 
     @Test
-    public void dml() throws ExecutionException, InterruptedException {
+    public void dml() {
         sql("CREATE TABLE TEST(ID INT PRIMARY KEY, VAL0 INT)");
 
-        IgniteSql sql = CLUSTER_NODES.get(0).sql();
+        IgniteSql sql = igniteSql();
         Session ses = sql.createSession();
 
         for (int i = 0; i < ROW_COUNT; ++i) {
@@ -152,6 +162,7 @@ public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
         checkDml(ROW_COUNT, ses, "DELETE FROM TEST WHERE VAL0 >= 0");
     }
 
+    @SuppressWarnings("UnstableApiUsage")
     @Test
     public void select() throws ExecutionException, InterruptedException {
         sql("CREATE TABLE TEST(ID INT PRIMARY KEY, VAL0 INT)");
@@ -159,7 +170,7 @@ public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
             sql("INSERT INTO TEST VALUES (?, ?)", i, i);
         }
 
-        IgniteSql sql = CLUSTER_NODES.get(0).sql();
+        IgniteSql sql = igniteSql();
         Session ses = sql.sessionBuilder().defaultPageSize(ROW_COUNT / 4).build();
 
         ResultSet rs = ses.execute(null, "SELECT ID FROM TEST");
@@ -175,7 +186,7 @@ public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
 
     @Test
     public void errors() {
-        IgniteSql sql = CLUSTER_NODES.get(0).sql();
+        IgniteSql sql = igniteSql();
         Session ses = sql.sessionBuilder().defaultPageSize(ROW_COUNT / 2).build();
 
         // Parse error.
@@ -207,7 +218,7 @@ public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
         );
     }
 
-    private void checkDdl(boolean expectedApplied, Session ses, String sql) {
+    private static void checkDdl(boolean expectedApplied, Session ses, String sql) {
         ResultSet res = ses.execute(
                 null,
                 sql
@@ -220,11 +231,11 @@ public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
         res.close();
     }
 
-    private void checkError(Class<? extends Throwable> expectedException, String msg, Session ses, String sql, Object... args) {
+    private static void checkError(Class<? extends Throwable> expectedException, String msg, Session ses, String sql) {
         assertThrowsWithCause(() -> ses.execute(null, sql), expectedException, msg);
     }
 
-    private void checkDml(int expectedAffectedRows, Session ses, String sql, Object... args) {
+    private static void checkDml(int expectedAffectedRows, Session ses, String sql, Object... args) {
         ResultSet res = ses.execute(
                 null,
                 sql,
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/SessionImpl.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/SessionImpl.java
index 2fb3900e7..c3d94e60a 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/SessionImpl.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/SessionImpl.java
@@ -34,7 +34,6 @@ import org.apache.ignite.internal.sql.engine.QueryTimeout;
 import org.apache.ignite.internal.util.IgniteSpinBusyLock;
 import org.apache.ignite.lang.IgniteException;
 import org.apache.ignite.sql.BatchedArguments;
-import org.apache.ignite.sql.ResultSet;
 import org.apache.ignite.sql.Session;
 import org.apache.ignite.sql.Statement;
 import org.apache.ignite.sql.async.AsyncResultSet;
@@ -86,18 +85,6 @@ public class SessionImpl implements Session {
         this.props = props;
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public ResultSet execute(@Nullable Transaction transaction, String query, @Nullable Object... arguments) {
-        return new ResultSetImpl(await(executeAsync(transaction, query, arguments)));
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public ResultSet execute(@Nullable Transaction transaction, Statement statement, @Nullable Object... arguments) {
-        throw new UnsupportedOperationException("Not implemented yet.");
-    }
-
     /** {@inheritDoc} */
     @Override
     public int[] executeBatch(@Nullable Transaction transaction, String dmlQuery, BatchedArguments batch) {
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/StatementBuilderImpl.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/StatementBuilderImpl.java
index 58a705ed1..5002888b6 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/StatementBuilderImpl.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/StatementBuilderImpl.java
@@ -17,6 +17,9 @@
 
 package org.apache.ignite.internal.sql.api;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 import org.apache.ignite.sql.Statement;
 import org.apache.ignite.sql.Statement.StatementBuilder;
@@ -27,12 +30,24 @@ import org.jetbrains.annotations.Nullable;
  * Statement builder.
  */
 class StatementBuilderImpl implements StatementBuilder {
+    /** Properties. */
+    private final Map<String, Object> properties = new HashMap<>();
+
     /** Query. */
     private String query;
 
+    /** Default schema. */
+    private String defaultSchema;
+
     /** Prepared flag. */
     private boolean prepared;
 
+    /** Query timeout. */
+    private Long queryTimeoutMs;
+
+    /** Page size. */
+    private Integer pageSize;
+
     /** {@inheritDoc} */
     @Override
     public @NotNull String query() {
@@ -64,54 +79,67 @@ class StatementBuilderImpl implements StatementBuilder {
     /** {@inheritDoc} */
     @Override
     public long queryTimeout(@NotNull TimeUnit timeUnit) {
-        throw new UnsupportedOperationException("Not implemented yet.");
+        Objects.requireNonNull(timeUnit);
+
+        return timeUnit.convert(queryTimeoutMs == null ? 0 : queryTimeoutMs, TimeUnit.MILLISECONDS);
     }
 
     /** {@inheritDoc} */
     @Override
     public StatementBuilder queryTimeout(long timeout, @NotNull TimeUnit timeUnit) {
-        throw new UnsupportedOperationException("Not implemented yet.");
+        Objects.requireNonNull(timeUnit);
+
+        queryTimeoutMs = TimeUnit.MILLISECONDS.convert(timeout, timeUnit);
+
+        return this;
     }
 
     /** {@inheritDoc} */
     @Override
     public String defaultSchema() {
-        throw new UnsupportedOperationException("Not implemented yet.");
+        return defaultSchema;
     }
 
     /** {@inheritDoc} */
     @Override
     public StatementBuilder defaultSchema(@NotNull String schema) {
-        throw new UnsupportedOperationException("Not implemented yet.");
+        defaultSchema = schema;
+
+        return this;
     }
 
     /** {@inheritDoc} */
     @Override
     public int pageSize() {
-        throw new UnsupportedOperationException("Not implemented yet.");
+        return pageSize == null ? 0 : pageSize;
     }
 
     /** {@inheritDoc} */
     @Override
     public StatementBuilder pageSize(int pageSize) {
-        throw new UnsupportedOperationException("Not implemented yet.");
+        this.pageSize = pageSize;
+
+        return this;
     }
 
     /** {@inheritDoc} */
     @Override
     public @Nullable Object property(@NotNull String name) {
-        throw new UnsupportedOperationException("Not implemented yet.");
+        return properties.get(name);
     }
 
     /** {@inheritDoc} */
     @Override
     public StatementBuilder property(@NotNull String name, @Nullable Object value) {
-        throw new UnsupportedOperationException("Not implemented yet.");
+        properties.put(name, value);
+
+        return this;
     }
 
     /** {@inheritDoc} */
     @Override
     public Statement build() {
+        // TODO IGNITE-16952
         return new StatementImpl(query);
     }
 }