You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ko...@apache.org on 2026/02/05 10:13:05 UTC

(ignite-3) branch main updated: IGNITE-27679 Sql. SelectCount plan is affected by consequent DML in script (#7524)

This is an automated email from the ASF dual-hosted git repository.

korlov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 7fc53f029ba IGNITE-27679 Sql. SelectCount plan is affected by consequent DML in script (#7524)
7fc53f029ba is described below

commit 7fc53f029ba3dba1018737324c0d3c196b799284
Author: korlov42 <ko...@apache.org>
AuthorDate: Thu Feb 5 12:12:59 2026 +0200

    IGNITE-27679 Sql. SelectCount plan is affected by consequent DML in script (#7524)
---
 .../internal/sql/engine/prepare/SelectCountPlan.java     | 16 ++++++++++++++++
 .../internal/sql/engine/exec/QueryTimeoutTest.java       | 12 ++++--------
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/SelectCountPlan.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/SelectCountPlan.java
index f8014499598..e25bc847810 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/SelectCountPlan.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/SelectCountPlan.java
@@ -161,6 +161,22 @@ public class SelectCountPlan implements ExplainablePlan, ExecutablePlan {
         return 1;
     }
 
+    @Override
+    public boolean lazyCursorPublication() {
+        // Fast SelectCount does not support transactions; therefore, when running concurrently with DML
+        // statements, it may return a non-transactionally-consistent result. For example, if a table is
+        // empty and two statements are executed in parallel -- one inserting 1,000 rows and another executing
+        // `SELECT count(*) FROM table` -- SelectCount may return any number in the range [0, 1000].
+        // This is not considered a problem when SelectCount runs independently (it is considered
+        // eventually consistent), but such behavior contradicts another guarantee we want to preserve:
+        // within a script, statements are executed sequentially, one after another.
+        //
+        // Lazy publication allows a race in which a subsequent DML statement can outrun the execution of
+        // the SelectCount plan, resulting in a situation where the SelectCount result includes changes
+        // made by that DML statement.
+        return false;
+    }
+
     private <RowT> Function<Long, Iterator<InternalSqlRow>> createResultProjection(ExecutionContext<RowT> ctx) {
         RelDataType getCountType = new RelDataTypeFactory.Builder(ctx.getTypeFactory())
                 .add("ROWCOUNT", SqlTypeName.BIGINT)
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/QueryTimeoutTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/QueryTimeoutTest.java
index 8a0c4979f27..11f262bcbaf 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/QueryTimeoutTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/QueryTimeoutTest.java
@@ -134,14 +134,10 @@ public class QueryTimeoutTest extends BaseIgniteAbstractTest {
 
     @Test
     void testTimeoutSelectCount() {
-        AsyncSqlCursor<?> cursor = gatewayNode.executeQuery(PROPS_WITH_TIMEOUT, "SELECT COUNT(*) FROM my_table");
-
-        assertThat(
-                cursor.requestNextAsync(1),
-                willThrowWithCauseOrSuppressed(
-                        QueryCancelledException.class,
-                        QueryCancelledException.TIMEOUT_MSG
-                )
+        assertThrows(
+                SqlException.class,
+                () -> gatewayNode.executeQuery(PROPS_WITH_TIMEOUT, "SELECT COUNT(*) FROM my_table"),
+                QueryCancelledException.TIMEOUT_MSG
         );
     }