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 354352ed7a IGNITE-21011 Fix SQL script API in Java client (#2917)
354352ed7a is described below

commit 354352ed7af1efcb7ee0a868390a32bd64a27549
Author: Pavel Tupitsyn <ptupit...@apache.org>
AuthorDate: Mon Dec 4 17:20:12 2023 +0200

    IGNITE-21011 Fix SQL script API in Java client (#2917)
    
    * Fix protocol - propagate session details correctly, skip `pageSize` for 
scripts
    * Fix `ItSqlClientAsynchronousApiTest` and `ItSqlClientSynchronousApiTest` 
- remove overloaded methods, they were missing `@Test` annotation, and we don't 
need an override anyway
    * Add script and properties propagation tests to `ClientSqlTest`
---
 .../internal/client/proto/ClientMessagePacker.java |  2 +-
 .../requests/sql/ClientSqlExecuteRequest.java      | 10 ++++--
 .../sql/ClientSqlExecuteScriptRequest.java         | 26 ++++++++++++--
 .../ignite/internal/client/sql/ClientSession.java  | 37 ++++++++++++--------
 .../org/apache/ignite/client/ClientSqlTest.java    | 39 +++++++++++++++++++++
 .../ignite/client/fakes/FakeAsyncResultSet.java    | 10 ++++--
 .../apache/ignite/client/fakes/FakeIgniteSql.java  |  4 ++-
 .../apache/ignite/client/fakes/FakeSession.java    | 40 ++++++++++++++++++++--
 .../ignite/client/fakes/FakeSessionBuilder.java    |  8 ++++-
 .../sql/api/ItSqlClientAsynchronousApiTest.java    | 10 ------
 .../sql/api/ItSqlClientSynchronousApiTest.java     | 12 -------
 11 files changed, 149 insertions(+), 49 deletions(-)

diff --git 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java
 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java
index e2ef846964..5d660fe66b 100644
--- 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java
+++ 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/proto/ClientMessagePacker.java
@@ -262,7 +262,7 @@ public class ClientMessagePacker implements AutoCloseable {
      *
      * @param v the value to be written.
      */
-    public void packLongNullable(Long v) {
+    public void packLongNullable(@Nullable Long v) {
         if (v == null) {
             packNil();
         } else {
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 702c5f6325..993c4e97f9 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
@@ -157,7 +157,7 @@ public class ClientSqlExecuteRequest {
         return statementBuilder.build();
     }
 
-    static Session readSession(ClientMessageUnpacker in, IgniteSql sql, 
@Nullable IgniteTransactions transactions) {
+    private static Session readSession(ClientMessageUnpacker in, IgniteSql 
sql, @Nullable IgniteTransactions transactions) {
         SessionBuilder sessionBuilder = sql.sessionBuilder();
 
         if (transactions != null && sessionBuilder instanceof 
SessionBuilderImpl) {
@@ -179,14 +179,18 @@ public class ClientSqlExecuteRequest {
             sessionBuilder.idleTimeout(in.unpackLong(), TimeUnit.MILLISECONDS);
         }
 
+        readSessionProperties(in, sessionBuilder);
+
+        return sessionBuilder.build();
+    }
+
+    static void readSessionProperties(ClientMessageUnpacker in, SessionBuilder 
sessionBuilder) {
         var propCount = in.unpackInt();
         var reader = new BinaryTupleReader(propCount * 4, 
in.readBinaryUnsafe());
 
         for (int i = 0; i < propCount; i++) {
             sessionBuilder.property(reader.stringValue(i * 4), 
ClientBinaryTupleUtils.readObject(reader, i * 4 + 1));
         }
-
-        return sessionBuilder.build();
     }
 
     private static void packMeta(ClientMessagePacker out, @Nullable 
ResultSetMetadata meta) {
diff --git 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlExecuteScriptRequest.java
 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlExecuteScriptRequest.java
index 0bdfe3dcbe..7b6a84dba0 100644
--- 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlExecuteScriptRequest.java
+++ 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/sql/ClientSqlExecuteScriptRequest.java
@@ -17,15 +17,17 @@
 
 package org.apache.ignite.client.handler.requests.sql;
 
-import static 
org.apache.ignite.client.handler.requests.sql.ClientSqlExecuteRequest.readSession;
+import static 
org.apache.ignite.client.handler.requests.sql.ClientSqlExecuteRequest.readSessionProperties;
 
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
 import org.apache.ignite.internal.client.proto.ClientMessageUnpacker;
 import org.apache.ignite.internal.hlc.HybridTimestamp;
 import org.apache.ignite.internal.tx.impl.IgniteTransactionsImpl;
 import org.apache.ignite.internal.util.ArrayUtils;
 import org.apache.ignite.sql.IgniteSql;
 import org.apache.ignite.sql.Session;
+import org.apache.ignite.sql.Session.SessionBuilder;
 
 /**
  * Client SQL execute script request.
@@ -43,7 +45,7 @@ public class ClientSqlExecuteScriptRequest {
             IgniteSql sql,
             IgniteTransactionsImpl transactions
     ) {
-        Session session = readSession(in, sql, null);
+        Session session = readSession(in, sql);
         String script = in.unpackString();
         Object[] arguments = in.unpackObjectArrayFromBinaryTuple();
 
@@ -59,4 +61,24 @@ public class ClientSqlExecuteScriptRequest {
 
         return session.executeScriptAsync(script, arguments);
     }
+
+    private static Session readSession(ClientMessageUnpacker in, IgniteSql 
sql) {
+        SessionBuilder sessionBuilder = sql.sessionBuilder();
+
+        if (!in.tryUnpackNil()) {
+            sessionBuilder.defaultSchema(in.unpackString());
+        }
+
+        if (!in.tryUnpackNil()) {
+            sessionBuilder.defaultQueryTimeout(in.unpackLong(), 
TimeUnit.MILLISECONDS);
+        }
+
+        if (!in.tryUnpackNil()) {
+            sessionBuilder.idleTimeout(in.unpackLong(), TimeUnit.MILLISECONDS);
+        }
+
+        readSessionProperties(in, sessionBuilder);
+
+        return sessionBuilder.build();
+    }
 }
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 448f2d7b09..1a6a10e3c4 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
@@ -154,7 +154,7 @@ public class ClientSession implements AbstractSession {
 
             w.out().packLongNullable(defaultSessionTimeout);
 
-            packProperties(w, clientStatement.properties());
+            packProperties(w, properties, clientStatement.properties());
 
             w.out().packString(clientStatement.query());
 
@@ -228,6 +228,12 @@ public class ClientSession implements AbstractSession {
         Objects.requireNonNull(query);
 
         PayloadWriter payloadWriter = w -> {
+            w.out().packString(defaultSchema);
+            w.out().packLongNullable(defaultQueryTimeout);
+            w.out().packLongNullable(defaultSessionTimeout);
+
+            packProperties(w, properties, null);
+
             w.out().packString(query);
             w.out().packObjectArrayAsBinaryTuple(arguments);
             w.out().packLong(ch.observableTimestamp());
@@ -303,39 +309,42 @@ public class ClientSession implements AbstractSession {
         throw new UnsupportedOperationException("Not implemented yet.");
     }
 
-    private void packProperties(PayloadOutputChannel w, Map<String, Object> 
props) {
+    private static void packProperties(
+            PayloadOutputChannel w,
+            @Nullable Map<String, Object> sessionProps,
+            @Nullable Map<String, Object> statementProps) {
         int size = 0;
 
-        if (props != null) {
-            size += props.size();
+        if (statementProps != null) {
+            size += statementProps.size();
         }
 
         // Statement properties override session properties.
-        if (properties != null) {
-            if (props != null) {
-                for (String k : properties.keySet()) {
-                    if (!props.containsKey(k)) {
+        if (sessionProps != null) {
+            if (statementProps != null) {
+                for (String k : sessionProps.keySet()) {
+                    if (!statementProps.containsKey(k)) {
                         size++;
                     }
                 }
             } else {
-                size += properties.size();
+                size += sessionProps.size();
             }
         }
 
         w.out().packInt(size);
         var builder = new BinaryTupleBuilder(size * 4);
 
-        if (props != null) {
-            for (Entry<String, Object> entry : props.entrySet()) {
+        if (statementProps != null) {
+            for (Entry<String, Object> entry : statementProps.entrySet()) {
                 builder.appendString(entry.getKey());
                 ClientBinaryTupleUtils.appendObject(builder, entry.getValue());
             }
         }
 
-        if (properties != null) {
-            for (Entry<String, Object> entry : properties.entrySet()) {
-                if (props == null || !props.containsKey(entry.getKey())) {
+        if (sessionProps != null) {
+            for (Entry<String, Object> entry : sessionProps.entrySet()) {
+                if (statementProps == null || 
!statementProps.containsKey(entry.getKey())) {
                     builder.appendString(entry.getKey());
                     ClientBinaryTupleUtils.appendObject(builder, 
entry.getValue());
                 }
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 3fe72fa7c1..ca567169f0 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
@@ -52,6 +52,7 @@ import org.junit.jupiter.api.Test;
 /**
  * SQL tests.
  */
+@SuppressWarnings("resource")
 public class ClientSqlTest extends AbstractClientTableTest {
     @Test
     public void testExecuteAsync() {
@@ -215,4 +216,42 @@ public class ClientSqlTest extends AbstractClientTableTest 
{
         assertEquals(BigInteger.valueOf(42), row.value(17));
         assertEquals(ColumnType.NUMBER, meta.columns().get(17).type());
     }
+
+    @Test
+    public void testExecuteScript() {
+        Session session = client.sql().createSession();
+
+        session.executeScript("foo");
+
+        ResultSet<SqlRow> resultSet = session.execute(null, "SELECT LAST 
SCRIPT");
+        SqlRow row = resultSet.next();
+
+        assertEquals(
+                "foo, arguments: [], properties: [], defaultPageSize=null, 
defaultSchema=null, "
+                        + "defaultQueryTimeout=null, 
defaultSessionTimeout=null",
+                row.value(0));
+    }
+
+    @Test
+    public void testExecuteScriptWithPropertiesAndArguments() {
+        Session session = client.sql().sessionBuilder()
+                .property("prop1", "val1")
+                .property("prop2", -5)
+                .property("prop3", null)
+                .defaultPageSize(123) // Should be ignored - not applicable to 
scripts.
+                .defaultQueryTimeout(456, TimeUnit.MILLISECONDS)
+                .defaultSchema("script-schema")
+                .idleTimeout(789, TimeUnit.SECONDS)
+                .build();
+
+        session.executeScript("do bar baz", "arg1", null, 2);
+
+        ResultSet<SqlRow> resultSet = session.execute(null, "SELECT LAST 
SCRIPT");
+        SqlRow row = resultSet.next();
+
+        assertEquals(
+                "do bar baz, arguments: [arg1, null, 2, ], properties: 
[prop2=-5, prop1=val1, prop3=null, ], "
+                        + "defaultPageSize=null, defaultSchema=script-schema, 
defaultQueryTimeout=456, defaultSessionTimeout=789000",
+                row.value(0));
+    }
 }
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 5e96bbb538..acb7d6d719 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
@@ -62,6 +62,8 @@ public class FakeAsyncResultSet implements AsyncResultSet {
 
     private final boolean hasMorePages;
 
+    private final FakeIgniteSql sql;
+
     /**
      * Constructor.
      *
@@ -70,7 +72,7 @@ public class FakeAsyncResultSet implements AsyncResultSet {
      * @param statement Statement.
      * @param arguments Arguments.
      */
-    public FakeAsyncResultSet(Session session, Transaction transaction, 
Statement statement, Object[] arguments) {
+    public FakeAsyncResultSet(Session session, Transaction transaction, 
Statement statement, Object[] arguments, FakeIgniteSql sql) {
         assert session != null;
         assert statement != null;
 
@@ -78,6 +80,7 @@ public class FakeAsyncResultSet implements AsyncResultSet {
         this.transaction = transaction;
         this.statement = statement;
         this.arguments = arguments;
+        this.sql = sql;
 
         hasMorePages = session.property("hasMorePages") != null;
 
@@ -142,6 +145,9 @@ public class FakeAsyncResultSet implements AsyncResultSet {
                     BigInteger.valueOf(42));
 
             rows = List.of(row);
+        } else if ("SELECT LAST SCRIPT".equals(statement.query())) {
+            rows = List.of(getRow(sql.lastScript));
+            columns = List.of(new FakeColumnMetadata("script", 
ColumnType.STRING));
         } else {
             rows = List.of(getRow(1));
             columns = List.of(new FakeColumnMetadata("col1", 
ColumnType.INT32));
@@ -197,7 +203,7 @@ public class FakeAsyncResultSet implements AsyncResultSet {
     /** {@inheritDoc} */
     @Override
     public CompletableFuture<? extends AsyncResultSet> fetchNextPage() {
-        return CompletableFuture.completedFuture(new 
FakeAsyncResultSet(session, transaction, statement, arguments));
+        return CompletableFuture.completedFuture(new 
FakeAsyncResultSet(session, transaction, statement, arguments, sql));
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeIgniteSql.java
 
b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeIgniteSql.java
index 2c3d69ed5b..7095c58fd5 100644
--- 
a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeIgniteSql.java
+++ 
b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeIgniteSql.java
@@ -28,6 +28,8 @@ import org.apache.ignite.sql.Statement.StatementBuilder;
  * Fake SQL implementation.
  */
 public class FakeIgniteSql implements IgniteSql {
+    String lastScript;
+
     @Override
     public Session createSession() {
         return sessionBuilder().build();
@@ -35,7 +37,7 @@ public class FakeIgniteSql implements IgniteSql {
 
     @Override
     public SessionBuilder sessionBuilder() {
-        return new FakeSessionBuilder();
+        return new FakeSessionBuilder(this);
     }
 
     @Override
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 43f677b34d..9a0e79eed1 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
@@ -58,6 +58,8 @@ public class FakeSession implements AbstractSession {
     @Nullable
     private final Map<String, Object> properties;
 
+    private final FakeIgniteSql sql;
+
     /**
      * Constructor.
      *
@@ -65,6 +67,7 @@ public class FakeSession implements AbstractSession {
      * @param defaultSchema Default schema.
      * @param defaultQueryTimeout Default timeout.
      * @param properties Properties.
+     * @param sql SQL.
      */
     @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
     public FakeSession(
@@ -72,12 +75,14 @@ public class FakeSession implements AbstractSession {
             @Nullable String defaultSchema,
             @Nullable Long defaultQueryTimeout,
             @Nullable Long defaultSessionTimeout,
-            @Nullable Map<String, Object> properties) {
+            @Nullable Map<String, Object> properties,
+            FakeIgniteSql sql) {
         this.defaultPageSize = defaultPageSize;
         this.defaultSchema = defaultSchema;
         this.defaultQueryTimeout = defaultQueryTimeout;
         this.defaultSessionTimeout = defaultSessionTimeout;
         this.properties = properties;
+        this.sql = sql;
     }
 
     /** {@inheritDoc} */
@@ -101,7 +106,7 @@ public class FakeSession implements AbstractSession {
             return CompletableFuture.failedFuture(new 
SqlException(STMT_VALIDATION_ERR, "Query failed"));
         }
 
-        return CompletableFuture.completedFuture(new FakeAsyncResultSet(this, 
transaction, statement, arguments));
+        return CompletableFuture.completedFuture(new FakeAsyncResultSet(this, 
transaction, statement, arguments, sql));
     }
 
     /** {@inheritDoc} */
@@ -178,7 +183,36 @@ public class FakeSession implements AbstractSession {
     /** {@inheritDoc} */
     @Override
     public CompletableFuture<Void> executeScriptAsync(String query, @Nullable 
Object... arguments) {
-        throw new UnsupportedOperationException();
+        var sb = new StringBuilder(query);
+
+        if (arguments != null) {
+            sb.append(", arguments: [");
+
+            for (Object arg : arguments) {
+                sb.append(arg).append(", ");
+            }
+
+            sb.append(']');
+        }
+
+        if (properties != null) {
+            sb.append(", properties: [");
+
+            for (Map.Entry<String, Object> entry : properties.entrySet()) {
+                
sb.append(entry.getKey()).append('=').append(entry.getValue()).append(", ");
+            }
+
+            sb.append(']');
+        }
+
+        sb.append(", ").append("defaultPageSize=").append(defaultPageSize);
+        sb.append(", ").append("defaultSchema=").append(defaultSchema);
+        sb.append(", 
").append("defaultQueryTimeout=").append(defaultQueryTimeout);
+        sb.append(", 
").append("defaultSessionTimeout=").append(defaultSessionTimeout);
+
+        sql.lastScript = sb.toString();
+
+        return nullCompletedFuture();
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeSessionBuilder.java
 
b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeSessionBuilder.java
index 9c71662fb1..3d8876167a 100644
--- 
a/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeSessionBuilder.java
+++ 
b/modules/client/src/test/java/org/apache/ignite/client/fakes/FakeSessionBuilder.java
@@ -31,6 +31,8 @@ import org.jetbrains.annotations.Nullable;
 public class FakeSessionBuilder implements SessionBuilder {
     private final Map<String, Object> properties = new HashMap<>();
 
+    private final FakeIgniteSql sql;
+
     private String defaultSchema;
 
     private Long defaultQueryTimeoutMs;
@@ -39,6 +41,10 @@ public class FakeSessionBuilder implements SessionBuilder {
 
     private Integer pageSize;
 
+    public FakeSessionBuilder(FakeIgniteSql sql) {
+        this.sql = sql;
+    }
+
     /** {@inheritDoc} */
     @Override
     public long defaultQueryTimeout(TimeUnit timeUnit) {
@@ -118,6 +124,6 @@ public class FakeSessionBuilder implements SessionBuilder {
     /** {@inheritDoc} */
     @Override
     public Session build() {
-        return new FakeSession(pageSize, defaultSchema, defaultQueryTimeoutMs, 
defaultSessionTimeoutMs, new HashMap<>(properties));
+        return new FakeSession(pageSize, defaultSchema, defaultQueryTimeoutMs, 
defaultSessionTimeoutMs, new HashMap<>(properties), sql);
     }
 }
diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java
index 200029fc80..2b2e174fd3 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java
@@ -68,14 +68,4 @@ public class ItSqlClientAsynchronousApiTest extends 
ItSqlAsynchronousApiTest {
     public void testLockIsNotReleasedAfterTxRollback() {
         super.testLockIsNotReleasedAfterTxRollback();
     }
-
-    @Override
-    public void runScriptThatCompletesSuccessfully() {
-        super.runScriptThatCompletesSuccessfully();
-    }
-
-    @Override
-    public void runScriptThatFails() {
-        super.runScriptThatFails();
-    }
 }
diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java
index f69a054fc2..fa48bff50f 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java
@@ -31,8 +31,6 @@ import org.junit.jupiter.api.Disabled;
 public class ItSqlClientSynchronousApiTest extends ItSqlSynchronousApiTest {
     private IgniteClient client;
 
-    private static final int ROW_COUNT = 16;
-
     @BeforeAll
     public void startClient() {
         client = 
IgniteClient.builder().addresses(getClientAddresses(List.of(CLUSTER.aliveNode())).get(0)).build();
@@ -70,14 +68,4 @@ public class ItSqlClientSynchronousApiTest extends 
ItSqlSynchronousApiTest {
     public void testLockIsNotReleasedAfterTxRollback() {
         super.testLockIsNotReleasedAfterTxRollback();
     }
-
-    @Override
-    public void runScriptThatCompletesSuccessfully() {
-        super.runScriptThatCompletesSuccessfully();
-    }
-
-    @Override
-    public void runScriptThatFails() {
-        super.runScriptThatFails();
-    }
 }

Reply via email to