This is an automated email from the ASF dual-hosted git repository. zstan 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 cee8310315 IGNITE-17953 Sql. NPE on some malformed queries - Fixes #1345. cee8310315 is described below commit cee831031501c36d1d24b1dd72a84747be8f18f6 Author: zstan <stanilov...@gmail.com> AuthorDate: Fri Nov 25 09:49:34 2022 +0300 IGNITE-17953 Sql. NPE on some malformed queries - Fixes #1345. Signed-off-by: zstan <stanilov...@gmail.com> --- .../client/io/netty/NettyClientConnection.java | 4 +-- .../runner/app/jdbc/ItJdbcErrorsSelfTest.java | 40 ++++++++++++++++++++++ .../internal/sql/engine/SqlQueryProcessor.java | 29 ++++++++++++++-- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/io/netty/NettyClientConnection.java b/modules/client/src/main/java/org/apache/ignite/internal/client/io/netty/NettyClientConnection.java index d21f175b52..a834318d99 100644 --- a/modules/client/src/main/java/org/apache/ignite/internal/client/io/netty/NettyClientConnection.java +++ b/modules/client/src/main/java/org/apache/ignite/internal/client/io/netty/NettyClientConnection.java @@ -21,7 +21,6 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.util.AttributeKey; -import java.io.IOException; import java.net.InetSocketAddress; import org.apache.ignite.internal.client.io.ClientConnection; import org.apache.ignite.internal.client.io.ClientConnectionStateHandler; @@ -88,9 +87,8 @@ public class NettyClientConnection implements ClientConnection { * Handles incoming message. * * @param buf Message. - * @throws IOException when message can't be decoded. */ - void onMessage(ByteBuf buf) throws IOException { + void onMessage(ByteBuf buf) { msgHnd.onMessage(buf); } diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ItJdbcErrorsSelfTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ItJdbcErrorsSelfTest.java index d15d1eed71..f10d2284c1 100644 --- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ItJdbcErrorsSelfTest.java +++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/jdbc/ItJdbcErrorsSelfTest.java @@ -22,6 +22,7 @@ import static org.apache.ignite.internal.jdbc.proto.SqlStateCode.INVALID_TRANSAC import static org.apache.ignite.internal.jdbc.proto.SqlStateCode.UNSUPPORTED_OPERATION; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -29,6 +30,7 @@ import java.sql.BatchUpdateException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; +import java.sql.Statement; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -51,6 +53,44 @@ public class ItJdbcErrorsSelfTest extends ItJdbcErrorsAbstractSelfTest { CLIENT_CONNECTION_FAILED, "Failed to connect to server"); } + /** + * Test that execution of erroneous queries are not stopping execution. + * Also check correctness of exception messages. + * + * @throws SQLException If connection can`t be established. + */ + @Test + public void processMixedQueries() throws SQLException { + conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1:10800/"); + + try (Statement stmt = conn.createStatement()) { + stmt.execute( + "CREATE TABLE CITIES (" + + "ID INT PRIMARY KEY," + + "NAME VARCHAR)" + ); + + SQLException ex = assertThrows(SQLException.class, () -> stmt.execute("non sql stuff")); + + assertTrue(ex.getMessage().contains("Failed to parse query")); + } + + try (Statement stmt = conn.createStatement()) { + stmt.execute( + "CREATE TABLE ACCOUNTS (" + + " ACCOUNT_ID INT PRIMARY KEY," + + " CITY_ID INT," + + " FIRST_NAME VARCHAR," + + " LAST_NAME VARCHAR," + + " BALANCE DOUBLE)" + ); + + SQLException ex = assertThrows(SQLException.class, () -> stmt.execute("CREATE TABLE ACCOUNTS (ACCOUNT_ID INT PRIMARY KEY)")); + + assertTrue(ex.getMessage().contains("Table already exists")); + } + } + /** * Test error code for the case when connection string is a mess. */ diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java index 8491b3ee99..fd74d12688 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java @@ -473,11 +473,19 @@ public class SqlQueryProcessor implements QueryProcessor { throw new IgniteInternalException(SCHEMA_NOT_FOUND_ERR, format("Schema not found [schemaName={}]", schemaName)); } - SqlNodeList nodes = Commons.parse(sql, FRAMEWORK_CONFIG.getParserConfig()); + CompletableFuture<Void> start = new CompletableFuture<>(); + + SqlNodeList nodes = SqlNodeList.EMPTY; var res = new ArrayList<CompletableFuture<AsyncSqlCursor<List<Object>>>>(nodes.size()); - CompletableFuture<Void> start = new CompletableFuture<>(); + try { + nodes = Commons.parse(sql, FRAMEWORK_CONFIG.getParserConfig()); + } catch (Throwable th) { + start.completeExceptionally(th); + + res.add(CompletableFuture.completedFuture(failedCursor(th))); + } for (SqlNode sqlNode : nodes) { boolean needStartTx = SqlKind.DML.contains(sqlNode.getKind()) || SqlKind.QUERY.contains(sqlNode.getKind()); @@ -526,6 +534,23 @@ public class SqlQueryProcessor implements QueryProcessor { return res; } + private static <T> AsyncSqlCursor<T> failedCursor(Throwable th) { + return new AsyncSqlCursorImpl<>( + null, null, null, + new AsyncCursor<>() { + @Override + public CompletableFuture<BatchedResult<T>> requestNextAsync(int rows) { + return CompletableFuture.failedFuture(th); + } + + @Override + public CompletableFuture<Void> closeAsync() { + return CompletableFuture.completedFuture(null); + } + } + ); + } + private abstract static class AbstractTableEventListener implements EventListener<TableEventParameters> { protected final SqlSchemaManagerImpl schemaHolder;