This is an automated email from the ASF dual-hosted git repository.
ppa 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 f4c33ff66f IGNITE-14865 Sql. Public SQL API should only throw public
exceptions (#2345)
f4c33ff66f is described below
commit f4c33ff66fb78897534027e210cf37ff8d357159
Author: Pavel Pereslegin <[email protected]>
AuthorDate: Wed Aug 9 14:12:41 2023 +0300
IGNITE-14865 Sql. Public SQL API should only throw public exceptions (#2345)
---
.../org/apache/ignite/sql/SqlBatchException.java | 6 +-
.../client/handler/JdbcQueryEventHandlerImpl.java | 5 +-
.../ignite/internal/sql/AbstractSession.java | 10 +-
.../dotnet/Apache.Ignite.Tests/Sql/SqlTests.cs | 8 +-
.../dotnet/Apache.Ignite/Internal/Sql/Sql.cs | 13 --
.../ignite/internal/sql/api/ItCommonApiTest.java | 7 +-
.../internal/sql/api/ItSqlAsynchronousApiTest.java | 157 +++++++++++++--------
.../internal/sql/api/ItSqlSynchronousApiTest.java | 101 +++++++------
.../internal/sql/engine/ItDataTypesTest.java | 5 +-
.../ignite/internal/sql/engine/ItDmlTest.java | 9 +-
.../sql/engine/ItDynamicParameterTest.java | 7 +-
.../internal/sql/engine/ItLimitOffsetTest.java | 41 +++---
modules/sql-engine/build.gradle | 2 +
.../ignite/internal/sql/api/SessionImpl.java | 67 ++++++---
.../internal/sql/engine/AsyncSqlCursorImpl.java | 17 +--
.../sql/engine/exec/ExchangeServiceImpl.java | 42 ++----
.../sql/engine/exec/exp/ExpressionFactoryImpl.java | 19 ++-
.../internal/sql/engine/exec/rel/RootNode.java | 14 +-
.../sql/engine/prepare/IgniteSqlValidator.java | 2 -
.../sql/engine/prepare/PrepareServiceImpl.java | 33 ++---
.../engine/util/SqlExceptionMapperProvider.java | 63 +++++++++
.../internal/sql/engine/util/SqlTestUtils.java | 22 +++
22 files changed, 392 insertions(+), 258 deletions(-)
diff --git
a/modules/api/src/main/java/org/apache/ignite/sql/SqlBatchException.java
b/modules/api/src/main/java/org/apache/ignite/sql/SqlBatchException.java
index 0cf0194065..3e5476eb6a 100644
--- a/modules/api/src/main/java/org/apache/ignite/sql/SqlBatchException.java
+++ b/modules/api/src/main/java/org/apache/ignite/sql/SqlBatchException.java
@@ -38,11 +38,13 @@ public class SqlBatchException extends SqlException {
/**
* Creates a grid exception with the given throwable as a cause and source
of error message.
*
+ * @param traceId Unique identifier of the exception.
+ * @param code Full error code.
* @param updCntrs Array that describes the outcome of a batch execution.
* @param cause Non-null throwable cause.
*/
- public SqlBatchException(int code, long[] updCntrs, Throwable cause) {
- super(code, cause.getMessage(), cause);
+ public SqlBatchException(UUID traceId, int code, long[] updCntrs,
Throwable cause) {
+ super(traceId, code, cause.getMessage(), cause);
this.updCntrs = updCntrs != null ? updCntrs : LONG_EMPTY_ARRAY;
}
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 92e30201b1..c04486f5ec 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
@@ -66,6 +66,7 @@ import
org.apache.ignite.internal.sql.engine.session.SessionNotFoundException;
import org.apache.ignite.internal.util.ExceptionUtils;
import org.apache.ignite.internal.util.Pair;
import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.lang.IgniteExceptionMapperUtil;
import org.apache.ignite.lang.IgniteInternalCheckedException;
import org.apache.ignite.lang.IgniteInternalException;
import org.apache.ignite.sql.ColumnType;
@@ -504,7 +505,7 @@ public class JdbcQueryEventHandlerImpl implements
JdbcQueryEventHandler {
return
CompletableFuture.completedFuture(resAndError.getFirst());
}
- Throwable error = resAndError.getSecond();
+ Throwable error =
ExceptionUtils.unwrapCause(resAndError.getSecond());
if (sessionExpiredError(error)) {
SessionId newSessionId =
recreateSession(finalSessionId);
@@ -512,7 +513,7 @@ public class JdbcQueryEventHandlerImpl implements
JdbcQueryEventHandler {
return action.perform(newSessionId);
}
- return CompletableFuture.failedFuture(error);
+ return
CompletableFuture.failedFuture(IgniteExceptionMapperUtil.mapToPublicException(error));
});
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/sql/AbstractSession.java
b/modules/core/src/main/java/org/apache/ignite/internal/sql/AbstractSession.java
index eccd9e06fa..24f8681ca0 100755
---
a/modules/core/src/main/java/org/apache/ignite/internal/sql/AbstractSession.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/sql/AbstractSession.java
@@ -60,7 +60,7 @@ public interface AbstractSession extends Session {
try {
return new SyncResultSetAdapter<>(executeAsync(transaction, query,
arguments).join());
} catch (CompletionException e) {
- throw ExceptionUtils.wrap(e);
+ throw
ExceptionUtils.sneakyThrow(ExceptionUtils.copyExceptionWithCause(e));
}
}
@@ -79,7 +79,7 @@ public interface AbstractSession extends Session {
try {
return new SyncResultSetAdapter<>(executeAsync(transaction,
statement, arguments).join());
} catch (CompletionException e) {
- throw ExceptionUtils.wrap(e);
+ throw
ExceptionUtils.sneakyThrow(ExceptionUtils.copyExceptionWithCause(e));
}
}
@@ -104,7 +104,7 @@ public interface AbstractSession extends Session {
try {
return new SyncResultSetAdapter<>(executeAsync(transaction,
mapper, query, arguments).join());
} catch (CompletionException e) {
- throw ExceptionUtils.wrap(e);
+ throw
ExceptionUtils.sneakyThrow(ExceptionUtils.copyExceptionWithCause(e));
}
}
@@ -129,7 +129,7 @@ public interface AbstractSession extends Session {
try {
return new SyncResultSetAdapter<>(executeAsync(transaction,
mapper, statement, arguments).join());
} catch (CompletionException e) {
- throw ExceptionUtils.wrap(e);
+ throw
ExceptionUtils.sneakyThrow(ExceptionUtils.copyExceptionWithCause(e));
}
}
@@ -147,7 +147,7 @@ public interface AbstractSession extends Session {
try {
return executeBatchAsync(transaction, dmlQuery, batch).join();
} catch (CompletionException e) {
- throw ExceptionUtils.wrap(e);
+ throw
ExceptionUtils.sneakyThrow(ExceptionUtils.copyExceptionWithCause(e));
}
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/SqlTests.cs
b/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/SqlTests.cs
index a7699e1454..1ae7b62c8f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/SqlTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/Sql/SqlTests.cs
@@ -334,8 +334,12 @@ namespace Apache.Ignite.Tests.Sql
[Test]
public void TestInvalidSqlThrowsException()
{
- var ex = Assert.ThrowsAsync<IgniteException>(async () => await
Client.Sql.ExecuteAsync(null, "select x from bad"));
- StringAssert.Contains("From line 1, column 15 to line 1, column
17: Object 'BAD' not found", ex!.Message);
+ var ex = Assert.ThrowsAsync<SqlException>(async () => await
Client.Sql.ExecuteAsync(null, "select x from bad"));
+ StringAssert.Contains("Invalid query, check inner exceptions for
details: select x from bad", ex!.Message);
+
+ var innerEx = ex.InnerException;
+ Assert.IsInstanceOf<SqlException>(innerEx);
+ StringAssert.Contains("From line 1, column 15 to line 1, column
17: Object 'BAD' not found", innerEx!.Message);
}
[Test]
diff --git a/modules/platforms/dotnet/Apache.Ignite/Internal/Sql/Sql.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/Sql/Sql.cs
index 2d23d8b4d3..bc7a569d28 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Internal/Sql/Sql.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/Sql/Sql.cs
@@ -152,19 +152,6 @@ namespace Apache.Ignite.Internal.Sql
"Invalid query, check inner exceptions for details: " +
statement.Query,
e);
}
-#if DEBUG
- catch (IgniteException e)
- {
- // TODO IGNITE-14865 Calcite error handling rework
- // This should not happen, all parsing errors must be wrapped
in SqlException.
- if ((e.InnerException?.Message ??
e.Message).StartsWith("org.apache.calcite.", StringComparison.Ordinal))
- {
- Console.WriteLine("SQL parsing failed: " +
statement.Query);
- }
-
- throw;
- }
-#endif
PooledArrayBuffer Write()
{
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItCommonApiTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItCommonApiTest.java
index 3fa83733d8..9b7a0d5227 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItCommonApiTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItCommonApiTest.java
@@ -23,12 +23,14 @@ import static
org.apache.ignite.internal.testframework.IgniteTestUtils.await;
import static
org.apache.ignite.internal.testframework.IgniteTestUtils.waitForCondition;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.ignite.Ignite;
@@ -84,8 +86,9 @@ public class ItCommonApiTest extends
ClusterPerClassIntegrationTest {
waitForCondition(() -> queryProcessor().liveSessions().size() == 1,
10_000);
// first session should no longer exist for the moment
- IgniteException err = assertThrows(IgniteException.class, () ->
ses1.execute(null, "SELECT 1 + 1"));
- assertThat(err.getMessage(), containsString("Session not found"));
+ ExecutionException err = assertThrows(ExecutionException.class, () ->
ses1.executeAsync(null, "SELECT 1 + 1").get());
+ assertThat(err.getCause(), instanceOf(IgniteException.class));
+ assertThat(err.getCause().getMessage(), containsString("Session not
found"));
// already started query should fail due to session has been expired
assertThrowsWithCause(() -> {
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 e1b6cb0f03..694a28e8af 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
@@ -22,7 +22,16 @@ import static
org.apache.ignite.internal.sql.engine.util.QueryChecker.containsTa
import static
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
import static org.apache.ignite.internal.testframework.IgniteTestUtils.await;
import static org.apache.ignite.lang.ErrorGroups.Sql.CONSTRAINT_VIOLATION_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.CURSOR_CLOSED_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.EXECUTION_CANCELLED_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.QUERY_NO_RESULT_SET_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.RUNTIME_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.SESSION_CLOSED_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_PARSE_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_VALIDATION_ERR;
+import static
org.apache.ignite.lang.ErrorGroups.Transactions.TX_FAILED_READ_WRITE_OPERATION_ERR;
+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.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -43,15 +52,19 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
+import javax.annotation.Nullable;
import org.apache.ignite.internal.client.sql.ClientSql;
import org.apache.ignite.internal.sql.api.ColumnMetadataImpl.ColumnOriginImpl;
import org.apache.ignite.internal.sql.engine.ClusterPerClassIntegrationTest;
import org.apache.ignite.internal.sql.engine.exec.ExecutionCancelledException;
import org.apache.ignite.internal.testframework.IgniteTestUtils;
+import org.apache.ignite.internal.testframework.IgniteTestUtils.RunnableX;
import org.apache.ignite.internal.tx.TxManager;
import org.apache.ignite.internal.util.CollectionUtils;
import org.apache.ignite.lang.ColumnAlreadyExistsException;
import org.apache.ignite.lang.ColumnNotFoundException;
+import org.apache.ignite.lang.ErrorGroups;
+import org.apache.ignite.lang.ErrorGroups.Index;
import org.apache.ignite.lang.IgniteException;
import org.apache.ignite.lang.IndexAlreadyExistsException;
import org.apache.ignite.lang.IndexNotFoundException;
@@ -102,7 +115,7 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
@Test
public void ddl() throws Exception {
- IgniteSql sql = CLUSTER_NODES.get(0).sql();
+ IgniteSql sql = igniteSql();
Session ses = sql.createSession();
// CREATE TABLE
@@ -114,7 +127,8 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
"CREATE TABLE TEST(ID INT PRIMARY KEY, VAL0 INT)"
);
checkError(
- IgniteException.class,
+ SqlException.class,
+ ErrorGroups.Table.TABLE_DEFINITION_ERR,
"Can't create table with duplicate columns: ID, VAL, VAL",
ses,
"CREATE TABLE TEST1(ID INT PRIMARY KEY, VAL INT, VAL INT)"
@@ -156,6 +170,7 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
checkDdl(true, ses, "CREATE INDEX TEST_IDX3 ON TEST(ID, VAL0, VAL1)");
checkError(
SqlException.class,
+ Index.INVALID_INDEX_DEFINITION_ERR,
"Can't create index on duplicate columns: VAL0, VAL0",
ses,
"CREATE INDEX TEST_IDX4 ON TEST(VAL0, VAL0)"
@@ -163,15 +178,19 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
checkError(
SqlException.class,
+ STMT_VALIDATION_ERR,
"Can`t delete column(s). Column VAL1 is used by indexes
[TEST_IDX3].",
ses,
"ALTER TABLE TEST DROP COLUMN val1"
);
- SqlException ex = IgniteTestUtils.cause(assertThrows(Throwable.class,
- () -> await(ses.executeAsync(null, "ALTER TABLE TEST DROP
COLUMN (val0, val1)"))), SqlException.class);
- assertNotNull(ex);
- assertEquals(STMT_VALIDATION_ERR, ex.code());
+ SqlException ex = checkError(
+ SqlException.class,
+ STMT_VALIDATION_ERR,
+ "Can`t delete column(s).",
+ ses,
+ "ALTER TABLE TEST DROP COLUMN (val0, val1)"
+ );
String msg = ex.getMessage();
String explainMsg = "Unexpected error message: " + msg;
@@ -182,6 +201,7 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
checkError(
SqlException.class,
+ STMT_VALIDATION_ERR,
"Can`t delete column, belongs to primary key: [name=ID]",
ses,
"ALTER TABLE TEST DROP COLUMN id"
@@ -231,7 +251,7 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
public void dml() {
sql("CREATE TABLE TEST(ID INT PRIMARY KEY, VAL0 INT)");
- IgniteSql sql = CLUSTER_NODES.get(0).sql();
+ IgniteSql sql = igniteSql();
Session ses = sql.createSession();
for (int i = 0; i < ROW_COUNT; ++i) {
@@ -337,12 +357,13 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
// Outdated tx.
Transaction outerTx0 = outerTx;
-
- assertThrows(SqlException.class,
+ IgniteException e = assertThrows(IgniteException.class,
() -> checkDml(1, ses, "INSERT INTO TEST VALUES (?, ?)",
outerTx0, ROW_COUNT, Integer.MAX_VALUE));
+ assertEquals(TX_FAILED_READ_WRITE_OPERATION_ERR, e.code());
- assertThrows(SqlException.class,
+ e = assertThrows(SqlException.class,
() -> checkDml(1, ses, "INSERT INTO TEST VALUES (?, ?)",
ROW_COUNT, Integer.MAX_VALUE));
+ assertEquals(CONSTRAINT_VIOLATION_ERR, e.code());
AsyncResultSet rs = await(ses.executeAsync(null, "SELECT VAL0 FROM
TEST ORDER BY VAL0"));
@@ -579,7 +600,7 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
@Test
public void errors() {
- sql("CREATE TABLE TEST(ID INT PRIMARY KEY, VAL0 INT)");
+ sql("CREATE TABLE TEST(ID INT PRIMARY KEY, VAL0 INT NOT NULL)");
for (int i = 0; i < ROW_COUNT; ++i) {
sql("INSERT INTO TEST VALUES (?, ?)", i, i);
}
@@ -588,33 +609,40 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
Session ses = sql.sessionBuilder().defaultPageSize(ROW_COUNT /
2).build();
// Parse error.
- assertThrowsWithCause(() -> await(ses.executeAsync(null, "SELECT ID
FROM")),
- SqlException.class, "Failed to parse query");
+ checkError(SqlException.class, STMT_PARSE_ERR, "Failed to parse
query", ses, "SELECT ID FROM");
+
+ // Validation errors.
+ checkError(SqlException.class, STMT_VALIDATION_ERR, "Column 'VAL0'
does not allow NULLs", ses,
+ "INSERT INTO TEST VALUES (2, NULL)");
+
+ checkError(SqlException.class, STMT_VALIDATION_ERR, "Object
'NOT_EXISTING_TABLE' not found", ses,
+ "SELECT * FROM NOT_EXISTING_TABLE");
+
+ checkError(SqlException.class, STMT_VALIDATION_ERR, "Column
'NOT_EXISTING_COLUMN' not found", ses,
+ "SELECT NOT_EXISTING_COLUMN FROM TEST");
- // Multiple statements error.
- assertThrowsWithCause(() -> await(ses.executeAsync(null, "SELECT 1;
SELECT 2")),
- SqlException.class, "Multiple statements are not allowed");
+ checkError(SqlException.class, STMT_VALIDATION_ERR, "Multiple
statements are not allowed", ses, "SELECT 1; SELECT 2");
- // Planning error.
- assertThrowsWithCause(() -> await(ses.executeAsync(null, "CREATE TABLE
TEST2 (VAL INT)")),
- SqlException.class, "Table without PRIMARY KEY is not
supported");
+ checkError(SqlException.class, STMT_VALIDATION_ERR, "Table without
PRIMARY KEY is not supported", ses,
+ "CREATE TABLE TEST2 (VAL INT)");
// Execute error.
- assertThrowsWithCause(() -> await(ses.executeAsync(null, "SELECT 1 /
?", 0)),
- IgniteException.class, "/ by zero");
+ checkError(SqlException.class, RUNTIME_ERR, "/ by zero", ses, "SELECT
1 / ?", 0);
+ checkError(SqlException.class, RUNTIME_ERR, "negative substring length
not allowed", ses, "SELECT SUBSTRING('foo', 1, -3)");
// No result set error.
{
AsyncResultSet ars = await(ses.executeAsync(null, "CREATE TABLE
TEST3 (ID INT PRIMARY KEY)"));
- assertThrowsWithCause(() -> await(ars.fetchNextPage()),
NoRowSetExpectedException.class,
- "Query has no result set");
+ assertThrowsPublicException(() -> await(ars.fetchNextPage()),
+ NoRowSetExpectedException.class, QUERY_NO_RESULT_SET_ERR,
"Query has no result set");
}
// Cursor closed error.
{
AsyncResultSet ars = await(ses.executeAsync(null, "SELECT * FROM
TEST"));
await(ars.closeAsync());
- assertThrowsWithCause(() -> await(ars.fetchNextPage()),
CursorClosedException.class);
+ assertThrowsPublicException(() -> await(ars.fetchNextPage()),
+ CursorClosedException.class, CURSOR_CLOSED_ERR, null);
}
}
@@ -629,8 +657,9 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
{
Transaction tx = igniteTx().begin();
try {
- assertThrowsWithCause(() -> await(ses.executeAsync(tx, "CREATE
TABLE TEST2(ID INT PRIMARY KEY, VAL0 INT)")),
+ assertThrowsPublicException(() -> await(ses.executeAsync(tx,
"CREATE TABLE TEST2(ID INT PRIMARY KEY, VAL0 INT)")),
SqlException.class,
+ STMT_VALIDATION_ERR,
"DDL doesn't support transactions."
);
} finally {
@@ -642,8 +671,9 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
AsyncResultSet<SqlRow> res = await(ses.executeAsync(tx, "INSERT
INTO TEST VALUES (?, ?)", -1, -1));
assertEquals(1, res.affectedRows());
- assertThrowsWithCause(() -> await(ses.executeAsync(tx, "CREATE
TABLE TEST2(ID INT PRIMARY KEY, VAL0 INT)")),
+ assertThrowsPublicException(() -> await(ses.executeAsync(tx,
"CREATE TABLE TEST2(ID INT PRIMARY KEY, VAL0 INT)")),
SqlException.class,
+ STMT_VALIDATION_ERR,
"DDL doesn't support transactions."
);
tx.commit();
@@ -669,16 +699,12 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
// Fetched page is available after cancel.
ars0.currentPage();
- assertThrowsWithCause(
- () -> await(ars0.fetchNextPage()),
- ExecutionCancelledException.class
- );
+ SqlException sqlEx = assertThrowsPublicException(() ->
await(ars0.fetchNextPage()),
+ SqlException.class, EXECUTION_CANCELLED_ERR, null);
+ assertTrue(IgniteTestUtils.hasCause(sqlEx,
ExecutionCancelledException.class, null));
- assertThrowsWithCause(
- () -> await(ses.executeAsync(null, "SELECT ID FROM TEST")),
- SqlException.class,
- "Session is closed"
- );
+ assertThrowsPublicException(() -> await(ses.executeAsync(null, "SELECT
ID FROM TEST")),
+ SqlException.class, SESSION_CLOSED_ERR, "Session is closed");
}
@Test
@@ -703,17 +729,11 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
IntStream.range(0, ROW_COUNT).forEach(i -> assertEquals(i,
res.get(i).get(0)));
// Check invalid query type
- assertThrowsWithCause(
- () -> await(ses.executeBatchAsync(null, "SELECT * FROM TEST",
args)),
- SqlException.class,
- "Invalid SQL statement type in the batch"
- );
+ assertThrowsPublicException(() -> await(ses.executeBatchAsync(null,
"SELECT * FROM TEST", args)),
+ SqlBatchException.class, STMT_VALIDATION_ERR, "Invalid SQL
statement type in the batch");
- assertThrowsWithCause(
- () -> await(ses.executeBatchAsync(null, "CREATE TABLE TEST1(ID
INT PRIMARY KEY, VAL0 INT)", args)),
- SqlException.class,
- "Invalid SQL statement type in the batch"
- );
+ assertThrowsPublicException(() -> await(ses.executeBatchAsync(null,
"CREATE TABLE TEST1(ID INT PRIMARY KEY, VAL0 INT)", args)),
+ SqlBatchException.class, STMT_VALIDATION_ERR, "Invalid SQL
statement type in the batch");
}
@Test
@@ -735,12 +755,13 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
}
}
- SqlBatchException ex = assertThrows(
+ SqlBatchException ex = assertThrowsPublicException(
+ () -> await(ses.executeBatchAsync(null, "INSERT INTO TEST
VALUES (?, ?)", args)),
SqlBatchException.class,
- () -> await(ses.executeBatchAsync(null, "INSERT INTO TEST
VALUES (?, ?)", args))
+ CONSTRAINT_VIOLATION_ERR,
+ null
);
- assertEquals(CONSTRAINT_VIOLATION_ERR, ex.code());
assertEquals(err, ex.updateCounters().length);
IntStream.range(0, ex.updateCounters().length).forEach(i ->
assertEquals(1, ex.updateCounters()[i]));
}
@@ -767,12 +788,19 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
checkDdl(expectedApplied, ses, sql, null);
}
- private static void checkError(Class<? extends Throwable>
expectedException, String msg, Session ses, String sql, Object... args) {
- assertThrowsWithCause(() -> await(ses.executeAsync(
- null,
- sql,
- args
- )), expectedException, msg);
+ private static <T extends IgniteException> T checkError(Class<T> expCls,
String msg, Session ses, String sql, Object... args) {
+ return checkError(expCls, null, msg, ses, sql, args);
+ }
+
+ private static <T extends IgniteException> T checkError(
+ Class<T> expCls,
+ @Nullable Integer code,
+ @Nullable String msg,
+ Session ses,
+ String sql,
+ Object... args
+ ) {
+ return assertThrowsPublicException(() -> await(ses.executeAsync(null,
sql, args)), expCls, code, msg);
}
protected static void checkDml(int expectedAffectedRows, Session ses,
String sql, Transaction tx, Object... args) {
@@ -788,10 +816,29 @@ public class ItSqlAsynchronousApiTest extends
ClusterPerClassIntegrationTest {
await(asyncRes.closeAsync());
}
- protected static void checkDml(int expectedAffectedRows, Session ses,
String sql, Object... args) {
+ private static void checkDml(int expectedAffectedRows, Session ses, String
sql, Object... args) {
checkDml(expectedAffectedRows, ses, sql, null, args);
}
+ static <T extends IgniteException> T assertThrowsPublicException(
+ RunnableX executable,
+ Class<T> expCls,
+ @Nullable Integer code,
+ @Nullable String msgPart
+ ) {
+ T ex = assertThrows(expCls, executable::run);
+
+ if (code != null) {
+ assertEquals(new IgniteException(code).codeAsString(),
ex.codeAsString());
+ }
+
+ if (msgPart != null) {
+ assertThat(ex.getMessage(), containsString(msgPart));
+ }
+
+ return ex;
+ }
+
static class TestPageProcessor implements
Function<AsyncResultSet<SqlRow>,
CompletionStage<AsyncResultSet<SqlRow>>> {
private int expectedPages;
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 38b8c69ad0..0a8f3f4d81 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
@@ -17,12 +17,14 @@
package org.apache.ignite.internal.sql.api;
+import static
org.apache.ignite.internal.sql.api.ItSqlAsynchronousApiTest.assertThrowsPublicException;
import static
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
-import static org.apache.ignite.internal.testframework.IgniteTestUtils.await;
+import static org.apache.ignite.lang.ErrorGroups.Sql.QUERY_NO_RESULT_SET_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.RUNTIME_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_PARSE_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_VALIDATION_ERR;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -32,12 +34,14 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
+import javax.annotation.Nullable;
import org.apache.ignite.internal.app.IgniteImpl;
import org.apache.ignite.internal.sql.engine.ClusterPerClassIntegrationTest;
-import org.apache.ignite.internal.testframework.IgniteTestUtils;
import org.apache.ignite.internal.tx.TxManager;
import org.apache.ignite.lang.ColumnAlreadyExistsException;
import org.apache.ignite.lang.ColumnNotFoundException;
+import org.apache.ignite.lang.ErrorGroups;
+import org.apache.ignite.lang.ErrorGroups.Index;
import org.apache.ignite.lang.ErrorGroups.Sql;
import org.apache.ignite.lang.IgniteException;
import org.apache.ignite.lang.IndexAlreadyExistsException;
@@ -45,7 +49,6 @@ import org.apache.ignite.lang.IndexNotFoundException;
import org.apache.ignite.lang.TableAlreadyExistsException;
import org.apache.ignite.lang.TableNotFoundException;
import org.apache.ignite.sql.BatchedArguments;
-import org.apache.ignite.sql.CursorClosedException;
import org.apache.ignite.sql.IgniteSql;
import org.apache.ignite.sql.NoRowSetExpectedException;
import org.apache.ignite.sql.ResultSet;
@@ -56,7 +59,6 @@ import org.apache.ignite.sql.SqlRow;
import org.apache.ignite.table.Table;
import org.apache.ignite.tx.Transaction;
import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
@@ -98,6 +100,7 @@ public class ItSqlSynchronousApiTest extends
ClusterPerClassIntegrationTest {
);
checkError(
SqlException.class,
+ ErrorGroups.Table.TABLE_DEFINITION_ERR,
"Can't create table with duplicate columns: ID, VAL, VAL",
ses,
"CREATE TABLE TEST1(ID INT PRIMARY KEY, VAL INT, VAL INT)"
@@ -139,6 +142,7 @@ public class ItSqlSynchronousApiTest extends
ClusterPerClassIntegrationTest {
checkDdl(true, ses, "CREATE INDEX TEST_IDX3 ON TEST(ID, VAL0, VAL1)");
checkError(
SqlException.class,
+ Index.INVALID_INDEX_DEFINITION_ERR,
"Can't create index on duplicate columns: VAL0, VAL0",
ses,
"CREATE INDEX TEST_IDX4 ON TEST(VAL0, VAL0)"
@@ -146,15 +150,19 @@ public class ItSqlSynchronousApiTest extends
ClusterPerClassIntegrationTest {
checkError(
SqlException.class,
+ STMT_VALIDATION_ERR,
"Can`t delete column(s). Column VAL1 is used by indexes
[TEST_IDX3].",
ses,
"ALTER TABLE TEST DROP COLUMN val1"
);
- SqlException ex = IgniteTestUtils.cause(assertThrows(Throwable.class,
- () -> await(ses.executeAsync(null, "ALTER TABLE TEST DROP
COLUMN (val0, val1)"))), SqlException.class);
- assertNotNull(ex);
- assertEquals(STMT_VALIDATION_ERR, ex.code());
+ SqlException ex = checkError(
+ SqlException.class,
+ STMT_VALIDATION_ERR,
+ "Can`t delete column(s).",
+ ses,
+ "ALTER TABLE TEST DROP COLUMN (val0, val1)"
+ );
String msg = ex.getMessage();
String explainMsg = "Unexpected error message: " + msg;
@@ -165,6 +173,7 @@ public class ItSqlSynchronousApiTest extends
ClusterPerClassIntegrationTest {
checkError(
SqlException.class,
+ STMT_VALIDATION_ERR,
"Can`t delete column, belongs to primary key: [name=ID]",
ses,
"ALTER TABLE TEST DROP COLUMN id"
@@ -259,9 +268,8 @@ public class ItSqlSynchronousApiTest extends
ClusterPerClassIntegrationTest {
}
@Test
- @Disabled("https://issues.apache.org/jira/browse/IGNITE-19919")
public void errors() throws InterruptedException {
- sql("CREATE TABLE TEST(ID INT PRIMARY KEY, VAL0 INT)");
+ sql("CREATE TABLE TEST(ID INT PRIMARY KEY, VAL0 INT NOT NULL)");
for (int i = 0; i < ROW_COUNT; ++i) {
sql("INSERT INTO TEST VALUES (?, ?)", i, i);
}
@@ -270,46 +278,42 @@ public class ItSqlSynchronousApiTest extends
ClusterPerClassIntegrationTest {
Session ses = sql.sessionBuilder().defaultPageSize(2).build();
// Parse error.
- assertThrowsWithCause(
- () -> ses.execute(null, "SELECT ID FROM"),
- SqlException.class,
- "Failed to parse query"
- );
+ checkError(SqlException.class, STMT_PARSE_ERR, "Failed to parse
query", ses, "SELECT ID FROM");
- // Multiple statements error.
- assertThrowsWithCause(
- () -> ses.execute(null, "SELECT 1; SELECT 2"),
- SqlException.class,
- "Multiple statements are not allowed"
- );
+ // Validation errors.
+ checkError(SqlException.class, STMT_VALIDATION_ERR, "Column 'VAL0'
does not allow NULLs", ses,
+ "INSERT INTO TEST VALUES (2, NULL)");
- // Planning error.
- assertThrowsWithCause(
- () -> ses.execute(null, "CREATE TABLE TEST2 (VAL INT)"),
- SqlException.class,
- "Table without PRIMARY KEY is not supported"
- );
+ checkError(SqlException.class, STMT_VALIDATION_ERR, "Object
'NOT_EXISTING_TABLE' not found", ses,
+ "SELECT * FROM NOT_EXISTING_TABLE");
+
+ checkError(SqlException.class, STMT_VALIDATION_ERR, "Column
'NOT_EXISTING_COLUMN' not found", ses,
+ "SELECT NOT_EXISTING_COLUMN FROM TEST");
+
+ checkError(SqlException.class, STMT_VALIDATION_ERR, "Multiple
statements are not allowed", ses, "SELECT 1; SELECT 2");
+
+ checkError(SqlException.class, STMT_VALIDATION_ERR, "Table without
PRIMARY KEY is not supported", ses,
+ "CREATE TABLE TEST2 (VAL INT)");
// Execute error.
- assertThrowsWithCause(
- () -> ses.execute(null, "SELECT 1 / ?", 0),
- IgniteException.class,
- "/ by zero"
- );
+ checkError(SqlException.class, RUNTIME_ERR, "/ by zero", ses, "SELECT
1 / ?", 0);
+ checkError(SqlException.class, RUNTIME_ERR, "negative substring length
not allowed", ses, "SELECT SUBSTRING('foo', 1, -3)");
// No result set error.
{
ResultSet rs = ses.execute(null, "CREATE TABLE TEST3 (ID INT
PRIMARY KEY)");
- assertThrowsWithCause(rs::next, NoRowSetExpectedException.class,
"Query has no result set");
+ assertThrowsPublicException(rs::next,
NoRowSetExpectedException.class, QUERY_NO_RESULT_SET_ERR, "Query has no result
set");
}
+ // TODO unmute after https://issues.apache.org/jira/browse/IGNITE-19919
// Cursor closed error.
- {
- ResultSet rs = ses.execute(null, "SELECT * FROM TEST");
- Thread.sleep(300); // ResultSetImpl fetches next page in
background, wait to it to complete to avoid flakiness.
- rs.close();
- assertThrowsWithCause(() -> rs.forEachRemaining(Object::hashCode),
CursorClosedException.class);
- }
+ // {
+ // ResultSet rs = ses.execute(null, "SELECT * FROM TEST");
+ // Thread.sleep(300); // ResultSetImpl fetches next page in
background, wait to it to complete to avoid flakiness.
+ // rs.close();
+ // assertThrowsPublicException(() ->
rs.forEachRemaining(Object::hashCode),
+ // CursorClosedException.class, CURSOR_CLOSED_ERR, null);
+ // }
}
/**
@@ -425,11 +429,22 @@ public class ItSqlSynchronousApiTest extends
ClusterPerClassIntegrationTest {
res.close();
}
- private static void checkError(Class<? extends Throwable>
expectedException, String msg, Session ses, String sql) {
- assertThrowsWithCause(() -> ses.execute(null, sql), expectedException,
msg);
+ private static <T extends IgniteException> T checkError(Class<T> expCls,
String msg, Session ses, String sql, Object... args) {
+ return checkError(expCls, null, msg, ses, sql, args);
+ }
+
+ private static <T extends IgniteException> T checkError(
+ Class<T> expCls,
+ @Nullable Integer code,
+ @Nullable String msg,
+ Session ses,
+ String sql,
+ Object... args
+ ) {
+ return assertThrowsPublicException(() -> ses.execute(null, sql, args),
expCls, code, msg);
}
- protected static void checkDml(int expectedAffectedRows, Session ses,
String sql, Object... args) {
+ static void checkDml(int expectedAffectedRows, Session ses, String sql,
Object... args) {
ResultSet res = ses.execute(
null,
sql,
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
index 4d54c7911d..90920a4192 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal.sql.engine;
+import static
org.apache.ignite.internal.sql.engine.util.SqlTestUtils.assertThrowsSqlException;
import static org.apache.ignite.lang.IgniteStringFormatter.format;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
@@ -36,6 +37,7 @@ import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.type.SqlTypeUtil;
import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.sql.engine.util.QueryChecker;
+import org.apache.ignite.lang.ErrorGroups.Sql;
import org.apache.ignite.lang.IgniteException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assumptions;
@@ -124,8 +126,7 @@ public class ItDataTypesTest extends
ClusterPerClassIntegrationTest {
assertEquals(Set.of(101), rows.stream().map(r ->
r.get(0)).collect(Collectors.toSet()));
- //todo: correct exception
https://issues.apache.org/jira/browse/IGNITE-16095
- assertThrows(IgniteException.class, () -> sql("INSERT INTO tbl(c1, c2)
VALUES (2, NULL)"));
+ assertThrowsSqlException(Sql.STMT_VALIDATION_ERR, () -> sql("INSERT
INTO tbl(c1, c2) VALUES (2, NULL)"));
}
/**
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
index 550638e5c7..27ed03a443 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDmlTest.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.sql.engine;
import static
org.apache.ignite.internal.sql.engine.util.SqlTestUtils.assertThrowsSqlException;
import static org.apache.ignite.lang.ErrorGroups.Sql.CONSTRAINT_VIOLATION_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_VALIDATION_ERR;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -539,11 +540,9 @@ public class ItDmlTest extends
ClusterPerClassIntegrationTest {
public void testCheckNullValueErrorMessageForColumnWithDefaultValue() {
sql("CREATE TABLE tbl(key int DEFAULT 9 primary key, val varchar)");
- var e = assertThrows(IgniteException.class,
- () -> sql("INSERT INTO tbl (key, val) VALUES (NULL,'AA')"));
+ var expectedMessage = "Failed to validate query. From line 1, column
28 to line 1, column 45: Column 'KEY' does not allow NULLs";
- var expectedMessage = "From line 1, column 28 to line 1, column 45:
Column 'KEY' does not allow NULLs";
- assertEquals(expectedMessage, e.getMessage(), "error message");
+ assertThrowsSqlException(STMT_VALIDATION_ERR, expectedMessage, () ->
sql("INSERT INTO tbl (key, val) VALUES (NULL,'AA')"));
}
private void checkQueryResult(String sql, List<Object> expectedVals) {
@@ -553,7 +552,7 @@ public class ItDmlTest extends
ClusterPerClassIntegrationTest {
private void checkWrongDefault(String sqlType, String sqlVal) {
try {
assertThrows(
- IgniteException.class,
+ SqlException.class,
() -> sql("CREATE TABLE test (val " + sqlType + " DEFAULT
" + sqlVal + ")"),
"Cannot convert literal"
);
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 7b28998f8c..357120bc94 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
@@ -17,6 +17,8 @@
package org.apache.ignite.internal.sql.engine;
+import static
org.apache.ignite.internal.sql.engine.util.SqlTestUtils.assertThrowsSqlException;
+import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_VALIDATION_ERR;
import static org.apache.ignite.lang.IgniteStringFormatter.format;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
@@ -35,7 +37,6 @@ import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.sql.engine.util.MetadataMatcher;
import org.apache.ignite.internal.sql.engine.util.SqlTestUtils;
import org.apache.ignite.internal.testframework.IgniteTestUtils;
-import org.apache.ignite.lang.IgniteException;
import org.apache.ignite.sql.ColumnType;
import org.apache.ignite.sql.SqlException;
import org.junit.jupiter.api.AfterEach;
@@ -159,8 +160,8 @@ public class ItDynamicParameterTest extends
ClusterPerClassIntegrationTest {
*/
@Test
public void testWithDifferentParametersTypesMismatch() {
- assertThrows(IgniteException.class, () -> assertQuery("SELECT
COALESCE(12.2, ?)").withParams("b").check());
- assertThrows(IgniteException.class, () -> assertQuery("SELECT
COALESCE(?, ?)").withParams(12.2, "b").check());
+ assertThrowsSqlException(STMT_VALIDATION_ERR, () ->
assertQuery("SELECT COALESCE(12.2, ?)").withParams("b").check());
+ assertThrowsSqlException(STMT_VALIDATION_ERR, () ->
assertQuery("SELECT COALESCE(?, ?)").withParams(12.2, "b").check());
}
@Test
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItLimitOffsetTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItLimitOffsetTest.java
index 08676a86af..eecebe80d1 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItLimitOffsetTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItLimitOffsetTest.java
@@ -17,15 +17,14 @@
package org.apache.ignite.internal.sql.engine;
+import static
org.apache.ignite.internal.sql.engine.util.SqlTestUtils.assertThrowsSqlException;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import org.apache.ignite.internal.sql.engine.util.Commons;
-import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.lang.ErrorGroups.Sql;
import org.apache.ignite.sql.Session;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -52,35 +51,33 @@ public class ItLimitOffsetTest extends
ClusterPerClassIntegrationTest {
String bigInt = BigDecimal.valueOf(10000000000L).toString();
- //todo: correct exception
https://issues.apache.org/jira/browse/IGNITE-16095, here and all checks near.
- IgniteException ret = assertThrows(IgniteException.class, ()
- -> session.execute(null, "SELECT * FROM test OFFSET " + bigInt
+ " ROWS"));
- assertTrue(ret.getMessage().contains("Illegal value of offset"));
+ assertThrowsSqlException(Sql.STMT_VALIDATION_ERR, "Illegal value of
offset",
+ () -> session.execute(null, "SELECT * FROM test OFFSET " +
bigInt + " ROWS"));
- ret = assertThrows(IgniteException.class,
+ assertThrowsSqlException(Sql.STMT_VALIDATION_ERR, "Illegal value of
fetch / limit",
() -> session.execute(null, "SELECT * FROM test FETCH FIRST "
+ bigInt + " ROWS ONLY"));
- assertTrue(ret.getMessage().contains("Illegal value of fetch /
limit"));
- ret = assertThrows(IgniteException.class, () -> session.execute(null,
"SELECT * FROM test LIMIT " + bigInt));
- assertTrue(ret.getMessage().contains("Illegal value of fetch /
limit"));
+ assertThrowsSqlException(Sql.STMT_VALIDATION_ERR, "Illegal value of
fetch / limit",
+ () -> session.execute(null, "SELECT * FROM test LIMIT " +
bigInt));
- assertThrows(IgniteException.class, () -> session.execute(null,
"SELECT * FROM test OFFSET -1 ROWS "
- + "FETCH FIRST -1 ROWS ONLY"));
+ assertThrowsSqlException(Sql.STMT_PARSE_ERR,
+ () -> session.execute(null, "SELECT * FROM test OFFSET -1 ROWS
FETCH FIRST -1 ROWS ONLY"));
- assertThrows(IgniteException.class, () -> session.execute(null,
"SELECT * FROM test OFFSET -1 ROWS"));
+ assertThrowsSqlException(Sql.STMT_PARSE_ERR,
+ () -> session.execute(null, "SELECT * FROM test OFFSET -1
ROWS"));
- assertThrows(IgniteException.class, () -> session.execute(null,
"SELECT * FROM test OFFSET 2+1 ROWS"));
+ assertThrowsSqlException(Sql.STMT_PARSE_ERR,
+ () -> session.execute(null, "SELECT * FROM test OFFSET 2+1
ROWS"));
// Check with parameters
- ret = assertThrows(IgniteException.class, () -> session.execute(null,
"SELECT * FROM test OFFSET ? "
- + "ROWS FETCH FIRST ? ROWS ONLY", -1, -1));
- assertTrue(ret.getMessage().contains("Illegal value of fetch /
limit"));
+ assertThrowsSqlException(Sql.STMT_VALIDATION_ERR, "Illegal value of
fetch / limit",
+ () -> session.execute(null, "SELECT * FROM test OFFSET ? ROWS
FETCH FIRST ? ROWS ONLY", -1, -1));
- ret = assertThrows(IgniteException.class, () -> session.execute(null,
"SELECT * FROM test OFFSET ? ROWS", -1));
- assertTrue(ret.getMessage().contains("Illegal value of offset"));
+ assertThrowsSqlException(Sql.STMT_VALIDATION_ERR, "Illegal value of
offset",
+ () -> session.execute(null, "SELECT * FROM test OFFSET ?
ROWS", -1));
- ret = assertThrows(IgniteException.class, () -> session.execute(null,
"SELECT * FROM test FETCH FIRST ? ROWS ONLY", -1));
- assertTrue(ret.getMessage().contains("Illegal value of fetch /
limit"));
+ assertThrowsSqlException(Sql.STMT_VALIDATION_ERR, "Illegal value of
fetch / limit",
+ () -> session.execute(null, "SELECT * FROM test FETCH FIRST ?
ROWS ONLY", -1));
}
/**
diff --git a/modules/sql-engine/build.gradle b/modules/sql-engine/build.gradle
index f181612f2a..20da54336e 100644
--- a/modules/sql-engine/build.gradle
+++ b/modules/sql-engine/build.gradle
@@ -56,9 +56,11 @@ dependencies {
}
implementation libs.classgraph
implementation libs.javassist
+ implementation libs.auto.service.annotations
annotationProcessor project(':ignite-network-annotation-processor')
annotationProcessor libs.value.annotation.processor
+ annotationProcessor libs.auto.service
testAnnotationProcessor project(':ignite-network-annotation-processor')
testAnnotationProcessor libs.jmh.annotation.processor
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 0b60c97e9b..638ad0495b 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,6 +20,7 @@ package org.apache.ignite.internal.sql.api;
import static org.apache.ignite.internal.util.ExceptionUtils.sneakyThrow;
import static org.apache.ignite.lang.ErrorGroups.Common.INTERNAL_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.SESSION_CLOSED_ERR;
+import static
org.apache.ignite.lang.IgniteExceptionMapperUtil.mapToPublicException;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import java.util.ArrayList;
@@ -29,6 +30,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Flow.Publisher;
import java.util.concurrent.TimeUnit;
@@ -47,8 +49,8 @@ import
org.apache.ignite.internal.sql.engine.session.SessionProperty;
import org.apache.ignite.internal.util.ArrayUtils;
import org.apache.ignite.internal.util.ExceptionUtils;
import org.apache.ignite.internal.util.IgniteSpinBusyLock;
-import org.apache.ignite.lang.IgniteException;
import org.apache.ignite.lang.IgniteInternalException;
+import org.apache.ignite.lang.TraceableException;
import org.apache.ignite.sql.BatchedArguments;
import org.apache.ignite.sql.SqlBatchException;
import org.apache.ignite.sql.SqlException;
@@ -167,13 +169,15 @@ public class SessionImpl implements AbstractSession {
return CompletableFuture.failedFuture(new
SqlException(SESSION_CLOSED_ERR, "Session is closed."));
}
+ CompletableFuture<AsyncResultSet<SqlRow>> result;
+
try {
QueryContext ctx = QueryContext.create(SqlQueryType.ALL,
transaction);
- CompletableFuture<AsyncResultSet<SqlRow>> result =
qryProc.querySingleAsync(sessionId, ctx, query, arguments)
+ result = qryProc.querySingleAsync(sessionId, ctx, query, arguments)
.thenCompose(cur -> cur.requestNextAsync(pageSize)
.thenApply(
- batchRes -> new AsyncResultSetImpl(
+ batchRes -> new AsyncResultSetImpl<>(
cur,
batchRes,
pageSize,
@@ -181,19 +185,22 @@ public class SessionImpl implements AbstractSession {
)
)
);
-
- result.whenComplete((rs, th) -> {
- if (th instanceof SessionNotFoundException) {
- closeInternal();
- }
- });
-
- return result;
} catch (Exception e) {
- return CompletableFuture.failedFuture(e);
+ return CompletableFuture.failedFuture(mapToPublicException(e));
} finally {
busyLock.leaveBusy();
}
+
+ // Closing a session must be done outside of the lock.
+ return result.exceptionally((th) -> {
+ Throwable cause = ExceptionUtils.unwrapCause(th);
+
+ if (cause instanceof SessionNotFoundException) {
+ closeInternal();
+ }
+
+ throw new CompletionException(mapToPublicException(cause));
+ });
}
/** {@inheritDoc} */
@@ -253,7 +260,7 @@ public class SessionImpl implements AbstractSession {
counters.add((long) page.items().get(0).get(0));
})
.whenComplete((v, ex) -> {
- if (ex instanceof CancellationException) {
+ if (ExceptionUtils.unwrapCause(ex) instanceof
CancellationException) {
qryFut.cancel(false);
}
});
@@ -265,22 +272,34 @@ public class SessionImpl implements AbstractSession {
.exceptionally((ex) -> {
Throwable cause = ExceptionUtils.unwrapCause(ex);
- throw new SqlBatchException(
- cause instanceof IgniteException ?
((IgniteException) cause).code() : INTERNAL_ERR,
- counters.toArray(ArrayUtils.LONG_EMPTY_ARRAY),
- ex);
+ if (cause instanceof CancellationException) {
+ throw (CancellationException) cause;
+ }
+
+ Throwable t = mapToPublicException(cause);
+
+ if (t instanceof TraceableException) {
+ throw new SqlBatchException(
+ ((TraceableException) t).traceId(),
+ ((TraceableException) t).code(),
+
counters.toArray(ArrayUtils.LONG_EMPTY_ARRAY),
+ t);
+ }
+
+ // JVM error.
+ throw new CompletionException(cause);
})
.thenApply(v ->
counters.toArray(ArrayUtils.LONG_EMPTY_ARRAY));
resFut.whenComplete((cur, ex) -> {
- if (ex instanceof CancellationException) {
+ if (ExceptionUtils.unwrapCause(ex) instanceof
CancellationException) {
batchFuts.forEach(f -> f.cancel(false));
}
});
return resFut;
} catch (Exception e) {
- return CompletableFuture.failedFuture(e);
+ return CompletableFuture.failedFuture(mapToPublicException(e));
} finally {
busyLock.leaveBusy();
}
@@ -326,7 +345,7 @@ public class SessionImpl implements AbstractSession {
@Override
public void close() {
try {
- closeAsync().toCompletableFuture().get();
+ closeAsync().get();
} catch (ExecutionException e) {
sneakyThrow(ExceptionUtils.copyExceptionWithCause(e));
} catch (InterruptedException e) {
@@ -337,9 +356,13 @@ public class SessionImpl implements AbstractSession {
/** {@inheritDoc} */
@Override
public CompletableFuture<Void> closeAsync() {
- closeInternal();
+ try {
+ closeInternal();
- return qryProc.closeSession(sessionId);
+ return qryProc.closeSession(sessionId);
+ } catch (Exception e) {
+ return CompletableFuture.failedFuture(mapToPublicException(e));
+ }
}
/** {@inheritDoc} */
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/AsyncSqlCursorImpl.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/AsyncSqlCursorImpl.java
index 3efd4b14f4..2be580ace8 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/AsyncSqlCursorImpl.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/AsyncSqlCursorImpl.java
@@ -18,11 +18,11 @@
package org.apache.ignite.internal.sql.engine;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
import org.apache.ignite.internal.tx.InternalTransaction;
import org.apache.ignite.internal.util.ExceptionUtils;
-import org.apache.ignite.lang.IgniteInternalException;
+import org.apache.ignite.lang.IgniteExceptionMapperUtil;
import org.apache.ignite.sql.ResultSetMetadata;
-import org.apache.ignite.sql.SqlException;
import org.jetbrains.annotations.Nullable;
/**
@@ -76,7 +76,7 @@ public class AsyncSqlCursorImpl<T> implements
AsyncSqlCursor<T> {
implicitTx.rollback();
}
- throw wrapIfNecessary(t);
+ throw new CompletionException(wrapIfNecessary(t));
}
if (implicitTx != null && !batch.hasMore()) {
@@ -94,16 +94,9 @@ public class AsyncSqlCursorImpl<T> implements
AsyncSqlCursor<T> {
return dataCursor.closeAsync();
}
- private static RuntimeException wrapIfNecessary(Throwable t) {
+ private static Throwable wrapIfNecessary(Throwable t) {
Throwable err = ExceptionUtils.unwrapCause(t);
- if (err instanceof IgniteInternalException) {
- IgniteInternalException iex = (IgniteInternalException) err;
-
- return new SqlException(iex.traceId(), iex.code(),
iex.getMessage(), iex);
- }
-
- // TODO https://issues.apache.org/jira/browse/IGNITE-19539
- return ExceptionUtils.wrap(t);
+ return IgniteExceptionMapperUtil.mapToPublicException(err);
}
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExchangeServiceImpl.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExchangeServiceImpl.java
index 996c082e37..c616389368 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExchangeServiceImpl.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExchangeServiceImpl.java
@@ -35,11 +35,8 @@ import
org.apache.ignite.internal.sql.engine.message.SqlQueryMessageGroup;
import org.apache.ignite.internal.sql.engine.message.SqlQueryMessagesFactory;
import org.apache.ignite.internal.sql.engine.util.Commons;
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.SqlException;
-import org.jetbrains.annotations.NotNull;
+import org.apache.ignite.lang.TraceableException;
import org.jetbrains.annotations.Nullable;
/**
@@ -111,12 +108,16 @@ public class ExchangeServiceImpl implements
ExchangeService {
/** {@inheritDoc} */
@Override
public CompletableFuture<Void> sendError(String nodeName, UUID queryId,
long fragmentId, Throwable error) {
- IgniteException errorWithCode = wrapIfNecessary(error);
+ Throwable traceableErr = ExceptionUtils.unwrapCause(error);
- if (!(error instanceof ExecutionCancelledException)) {
- LOG.info(format("Failed to execute query fragment: queryId={},
fragmentId={}", queryId, fragmentId), errorWithCode);
+ if (!(traceableErr instanceof TraceableException)) {
+ traceableErr = error = new IgniteInternalException(INTERNAL_ERR,
error);
+ }
+
+ if (!(traceableErr instanceof ExecutionCancelledException)) {
+ LOG.info(format("Failed to execute query fragment: queryId={},
fragmentId={}", queryId, fragmentId), error);
} else if (LOG.isDebugEnabled()) {
- LOG.debug(format("Failed to execute query fragment: queryId={},
fragmentId={}", queryId, fragmentId), errorWithCode);
+ LOG.debug(format("Failed to execute query fragment: queryId={},
fragmentId={}", queryId, fragmentId), error);
}
return messageService.send(
@@ -124,32 +125,13 @@ public class ExchangeServiceImpl implements
ExchangeService {
FACTORY.errorMessage()
.queryId(queryId)
.fragmentId(fragmentId)
- .traceId(errorWithCode.traceId())
- .code(errorWithCode.code())
- .message(errorWithCode.getMessage())
+ .traceId(((TraceableException) traceableErr).traceId())
+ .code(((TraceableException) traceableErr).code())
+ .message(traceableErr.getMessage())
.build()
);
}
- // TODO https://issues.apache.org/jira/browse/IGNITE-19539
- private static IgniteException wrapIfNecessary(@NotNull Throwable t) {
- Throwable cause = ExceptionUtils.unwrapCause(t);
-
- if (cause instanceof IgniteException) {
- return cause == t ? (IgniteException) cause :
ExceptionUtils.wrap(t);
- } else if (cause instanceof IgniteInternalException) {
- IgniteInternalException iex = (IgniteInternalException) cause;
-
- return new SqlException(iex.traceId(), iex.code(),
iex.getMessage(), iex);
- } else if (cause instanceof IgniteInternalCheckedException) {
- IgniteInternalCheckedException iex =
(IgniteInternalCheckedException) cause;
-
- return new SqlException(iex.traceId(), iex.code(),
iex.getMessage(), iex);
- } else {
- return new SqlException(INTERNAL_ERR, cause);
- }
- }
-
private void onMessage(String nodeName, QueryBatchRequestMessage msg) {
CompletableFuture<Outbox<?>> outboxFut =
mailboxRegistry.outbox(msg.queryId(), msg.exchangeId());
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImpl.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImpl.java
index 37161f950c..2b7e66ff7b 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImpl.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/ExpressionFactoryImpl.java
@@ -80,6 +80,8 @@ import
org.apache.ignite.internal.sql.engine.type.IgniteTypeFactory;
import org.apache.ignite.internal.sql.engine.util.Commons;
import org.apache.ignite.internal.sql.engine.util.IgniteMethod;
import org.apache.ignite.internal.sql.engine.util.Primitives;
+import org.apache.ignite.lang.ErrorGroups.Sql;
+import org.apache.ignite.sql.SqlException;
import org.jetbrains.annotations.Nullable;
/**
@@ -517,18 +519,25 @@ public class ExpressionFactoryImpl<RowT> implements
ExpressionFactory<RowT> {
assert nodes.size() == projects.size();
+ BlockBuilder tryCatchBlock = new BlockBuilder();
+
for (int i = 0; i < projects.size(); i++) {
Expression val = unspecifiedValues.get(i)
? Expressions.field(null, ExpressionFactoryImpl.class,
"UNSPECIFIED_VALUE_PLACEHOLDER")
: projects.get(i);
- builder.add(
- Expressions.statement(
- Expressions.call(hnd,
- IgniteMethod.ROW_HANDLER_SET.method(),
- Expressions.constant(i), out, val)));
+ tryCatchBlock.add(
+ Expressions.statement(
+ Expressions.call(hnd,
+ IgniteMethod.ROW_HANDLER_SET.method(),
+ Expressions.constant(i), out, val)));
}
+ ParameterExpression ex = Expressions.parameter(0, Exception.class,
"e");
+ Expression sqlException = Expressions.new_(SqlException.class,
Expressions.constant(Sql.RUNTIME_ERR), ex);
+
+ builder.add(Expressions.tryCatch(tryCatchBlock.toBlock(),
Expressions.catch_(ex, Expressions.throw_(sqlException))));
+
String methodName = biInParams ?
IgniteMethod.BI_SCALAR_EXECUTE.method().getName() :
IgniteMethod.SCALAR_EXECUTE.method().getName();
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/RootNode.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/RootNode.java
index ce2dec9e20..1d656f92b9 100644
---
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/RootNode.java
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/RootNode.java
@@ -18,7 +18,6 @@
package org.apache.ignite.internal.sql.engine.exec.rel;
import static org.apache.ignite.internal.util.CollectionUtils.nullOrEmpty;
-import static org.apache.ignite.lang.ErrorGroups.Common.INTERNAL_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.EXECUTION_CANCELLED_ERR;
import com.google.common.base.Functions;
@@ -34,7 +33,7 @@ import java.util.function.Function;
import org.apache.ignite.internal.sql.engine.exec.ExecutionCancelledException;
import org.apache.ignite.internal.sql.engine.exec.ExecutionContext;
import org.apache.ignite.internal.sql.engine.util.Commons;
-import org.apache.ignite.lang.IgniteInternalException;
+import org.apache.ignite.internal.util.ExceptionUtils;
import org.apache.ignite.sql.SqlException;
/**
@@ -284,15 +283,6 @@ public class RootNode<RowT> extends AbstractNode<RowT>
implements SingleNode<Row
return;
}
- if (e instanceof RuntimeException) {
- throw (RuntimeException) e;
- } else {
- throw new IgniteInternalException(INTERNAL_ERR, "An error occurred
while query executing.", e);
- }
- // TODO: rework with SQL error code
- // if (e instanceof IgniteSQLException)
- // throw (IgniteSQLException)e;
- // else
- // throw new IgniteSQLException("An error occurred while
query executing.", IgniteQueryErrorCode.UNKNOWN, e);
+ ExceptionUtils.sneakyThrow(e);
}
}
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 fd58fed92e..0708443984 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
@@ -220,7 +220,6 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
final SqlValidatorTable table =
getCatalogReader().getTable(targetTable.names);
if (table == null) {
- // TODO IGNITE-14865 Calcite exception should be converted/wrapped
into a public ignite exception.
throw newValidationError(call.getTargetTable(),
RESOURCE.objectNotFound(targetTable.toString()));
}
@@ -267,7 +266,6 @@ public class IgniteSqlValidator extends SqlValidatorImpl {
final SqlValidatorTable table =
getCatalogReader().getTable(targetTable.names);
if (table == null) {
- // TODO IGNITE-14865 Calcite exception should be converted/wrapped
into a public ignite exception.
throw newValidationError(targetTable,
RESOURCE.objectNotFound(targetTable.toString()));
}
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 81b58c958f..12ccee6fdd 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
@@ -21,13 +21,13 @@ import static
org.apache.ignite.internal.sql.engine.prepare.CacheKey.EMPTY_CLASS
import static
org.apache.ignite.internal.sql.engine.prepare.PlannerHelper.optimize;
import static
org.apache.ignite.internal.sql.engine.trait.TraitUtils.distributionPresent;
import static org.apache.ignite.lang.ErrorGroups.Sql.PLANNING_TIMEOUT_ERR;
-import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_VALIDATION_ERR;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -35,7 +35,6 @@ import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
-import org.apache.calcite.runtime.CalciteContextException;
import org.apache.calcite.sql.SqlDdl;
import org.apache.calcite.sql.SqlExplain;
import org.apache.calcite.sql.SqlExplainLevel;
@@ -59,7 +58,7 @@ import
org.apache.ignite.internal.sql.metrics.SqlPlanCacheMetricSource;
import org.apache.ignite.internal.storage.DataStorageManager;
import org.apache.ignite.internal.thread.NamedThreadFactory;
import org.apache.ignite.internal.util.ExceptionUtils;
-import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.lang.IgniteExceptionMapperUtil;
import org.apache.ignite.sql.ColumnMetadata;
import org.apache.ignite.sql.ColumnType;
import org.apache.ignite.sql.ResultSetMetadata;
@@ -192,27 +191,23 @@ public class PrepareServiceImpl implements
PrepareService, SchemaUpdateListener
throw new SqlException(PLANNING_TIMEOUT_ERR);
}
- throw new IgniteException(th);
+ throw new
CompletionException(IgniteExceptionMapperUtil.mapToPublicException(th));
}
);
}
private CompletableFuture<QueryPlan> prepareAsync0(ParsedResult
parsedResult, PlanningContext planningContext) {
- try {
- switch (parsedResult.queryType()) {
- case QUERY:
- return prepareQuery(parsedResult, planningContext);
- case DDL:
- return prepareDdl(parsedResult, planningContext);
- case DML:
- return prepareDml(parsedResult, planningContext);
- case EXPLAIN:
- return prepareExplain(parsedResult, planningContext);
- default:
- throw new AssertionError("Unexpected queryType=" +
parsedResult.queryType());
- }
- } catch (CalciteContextException e) {
- throw new SqlException(STMT_VALIDATION_ERR, "Failed to validate
query. " + e.getMessage(), e);
+ switch (parsedResult.queryType()) {
+ case QUERY:
+ return prepareQuery(parsedResult, planningContext);
+ case DDL:
+ return prepareDdl(parsedResult, planningContext);
+ case DML:
+ return prepareDml(parsedResult, planningContext);
+ case EXPLAIN:
+ return prepareExplain(parsedResult, planningContext);
+ default:
+ throw new AssertionError("Unexpected queryType=" +
parsedResult.queryType());
}
}
diff --git
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/SqlExceptionMapperProvider.java
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/SqlExceptionMapperProvider.java
new file mode 100644
index 0000000000..277ac5781a
--- /dev/null
+++
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/SqlExceptionMapperProvider.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.util;
+
+import static org.apache.ignite.lang.ErrorGroups.Sql.SQL_ERR_GROUP;
+import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_VALIDATION_ERR;
+import static org.apache.ignite.lang.IgniteExceptionMapper.unchecked;
+
+import com.google.auto.service.AutoService;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.calcite.runtime.CalciteContextException;
+import org.apache.ignite.internal.sql.engine.exec.ExecutionCancelledException;
+import org.apache.ignite.internal.sql.engine.exec.QueryValidationException;
+import
org.apache.ignite.internal.sql.engine.metadata.RemoteFragmentExecutionException;
+import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.lang.IgniteExceptionMapper;
+import org.apache.ignite.lang.IgniteExceptionMappersProvider;
+import org.apache.ignite.sql.SqlException;
+
+/**
+ * SQL module exception mapper.
+ */
+@AutoService(IgniteExceptionMappersProvider.class)
+public class SqlExceptionMapperProvider implements
IgniteExceptionMappersProvider {
+ @Override
+ public Collection<IgniteExceptionMapper<?, ?>> mappers() {
+ List<IgniteExceptionMapper<?, ?>> mappers = new ArrayList<>();
+
+ mappers.add(unchecked(ExecutionCancelledException.class, err -> new
SqlException(err.traceId(), err.code(), err)));
+
+ mappers.add(unchecked(QueryValidationException.class, err -> new
SqlException(err.traceId(), err.code(), err)));
+
+ mappers.add(unchecked(RemoteFragmentExecutionException.class, err -> {
+ if (err.groupCode() == SQL_ERR_GROUP.groupCode()) {
+ return new SqlException(err.traceId(), err.code(),
err.getMessage(), err);
+ }
+
+ return new IgniteException(err.traceId(), err.code(),
err.getMessage(), err);
+ }));
+
+ mappers.add(unchecked(CalciteContextException.class,
+ err -> new SqlException(STMT_VALIDATION_ERR, "Failed to
validate query. " + err.getMessage(), err)));
+
+ return mappers;
+ }
+}
diff --git
a/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/SqlTestUtils.java
b/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/SqlTestUtils.java
index 1808763a72..36cd0e9ba0 100644
---
a/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/SqlTestUtils.java
+++
b/modules/sql-engine/src/testFixtures/java/org/apache/ignite/internal/sql/engine/util/SqlTestUtils.java
@@ -18,7 +18,9 @@
package org.apache.ignite.internal.sql.engine.util;
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 static org.junit.jupiter.api.Assertions.assertTrue;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -60,6 +62,26 @@ public class SqlTestUtils {
return ex;
}
+ /**
+ * <em>Assert</em> that execution of the supplied {@code executable} throws
+ * an {@link SqlException} with expected error code and message.
+ *
+ * @param expectedCode Expected error code of {@link SqlException}.
+ * @param expectedMessage Expected error message of {@link SqlException}.
+ * @param executable Supplier to execute and check thrown exception.
+ * @return Thrown the {@link SqlException}.
+ */
+ public static SqlException assertThrowsSqlException(int expectedCode,
String expectedMessage, Executable executable) {
+ SqlException ex = assertThrowsSqlException(expectedCode, executable);
+
+ String msg = ex.getMessage();
+
+ assertNotNull(msg, "Error message was null, but expected '" +
expectedMessage + "'.");
+ assertTrue(msg.contains(expectedMessage), "Error message '" +
ex.getMessage() + "' doesn't contain '" + expectedMessage + "'.");
+
+ return ex;
+ }
+
/**
* Convert {@link ColumnType} to string representation of SQL type.
*