You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2022/07/29 13:02:00 UTC
[ignite-3] branch main updated: IGNITE-17433 Fix SQL exceptions when cursor is closed or has no more pages (#958)
This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new b7c793f78 IGNITE-17433 Fix SQL exceptions when cursor is closed or has no more pages (#958)
b7c793f78 is described below
commit b7c793f780968d2e01012544b609b296e684cadf
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Fri Jul 29 16:01:55 2022 +0300
IGNITE-17433 Fix SQL exceptions when cursor is closed or has no more pages (#958)
* Remove internal `SessionNotFoundException` - use the error code for internal logic.
* Move `CursorClosedException` to public API.
* Fix thrown exceptions on server and client.
* Add shared client/server tests to ensure consistent behavior.
---
.../internal/lang/IgniteExceptionUtils.java} | 17 ++++++++---
.../apache/ignite/internal/sql/ResultSetImpl.java | 8 ++----
.../apache/ignite/sql/CursorClosedException.java} | 33 ++++++++++------------
.../ignite/sql/NoRowSetExpectedException.java | 22 +++++++++++----
.../java/org/apache/ignite/sql/SqlException.java | 9 ++++++
.../internal/client/sql/ClientAsyncResultSet.java | 14 ++++-----
.../java/org/apache/ignite/lang/ErrorGroups.java | 3 ++
.../internal/sql/api/ItSqlAsynchronousApiTest.java | 30 ++++++++++++++++----
.../internal/sql/api/ItSqlSynchronousApiTest.java | 27 ++++++++++++++++--
.../internal/sql/api/AsyncResultSetImpl.java | 4 ++-
.../ignite/internal/sql/api/SessionImpl.java | 4 +--
.../ignite/internal/sql/engine/AsyncCursor.java | 2 +-
.../internal/sql/engine/SqlQueryProcessor.java | 5 ++--
.../internal/sql/engine/exec/AsyncWrapper.java | 6 ++--
.../sql/engine/exec/rel/AsyncRootNode.java | 4 +--
.../sql/engine/exec/AsyncWrapperSelfTest.java | 9 +++---
16 files changed, 134 insertions(+), 63 deletions(-)
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/ClosedCursorException.java b/modules/api/src/main/java/org/apache/ignite/internal/lang/IgniteExceptionUtils.java
similarity index 62%
rename from modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/ClosedCursorException.java
rename to modules/api/src/main/java/org/apache/ignite/internal/lang/IgniteExceptionUtils.java
index 97010c2a4..e77cde70a 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/ClosedCursorException.java
+++ b/modules/api/src/main/java/org/apache/ignite/internal/lang/IgniteExceptionUtils.java
@@ -15,12 +15,21 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.sql.engine;
+package org.apache.ignite.internal.lang;
-import org.apache.ignite.lang.IgniteInternalCheckedException;
+import org.apache.ignite.lang.IgniteException;
/**
- * The exception is used to complete result stage of {@link AsyncCursor#requestNextAsync(int)} invocation when invoked on a closed cursor.
+ * Ignite exception utils.
*/
-public class ClosedCursorException extends IgniteInternalCheckedException {
+public final class IgniteExceptionUtils {
+ /**
+ * Gets the Ignite error code if the specified throwable is an {@link IgniteException}.
+ *
+ * @param t Throwable.
+ * @return Ignite error code or null.
+ */
+ public static Integer getIgniteErrorCode(Throwable t) {
+ return (t instanceof IgniteException) ? ((IgniteException) t).code() : null;
+ }
}
diff --git a/modules/api/src/main/java/org/apache/ignite/internal/sql/ResultSetImpl.java b/modules/api/src/main/java/org/apache/ignite/internal/sql/ResultSetImpl.java
index db7e329d5..281ac63ad 100644
--- a/modules/api/src/main/java/org/apache/ignite/internal/sql/ResultSetImpl.java
+++ b/modules/api/src/main/java/org/apache/ignite/internal/sql/ResultSetImpl.java
@@ -17,14 +17,12 @@
package org.apache.ignite.internal.sql;
-import static org.apache.ignite.lang.ErrorGroups.Sql.QUERY_NO_RESULT_SET_ERR;
-
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.CompletionStage;
+import org.apache.ignite.sql.NoRowSetExpectedException;
import org.apache.ignite.sql.ResultSet;
import org.apache.ignite.sql.ResultSetMetadata;
-import org.apache.ignite.sql.SqlException;
import org.apache.ignite.sql.SqlRow;
import org.apache.ignite.sql.async.AsyncResultSet;
import org.jetbrains.annotations.Nullable;
@@ -85,7 +83,7 @@ public class ResultSetImpl implements ResultSet {
@Override
public boolean hasNext() {
if (it == null) {
- throw new SqlException(QUERY_NO_RESULT_SET_ERR, "There are no results");
+ throw new NoRowSetExpectedException();
}
return it.hasNext();
@@ -95,7 +93,7 @@ public class ResultSetImpl implements ResultSet {
@Override
public SqlRow next() {
if (it == null) {
- throw new SqlException(QUERY_NO_RESULT_SET_ERR, "There are no results");
+ throw new NoRowSetExpectedException();
}
return it.next();
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/session/SessionNotFoundException.java b/modules/api/src/main/java/org/apache/ignite/sql/CursorClosedException.java
similarity index 50%
rename from modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/session/SessionNotFoundException.java
rename to modules/api/src/main/java/org/apache/ignite/sql/CursorClosedException.java
index 3f58c0622..8e1e46d84 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/session/SessionNotFoundException.java
+++ b/modules/api/src/main/java/org/apache/ignite/sql/CursorClosedException.java
@@ -15,36 +15,33 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.sql.engine.session;
+package org.apache.ignite.sql;
-import static org.apache.ignite.lang.ErrorGroups.Sql.SESSION_NOT_FOUND_ERR;
-import static org.apache.ignite.lang.IgniteStringFormatter.format;
+import static org.apache.ignite.lang.ErrorGroups.Sql.CURSOR_CLOSED_ERR;
-import org.apache.ignite.sql.SqlException;
+import java.util.UUID;
/**
- * Exception is thrown when someone tries to perform action on behalf of a session that has already expired or never exists.
+ * Exception is thrown when query cursor data fetch attempt is performed on a closed cursor.
*/
-public class SessionNotFoundException extends SqlException {
- private final SessionId sessionId;
-
+public class CursorClosedException extends SqlException {
/**
- * Constructor.
+ * Creates a new exception instance.
*
- * @param sessionId A session id.
*/
- public SessionNotFoundException(SessionId sessionId) {
- super(SESSION_NOT_FOUND_ERR, format("Session not found [{}]", sessionId));
-
- this.sessionId = sessionId;
+ public CursorClosedException() {
+ super(CURSOR_CLOSED_ERR);
}
/**
- * Returns a sessionId of session which was not found.
+ * Creates a new exception with the given trace id, error code, detail message and cause.
*
- * @return A session id.
+ * @param traceId Unique identifier of this exception.
+ * @param code Full error code.
+ * @param message Detail message.
+ * @param cause Optional nested exception (can be {@code null}).
*/
- public SessionId sessionId() {
- return sessionId;
+ public CursorClosedException(UUID traceId, int code, String message, Throwable cause) {
+ super(traceId, code, message, cause);
}
}
diff --git a/modules/api/src/main/java/org/apache/ignite/sql/NoRowSetExpectedException.java b/modules/api/src/main/java/org/apache/ignite/sql/NoRowSetExpectedException.java
index 45bae3236..6813b1281 100644
--- a/modules/api/src/main/java/org/apache/ignite/sql/NoRowSetExpectedException.java
+++ b/modules/api/src/main/java/org/apache/ignite/sql/NoRowSetExpectedException.java
@@ -17,18 +17,30 @@
package org.apache.ignite.sql;
-import org.apache.ignite.lang.IgniteException;
+import static org.apache.ignite.lang.ErrorGroups.Sql.QUERY_NO_RESULT_SET_ERR;
+
+import java.util.UUID;
/**
* Exception is thrown when the query doesn't intend to return any rows. E.g. DML or DDL queries.
*/
-public class NoRowSetExpectedException extends IgniteException {
+public class NoRowSetExpectedException extends SqlException {
/**
* Creates an exception.
+ */
+ public NoRowSetExpectedException() {
+ super(QUERY_NO_RESULT_SET_ERR, "Query has no result set");
+ }
+
+ /**
+ * Creates a new exception with the given trace id, error code, detail message and cause.
*
- * @param msg Message.
+ * @param traceId Unique identifier of this exception.
+ * @param code Full error code.
+ * @param message Detail message.
+ * @param cause Optional nested exception (can be {@code null}).
*/
- public NoRowSetExpectedException(String msg) {
- super(msg);
+ public NoRowSetExpectedException(UUID traceId, int code, String message, Throwable cause) {
+ super(traceId, code, message, cause);
}
}
diff --git a/modules/api/src/main/java/org/apache/ignite/sql/SqlException.java b/modules/api/src/main/java/org/apache/ignite/sql/SqlException.java
index 54016e24d..c28e3a0c3 100644
--- a/modules/api/src/main/java/org/apache/ignite/sql/SqlException.java
+++ b/modules/api/src/main/java/org/apache/ignite/sql/SqlException.java
@@ -24,6 +24,15 @@ import org.apache.ignite.lang.IgniteException;
* SQL exception base class.
*/
public class SqlException extends IgniteException {
+ /**
+ * Creates a new exception with the given error code.
+ *
+ * @param code Full error code.
+ */
+ public SqlException(int code) {
+ super(code);
+ }
+
/**
* Creates a new exception with the given error code and detail message.
*
diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientAsyncResultSet.java b/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientAsyncResultSet.java
index ffcca9bf8..5a1280ee7 100644
--- a/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientAsyncResultSet.java
+++ b/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientAsyncResultSet.java
@@ -17,7 +17,7 @@
package org.apache.ignite.internal.client.sql;
-import static org.apache.ignite.lang.ErrorGroups.Common.UNKNOWN_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.CURSOR_NO_MORE_PAGES_ERR;
import java.time.Duration;
import java.time.Period;
@@ -29,10 +29,11 @@ import java.util.concurrent.CompletionStage;
import org.apache.ignite.internal.client.ClientChannel;
import org.apache.ignite.internal.client.proto.ClientMessageUnpacker;
import org.apache.ignite.internal.client.proto.ClientOp;
-import org.apache.ignite.lang.IgniteException;
+import org.apache.ignite.sql.CursorClosedException;
import org.apache.ignite.sql.NoRowSetExpectedException;
import org.apache.ignite.sql.ResultSetMetadata;
import org.apache.ignite.sql.SqlColumnType;
+import org.apache.ignite.sql.SqlException;
import org.apache.ignite.sql.SqlRow;
import org.apache.ignite.sql.async.AsyncResultSet;
import org.jetbrains.annotations.Nullable;
@@ -136,13 +137,12 @@ class ClientAsyncResultSet implements AsyncResultSet {
requireResultSet();
if (closed) {
- // TODO IGNITE-17135 - same error code and message as on server.
- return CompletableFuture.failedFuture(new IgniteException(UNKNOWN_ERR, "Cursor is closed."));
+ return CompletableFuture.failedFuture(new CursorClosedException());
}
if (!hasMorePages()) {
- // TODO IGNITE-17135 - same error code and message as on server.
- return CompletableFuture.failedFuture(new IgniteException(UNKNOWN_ERR, "No more pages."));
+ return CompletableFuture.failedFuture(
+ new SqlException(CURSOR_NO_MORE_PAGES_ERR, "There are no more pages."));
}
return ch.serviceAsync(
@@ -181,7 +181,7 @@ class ClientAsyncResultSet implements AsyncResultSet {
private void requireResultSet() {
if (!hasRowSet()) {
- throw new NoRowSetExpectedException("Query has no result set");
+ throw new NoRowSetExpectedException();
}
}
diff --git a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
index 0bd9277e2..ab765cbd1 100755
--- a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
+++ b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
@@ -104,5 +104,8 @@ public class ErrorGroups {
/** Storage engine not valid. */
public static final int STORAGE_ENGINE_NOT_VALID_ERR = SQL_ERR_GROUP.registerErrorCode(8);
+
+ /** Cursor is already closed error. */
+ public static final int CURSOR_CLOSED_ERR = SQL_ERR_GROUP.registerErrorCode(9);
}
}
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 05970d5a3..2f3a7b002 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
@@ -49,7 +49,6 @@ import org.apache.ignite.internal.app.IgniteImpl;
import org.apache.ignite.internal.client.sql.ClientSql;
import org.apache.ignite.internal.sql.api.ColumnMetadataImpl.ColumnOriginImpl;
import org.apache.ignite.internal.sql.engine.AbstractBasicIntegrationTest;
-import org.apache.ignite.internal.sql.engine.ClosedCursorException;
import org.apache.ignite.internal.testframework.IgniteTestUtils;
import org.apache.ignite.internal.tx.TxManager;
import org.apache.ignite.internal.tx.TxState;
@@ -64,7 +63,9 @@ import org.apache.ignite.lang.TableAlreadyExistsException;
import org.apache.ignite.lang.TableNotFoundException;
import org.apache.ignite.sql.BatchedArguments;
import org.apache.ignite.sql.ColumnMetadata;
+import org.apache.ignite.sql.CursorClosedException;
import org.apache.ignite.sql.IgniteSql;
+import org.apache.ignite.sql.NoRowSetExpectedException;
import org.apache.ignite.sql.ResultSetMetadata;
import org.apache.ignite.sql.Session;
import org.apache.ignite.sql.SqlBatchException;
@@ -461,6 +462,11 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
@Test
public void errors() {
+ sql("CREATE TABLE TEST(ID INT PRIMARY KEY, VAL0 INT)");
+ for (int i = 0; i < ROW_COUNT; ++i) {
+ sql("INSERT INTO TEST VALUES (?, ?)", i, i);
+ }
+
IgniteSql sql = igniteSql();
Session ses = sql.sessionBuilder().defaultPageSize(ROW_COUNT / 2).build();
@@ -478,8 +484,8 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
// Planning error.
{
- CompletableFuture<AsyncResultSet> f = ses.executeAsync(null, "CREATE TABLE TEST (VAL INT)");
- assertThrowsWithCause(f::get, IgniteException.class, "Table without PRIMARY KEY is not supported");
+ CompletableFuture<AsyncResultSet> f = ses.executeAsync(null, "CREATE TABLE TEST2 (VAL INT)");
+ assertThrowsWithCause(f::get, SqlException.class, "Table without PRIMARY KEY is not supported");
}
// Execute error.
@@ -487,6 +493,20 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
CompletableFuture<AsyncResultSet> f = ses.executeAsync(null, "SELECT 1 / ?", 0);
assertThrowsWithCause(f::get, IgniteException.class, "/ by zero");
}
+
+ // No result set error.
+ {
+ AsyncResultSet ars = ses.executeAsync(null, "CREATE TABLE TEST3 (ID INT PRIMARY KEY)").join();
+ assertThrowsWithCause(() -> ars.fetchNextPage().toCompletableFuture().get(), NoRowSetExpectedException.class,
+ "Query has no result set");
+ }
+
+ // Cursor closed error.
+ {
+ AsyncResultSet ars = ses.executeAsync(null, "SELECT * FROM TEST").join();
+ ars.closeAsync().toCompletableFuture().join();
+ assertThrowsWithCause(() -> ars.fetchNextPage().toCompletableFuture().get(), CursorClosedException.class);
+ }
}
@Test
@@ -503,12 +523,12 @@ public class ItSqlAsynchronousApiTest extends AbstractBasicIntegrationTest {
ses.closeAsync().get();
- // Fetched page is available after cancel.
+ // Fetched page is available after cancel.
ars0.currentPage();
assertThrowsWithCause(
() -> ars0.fetchNextPage().toCompletableFuture().get(),
- ClosedCursorException.class
+ SqlException.class
);
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 91955b850..d9ce59d95 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
@@ -48,7 +48,9 @@ import org.apache.ignite.lang.IndexAlreadyExistsException;
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;
import org.apache.ignite.sql.Session;
import org.apache.ignite.sql.SqlBatchException;
@@ -211,9 +213,14 @@ public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
}
@Test
- public void errors() {
+ public void errors() throws InterruptedException {
+ sql("CREATE TABLE TEST(ID INT PRIMARY KEY, VAL0 INT)");
+ for (int i = 0; i < ROW_COUNT; ++i) {
+ sql("INSERT INTO TEST VALUES (?, ?)", i, i);
+ }
+
IgniteSql sql = igniteSql();
- Session ses = sql.sessionBuilder().defaultPageSize(ROW_COUNT / 2).build();
+ Session ses = sql.sessionBuilder().defaultPageSize(2).build();
// Parse error.
assertThrowsWithCause(
@@ -231,7 +238,7 @@ public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
// Planning error.
assertThrowsWithCause(
- () -> ses.execute(null, "CREATE TABLE TEST (VAL INT)"),
+ () -> ses.execute(null, "CREATE TABLE TEST2 (VAL INT)"),
SqlException.class,
"Table without PRIMARY KEY is not supported"
);
@@ -242,6 +249,20 @@ public class ItSqlSynchronousApiTest extends AbstractBasicIntegrationTest {
IgniteException.class,
"/ by zero"
);
+
+ // 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");
+ }
+
+ // 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);
+ }
}
@Test
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/AsyncResultSetImpl.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/AsyncResultSetImpl.java
index 3f1acfd9f..ce2e0fcc6 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/AsyncResultSetImpl.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/AsyncResultSetImpl.java
@@ -134,6 +134,8 @@ public class AsyncResultSetImpl implements AsyncResultSet {
/** {@inheritDoc} */
@Override
public CompletionStage<? extends AsyncResultSet> fetchNextPage() {
+ requireResultSet();
+
if (!hasMorePages()) {
return HAS_NO_MORE_PAGE_FUTURE;
} else {
@@ -160,7 +162,7 @@ public class AsyncResultSetImpl implements AsyncResultSet {
private void requireResultSet() {
if (!hasRowSet()) {
- throw new NoRowSetExpectedException("Query has no result set: [type=" + cur.queryType() + ']');
+ throw new NoRowSetExpectedException();
}
}
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 9cbbd0428..b0ef5cd22 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
@@ -32,6 +32,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Flow.Publisher;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.ignite.internal.lang.IgniteExceptionUtils;
import org.apache.ignite.internal.sql.engine.AsyncCursor;
import org.apache.ignite.internal.sql.engine.QueryContext;
import org.apache.ignite.internal.sql.engine.QueryProcessor;
@@ -40,7 +41,6 @@ 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.property.PropertiesHolder;
import org.apache.ignite.internal.sql.engine.session.SessionId;
-import org.apache.ignite.internal.sql.engine.session.SessionNotFoundException;
import org.apache.ignite.internal.util.ArrayUtils;
import org.apache.ignite.internal.util.ExceptionUtils;
import org.apache.ignite.internal.util.IgniteSpinBusyLock;
@@ -163,7 +163,7 @@ public class SessionImpl implements Session {
);
result.whenComplete((rs, th) -> {
- if (th instanceof SessionNotFoundException) {
+ if (IgniteExceptionUtils.getIgniteErrorCode(th) == SESSION_NOT_FOUND_ERR) {
closeInternal();
}
});
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/AsyncCursor.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/AsyncCursor.java
index fdeadf2dd..41bdb057f 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/AsyncCursor.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/AsyncCursor.java
@@ -32,7 +32,7 @@ public interface AsyncCursor<T> {
*
* <p>Several calls to this method should be chained and resulting stages should be completed in the order of invocation. Any call
* to this method after call to {@link #closeAsync()} should be completed immediately with
- * {@link org.apache.ignite.internal.sql.engine.ClosedCursorException} even if the future returned by {@link #closeAsync()}
+ * {@link org.apache.ignite.sql.CursorClosedException} even if the future returned by {@link #closeAsync()}
* is not completed yet.
*
* @param rows Desired amount of rows.
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 7de73d005..1e81423c7 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
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.sql.engine;
import static org.apache.ignite.internal.sql.engine.util.Commons.FRAMEWORK_CONFIG;
import static org.apache.ignite.lang.ErrorGroups.Sql.QUERY_INVALID_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Sql.SESSION_NOT_FOUND_ERR;
import static org.apache.ignite.lang.IgniteStringFormatter.format;
import java.util.ArrayList;
@@ -59,7 +60,6 @@ import org.apache.ignite.internal.sql.engine.schema.SqlSchemaManager;
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.SessionManager;
-import org.apache.ignite.internal.sql.engine.session.SessionNotFoundException;
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;
@@ -292,7 +292,8 @@ public class SqlQueryProcessor implements QueryProcessor {
var session = sessionManager.session(sessionId);
if (session == null) {
- return CompletableFuture.failedFuture(new SessionNotFoundException(sessionId));
+ return CompletableFuture.failedFuture(
+ new SqlException(SESSION_NOT_FOUND_ERR, format("Session not found [{}]", sessionId)));
}
var schemaName = session.queryProperties().get(QueryProperty.DEFAULT_SCHEMA);
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/AsyncWrapper.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/AsyncWrapper.java
index fa9a23a68..7e9918f26 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/AsyncWrapper.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/AsyncWrapper.java
@@ -26,7 +26,7 @@ import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.Function;
import org.apache.ignite.internal.sql.engine.AsyncCursor;
-import org.apache.ignite.internal.sql.engine.ClosedCursorException;
+import org.apache.ignite.sql.CursorClosedException;
/**
* Wrapper that converts a synchronous iterator to an asynchronous one.
@@ -82,7 +82,7 @@ public class AsyncWrapper<T> implements AsyncCursor<T> {
synchronized (lock) {
if (cancelled) {
- next.completeExceptionally(new ClosedCursorException());
+ next.completeExceptionally(new CursorClosedException());
return next;
}
@@ -124,7 +124,7 @@ public class AsyncWrapper<T> implements AsyncCursor<T> {
if (!cancelled) {
synchronized (lock) {
if (!cancelled) {
- requestChainTail.completeExceptionally(new ClosedCursorException());
+ requestChainTail.completeExceptionally(new CursorClosedException());
cursorFut.thenAcceptAsync(cursor -> {
if (cursor instanceof AutoCloseable) {
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/AsyncRootNode.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/AsyncRootNode.java
index 56663fa0f..5a2c4744b 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/AsyncRootNode.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/rel/AsyncRootNode.java
@@ -27,8 +27,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import org.apache.ignite.internal.sql.engine.AsyncCursor;
-import org.apache.ignite.internal.sql.engine.ClosedCursorException;
import org.apache.ignite.internal.sql.engine.exec.ExecutionCancelledException;
+import org.apache.ignite.sql.CursorClosedException;
import org.jetbrains.annotations.Nullable;
/**
@@ -164,7 +164,7 @@ public class AsyncRootNode<InRowT, OutRowT> implements Downstream<InRowT>, Async
synchronized (lock) {
if (closed) {
- next.completeExceptionally(new ClosedCursorException());
+ next.completeExceptionally(new CursorClosedException());
return next;
}
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/AsyncWrapperSelfTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/AsyncWrapperSelfTest.java
index f44e718a3..ec75cec3f 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/AsyncWrapperSelfTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/AsyncWrapperSelfTest.java
@@ -33,7 +33,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ForkJoinPool;
import org.apache.ignite.internal.sql.engine.AsyncCursor;
-import org.apache.ignite.internal.sql.engine.ClosedCursorException;
+import org.apache.ignite.sql.SqlException;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -99,7 +99,6 @@ public class AsyncWrapperSelfTest {
* Call to {@link AsyncCursor#closeAsync()} should be passed to delegate in case the latter implements {@link AutoCloseable}.
*/
@Test
- @SuppressWarnings("unchecked")
public void testClosePropagatedToDelegate() throws Exception {
var mockIt = (ClosableIterator<Object>) Mockito.mock(ClosableIterator.class);
var cursor = new AsyncWrapper<>(mockIt);
@@ -153,14 +152,14 @@ public class AsyncWrapperSelfTest {
.thenAccept(batch -> assertThat(batch.items(), equalTo(data.subList(0, 1))))
.exceptionally(ex -> {
assertInstanceOf(CompletionException.class, ex);
- assertInstanceOf(ClosedCursorException.class, ex.getCause());
+ assertInstanceOf(SqlException.class, ex.getCause());
return null;
});
var stage2 = cursor.closeAsync();
var stage3 = cursor.requestNextAsync(1)
.exceptionally(ex -> {
- assertInstanceOf(ClosedCursorException.class, ex);
+ assertInstanceOf(SqlException.class, ex);
return null;
});
@@ -187,4 +186,4 @@ public class AsyncWrapperSelfTest {
private interface ClosableIterator<T> extends Iterator<T>, AutoCloseable {
}
-}
\ No newline at end of file
+}