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

caicancai pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite-avatica.git


The following commit(s) were added to refs/heads/main by this push:
     new 9efbff828 [CALCITE-6781] The isUpdateCapable method of calcite.avatica 
will incorrectly traverse the returned result value
9efbff828 is described below

commit 9efbff828397c7cfb9a5885aa06d94da8d2262dc
Author: cc.cai <[email protected]>
AuthorDate: Fri Mar 27 22:38:21 2026 +0800

    [CALCITE-6781] The isUpdateCapable method of calcite.avatica will 
incorrectly traverse the returned result value
---
 .../apache/calcite/avatica/AvaticaConnection.java  | 23 +++++------
 .../calcite/avatica/AvaticaConnectionTest.java     | 46 ++++++++++++++++++++++
 2 files changed, 58 insertions(+), 11 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java 
b/core/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
index f740d85ff..bb067a6f7 100644
--- a/core/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
+++ b/core/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
@@ -614,18 +614,19 @@ private void isUpdateCapable(final AvaticaStatement 
statement)
       return;
     }
     if (signature.statementType.canUpdate() && statement.updateCount == -1) {
-      statement.openResultSet.next();
-      Object obj = statement.openResultSet.getObject(ROWCOUNT_COLUMN_NAME);
-      if (obj instanceof Number) {
-        statement.updateCount = ((Number) obj).intValue();
-      } else if (obj instanceof List) {
-        @SuppressWarnings("unchecked")
-        final List<Number> numbers = (List<Number>) obj;
-        statement.updateCount = numbers.get(0).intValue();
-      } else {
-        throw HELPER.createException("Not a valid return result.");
+      if (statement.openResultSet.next()) {
+        Object obj = statement.openResultSet.getObject(ROWCOUNT_COLUMN_NAME);
+        if (obj instanceof Number) {
+          statement.updateCount = ((Number) obj).intValue();
+        } else if (obj instanceof List) {
+          @SuppressWarnings("unchecked")
+          final List<Number> numbers = (List<Number>) obj;
+          statement.updateCount = numbers.get(0).intValue();
+        } else {
+          throw HELPER.createException("Not a valid return result.");
+        }
+        statement.openResultSet = null;
       }
-      statement.openResultSet = null;
     }
   }
 
diff --git 
a/core/src/test/java/org/apache/calcite/avatica/AvaticaConnectionTest.java 
b/core/src/test/java/org/apache/calcite/avatica/AvaticaConnectionTest.java
index 9482eba2a..463711a10 100644
--- a/core/src/test/java/org/apache/calcite/avatica/AvaticaConnectionTest.java
+++ b/core/src/test/java/org/apache/calcite/avatica/AvaticaConnectionTest.java
@@ -20,7 +20,10 @@
 import org.junit.Test;
 import org.mockito.Mockito;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.sql.SQLException;
+import java.util.Collections;
 import java.util.Properties;
 
 /**
@@ -71,6 +74,49 @@ public void testNumExecuteRetries() {
     Assert.assertEquals(10, connection.getNumStatementRetries(props));
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6781";>[CALCITE-6781]
+   * The isUpdateCapable method of calcite.avatica will incorrectly traverse
+   * the returned result value</a>.
+   */
+  @Test
+  public void testIsUpdateCapableSkipsRowCountWhenResultSetHasNoRows() throws 
Exception {
+    AvaticaConnection connection = Mockito.mock(
+        AvaticaConnection.class, Mockito.CALLS_REAL_METHODS);
+    AvaticaStatement statement = Mockito.mock(AvaticaStatement.class);
+    AvaticaResultSet resultSet = Mockito.mock(AvaticaResultSet.class);
+
+    Meta.Signature signature = new 
Meta.Signature(Collections.<ColumnMetaData>emptyList(), null,
+        Collections.<AvaticaParameter>emptyList(), Collections.<String, 
Object>emptyMap(), null,
+        Meta.StatementType.INSERT);
+
+    Mockito.when(statement.getSignature()).thenReturn(signature);
+    Mockito.when(resultSet.next()).thenReturn(false);
+    statement.updateCount = -1;
+    statement.openResultSet = resultSet;
+
+    invokeIsUpdateCapable(connection, statement);
+
+    Assert.assertEquals(-1, statement.updateCount);
+    Assert.assertSame(resultSet, statement.openResultSet);
+    Mockito.verify(resultSet, 
Mockito.never()).getObject(AvaticaConnection.ROWCOUNT_COLUMN_NAME);
+  }
+
+  private static void invokeIsUpdateCapable(
+      AvaticaConnection connection, AvaticaStatement statement) throws 
Exception {
+    Method method = AvaticaConnection.class
+        .getDeclaredMethod("isUpdateCapable", AvaticaStatement.class);
+    method.setAccessible(true);
+    try {
+      method.invoke(connection, statement);
+    } catch (InvocationTargetException e) {
+      if (e.getCause() instanceof SQLException) {
+        throw (SQLException) e.getCause();
+      }
+      throw e;
+    }
+  }
+
 }
 
 // End AvaticaConnectionTest.java

Reply via email to