This is an automated email from the ASF dual-hosted git repository.
korlov 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 91fd5e2808 IGNITE-18653: Sql. The number of dynamic parameters can be
checked once (#1732)
91fd5e2808 is described below
commit 91fd5e2808c34409dcc00ba39ace5a19e9ab58ec
Author: Max Zhuravkov <[email protected]>
AuthorDate: Tue Mar 21 15:09:15 2023 +0400
IGNITE-18653: Sql. The number of dynamic parameters can be checked once
(#1732)
Co-authored-by: korlov42 <[email protected]>
Co-authored-by: ygerzhedovich
<[email protected]>
---
.../internal/cli/CliIntegrationTestBase.java | 3 +-
.../client/handler/JdbcQueryEventHandlerImpl.java | 54 ++++---
.../apache/ignite/jdbc/ItJdbcBatchSelfTest.java | 36 +++--
.../internal/sql/api/ItSqlAsynchronousApiTest.java | 4 +-
.../internal/sql/api/ItSqlSynchronousApiTest.java | 4 +-
.../sql/engine/ClusterPerClassIntegrationTest.java | 2 +-
.../sql/engine/ItDynamicParameterTest.java | 3 +-
.../ignite/internal/sql/engine/ItUuidTest.java | 2 +-
.../internal/sql/engine/util/QueryChecker.java | 3 +-
.../ignite/internal/sql/api/SessionImpl.java | 18 +--
.../ignite/internal/sql/engine/QueryContext.java | 80 +++++++---
.../internal/sql/engine/SqlQueryProcessor.java | 87 ++++++++---
.../ignite/internal/sql/engine/SqlQueryType.java | 24 +--
.../sql/engine/exec/ExecutionServiceImpl.java | 8 +-
.../internal/sql/engine/prepare/DdlPlan.java | 5 +-
.../internal/sql/engine/prepare/ExplainPlan.java | 5 +-
.../internal/sql/engine/prepare/FragmentPlan.java | 6 +-
.../internal/sql/engine/prepare/IgnitePlanner.java | 21 ++-
.../sql/engine/prepare/IgniteSqlValidator.java | 87 +++--------
.../sql/engine/prepare/MultiStepDmlPlan.java | 5 +-
.../sql/engine/prepare/MultiStepQueryPlan.java | 5 +-
.../sql/engine/prepare/PrepareServiceImpl.java | 34 ++---
.../internal/sql/engine/prepare/QueryPlan.java | 11 +-
.../internal/sql/engine/sql/IgniteSqlParser.java | 162 +++++++++++++++++++++
.../ignite/internal/sql/engine/sql/ParseMode.java | 48 ++++++
.../{QueryValidator.java => sql/ParseResult.java} | 34 +++--
.../internal/sql/engine/sql/ScriptParseResult.java | 63 ++++++++
.../sql/engine/sql/StatementParseResult.java | 78 ++++++++++
.../ignite/internal/sql/engine/util/Commons.java | 93 ++++++------
.../internal/sql/engine/util/IgniteResource.java | 3 -
.../sql/engine/benchmarks/TpchParseBenchmark.java | 6 +-
.../engine/benchmarks/TpchPrepareBenchmark.java | 7 +-
.../sql/engine/exec/ExecutionServiceImplTest.java | 12 +-
.../internal/sql/engine/framework/TestNode.java | 12 +-
.../sql/engine/sql/AbstractDdlParserTest.java | 12 +-
.../sql/DistributionZoneSqlDdlParserTest.java | 38 ++---
.../engine/sql/IgniteSqlDecimalLiteralTest.java | 11 +-
.../sql/engine/sql/IgniteSqlParserTest.java | 62 ++++++++
.../internal/sql/engine/sql/SqlDdlParserTest.java | 50 +++----
39 files changed, 837 insertions(+), 361 deletions(-)
diff --git
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/CliIntegrationTestBase.java
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/CliIntegrationTestBase.java
index 0db0d1e8e6..e570676d3c 100644
---
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/CliIntegrationTestBase.java
+++
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/CliIntegrationTestBase.java
@@ -32,6 +32,7 @@ import org.apache.ignite.internal.sql.engine.AsyncCursor;
import org.apache.ignite.internal.sql.engine.AsyncCursor.BatchedResult;
import org.apache.ignite.internal.sql.engine.QueryContext;
import org.apache.ignite.internal.sql.engine.QueryProperty;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.internal.sql.engine.property.PropertiesHolder;
import org.apache.ignite.internal.sql.engine.session.SessionId;
import org.apache.ignite.internal.testframework.IntegrationTestBase;
@@ -106,7 +107,7 @@ public class CliIntegrationTestBase extends
IntegrationTestBase {
));
try {
- var context = tx != null ? QueryContext.of(tx) : QueryContext.of();
+ var context = QueryContext.create(SqlQueryType.ALL, tx);
return getAllFromCursor(
await(queryEngine.querySingleAsync(sessionId, context,
sql, args))
diff --git
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/JdbcQueryEventHandlerImpl.java
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/JdbcQueryEventHandlerImpl.java
index 36ec19d982..9426036913 100644
---
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/JdbcQueryEventHandlerImpl.java
+++
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/JdbcQueryEventHandlerImpl.java
@@ -28,6 +28,7 @@ import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;
@@ -53,11 +54,10 @@ import org.apache.ignite.internal.jdbc.proto.event.Response;
import org.apache.ignite.internal.sql.engine.AsyncSqlCursor;
import org.apache.ignite.internal.sql.engine.QueryContext;
import org.apache.ignite.internal.sql.engine.QueryProcessor;
-import org.apache.ignite.internal.sql.engine.QueryValidator;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.internal.sql.engine.exec.QueryValidationException;
-import org.apache.ignite.internal.sql.engine.prepare.QueryPlan;
-import org.apache.ignite.internal.sql.engine.prepare.QueryPlan.Type;
import org.apache.ignite.internal.util.ExceptionUtils;
+import org.apache.ignite.lang.IgniteException;
import org.apache.ignite.lang.IgniteInternalCheckedException;
import org.apache.ignite.lang.IgniteInternalException;
import org.apache.ignite.sql.ColumnType;
@@ -67,6 +67,13 @@ import org.apache.ignite.sql.ResultSetMetadata;
* Jdbc query event handler implementation.
*/
public class JdbcQueryEventHandlerImpl implements JdbcQueryEventHandler {
+
+ /** {@link SqlQueryType}s allowed in JDBC select statements. **/
+ private static final Set<SqlQueryType> SELECT_STATEMENT_QUERIES =
Set.of(SqlQueryType.QUERY, SqlQueryType.EXPLAIN);
+
+ /** {@link SqlQueryType}s allowed in JDBC update statements. **/
+ private static final Set<SqlQueryType> UPDATE_STATEMENT_QUERIES =
Set.of(SqlQueryType.DML, SqlQueryType.DDL);
+
/** Sql query processor. */
private final QueryProcessor processor;
@@ -142,24 +149,16 @@ public class JdbcQueryEventHandlerImpl implements
JdbcQueryEventHandler {
}
private QueryContext createQueryContext(JdbcStatementType stmtType) {
- if (stmtType == JdbcStatementType.ANY_STATEMENT_TYPE) {
- return QueryContext.of();
+ switch (stmtType) {
+ case ANY_STATEMENT_TYPE:
+ return QueryContext.create(SqlQueryType.ALL);
+ case SELECT_STATEMENT_TYPE:
+ return QueryContext.create(SELECT_STATEMENT_QUERIES);
+ case UPDATE_STATEMENT_TYPE:
+ return QueryContext.create(UPDATE_STATEMENT_QUERIES);
+ default:
+ throw new AssertionError("Unexpected jdbc statement type: " +
stmtType);
}
-
- QueryValidator validator = (QueryPlan plan) -> {
- if (plan.type() == Type.QUERY || plan.type() == Type.EXPLAIN) {
- if (stmtType == JdbcStatementType.SELECT_STATEMENT_TYPE) {
- return;
- }
- throw new QueryValidationException("Given statement type does
not match that declared by JDBC driver.");
- }
- if (stmtType == JdbcStatementType.UPDATE_STATEMENT_TYPE) {
- return;
- }
- throw new QueryValidationException("Given statement type does not
match that declared by JDBC driver.");
- };
-
- return QueryContext.of(validator);
}
/** {@inheritDoc} */
@@ -272,12 +271,19 @@ public class JdbcQueryEventHandlerImpl implements
JdbcQueryEventHandler {
* @return StringWriter filled with exception.
*/
private StringWriter getWriterWithStackTrace(Throwable t) {
- String message = ExceptionUtils.unwrapCause(t).getMessage();
+ Throwable cause = ExceptionUtils.unwrapCause(t);
StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- pw.print(message);
- return sw;
+ try (PrintWriter pw = new PrintWriter(sw)) {
+ // We need to remap QueryValidationException into a jdbc error.
+ if (cause instanceof IgniteException && cause.getCause()
instanceof QueryValidationException) {
+ pw.print("Given statement type does not match that declared by
JDBC driver.");
+ } else {
+ pw.print(cause.getMessage());
+ }
+
+ return sw;
+ }
}
/**
diff --git
a/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcBatchSelfTest.java
b/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcBatchSelfTest.java
index 54fa194843..2dc6a7c588 100644
---
a/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcBatchSelfTest.java
+++
b/modules/jdbc/src/integrationTest/java/org/apache/ignite/jdbc/ItJdbcBatchSelfTest.java
@@ -17,6 +17,8 @@
package org.apache.ignite.jdbc;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -158,11 +160,31 @@ public class ItJdbcBatchSelfTest extends
AbstractJdbcSelfTest {
assertEquals(0, updCnts.length, "Invalid update counts size");
- if (!e.getMessage().contains("Unexpected number of query
parameters. Provided 1 but there is only 0 dynamic parameter(s).")) {
- log.error("Invalid exception: ", e);
+ assertThat(e.getMessage(), containsString("Given statement type
does not match that declared by JDBC driver"));
- fail();
- }
+ assertEquals(SqlStateCode.INTERNAL_ERROR, e.getSQLState(),
"Invalid SQL state.");
+ assertEquals(IgniteQueryErrorCode.UNKNOWN, e.getErrorCode(),
"Invalid error code.");
+ }
+ }
+
+ @Test
+ public void
testPreparedStatementSupplyParametersToQueryWithoutParameters() throws
Exception {
+ PreparedStatement preparedStatement = conn.prepareStatement("UPDATE
Person SET firstName='NONE'");
+
+ preparedStatement.setString(1, "broken");
+ preparedStatement.addBatch();
+
+ try {
+ preparedStatement.executeBatch();
+
+ fail("BatchUpdateException must be thrown");
+ } catch (BatchUpdateException e) {
+ int[] updCnts = e.getUpdateCounts();
+
+ assertEquals(0, updCnts.length, "Invalid update counts size");
+
+ assertThat(e.getMessage(),
+ containsString("Unexpected number of query parameters.
Provided 1 but there is only 0 dynamic parameter(s)."));
assertEquals(SqlStateCode.INTERNAL_ERROR, e.getSQLState(),
"Invalid SQL state.");
assertEquals(IgniteQueryErrorCode.UNKNOWN, e.getErrorCode(),
"Invalid error code.");
@@ -196,11 +218,7 @@ public class ItJdbcBatchSelfTest extends
AbstractJdbcSelfTest {
assertEquals(i + 1, updCnts[i], "Invalid update count");
}
- if (!e.getMessage().contains("Given statement type does not match
that declared by JDBC driver")) {
- log.error("Invalid exception: ", e);
-
- fail();
- }
+ assertThat(e.getMessage(), containsString("Given statement type
does not match that declared by JDBC driver"));
assertEquals(SqlStateCode.INTERNAL_ERROR, e.getSQLState(),
"Invalid SQL state.");
assertEquals(IgniteQueryErrorCode.UNKNOWN, e.getErrorCode(),
"Invalid error code.");
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 f8b6cb8907..1940806887 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
@@ -571,7 +571,7 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
// Multiple statements error.
assertThrowsWithCause(() -> await(ses.executeAsync(null, "SELECT 1;
SELECT 2")),
- SqlException.class, "Multiple statements aren't allowed");
+ SqlException.class, "Multiple statements are not allowed");
// Planning error.
assertThrowsWithCause(() -> await(ses.executeAsync(null, "CREATE TABLE
TEST2 (VAL INT)")),
@@ -650,7 +650,7 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
assertThrowsWithCause(
() -> await(ses.executeBatchAsync(null, "SELECT * FROM TEST",
args)),
SqlException.class,
- "Unexpected number of query parameters. Provided 2 but there
is only 0 dynamic parameter(s)"
+ "Invalid SQL statement type in the batch"
);
assertThrowsWithCause(
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 a3b492a560..fcc37bae01 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
@@ -246,7 +246,7 @@ public class ItSqlSynchronousApiTest extends
ClusterPerClassIntegrationTest {
assertThrowsWithCause(
() -> ses.execute(null, "SELECT 1; SELECT 2"),
SqlException.class,
- "Multiple statements aren't allowed"
+ "Multiple statements are not allowed"
);
// Planning error.
@@ -309,7 +309,7 @@ public class ItSqlSynchronousApiTest extends
ClusterPerClassIntegrationTest {
assertThrowsWithCause(
() -> ses.executeBatch(null, "SELECT * FROM TEST", args),
SqlException.class,
- "Unexpected number of query parameters. Provided 2 but there
is only 0 dynamic parameter(s)"
+ "Invalid SQL statement type in the batch"
);
assertThrowsWithCause(
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ClusterPerClassIntegrationTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ClusterPerClassIntegrationTest.java
index 6cab3df26b..341ab7216a 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ClusterPerClassIntegrationTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ClusterPerClassIntegrationTest.java
@@ -411,7 +411,7 @@ public abstract class ClusterPerClassIntegrationTest
extends IgniteIntegrationTe
));
try {
- var context = tx != null ? QueryContext.of(tx) : QueryContext.of();
+ var context = QueryContext.create(SqlQueryType.ALL, tx);
return getAllFromCursor(
await(queryEngine.querySingleAsync(sessionId, context,
sql, args))
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
index 1cd14647b2..b953fa7667 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDynamicParameterTest.java
@@ -36,6 +36,7 @@ import java.util.concurrent.ThreadLocalRandom;
import org.apache.calcite.runtime.CalciteContextException;
import org.apache.ignite.internal.sql.engine.util.MetadataMatcher;
import org.apache.ignite.sql.ColumnType;
+import org.apache.ignite.sql.SqlException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
@@ -243,7 +244,7 @@ public class ItDynamicParameterTest extends
ClusterPerClassIntegrationTest {
}
private static void assertUnexpectedNumberOfParameters(String query,
Object... params) {
- CalciteContextException err =
assertThrows(CalciteContextException.class, () -> {
+ SqlException err = assertThrows(SqlException.class, () -> {
assertQuery(query).withParams(params).check();
}, "query: " + query);
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItUuidTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItUuidTest.java
index a80ccf87d2..7fdcf8ed5d 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItUuidTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItUuidTest.java
@@ -175,7 +175,7 @@ public class ItUuidTest extends
ClusterPerClassIntegrationTest {
// CASE <boolean> WHEN ... END
var query = "SELECT id, CASE uuid_key WHEN uuid_key = ? THEN uuid_key
ELSE ? END FROM t;";
- var t = assertThrows(CalciteContextException.class, () -> sql(query,
UUID_1));
+ var t = assertThrows(CalciteContextException.class, () -> sql(query,
UUID_1, UUID_1));
assertThat(t.getMessage(), containsString("Invalid types for
comparison: UUID = BOOLEAN"));
}
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
index 33e1ad4417..e1a9bf00de 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/util/QueryChecker.java
@@ -44,6 +44,7 @@ import org.apache.ignite.internal.sql.engine.AsyncSqlCursor;
import org.apache.ignite.internal.sql.engine.QueryContext;
import org.apache.ignite.internal.sql.engine.QueryProcessor;
import org.apache.ignite.internal.sql.engine.QueryProperty;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.internal.sql.engine.property.PropertiesHolder;
import org.apache.ignite.internal.sql.engine.session.SessionId;
import org.apache.ignite.internal.util.CollectionUtils;
@@ -420,7 +421,7 @@ public abstract class QueryChecker {
Map.of(QueryProperty.DEFAULT_SCHEMA, "PUBLIC")
));
- QueryContext context = tx != null ? QueryContext.of(tx) :
QueryContext.of();
+ QueryContext context = QueryContext.create(SqlQueryType.ALL, tx);
String qry = originalQuery;
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 a7c019a174..31a0a9934c 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
@@ -20,13 +20,13 @@ package org.apache.ignite.internal.sql.api;
import static org.apache.ignite.lang.ErrorGroups.Common.UNEXPECTED_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.INVALID_DML_RESULT_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.OPERATION_INTERRUPTED_ERR;
-import static org.apache.ignite.lang.ErrorGroups.Sql.QUERY_INVALID_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.SESSION_NOT_FOUND_ERR;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
@@ -38,8 +38,7 @@ import org.apache.ignite.internal.sql.engine.AsyncCursor;
import org.apache.ignite.internal.sql.engine.QueryContext;
import org.apache.ignite.internal.sql.engine.QueryProcessor;
import org.apache.ignite.internal.sql.engine.QueryProperty;
-import org.apache.ignite.internal.sql.engine.QueryValidator;
-import org.apache.ignite.internal.sql.engine.prepare.QueryPlan.Type;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.internal.sql.engine.property.PropertiesHolder;
import org.apache.ignite.internal.sql.engine.session.SessionId;
import org.apache.ignite.internal.util.ArrayUtils;
@@ -165,7 +164,7 @@ public class SessionImpl implements Session {
}
try {
- QueryContext ctx = QueryContext.of(transaction);
+ QueryContext ctx = QueryContext.create(SqlQueryType.ALL,
transaction);
CompletableFuture<AsyncResultSet<SqlRow>> result =
qryProc.querySingleAsync(sessionId, ctx, query, arguments)
.thenCompose(cur -> cur.requestNextAsync(pageSize)
@@ -231,16 +230,9 @@ public class SessionImpl implements Session {
}
try {
- QueryContext ctx = QueryContext.of(
- transaction,
- (QueryValidator) plan -> {
- if (plan.type() != Type.DML) {
- throw new SqlException(QUERY_INVALID_ERR, "Invalid
SQL statement type in the batch [plan=" + plan + ']');
- }
- }
- );
+ QueryContext ctx = QueryContext.create(Set.of(SqlQueryType.DML),
transaction);
- final var counters = new LongArrayList(batch.size());
+ var counters = new LongArrayList(batch.size());
CompletableFuture<Void> tail =
CompletableFuture.completedFuture(null);
ArrayList<CompletableFuture<Void>> batchFuts = new
ArrayList<>(batch.size());
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryContext.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryContext.java
index cc84361b40..fec3794cfd 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryContext.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryContext.java
@@ -20,24 +20,36 @@ package org.apache.ignite.internal.sql.engine;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
import org.apache.calcite.plan.Context;
import org.apache.ignite.internal.util.ArrayUtils;
-import org.checkerframework.checker.nullness.qual.Nullable;
+import org.jetbrains.annotations.Nullable;
/**
* User query context.
*/
public class QueryContext implements Context {
+
+ /** A set of types of SQL commands that can be executed within an
operation this context is associated with. **/
+ private final Set<SqlQueryType> allowedQueries;
+
/** Context params. */
private final Object[] params;
/**
* Constructor.
*
+ * @param allowedQueries Allowed query types.
* @param params Context params.
*/
- private QueryContext(Object[] params) {
+ private QueryContext(Set<SqlQueryType> allowedQueries, Object[] params) {
this.params = params;
+ this.allowedQueries = allowedQueries;
+ }
+
+ /** Returns a set of {@link SqlQueryType allowed query types}. **/
+ public Set<SqlQueryType> allowedQueryTypes() {
+ return allowedQueries;
}
/** {@inheritDoc} */
@@ -51,33 +63,61 @@ public class QueryContext implements Context {
}
/**
- * Creates a context from a list of parameters.
+ * Creates a context that allows the given query types.
+ *
+ * @param allowedQueries A set of allowed query types.
+ * @return Query context.
+ */
+ public static QueryContext create(Set<SqlQueryType> allowedQueries) {
+ return create(allowedQueries, null, ArrayUtils.OBJECT_EMPTY_ARRAY);
+ }
+
+ /**
+ * Creates a context that allows the given query types and includes an
optional parameter.
*
- * @param params Context parameters.
+ * @param allowedQueries A set of allowed query types.
+ * @param param A context parameter.
* @return Query context.
*/
- public static QueryContext of(Object... params) {
- return !ArrayUtils.nullOrEmpty(params) ? new QueryContext(build(null,
params).toArray())
- : new QueryContext(ArrayUtils.OBJECT_EMPTY_ARRAY);
+ public static QueryContext create(Set<SqlQueryType> allowedQueries,
@Nullable Object param) {
+ return create(allowedQueries, param, ArrayUtils.OBJECT_EMPTY_ARRAY);
}
- private static List<Object> build(List<Object> dst, Object[] src) {
- if (dst == null) {
- dst = new ArrayList<>();
+ /**
+ * Creates a context that allows the given query types and includes a list
of parameters.
+ *
+ * @param allowedQueries A set of allowed query types.
+ * @param param An optional parameter.
+ * @param params Optional array of additional parameters.
+ * @return Query context.
+ */
+ public static QueryContext create(Set<SqlQueryType> allowedQueries,
@Nullable Object param, Object... params) {
+ Object[] paramsArray = params == null ? ArrayUtils.OBJECT_EMPTY_ARRAY
: params;
+
+ if (param == null && paramsArray.length == 0) {
+ return new QueryContext(allowedQueries,
ArrayUtils.OBJECT_EMPTY_ARRAY);
+ } else {
+ ArrayList<Object> dst = new ArrayList<>();
+ build(dst, param);
+ build(dst, paramsArray);
+ return new QueryContext(allowedQueries, dst.toArray());
}
+ }
+ private static void build(List<Object> dst, Object[] src) {
for (Object obj : src) {
- if (obj == null) {
- continue;
- }
-
- if (obj.getClass() == QueryContext.class) {
- build(dst, ((QueryContext) obj).params);
- } else {
- dst.add(obj);
- }
+ build(dst, obj);
}
+ }
- return dst;
+ private static void build(List<Object> dst, @Nullable Object obj) {
+ if (obj == null) {
+ return;
+ }
+ if (obj.getClass() == QueryContext.class) {
+ build(dst, ((QueryContext) obj).params);
+ } else {
+ dst.add(obj);
+ }
}
}
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 8d084d192c..115a2d4b51 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
@@ -23,12 +23,14 @@ import static
org.apache.ignite.lang.ErrorGroups.Sql.QUERY_INVALID_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.SCHEMA_NOT_FOUND_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.SESSION_EXPIRED_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.SESSION_NOT_FOUND_ERR;
+import static
org.apache.ignite.lang.ErrorGroups.Sql.UNSUPPORTED_SQL_OPERATION_KIND_ERR;
import static org.apache.ignite.lang.IgniteStringFormatter.format;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@@ -40,7 +42,6 @@ import java.util.stream.Stream;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.tools.Frameworks;
import org.apache.calcite.util.Pair;
import org.apache.ignite.internal.distributionzones.DistributionZoneManager;
@@ -62,6 +63,7 @@ import
org.apache.ignite.internal.sql.engine.exec.LifecycleAware;
import org.apache.ignite.internal.sql.engine.exec.MailboxRegistryImpl;
import org.apache.ignite.internal.sql.engine.exec.QueryTaskExecutor;
import org.apache.ignite.internal.sql.engine.exec.QueryTaskExecutorImpl;
+import org.apache.ignite.internal.sql.engine.exec.QueryValidationException;
import org.apache.ignite.internal.sql.engine.exec.ddl.DdlCommandHandler;
import org.apache.ignite.internal.sql.engine.message.MessageServiceImpl;
import org.apache.ignite.internal.sql.engine.prepare.PrepareService;
@@ -72,6 +74,10 @@ import
org.apache.ignite.internal.sql.engine.schema.SqlSchemaManagerImpl;
import org.apache.ignite.internal.sql.engine.session.SessionId;
import org.apache.ignite.internal.sql.engine.session.SessionInfo;
import org.apache.ignite.internal.sql.engine.session.SessionManager;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlParser;
+import org.apache.ignite.internal.sql.engine.sql.ParseResult;
+import org.apache.ignite.internal.sql.engine.sql.ScriptParseResult;
+import org.apache.ignite.internal.sql.engine.sql.StatementParseResult;
import org.apache.ignite.internal.sql.engine.util.BaseQueryContext;
import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.storage.DataStorageManager;
@@ -305,7 +311,9 @@ public class SqlQueryProcessor implements QueryProcessor {
/** {@inheritDoc} */
@Override
public List<CompletableFuture<AsyncSqlCursor<List<Object>>>>
queryAsync(String schemaName, String qry, Object... params) {
- return queryAsync(QueryContext.of(), schemaName, qry, params);
+ QueryContext context = QueryContext.create(SqlQueryType.ALL);
+
+ return queryAsync(context, schemaName, qry, params);
}
/** {@inheritDoc} */
@@ -401,13 +409,12 @@ public class SqlQueryProcessor implements QueryProcessor {
CompletableFuture<AsyncSqlCursor<List<Object>>> stage = start
.thenApply(v -> {
- var nodes = Commons.parse(sql, Commons.PARSER_CONFIG);
+ StatementParseResult parseResult =
IgniteSqlParser.parse(sql, StatementParseResult.MODE);
+ SqlNode sqlNode = parseResult.statement();
- if (nodes.size() > 1) {
- throw new SqlException(QUERY_INVALID_ERR, "Multiple
statements aren't allowed.");
- }
+ validateParsedStatement(context, parseResult, sqlNode,
params);
- return nodes.get(0);
+ return sqlNode;
})
.thenCompose(sqlNode -> {
boolean rwOp = dataModificationOp(sqlNode);
@@ -426,17 +433,17 @@ public class SqlQueryProcessor implements QueryProcessor {
return prepareSvc.prepareAsync(sqlNode, ctx)
.thenApply(plan -> {
- context.maybeUnwrap(QueryValidator.class)
- .ifPresent(queryValidator ->
queryValidator.validatePlan(plan));
-
boolean implicitTxRequired = outerTx == null;
InternalTransaction tx = implicitTxRequired ?
txManager.begin(!rwOp) : outerTx;
var dataCursor = executionSrvc.executePlan(tx,
plan, ctx);
+ SqlQueryType queryType = plan.type();
+ assert queryType != null : "Expected a full
plan but got a fragment: " + plan;
+
return new AsyncSqlCursorImpl<>(
-
SqlQueryType.mapPlanTypeToSqlType(plan.type()),
+ queryType,
plan.metadata(),
implicitTxRequired ? tx : null,
new AsyncCursor<List<Object>>() {
@@ -483,19 +490,29 @@ public class SqlQueryProcessor implements QueryProcessor {
CompletableFuture<Void> start = new CompletableFuture<>();
- SqlNodeList nodes = SqlNodeList.EMPTY;
-
- var res = new
ArrayList<CompletableFuture<AsyncSqlCursor<List<Object>>>>(nodes.size());
+ ScriptParseResult parseResult;
+ List<CompletableFuture<AsyncSqlCursor<List<Object>>>> res;
try {
- nodes = Commons.parse(sql, FRAMEWORK_CONFIG.getParserConfig());
+ parseResult = IgniteSqlParser.parse(sql, ScriptParseResult.MODE);
+ res = new ArrayList<>(parseResult.statements().size());
} catch (Throwable th) {
start.completeExceptionally(th);
- res.add(CompletableFuture.completedFuture(failedCursor(th)));
+ parseResult = new ScriptParseResult(Collections.emptyList(), 0);
+ res =
Collections.singletonList(CompletableFuture.completedFuture(failedCursor(th)));
}
- for (SqlNode sqlNode : nodes) {
+ for (SqlNode sqlNode : parseResult.statements()) {
+ try {
+ validateParsedStatement(context, parseResult, sqlNode, params);
+ } catch (Exception e) {
+ start.completeExceptionally(e);
+
+ res =
Collections.singletonList(CompletableFuture.completedFuture(failedCursor(e)));
+ return res;
+ }
+
// Only rw transactions for now.
InternalTransaction implicitTx = txManager.begin(false);
@@ -512,13 +529,14 @@ public class SqlQueryProcessor implements QueryProcessor {
.build();
// TODO https://issues.apache.org/jira/browse/IGNITE-17746 Fix
query execution flow.
- CompletableFuture<AsyncSqlCursor<List<Object>>> stage =
start.thenCompose(none -> prepareSvc.prepareAsync(sqlNode, ctx))
+ CompletableFuture<AsyncSqlCursor<List<Object>>> stage = start
+ .thenCompose(none -> prepareSvc.prepareAsync(sqlNode, ctx))
.thenApply(plan -> {
- context.maybeUnwrap(QueryValidator.class)
- .ifPresent(queryValidator ->
queryValidator.validatePlan(plan));
+ SqlQueryType queryType = plan.type();
+ assert queryType != null : "Expected a full plan but
got a fragment: " + plan;
return new AsyncSqlCursorImpl<>(
- SqlQueryType.mapPlanTypeToSqlType(plan.type()),
+ queryType,
plan.metadata(),
implicitTx,
executionSrvc.executePlan(implicitTx, plan,
ctx)
@@ -664,4 +682,31 @@ public class SqlQueryProcessor implements QueryProcessor {
private static boolean dataModificationOp(SqlNode sqlNode) {
return SqlKind.DML.contains(sqlNode.getKind());
}
+
+ /** Performs additional validation of a parsed statement. **/
+ private static void validateParsedStatement(QueryContext context,
ParseResult parseResult, SqlNode node, Object[] params) {
+ Set<SqlQueryType> allowedTypes = context.allowedQueryTypes();
+ SqlQueryType queryType = Commons.getQueryType(node);
+
+ if (queryType == null) {
+ throw new
IgniteInternalException(UNSUPPORTED_SQL_OPERATION_KIND_ERR, "Unsupported
operation ["
+ + "sqlNodeKind=" + node.getKind() + "; "
+ + "querySql=\"" + node + "\"]");
+ }
+
+ if (!allowedTypes.contains(queryType)) {
+ String message = format("Invalid SQL statement type in the batch.
Expected {} but got {}.", allowedTypes, queryType);
+
+ throw new QueryValidationException(message);
+ }
+
+ if (parseResult.dynamicParamsCount() != params.length) {
+ String message = format(
+ "Unexpected number of query parameters. Provided {} but
there is only {} dynamic parameter(s).",
+ params.length, parseResult.dynamicParamsCount()
+ );
+
+ throw new SqlException(QUERY_INVALID_ERR, message);
+ }
+ }
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryType.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryType.java
index 9fde2c55ed..92e718a7d0 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryType.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryType.java
@@ -17,7 +17,7 @@
package org.apache.ignite.internal.sql.engine;
-import org.apache.ignite.internal.sql.engine.prepare.QueryPlan;
+import java.util.Set;
/**
* Possible query types.
@@ -35,24 +35,6 @@ public enum SqlQueryType {
/** Explain. */
EXPLAIN;
- /**
- * Map query plan type to sql type.
- *
- * @param type QueryPlan.Type.
- * @return Associated SqlQueryType.
- */
- public static SqlQueryType mapPlanTypeToSqlType(QueryPlan.Type type) {
- switch (type) {
- case QUERY:
- return QUERY;
- case DML:
- return DML;
- case DDL:
- return DDL;
- case EXPLAIN:
- return EXPLAIN;
- default:
- throw new UnsupportedOperationException("Unexpected query plan
type: " + type.name());
- }
- }
+ /** A set of all query types. **/
+ public static final Set<SqlQueryType> ALL = Set.of(values());
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImpl.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImpl.java
index fd4ffaa2c1..555da1183a 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImpl.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImpl.java
@@ -46,6 +46,7 @@ import
org.apache.ignite.configuration.ConfigurationChangeException;
import org.apache.ignite.internal.logger.IgniteLogger;
import org.apache.ignite.internal.logger.Loggers;
import org.apache.ignite.internal.sql.engine.AsyncCursor;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.internal.sql.engine.exec.ddl.DdlCommandHandler;
import org.apache.ignite.internal.sql.engine.exec.rel.AbstractNode;
import org.apache.ignite.internal.sql.engine.exec.rel.AsyncRootNode;
@@ -256,7 +257,10 @@ public class ExecutionServiceImpl<RowT> implements
ExecutionService, TopologyEve
public AsyncCursor<List<Object>> executePlan(
InternalTransaction tx, QueryPlan plan, BaseQueryContext ctx
) {
- switch (plan.type()) {
+ SqlQueryType queryType = plan.type();
+ assert queryType != null : "Root plan can not be a fragment";
+
+ switch (queryType) {
case DML:
// TODO a barrier between previous operation and this one
case QUERY:
@@ -267,7 +271,7 @@ public class ExecutionServiceImpl<RowT> implements
ExecutionService, TopologyEve
return executeDdl((DdlPlan) plan);
default:
- throw new AssertionError("Unexpected plan type: " + plan);
+ throw new AssertionError("Unexpected query type: " + plan);
}
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/DdlPlan.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/DdlPlan.java
index 759a9766ff..c594cc0e46 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/DdlPlan.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/DdlPlan.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.sql.engine.prepare;
import java.util.List;
import org.apache.ignite.internal.sql.api.ColumnMetadataImpl;
import org.apache.ignite.internal.sql.api.ResultSetMetadataImpl;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.internal.sql.engine.prepare.ddl.DdlCommand;
import org.apache.ignite.sql.ColumnMetadata;
import org.apache.ignite.sql.ColumnType;
@@ -46,8 +47,8 @@ public class DdlPlan implements QueryPlan {
/** {@inheritDoc} */
@Override
- public Type type() {
- return Type.DDL;
+ public SqlQueryType type() {
+ return SqlQueryType.DDL;
}
/** {@inheritDoc} */
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ExplainPlan.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ExplainPlan.java
index 6f4d118c46..78089a7ef0 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ExplainPlan.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ExplainPlan.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.sql.engine.prepare;
import java.util.List;
import org.apache.ignite.internal.sql.api.ColumnMetadataImpl;
import org.apache.ignite.internal.sql.api.ResultSetMetadataImpl;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.sql.ColumnMetadata;
import org.apache.ignite.sql.ColumnType;
import org.apache.ignite.sql.ResultSetMetadata;
@@ -44,8 +45,8 @@ public class ExplainPlan implements QueryPlan {
}
/** {@inheritDoc} */
- @Override public Type type() {
- return Type.EXPLAIN;
+ @Override public SqlQueryType type() {
+ return SqlQueryType.EXPLAIN;
}
/** {@inheritDoc} */
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/FragmentPlan.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/FragmentPlan.java
index 08b7961bd8..658b0874b8 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/FragmentPlan.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/FragmentPlan.java
@@ -18,9 +18,11 @@
package org.apache.ignite.internal.sql.engine.prepare;
import org.apache.calcite.plan.RelOptCluster;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.sql.ResultSetMetadata;
+import org.jetbrains.annotations.Nullable;
/**
* FragmentPlan.
@@ -45,8 +47,8 @@ public class FragmentPlan implements QueryPlan {
/** {@inheritDoc} */
@Override
- public Type type() {
- return Type.FRAGMENT;
+ public @Nullable SqlQueryType type() {
+ return null;
}
/** {@inheritDoc} */
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgnitePlanner.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgnitePlanner.java
index 4e041770a9..0f19a5c096 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgnitePlanner.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgnitePlanner.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.sql.engine.prepare;
import static org.apache.ignite.internal.sql.engine.util.Commons.shortRuleName;
import static org.apache.ignite.lang.ErrorGroups.Sql.QUERY_INVALID_ERR;
+import static org.apache.ignite.lang.IgniteStringFormatter.format;
import java.io.PrintWriter;
import java.io.Reader;
@@ -61,7 +62,6 @@ import org.apache.calcite.rex.RexShuttle;
import org.apache.calcite.sql.SqlDataTypeSpec;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.SqlOperatorTable;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser;
@@ -76,10 +76,12 @@ import org.apache.calcite.util.Pair;
import org.apache.ignite.internal.sql.engine.metadata.IgniteMetadata;
import org.apache.ignite.internal.sql.engine.metadata.RelMetadataQueryEx;
import org.apache.ignite.internal.sql.engine.rex.IgniteRexBuilder;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlParser;
+import org.apache.ignite.internal.sql.engine.sql.StatementParseResult;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.util.FastTimestamps;
import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.sql.SqlException;
/**
* Query planer.
@@ -165,9 +167,20 @@ public class IgnitePlanner implements Planner,
RelOptTable.ViewExpander {
/** {@inheritDoc} */
@Override
public SqlNode parse(Reader reader) throws SqlParseException {
- SqlNodeList sqlNodes = Commons.parse(reader, parserCfg);
+ StatementParseResult parseResult = IgniteSqlParser.parse(reader,
StatementParseResult.MODE);
+ Object[] parameters = ctx.parameters();
- return sqlNodes.size() == 1 ? sqlNodes.get(0) : sqlNodes;
+ // Parse method is only used in tests.
+ if (parameters.length != parseResult.dynamicParamsCount()) {
+ String message = format(
+ "Unexpected number of query parameters. Provided {} but
there is only {} dynamic parameter(s).",
+ parameters.length, parseResult.dynamicParamsCount()
+ );
+
+ throw new SqlException(QUERY_INVALID_ERR, message);
+ }
+
+ return parseResult.statement();
}
/** {@inheritDoc} */
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java
index 62874427a1..e084e73113 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java
@@ -102,8 +102,6 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
/** Dynamic parameters. */
private final Object[] parameters;
- private int dynamicParameterCount;
-
/**
* Creates a validator.
*
@@ -123,34 +121,18 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
/** {@inheritDoc} */
@Override
public SqlNode validate(SqlNode topNode) {
- this.dynamicParameterCount = 0;
- try {
- SqlNode topNodeToValidate;
- // Calcite fails to validate a query when its top node is EXPLAIN
PLAN FOR
- // java.lang.NullPointerException: namespace for <query>
- // at
org.apache.calcite.sql.validate.SqlValidatorImpl.getNamespaceOrThrow(SqlValidatorImpl.java:1280)
- boolean explain = topNode instanceof SqlExplain;
- if (explain) {
- SqlExplain explainNode = (SqlExplain) topNode;
- topNodeToValidate = explainNode.getExplicandum();
- } else {
- topNodeToValidate = topNode;
- }
+ // Calcite fails to validate a query when its top node is EXPLAIN PLAN
FOR
+ // java.lang.NullPointerException: namespace for <query>
+ // at
org.apache.calcite.sql.validate.SqlValidatorImpl.getNamespaceOrThrow(SqlValidatorImpl.java:1280)
+ if (topNode instanceof SqlExplain) {
+ SqlExplain explainNode = (SqlExplain) topNode;
+ SqlNode topNodeToValidate = explainNode.getExplicandum();
SqlNode validatedNode = super.validate(topNodeToValidate);
- if (parameters.length != dynamicParameterCount) {
- throw newValidationError(topNode,
IgniteResource.INSTANCE.unexpectedParameter(parameters.length,
dynamicParameterCount));
- }
-
- if (explain) {
- SqlExplain explainNode = (SqlExplain) topNode;
- explainNode.setOperand(0, validatedNode);
- return explainNode;
- } else {
- return validatedNode;
- }
- } finally {
- this.dynamicParameterCount = 0;
+ explainNode.setOperand(0, validatedNode);
+ return explainNode;
+ } else {
+ return super.validate(topNode);
}
}
@@ -272,18 +254,10 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
} else if (n instanceof SqlDynamicParam) {
SqlDynamicParam dynamicParam = (SqlDynamicParam) n;
int idx = dynamicParam.getIndex();
- // validateDynamicParam is not called by a validator we must call
it ourselves.
- validateDynamicParam(dynamicParam);
-
- // We must check the number of dynamic parameters unless
- // https://issues.apache.org/jira/browse/IGNITE-18653
- // is resolved.
- if (idx < parameters.length) {
- Object param = parameters[idx];
- if (parameters[idx] instanceof Integer) {
- if ((Integer) param < 0) {
- throw newValidationError(n,
IgniteResource.INSTANCE.correctIntegerLimit(nodeName));
- }
+ Object param = parameters[idx];
+ if (param instanceof Integer) {
+ if ((Integer) param < 0) {
+ throw newValidationError(n,
IgniteResource.INSTANCE.correctIntegerLimit(nodeName));
}
}
}
@@ -567,21 +541,12 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
return Commons.implicitPkEnabled() &&
Commons.IMPLICIT_PK_COL_NAME.equals(alias);
}
- /** {@inheritDoc} */
- @Override
- public void validateDynamicParam(SqlDynamicParam dynamicParam) {
- this.dynamicParameterCount = Integer.max(dynamicParameterCount,
dynamicParam.getIndex() + 1);
- }
-
/** {@inheritDoc} */
@Override
protected void inferUnknownTypes(RelDataType inferredType,
SqlValidatorScope scope, SqlNode node) {
if (node instanceof SqlDynamicParam &&
inferredType.equals(unknownType)) {
SqlDynamicParam dynamicParam = (SqlDynamicParam) node;
- // We explicitly call validateDynamicParam because the validator
does not call it.
- validateDynamicParam(dynamicParam);
-
RelDataType type = inferDynamicParamType(dynamicParam);
setValidatedNodeType(node, type);
} else if (node instanceof SqlCall) {
@@ -633,26 +598,16 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
}
private RelDataType inferDynamicParamType(SqlDynamicParam dynamicParam) {
- // We must check the number of dynamic parameters unless
- // https://issues.apache.org/jira/browse/IGNITE-18653
- // is resolved.
-
RelDataType parameterType;
- if (dynamicParam.getIndex() < parameters.length) {
- Object param = parameters[dynamicParam.getIndex()];
- // IgniteCustomType: first we must check whether dynamic parameter
is a custom data type.
- // If so call createCustomType with appropriate arguments.
- if (param instanceof UUID) {
- parameterType = typeFactory().createCustomType(UuidType.NAME);
- } else if (param != null) {
- parameterType =
typeFactory().toSql(typeFactory().createType(param.getClass()));
- } else {
- parameterType = typeFactory().createSqlType(SqlTypeName.NULL);
- }
+ Object param = parameters[dynamicParam.getIndex()];
+ // IgniteCustomType: first we must check whether dynamic parameter is
a custom data type.
+ // If so call createCustomType with appropriate arguments.
+ if (param instanceof UUID) {
+ parameterType = typeFactory().createCustomType(UuidType.NAME);
+ } else if (param != null) {
+ parameterType =
typeFactory().toSql(typeFactory().createType(param.getClass()));
} else {
- // This query will be rejected since the number of dynamic
parameters
- // is not valid.
parameterType = typeFactory().createSqlType(SqlTypeName.NULL);
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/MultiStepDmlPlan.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/MultiStepDmlPlan.java
index 36775f6627..1331fba1fa 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/MultiStepDmlPlan.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/MultiStepDmlPlan.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.sql.engine.prepare;
import java.util.List;
import org.apache.ignite.internal.sql.api.ColumnMetadataImpl;
import org.apache.ignite.internal.sql.api.ResultSetMetadataImpl;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.sql.ColumnMetadata;
import org.apache.ignite.sql.ColumnType;
import org.apache.ignite.sql.ResultSetMetadata;
@@ -42,8 +43,8 @@ public class MultiStepDmlPlan extends AbstractMultiStepPlan {
}
/** {@inheritDoc} */
- @Override public Type type() {
- return Type.DML;
+ @Override public SqlQueryType type() {
+ return SqlQueryType.DML;
}
/** {@inheritDoc} */
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/MultiStepQueryPlan.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/MultiStepQueryPlan.java
index 8ca13c53f9..0b23418c0a 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/MultiStepQueryPlan.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/MultiStepQueryPlan.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal.sql.engine.prepare;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.sql.ResultSetMetadata;
/**
@@ -34,8 +35,8 @@ public class MultiStepQueryPlan extends AbstractMultiStepPlan
{
}
/** {@inheritDoc} */
- @Override public Type type() {
- return Type.QUERY;
+ @Override public SqlQueryType type() {
+ return SqlQueryType.QUERY;
}
/** {@inheritDoc} */
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java
index 4611036835..55efa978e8 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java
@@ -40,17 +40,18 @@ import org.apache.calcite.runtime.CalciteContextException;
import org.apache.calcite.sql.SqlDdl;
import org.apache.calcite.sql.SqlExplain;
import org.apache.calcite.sql.SqlExplainLevel;
-import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
import org.apache.ignite.internal.logger.IgniteLogger;
import org.apache.ignite.internal.logger.Loggers;
import org.apache.ignite.internal.sql.api.ColumnMetadataImpl;
import org.apache.ignite.internal.sql.api.ResultSetMetadataImpl;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import
org.apache.ignite.internal.sql.engine.prepare.ddl.DdlSqlToCommandConverter;
import org.apache.ignite.internal.sql.engine.rel.IgniteRel;
import org.apache.ignite.internal.sql.engine.schema.SchemaUpdateListener;
import org.apache.ignite.internal.sql.engine.util.BaseQueryContext;
+import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.sql.engine.util.TypeUtils;
import org.apache.ignite.internal.storage.DataStorageManager;
import org.apache.ignite.internal.thread.NamedThreadFactory;
@@ -146,28 +147,21 @@ public class PrepareServiceImpl implements
PrepareService, SchemaUpdateListener
try {
assert single(sqlNode);
- var planningContext = PlanningContext.builder()
+ SqlQueryType queryType = Commons.getQueryType(sqlNode);
+ assert queryType != null : "No query type for query: " + sqlNode;
+
+ PlanningContext planningContext = PlanningContext.builder()
.parentContext(ctx)
.build();
- if (SqlKind.DDL.contains(sqlNode.getKind())) {
- return prepareDdl(sqlNode, planningContext);
- }
-
- switch (sqlNode.getKind()) {
- case SELECT:
- case ORDER_BY:
- case WITH:
- case VALUES:
- case UNION:
- case EXCEPT:
- case INTERSECT:
+ switch (queryType) {
+ case QUERY:
return prepareQuery(sqlNode, planningContext);
- case INSERT:
- case DELETE:
- case UPDATE:
- case MERGE:
+ case DDL:
+ return prepareDdl(sqlNode, planningContext);
+
+ case DML:
return prepareDml(sqlNode, planningContext);
case EXPLAIN:
@@ -227,7 +221,7 @@ public class PrepareServiceImpl implements PrepareService,
SchemaUpdateListener
var key = new CacheKey(ctx.schemaName(), sqlNode.toString(),
distributed, paramTypes);
- var planFut = cache.computeIfAbsent(key, k ->
CompletableFuture.supplyAsync(() -> {
+ CompletableFuture<QueryPlan> planFut = cache.computeIfAbsent(key, k ->
CompletableFuture.supplyAsync(() -> {
IgnitePlanner planner = ctx.planner();
// Validate
@@ -251,7 +245,7 @@ public class PrepareServiceImpl implements PrepareService,
SchemaUpdateListener
private CompletableFuture<QueryPlan> prepareDml(SqlNode sqlNode,
PlanningContext ctx) {
var key = new CacheKey(ctx.schemaName(), sqlNode.toString());
- var planFut = cache.computeIfAbsent(key, k ->
CompletableFuture.supplyAsync(() -> {
+ CompletableFuture<QueryPlan> planFut = cache.computeIfAbsent(key, k ->
CompletableFuture.supplyAsync(() -> {
IgnitePlanner planner = ctx.planner();
// Validate
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/QueryPlan.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/QueryPlan.java
index 142027057e..c26f2d75e6 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/QueryPlan.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/QueryPlan.java
@@ -17,22 +17,19 @@
package org.apache.ignite.internal.sql.engine.prepare;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.sql.ResultSetMetadata;
+import org.jetbrains.annotations.Nullable;
/**
* QueryPlan interface.
* TODO Documentation https://issues.apache.org/jira/browse/IGNITE-15859
*/
public interface QueryPlan {
- /** Query type. */
- enum Type {
- QUERY, FRAGMENT, DML, DDL, EXPLAIN
- }
-
/**
- * Get query type.
+ * Get query type, or {@code null} if this is a fragment.
*/
- Type type();
+ @Nullable SqlQueryType type();
/**
* Get fields metadata.
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlParser.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlParser.java
new file mode 100644
index 0000000000..6d1899cd78
--- /dev/null
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlParser.java
@@ -0,0 +1,162 @@
+/*
+ * 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.engine.sql;
+
+import static org.apache.ignite.internal.util.ExceptionUtils.withCauseAndCode;
+import static org.apache.ignite.lang.ErrorGroup.extractCauseMessage;
+import static org.apache.ignite.lang.ErrorGroups.Sql.QUERY_INVALID_ERR;
+
+import java.io.Reader;
+import org.apache.calcite.config.Lex;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlNodeList;
+import org.apache.calcite.sql.parser.SqlAbstractParserImpl;
+import org.apache.calcite.sql.parser.SqlParseException;
+import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.parser.SqlParserImplFactory;
+import org.apache.calcite.util.SourceStringReader;
+import
org.apache.ignite.internal.generated.query.calcite.sql.IgniteSqlParserImpl;
+import org.apache.ignite.sql.SqlException;
+
+/**
+ * Provides method for parsing SQL statements in SQL dialect of Apache Ignite
3.
+ *
+ * <p>One should use parsing methods defined in this class,
+ * instead of creating {@link SqlParser} that use {@link IgniteSqlParserImpl}
directly.
+ */
+public final class IgniteSqlParser {
+
+ /**
+ * Parser configuration.
+ */
+ public static final SqlParser.Config PARSER_CONFIG = SqlParser.config()
+ .withParserFactory(InternalIgniteSqlParser.FACTORY)
+ .withLex(Lex.ORACLE)
+ .withConformance(IgniteSqlConformance.INSTANCE);
+
+ private IgniteSqlParser() {
+
+ }
+
+ /**
+ * Parses the given SQL string in the specified {@link ParseMode mode},
+ * which determines the result of the parse operation.
+ *
+ * @param sql An SQL string.
+ * @param mode A parse mode.
+ * @return A parse result.
+ *
+ * @see StatementParseResult#MODE
+ * @see ScriptParseResult#MODE
+ */
+ public static <T extends ParseResult> T parse(String sql, ParseMode<T>
mode) {
+ try (SourceStringReader reader = new SourceStringReader(sql)) {
+ return parse(reader, mode);
+ }
+ }
+
+ /**
+ * Parses an SQL string from the given reader in the specified {@link
ParseMode mode},
+ * which determines the result of the parse operation.
+ *
+ * @param reader A read that contains an SQL string.
+ * @param mode A parse mode.
+ * @return A parse result.
+ *
+ * @see StatementParseResult#MODE
+ * @see ScriptParseResult#MODE
+ */
+ public static <T extends ParseResult> T parse(Reader reader, ParseMode<T>
mode) {
+ try {
+ InternalIgniteSqlParser.dynamicParamCount.set(null);
+
+ SqlParser parser = SqlParser.create(reader, PARSER_CONFIG);
+ SqlNodeList nodeList = parser.parseStmtList();
+
+ Integer dynamicParamsCount =
InternalIgniteSqlParser.dynamicParamCount.get();
+ assert dynamicParamsCount != null : "dynamicParamCount has not
been updated";
+
+ return mode.createResult(nodeList.getList(), dynamicParamsCount);
+ } catch (SqlParseException e) {
+ throw withCauseAndCode(
+ SqlException::new,
+ QUERY_INVALID_ERR,
+ "Failed to parse query: " +
extractCauseMessage(e.getMessage()),
+ e);
+ } finally {
+ InternalIgniteSqlParser.dynamicParamCount.set(null);
+ }
+ }
+
+ private static final class InternalIgniteSqlParser extends
IgniteSqlParserImpl {
+
+ /**
+ * A factory that create instances of {@link IgniteSqlParser}.
+ */
+ private static final SqlParserImplFactory FACTORY = new
SqlParserImplFactory() {
+ @Override
+ public SqlAbstractParserImpl getParser(Reader reader) {
+ InternalIgniteSqlParser parser = new
InternalIgniteSqlParser(reader);
+ if (reader instanceof SourceStringReader) {
+ String sql = ((SourceStringReader)
reader).getSourceString();
+ parser.setOriginalSql(sql);
+ }
+ return parser;
+ }
+ };
+
+
+ // We store the number of dynamic parameters in a thread local since
+ // it is not possible to access an instance of IgniteSqlParser created
by a parser factory.
+ static final ThreadLocal<Integer> dynamicParamCount = new
ThreadLocal<>();
+
+ InternalIgniteSqlParser(Reader reader) {
+ super(reader);
+ }
+
+ /** {@inheritDoc} **/
+ @Override
+ public SqlNode parseSqlExpressionEof() throws Exception {
+ try {
+ return super.parseSqlExpressionEof();
+ } finally {
+ dynamicParamCount.set(nDynamicParams);
+ }
+ }
+
+ /** {@inheritDoc} **/
+ @Override
+ public SqlNode parseSqlStmtEof() throws Exception {
+ try {
+ return super.parseSqlStmtEof();
+ } finally {
+ dynamicParamCount.set(nDynamicParams);
+ }
+ }
+
+ /** {@inheritDoc} **/
+ @Override
+ public SqlNodeList parseSqlStmtList() throws Exception {
+ try {
+ return super.parseSqlStmtList();
+ } finally {
+ dynamicParamCount.set(nDynamicParams);
+ }
+ }
+ }
+}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParseMode.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParseMode.java
new file mode 100644
index 0000000000..68db3395f3
--- /dev/null
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParseMode.java
@@ -0,0 +1,48 @@
+/*
+ * 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.engine.sql;
+
+import java.util.List;
+import org.apache.calcite.sql.SqlNode;
+
+/**
+ * Parse mode determines the expected result of parse operation.
+ *
+ * <p>For example, {@link StatementParseResult#MODE statement mode} guarantees
that a parse operation returns a single statement
+ * and when input contains multiple statements, it throws an exception.
+ *
+ * @param <T> A class of parse result.
+ * @see StatementParseResult#MODE
+ * @see ScriptParseResult#MODE
+ */
+public abstract class ParseMode<T extends ParseResult> {
+
+ // Do not allow subclasses outside this package.
+ ParseMode() {
+
+ }
+
+ /**
+ * Constructs an instance of ParseResult from the given list of statements.
+ *
+ * @param list A list of statements.
+ * @param dynamicParamsCount The number of dynamic parameters in the given
input.
+ * @return a result.
+ */
+ abstract T createResult(List<SqlNode> list, int dynamicParamsCount);
+}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryValidator.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParseResult.java
similarity index 50%
rename from
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryValidator.java
rename to
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParseResult.java
index b0ba3cf6a4..b36a984f96 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryValidator.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParseResult.java
@@ -15,19 +15,35 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.sql.engine;
+package org.apache.ignite.internal.sql.engine.sql;
-import org.apache.ignite.internal.sql.engine.exec.QueryValidationException;
-import org.apache.ignite.internal.sql.engine.prepare.QueryPlan;
+import java.util.List;
+import org.apache.calcite.sql.SqlNode;
/**
- * The query validator interface. Allows validating query plan.
- * */
-public interface QueryValidator {
+ * Result of parsing SQL string.
+ */
+public abstract class ParseResult {
+
+ private final int dynamicParamsCount;
+
/**
- * Validate the prepared query plan.
+ * Constructor.
*
- * @throws QueryValidationException in the case of a validation error.
+ * @param dynamicParamsCount the number of dynamic parameters.
*/
- void validatePlan(QueryPlan plan) throws QueryValidationException;
+ ParseResult(int dynamicParamsCount) {
+ if (dynamicParamsCount < 0) {
+ throw new IllegalArgumentException("Number of dynamic parameters
must be positive but got " + dynamicParamsCount);
+ }
+ this.dynamicParamsCount = dynamicParamsCount;
+ }
+
+ /** The number of dynamic parameters in this result. */
+ public int dynamicParamsCount() {
+ return dynamicParamsCount;
+ }
+
+ /** Returns a list of parsed statements. */
+ public abstract List<SqlNode> statements();
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ScriptParseResult.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ScriptParseResult.java
new file mode 100644
index 0000000000..82c77d24fc
--- /dev/null
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ScriptParseResult.java
@@ -0,0 +1,63 @@
+/*
+ * 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.engine.sql;
+
+import java.util.List;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.ignite.internal.tostring.S;
+
+/**
+ * Result of parsing SQL string that multiple statements.
+ */
+public final class ScriptParseResult extends ParseResult {
+
+ /**
+ * Parse operation is expected to return one or multiple statements.
+ */
+ public static final ParseMode<ScriptParseResult> MODE = new ParseMode<>() {
+ @Override
+ ScriptParseResult createResult(List<SqlNode> list, int
dynamicParamsCount) {
+ return new ScriptParseResult(list, dynamicParamsCount);
+ }
+ };
+
+ private final List<SqlNode> statements;
+
+ /**
+ * Constructor.
+ *
+ * @param statements A list of parsed statements.
+ * @param dynamicParamsCount The number of dynamic parameters.
+ */
+ public ScriptParseResult(List<SqlNode> statements, int dynamicParamsCount)
{
+ super(dynamicParamsCount);
+ this.statements = statements;
+ }
+
+ /** Returns a list of parsed statements. */
+ @Override
+ public List<SqlNode> statements() {
+ return statements;
+ }
+
+ /** {@inheritDoc} **/
+ @Override
+ public String toString() {
+ return S.toString(ScriptParseResult.class, this);
+ }
+}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/StatementParseResult.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/StatementParseResult.java
new file mode 100644
index 0000000000..9787a5dec3
--- /dev/null
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/StatementParseResult.java
@@ -0,0 +1,78 @@
+/*
+ * 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.engine.sql;
+
+import static org.apache.ignite.lang.ErrorGroups.Sql.QUERY_INVALID_ERR;
+
+import java.util.List;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlNodeList;
+import org.apache.ignite.internal.tostring.S;
+import org.apache.ignite.sql.SqlException;
+
+/**
+ * Result of parsing SQL string that contains exactly one statement.
+ */
+public final class StatementParseResult extends ParseResult {
+
+ /**
+ * Expected result of a parse operation is a single statement. When there
is more than one statement, parse operation fails with
+ * {@link SqlException}.
+ */
+ public static final ParseMode<StatementParseResult> MODE = new
ParseMode<>() {
+ @Override
+ StatementParseResult createResult(List<SqlNode> list, int
dynamicParamsCount) {
+ if (list.size() > 1) {
+ throw new SqlException(QUERY_INVALID_ERR, "Multiple statements
are not allowed.");
+ }
+
+ return new StatementParseResult(list.get(0), dynamicParamsCount);
+ }
+ };
+
+ private final List<SqlNode> list;
+
+ /**
+ * Constructor.
+ *
+ * @param sqlNode A parsed statement.
+ * @param dynamicParamsCount The number of dynamic parameters.
+ */
+ public StatementParseResult(SqlNode sqlNode, int dynamicParamsCount) {
+ super(dynamicParamsCount);
+ assert !(sqlNode instanceof SqlNodeList) : "Can not create a statement
result from a node list: " + sqlNode;
+ this.list = List.of(sqlNode);
+ }
+
+ /** Returns a parsed statement. */
+ public SqlNode statement() {
+ return list.get(0);
+ }
+
+ /** {@inheritDoc} **/
+ @Override
+ public List<SqlNode> statements() {
+ return list;
+ }
+
+ /** {@inheritDoc} **/
+ @Override
+ public String toString() {
+ return S.toString(StatementParseResult.class, this, "statement",
statement());
+ }
+}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Commons.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Commons.java
index acf22f06b7..0ad36b3b67 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Commons.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/Commons.java
@@ -19,15 +19,11 @@ package org.apache.ignite.internal.sql.engine.util;
import static
org.apache.ignite.internal.sql.engine.util.BaseQueryContext.CLUSTER;
import static org.apache.ignite.internal.util.CollectionUtils.nullOrEmpty;
-import static org.apache.ignite.internal.util.ExceptionUtils.withCauseAndCode;
-import static org.apache.ignite.lang.ErrorGroup.extractCauseMessage;
import static
org.apache.ignite.lang.ErrorGroups.Sql.EXPRESSION_COMPILATION_ERR;
-import static org.apache.ignite.lang.ErrorGroups.Sql.QUERY_INVALID_ERR;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
-import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -53,7 +49,6 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.calcite.DataContexts;
import org.apache.calcite.config.CalciteSystemProperty;
-import org.apache.calcite.config.Lex;
import org.apache.calcite.config.NullCollation;
import org.apache.calcite.linq4j.Ord;
import org.apache.calcite.plan.Context;
@@ -67,22 +62,19 @@ import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.hint.HintStrategyTable;
import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.sql.SqlNodeList;
-import org.apache.calcite.sql.parser.SqlParseException;
-import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.validate.SqlValidator;
import org.apache.calcite.sql2rel.SqlToRelConverter;
import org.apache.calcite.tools.FrameworkConfig;
import org.apache.calcite.tools.Frameworks;
import org.apache.calcite.util.ImmutableBitSet;
import org.apache.calcite.util.ImmutableIntList;
-import org.apache.calcite.util.SourceStringReader;
import org.apache.calcite.util.Util;
import org.apache.calcite.util.mapping.Mapping;
import org.apache.calcite.util.mapping.MappingType;
import org.apache.calcite.util.mapping.Mappings;
import org.apache.calcite.util.mapping.Mappings.TargetMapping;
-import
org.apache.ignite.internal.generated.query.calcite.sql.IgniteSqlParserImpl;
import org.apache.ignite.internal.logger.IgniteLogger;
import org.apache.ignite.internal.schema.BitmaskNativeType;
import org.apache.ignite.internal.schema.DecimalNativeType;
@@ -90,6 +82,7 @@ import org.apache.ignite.internal.schema.NativeType;
import org.apache.ignite.internal.schema.NumberNativeType;
import org.apache.ignite.internal.schema.TemporalNativeType;
import org.apache.ignite.internal.schema.VarlenNativeType;
+import org.apache.ignite.internal.sql.engine.SqlQueryType;
import org.apache.ignite.internal.sql.engine.exec.RowHandler;
import org.apache.ignite.internal.sql.engine.exec.exp.ExpressionFactoryImpl;
import org.apache.ignite.internal.sql.engine.exec.exp.RexExecutorImpl;
@@ -98,6 +91,7 @@ import
org.apache.ignite.internal.sql.engine.prepare.IgniteConvertletTable;
import org.apache.ignite.internal.sql.engine.prepare.IgniteTypeCoercion;
import org.apache.ignite.internal.sql.engine.prepare.PlanningContext;
import org.apache.ignite.internal.sql.engine.sql.IgniteSqlConformance;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlParser;
import org.apache.ignite.internal.sql.engine.sql.fun.IgniteSqlOperatorTable;
import org.apache.ignite.internal.sql.engine.trait.DistributionTraitDef;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
@@ -129,11 +123,6 @@ public final class Commons {
*/
public static final int SORTED_IDX_PART_PREFETCH_SIZE = 100;
- public static final SqlParser.Config PARSER_CONFIG = SqlParser.config()
- .withParserFactory(IgniteSqlParserImpl.FACTORY)
- .withLex(Lex.ORACLE)
- .withConformance(IgniteSqlConformance.INSTANCE);
-
@SuppressWarnings("rawtypes")
public static final List<RelTraitDef> DISTRIBUTED_TRAITS_SET = List.of(
ConventionTraitDef.INSTANCE,
@@ -159,7 +148,7 @@ public final class Commons {
)
)
.convertletTable(IgniteConvertletTable.INSTANCE)
- .parserConfig(PARSER_CONFIG)
+ .parserConfig(IgniteSqlParser.PARSER_CONFIG)
.sqlValidatorConfig(SqlValidator.Config.DEFAULT
.withIdentifierExpansion(true)
.withDefaultNullCollation(NullCollation.HIGH)
@@ -738,39 +727,6 @@ public final class Commons {
};
}
- /**
- * Parses a SQL statement.
- *
- * @param qry Query string.
- * @param parserCfg Parser config.
- * @return Parsed query.
- */
- public static SqlNodeList parse(String qry, SqlParser.Config parserCfg) {
- try {
- return parse(new SourceStringReader(qry), parserCfg);
- } catch (SqlParseException e) {
- throw withCauseAndCode(
- SqlException::new,
- QUERY_INVALID_ERR,
- "Failed to parse query: " +
extractCauseMessage(e.getMessage()),
- e);
- }
- }
-
- /**
- * Parses a SQL statement.
- *
- * @param reader Source string reader.
- * @param parserCfg Parser config.
- * @return Parsed query.
- * @throws org.apache.calcite.sql.parser.SqlParseException on parse error.
- */
- public static SqlNodeList parse(Reader reader, SqlParser.Config parserCfg)
throws SqlParseException {
- SqlParser parser = SqlParser.create(reader, parserCfg);
-
- return parser.parseStmtList();
- }
-
public static RelOptCluster cluster() {
return CLUSTER;
}
@@ -805,4 +761,43 @@ public final class Commons {
return ruleDescription.substring(0, pos);
}
+
+ /**
+ * Returns a {@link SqlQueryType} for the given {@link SqlNode}.
+ *
+ * <p>If the given node is neither {@code QUERY}, nor {@code DDL}, nor
{@code DML}, this method returns {@code null}.
+ *
+ * @param sqlNode An SQL node.
+ * @return A query type.
+ */
+ @Nullable
+ public static SqlQueryType getQueryType(SqlNode sqlNode) {
+ SqlKind sqlKind = sqlNode.getKind();
+ if (SqlKind.DDL.contains(sqlKind)) {
+ return SqlQueryType.DDL;
+ }
+
+ switch (sqlKind) {
+ case SELECT:
+ case ORDER_BY:
+ case WITH:
+ case VALUES:
+ case UNION:
+ case EXCEPT:
+ case INTERSECT:
+ return SqlQueryType.QUERY;
+
+ case INSERT:
+ case DELETE:
+ case UPDATE:
+ case MERGE:
+ return SqlQueryType.DML;
+
+ case EXPLAIN:
+ return SqlQueryType.EXPLAIN;
+
+ default:
+ return null;
+ }
+ }
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteResource.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteResource.java
index b9265a20ac..18bbbb14c7 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteResource.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteResource.java
@@ -38,9 +38,6 @@ public interface IgniteResource {
@Resources.BaseMessage("Illegal value of {0}. The value must be positive
and less than Integer.MAX_VALUE (" + Integer.MAX_VALUE + ").")
Resources.ExInst<SqlValidatorException> correctIntegerLimit(String a0);
- @Resources.BaseMessage("Unexpected number of query parameters. Provided
{0} but there is only {1} dynamic parameter(s).")
- Resources.ExInst<SqlValidatorException> unexpectedParameter(int provided,
int expected);
-
@Resources.BaseMessage("Invalid decimal literal")
Resources.ExInst<SqlValidatorException> decimalLiteralInvalid();
}
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/benchmarks/TpchParseBenchmark.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/benchmarks/TpchParseBenchmark.java
index ac099953f2..7392ed9074 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/benchmarks/TpchParseBenchmark.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/benchmarks/TpchParseBenchmark.java
@@ -18,7 +18,8 @@
package org.apache.ignite.internal.sql.engine.benchmarks;
import java.util.concurrent.TimeUnit;
-import org.apache.ignite.internal.sql.engine.util.Commons;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlParser;
+import org.apache.ignite.internal.sql.engine.sql.StatementParseResult;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
@@ -68,7 +69,8 @@ public class TpchParseBenchmark {
*/
@Benchmark
public void parseQuery(Blackhole bh) {
- bh.consume(Commons.parse(queryString, Commons.PARSER_CONFIG));
+ StatementParseResult parseResult = IgniteSqlParser.parse(queryString,
StatementParseResult.MODE);
+ bh.consume(parseResult.statement());
}
/**
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/benchmarks/TpchPrepareBenchmark.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/benchmarks/TpchPrepareBenchmark.java
index c22cb1726f..f988ad024a 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/benchmarks/TpchPrepareBenchmark.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/benchmarks/TpchPrepareBenchmark.java
@@ -22,7 +22,8 @@ import org.apache.calcite.sql.SqlNode;
import org.apache.ignite.internal.sql.engine.framework.TestBuilders;
import org.apache.ignite.internal.sql.engine.framework.TestCluster;
import org.apache.ignite.internal.sql.engine.framework.TestNode;
-import org.apache.ignite.internal.sql.engine.util.Commons;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlParser;
+import org.apache.ignite.internal.sql.engine.sql.StatementParseResult;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
@@ -77,7 +78,9 @@ public class TpchPrepareBenchmark {
testCluster.start();
gatewayNode = testCluster.node("N1");
- queryAst = Commons.parse(TpchQueries.getQuery(queryId),
Commons.PARSER_CONFIG).get(0);
+ String query = TpchQueries.getQuery(queryId);
+ StatementParseResult parseResult = IgniteSqlParser.parse(query,
StatementParseResult.MODE);
+ queryAst = parseResult.statement();
}
/** Stops the cluster. */
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImplTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImplTest.java
index 5f944a52ff..3939f6ed36 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImplTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImplTest.java
@@ -22,8 +22,6 @@ import static
org.apache.ignite.internal.testframework.IgniteTestUtils.await;
import static
org.apache.ignite.internal.testframework.IgniteTestUtils.waitForCondition;
import static org.apache.ignite.lang.ErrorGroups.Sql.OPERATION_INTERRUPTED_ERR;
import static org.apache.ignite.lang.IgniteStringFormatter.format;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -48,7 +46,6 @@ import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import org.apache.calcite.jdbc.CalciteSchema;
import org.apache.calcite.schema.SchemaPlus;
-import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.tools.Frameworks;
import org.apache.ignite.internal.logger.IgniteLogger;
import org.apache.ignite.internal.logger.Loggers;
@@ -81,10 +78,11 @@ import
org.apache.ignite.internal.sql.engine.schema.DefaultValueStrategy;
import org.apache.ignite.internal.sql.engine.schema.IgniteSchema;
import org.apache.ignite.internal.sql.engine.schema.SqlSchemaManager;
import org.apache.ignite.internal.sql.engine.schema.TableDescriptorImpl;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlParser;
+import org.apache.ignite.internal.sql.engine.sql.StatementParseResult;
import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution;
import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions;
import org.apache.ignite.internal.sql.engine.util.BaseQueryContext;
-import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.sql.engine.util.HashFunctionFactory;
import org.apache.ignite.internal.sql.engine.util.HashFunctionFactoryImpl;
import org.apache.ignite.internal.testframework.IgniteTestUtils.RunnableX;
@@ -452,11 +450,11 @@ public class ExecutionServiceImplTest {
}
private QueryPlan prepare(String query, BaseQueryContext ctx) {
- SqlNodeList nodes = Commons.parse(query,
FRAMEWORK_CONFIG.getParserConfig());
+ StatementParseResult parseResult = IgniteSqlParser.parse(query,
StatementParseResult.MODE);
- assertThat(nodes, hasSize(1));
+ assertEquals(ctx.parameters().length,
parseResult.dynamicParamsCount(), "Invalid number of dynamic parameters");
- return await(prepareService.prepareAsync(nodes.get(0), ctx));
+ return await(prepareService.prepareAsync(parseResult.statement(),
ctx));
}
static class TestCluster {
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestNode.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestNode.java
index b6230a4d26..9678100c33 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestNode.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/TestNode.java
@@ -21,8 +21,8 @@ import static
org.apache.ignite.internal.sql.engine.util.Commons.FRAMEWORK_CONFI
import static org.apache.ignite.internal.testframework.IgniteTestUtils.await;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import java.util.ArrayList;
@@ -59,8 +59,9 @@ import
org.apache.ignite.internal.sql.engine.prepare.QueryPlan;
import
org.apache.ignite.internal.sql.engine.prepare.ddl.DdlSqlToCommandConverter;
import org.apache.ignite.internal.sql.engine.rel.IgniteTableScan;
import org.apache.ignite.internal.sql.engine.schema.SqlSchemaManager;
+import org.apache.ignite.internal.sql.engine.sql.IgniteSqlParser;
+import org.apache.ignite.internal.sql.engine.sql.StatementParseResult;
import org.apache.ignite.internal.sql.engine.util.BaseQueryContext;
-import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.sql.engine.util.HashFunctionFactoryImpl;
import org.apache.ignite.internal.util.IgniteSpinBusyLock;
import org.apache.ignite.internal.util.IgniteUtils;
@@ -177,11 +178,12 @@ public class TestNode implements LifecycleAware {
* @return A plan to execute.
*/
public QueryPlan prepare(String query) {
- SqlNodeList nodes = Commons.parse(query,
FRAMEWORK_CONFIG.getParserConfig());
+ StatementParseResult parseResult = IgniteSqlParser.parse(query,
StatementParseResult.MODE);
+ BaseQueryContext ctx = createContext();
- assertThat(nodes, hasSize(1));
+ assertEquals(ctx.parameters().length,
parseResult.dynamicParamsCount(), "Invalid number of dynamic parameters");
- return await(prepareService.prepareAsync(nodes.get(0),
createContext()));
+ return await(prepareService.prepareAsync(parseResult.statement(),
ctx));
}
/**
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/AbstractDdlParserTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/AbstractDdlParserTest.java
index 1570d46e39..9135cc01b3 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/AbstractDdlParserTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/AbstractDdlParserTest.java
@@ -19,9 +19,6 @@ package org.apache.ignite.internal.sql.engine.sql;
import java.util.function.Predicate;
import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.parser.SqlParseException;
-import org.apache.calcite.sql.parser.SqlParser;
-import
org.apache.ignite.internal.generated.query.calcite.sql.IgniteSqlParserImpl;
import org.hamcrest.CustomMatcher;
import org.hamcrest.Matcher;
@@ -35,10 +32,9 @@ public abstract class AbstractDdlParserTest {
* @param stmt Statement to parse.
* @return An AST.
*/
- protected SqlNode parse(String stmt) throws SqlParseException {
- SqlParser parser = SqlParser.create(stmt,
SqlParser.config().withParserFactory(IgniteSqlParserImpl.FACTORY));
-
- return parser.parseStmt();
+ protected SqlNode parse(String stmt) {
+ StatementParseResult parseResult = IgniteSqlParser.parse(stmt,
StatementParseResult.MODE);
+ return parseResult.statement();
}
/**
@@ -50,7 +46,7 @@ public abstract class AbstractDdlParserTest {
* @return {@code true} in case the object if instance of the given class
and matches the predicat.
*/
protected <T> Matcher<T> ofTypeMatching(String desc, Class<T> cls,
Predicate<T> pred) {
- return new CustomMatcher<T>(desc) {
+ return new CustomMatcher<>(desc) {
/** {@inheritDoc} */
@Override
public boolean matches(Object item) {
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/DistributionZoneSqlDdlParserTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/DistributionZoneSqlDdlParserTest.java
index 6362f751e6..ffa0fa2a2b 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/DistributionZoneSqlDdlParserTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/DistributionZoneSqlDdlParserTest.java
@@ -35,8 +35,8 @@ import java.util.Objects;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlWriter;
-import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.pretty.SqlPrettyWriter;
+import org.apache.ignite.sql.SqlException;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
@@ -53,7 +53,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
* Parse simple CREATE ZONE statement.
*/
@Test
- public void createZoneNoOptions() throws SqlParseException {
+ public void createZoneNoOptions() {
// Simple name.
IgniteSqlCreateZone createZone = parseCreateZone("create zone
test_zone");
@@ -77,7 +77,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
* Parse CREATE ZONE IF NOT EXISTS statement.
*/
@Test
- public void createZoneIfNotExists() throws SqlParseException {
+ public void createZoneIfNotExists() {
IgniteSqlCreateZone createZone = parseCreateZone("create zone if not
exists test_zone");
assertTrue(createZone.ifNotExists());
@@ -88,7 +88,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
* Parse CREATE ZONE WITH ... statement.
*/
@Test
- public void createZoneWithOptions() throws SqlParseException {
+ public void createZoneWithOptions() {
IgniteSqlCreateZone createZone = parseCreateZone(
"create zone test_zone with "
+ "replicas=2, "
@@ -126,7 +126,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
@Test
public void createZoneWithInvalidOptions() {
// Unknown option.
- assertThrows(SqlParseException.class, () -> parseCreateZone("create
zone test_zone with foo='bar'"));
+ assertThrows(SqlException.class, () -> parseCreateZone("create zone
test_zone with foo='bar'"));
// Invalid option type.
String query = "create zone test_zone with %s=%s";
@@ -144,7 +144,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
* Parsing DROP ZONE statement.
*/
@Test
- public void dropZone() throws SqlParseException {
+ public void dropZone() {
// Simple name.
SqlNode node = parse("drop zone test_zone");
@@ -165,7 +165,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
* Parsing DROP ZONE IF EXISTS statement.
*/
@Test
- public void dropZoneIfExists() throws SqlParseException {
+ public void dropZoneIfExists() {
IgniteSqlDropZone dropZone = (IgniteSqlDropZone) parse("drop zone if
exists test_zone");
assertTrue(dropZone.ifExists());
@@ -177,7 +177,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
* Parsing ALTER ZONE RENAME TO statement.
*/
@Test
- public void alterZoneRenameTo() throws SqlParseException {
+ public void alterZoneRenameTo() {
IgniteSqlAlterZoneRenameTo alterZone = parseAlterZoneRenameTo("alter
zone a.test_zone rename to zone1");
assertFalse(alterZone.ifExists());
@@ -189,7 +189,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
* Parsing ALTER ZONE RENAME TO statement.
*/
@Test
- public void alterZoneIfExistsRenameTo() throws SqlParseException {
+ public void alterZoneIfExistsRenameTo() {
IgniteSqlAlterZoneRenameTo alterZone = parseAlterZoneRenameTo("alter
zone if exists a.test_zone rename to zone1");
assertTrue(alterZone.ifExists());
@@ -202,14 +202,14 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
*/
@Test
public void alterZoneRenameToWithCompoundIdIsIllegal() {
- assertThrows(SqlParseException.class, () -> parse("alter zone
a.test_zone rename to b.zone1"));
+ assertThrows(SqlException.class, () -> parse("alter zone a.test_zone
rename to b.zone1"));
}
/**
* Parsing ALTER ZONE SET statement.
*/
@Test
- public void alterZoneSet() throws SqlParseException {
+ public void alterZoneSet() {
IgniteSqlAlterZoneSet alterZoneSet = parseAlterZoneSet("alter zone
a.test_zone set replicas=2");
assertFalse(alterZoneSet.ifExists());
@@ -221,7 +221,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
* Parsing ALTER ZONE IF EXISTS SET statement.
*/
@Test
- public void alterZoneIfExistsSet() throws SqlParseException {
+ public void alterZoneIfExistsSet() {
IgniteSqlAlterZoneSet alterZoneSet = parseAlterZoneSet("alter zone if
exists a.test_zone set replicas=2");
assertTrue(alterZoneSet.ifExists());
@@ -233,7 +233,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
* Parsing ALTER ZONE SET statement.
*/
@Test
- public void alterZoneSetOptions() throws SqlParseException {
+ public void alterZoneSetOptions() {
IgniteSqlAlterZoneSet alterZoneSet = parseAlterZoneSet(
"alter zone a.test_zone set "
+ "replicas=2, "
@@ -267,7 +267,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
*/
@Test
public void alterZoneSetNoOptionsIsIllegal() {
- assertThrows(SqlParseException.class, () -> parse("alter zone
test_zone set"));
+ assertThrows(SqlException.class, () -> parse("alter zone test_zone
set"));
}
/**
@@ -279,7 +279,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
// invalid option
- assertThrows(SqlParseException.class, () -> parse(String.format(query,
"foo", "'bar'")));
+ assertThrows(SqlException.class, () -> parse(String.format(query,
"foo", "'bar'")));
// invalid option values
@@ -303,7 +303,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
* @param stmt Create zone query.
* @return {@link org.apache.calcite.sql.SqlCreate SqlCreate} node.
*/
- private IgniteSqlCreateZone parseCreateZone(String stmt) throws
SqlParseException {
+ private IgniteSqlCreateZone parseCreateZone(String stmt) {
SqlNode node = parse(stmt);
return assertInstanceOf(IgniteSqlCreateZone.class, node);
@@ -312,7 +312,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
/**
* Parse ALTER ZONE SET statement.
*/
- private IgniteSqlAlterZoneSet parseAlterZoneSet(String stmt) throws
SqlParseException {
+ private IgniteSqlAlterZoneSet parseAlterZoneSet(String stmt) {
SqlNode node = parse(stmt);
return assertInstanceOf(IgniteSqlAlterZoneSet.class, node);
@@ -321,7 +321,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
/**
* Parse ALTER ZONE RENAME TO statement.
*/
- private IgniteSqlAlterZoneRenameTo parseAlterZoneRenameTo(String stmt)
throws SqlParseException {
+ private IgniteSqlAlterZoneRenameTo parseAlterZoneRenameTo(String stmt) {
SqlNode node = parse(stmt);
return assertInstanceOf(IgniteSqlAlterZoneRenameTo.class, node);
@@ -338,7 +338,7 @@ public class DistributionZoneSqlDdlParserTest extends
AbstractDdlParserTest {
}
private void assertSqlParseError(String stmt, String name) {
- assertThrows(SqlParseException.class, () -> parse(stmt), name);
+ assertThrows(SqlException.class, () -> parse(stmt), name);
}
private void assertThatZoneOptionPresent(List<SqlNode> optionList,
IgniteSqlZoneOptionEnum name, Object expVal) {
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDecimalLiteralTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDecimalLiteralTest.java
index 1fda6fbab9..c5eb42b08a 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDecimalLiteralTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDecimalLiteralTest.java
@@ -28,7 +28,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.math.BigDecimal;
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.SqlWriter;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.pretty.SqlPrettyWriter;
@@ -36,7 +35,6 @@ import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.Litmus;
import org.apache.ignite.internal.sql.engine.planner.AbstractPlannerTest;
import org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
-import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.sql.SqlException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -150,12 +148,13 @@ public class IgniteSqlDecimalLiteralTest extends
AbstractPlannerTest {
*/
@Test
public void testDecimalAsAlias() {
- SqlNodeList nodeList = parseQuery("SELECT DECIMAL \"10\"");
+ SqlNode node = parseQuery("SELECT DECIMAL \"10\"");
- assertEquals("SELECT `DECIMAL` AS `10`", nodeList.get(0).toString());
+ assertEquals("SELECT `DECIMAL` AS `10`", node.toString());
}
- private static SqlNodeList parseQuery(String qry) {
- return Commons.parse(qry, Commons.PARSER_CONFIG);
+ private static SqlNode parseQuery(String qry) {
+ StatementParseResult parseResult = IgniteSqlParser.parse(qry,
StatementParseResult.MODE);
+ return parseResult.statement();
}
}
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlParserTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlParserTest.java
new file mode 100644
index 0000000000..af5d00810c
--- /dev/null
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlParserTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.engine.sql;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.List;
+import org.apache.ignite.sql.SqlException;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for sql parser.
+ */
+public class IgniteSqlParserTest {
+
+ @Test
+ public void testStatementMode() {
+ StatementParseResult result = IgniteSqlParser.parse("SELECT 1 + ?",
StatementParseResult.MODE);
+
+ assertEquals(1, result.dynamicParamsCount());
+ assertNotNull(result.statement());
+ assertEquals(List.of(result.statement()), result.statements());
+ }
+
+ @Test
+ public void testScriptMode() {
+ ScriptParseResult result = IgniteSqlParser.parse("SELECT 1 + ?; SELECT
1; SELECT 2 + ?", ScriptParseResult.MODE);
+
+ assertEquals(2, result.dynamicParamsCount());
+ assertEquals(3, result.statements().size());
+ }
+
+ /**
+ * {@link StatementParseResult#MODE} does not allow input that contains
multiple statements.
+ */
+ @Test
+ public void testStatementModeRejectMultipleStatements() {
+ SqlException t = assertThrows(SqlException.class,
+ () -> IgniteSqlParser.parse("SELECT 1; SELECT 2",
StatementParseResult.MODE));
+ assertThat(t.getMessage(), containsString("Multiple statements are not
allowed"));
+
+ }
+}
diff --git
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
index fcfc62c586..bcfbfc61ea 100644
---
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
+++
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/SqlDdlParserTest.java
@@ -40,8 +40,8 @@ import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.ddl.SqlColumnDeclaration;
import org.apache.calcite.sql.ddl.SqlKeyConstraint;
-import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.pretty.SqlPrettyWriter;
+import org.apache.ignite.sql.SqlException;
import org.hamcrest.CustomMatcher;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;
@@ -54,7 +54,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest {
* Very simple case where only table name and a few columns are presented.
*/
@Test
- public void createTableSimpleCase() throws SqlParseException {
+ public void createTableSimpleCase() {
String query = "create table my_table(id int, val varchar)";
SqlNode node = parse(query);
@@ -73,7 +73,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest {
* Parsing of CREATE TABLE with function identifier as a default
expression.
*/
@Test
- public void createTableAutogenFuncDefault() throws SqlParseException {
+ public void createTableAutogenFuncDefault() {
String query = "create table my_table(id varchar default
gen_random_uuid primary key, val varchar)";
SqlNode node = parse(query);
@@ -102,7 +102,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
* Parsing of CREATE TABLE statement with quoted identifiers.
*/
@Test
- public void createTableQuotedIdentifiers() throws SqlParseException {
+ public void createTableQuotedIdentifiers() {
String query = "create table \"My_Table\"(\"Id\" int, \"Val\"
varchar)";
SqlNode node = parse(query);
@@ -121,7 +121,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
* Parsing of CREATE TABLE statement with IF NOT EXISTS.
*/
@Test
- public void createTableIfNotExists() throws SqlParseException {
+ public void createTableIfNotExists() {
String query = "create table if not exists my_table(id int, val
varchar)";
SqlNode node = parse(query);
@@ -140,7 +140,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
* Parsing of CREATE TABLE with specified PK constraint where constraint
is a shortcut within a column definition.
*/
@Test
- public void createTableWithPkCase1() throws SqlParseException {
+ public void createTableWithPkCase1() {
String query = "create table my_table(id int primary key, val
varchar)";
SqlNode node = parse(query);
@@ -163,7 +163,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
* Parsing of CREATE TABLE with specified PK constraint where constraint
is set explicitly and has no name.
*/
@Test
- public void createTableWithPkCase2() throws SqlParseException {
+ public void createTableWithPkCase2() {
String query = "create table my_table(id int, val varchar, primary
key(id))";
SqlNode node = parse(query);
@@ -186,7 +186,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
* Parsing of CREATE TABLE with specified PK constraint where constraint
is set explicitly and has a name.
*/
@Test
- public void createTableWithPkCase3() throws SqlParseException {
+ public void createTableWithPkCase3() {
String query = "create table my_table(id int, val varchar, constraint
pk_key primary key(id))";
SqlNode node = parse(query);
@@ -209,7 +209,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
* Parsing of CREATE TABLE with specified PK constraint where constraint
consists of several columns.
*/
@Test
- public void createTableWithPkCase4() throws SqlParseException {
+ public void createTableWithPkCase4() {
String query = "create table my_table(id1 int, id2 int, val varchar,
primary key(id1, id2))";
SqlNode node = parse(query);
@@ -234,7 +234,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
* Parsing of CREATE TABLE with specified colocation columns.
*/
@Test
- public void createTableWithColocationBy() throws SqlParseException {
+ public void createTableWithColocationBy() {
IgniteSqlCreateTable createTable;
createTable = parseCreateTable(
@@ -287,7 +287,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void createTableWithEngine() throws SqlParseException {
+ public void createTableWithEngine() {
SqlNode node = parse("create table my_table(id int, val varchar)
engine test_engine_name");
assertThat(node, instanceOf(IgniteSqlCreateTable.class));
@@ -299,7 +299,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void createTableWithoutEngine() throws SqlParseException {
+ public void createTableWithoutEngine() {
SqlNode node = parse("create table my_table(id int, val varchar)");
assertThat(node, instanceOf(IgniteSqlCreateTable.class));
@@ -311,7 +311,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void createTableWithOptions() throws SqlParseException {
+ public void createTableWithOptions() {
String query = "create table my_table(id int) with"
+ " replicas=2,"
+ " partitions=3,"
@@ -335,7 +335,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void createIndexSimpleCase() throws SqlParseException {
+ public void createIndexSimpleCase() {
var query = "create index my_index on my_table (col)";
SqlNode node = parse(query);
@@ -353,7 +353,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void createIndexImplicitTypeExplicitDirection() throws
SqlParseException {
+ public void createIndexImplicitTypeExplicitDirection() {
var query = "create index my_index on my_table (col1 asc, col2 desc)";
SqlNode node = parse(query);
@@ -377,7 +377,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void createIndexExplicitTypeMixedDirection() throws
SqlParseException {
+ public void createIndexExplicitTypeMixedDirection() {
var query = "create index my_index on my_table using tree (col1, col2
asc, col3 desc)";
SqlNode node = parse(query);
@@ -403,7 +403,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void createHashIndex() throws SqlParseException {
+ public void createHashIndex() {
var query = "create index my_index on my_table using hash (col)";
SqlNode node = parse(query);
@@ -424,12 +424,12 @@ public class SqlDdlParserTest extends
AbstractDdlParserTest {
public void sortDirectionMustNotBeSpecifiedForHashIndex() {
var query = "create index my_index on my_table using hash (col1, col2
asc)";
- var ex = assertThrows(SqlParseException.class, () -> parse(query));
+ var ex = assertThrows(SqlException.class, () -> parse(query));
assertThat(ex.getMessage(), containsString("Encountered \" \"ASC\""));
}
@Test
- public void createIndexIfNotExists() throws SqlParseException {
+ public void createIndexIfNotExists() {
var query = "create index if not exists my_index on my_table (col)";
SqlNode node = parse(query);
@@ -444,7 +444,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void createIndexTableInParticularSchema() throws SqlParseException {
+ public void createIndexTableInParticularSchema() {
var query = "create index my_index on my_schema.my_table (col)";
SqlNode node = parse(query);
@@ -458,7 +458,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void createIndexExplicitNullDirection() throws SqlParseException {
+ public void createIndexExplicitNullDirection() {
var query = "create index my_index on my_table (col1 nulls first, col2
nulls last, col3 desc nulls first)";
SqlNode node = parse(query);
@@ -494,7 +494,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void dropIndexSimpleCase() throws SqlParseException {
+ public void dropIndexSimpleCase() {
var query = "drop index my_index";
SqlNode node = parse(query);
@@ -508,7 +508,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void dropIndexSchemaSpecified() throws SqlParseException {
+ public void dropIndexSchemaSpecified() {
var query = "drop index my_schema.my_index";
SqlNode node = parse(query);
@@ -522,7 +522,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
}
@Test
- public void dropIndexIfExists() throws SqlParseException {
+ public void dropIndexIfExists() {
var query = "drop index if exists my_index";
SqlNode node = parse(query);
@@ -535,7 +535,7 @@ public class SqlDdlParserTest extends AbstractDdlParserTest
{
assertThat(dropIndex.indexName().names, is(List.of("MY_INDEX")));
}
- private IgniteSqlCreateTable parseCreateTable(String stmt) throws
SqlParseException {
+ private IgniteSqlCreateTable parseCreateTable(String stmt) {
SqlNode node = parse(stmt);
assertThat(node, instanceOf(IgniteSqlCreateTable.class));