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

lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-java.git


The following commit(s) were added to refs/heads/main by this push:
     new 156b465f GH-797: [JDBC] Fix PreparedStatement#execute for DML/DDL 
(#811)
156b465f is described below

commit 156b465f7836dec3c3a109dbc101ee7270009ff7
Author: Pedro Matias <[email protected]>
AuthorDate: Wed Aug 20 11:36:12 2025 +0100

    GH-797: [JDBC] Fix PreparedStatement#execute for DML/DDL (#811)
    
    ## What's Changed
    
    Instead of always obtaining a result set for queries issued via
    PreparedStatement.execute(), we now inspect the dataset_schema
    returned in ActionCreatePreparedStatementResult. If the schema has no
    fields, we retrieve the update count instead. This aligns the return
    value with the expectations of the JDBC API.
    
    For such cases, the Arrow Flight SQL path now uses
    CommandPreparedStatementUpdate instead of
    CommandPreparedStatementQuery. This change mirrors the existing
    approach in Statement.execute() and Statement.executeUpdate().
    
    ### Are these changes tested?
    
    Yes
    
    Closes #797.
---
 .../arrow/driver/jdbc/ArrowFlightMetaImpl.java     | 10 +++++---
 .../jdbc/ArrowFlightPreparedStatementTest.java     | 29 ++++++++++++++++++++++
 2 files changed, 36 insertions(+), 3 deletions(-)

diff --git 
a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightMetaImpl.java
 
b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightMetaImpl.java
index 9c7112f1..21cc3e43 100644
--- 
a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightMetaImpl.java
+++ 
b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightMetaImpl.java
@@ -62,14 +62,17 @@ public class ArrowFlightMetaImpl extends MetaImpl {
         parameterSchema == null
             ? new ArrayList<>()
             : 
ConvertUtils.convertArrowFieldsToAvaticaParameters(parameterSchema.getFields());
-
+    StatementType statementType =
+        resultSetSchema == null || resultSetSchema.getFields().isEmpty()
+            ? StatementType.IS_DML
+            : StatementType.SELECT;
     return new Signature(
         columnMetaData,
         sql,
         parameters,
         Collections.emptyMap(),
         null, // unnecessary, as SQL requests use ArrowFlightJdbcCursor
-        StatementType.SELECT);
+        statementType);
   }
 
   @Override
@@ -105,7 +108,8 @@ public class ArrowFlightMetaImpl extends MetaImpl {
             preparedStatement, ((ArrowFlightConnection) 
connection).getBufferAllocator())
         .bind(typedValues);
 
-    if (statementHandle.signature == null) {
+    if (statementHandle.signature == null
+        || statementHandle.signature.statementType == StatementType.IS_DML) {
       // Update query
       long updatedCount = preparedStatement.executeUpdate();
       return new ExecuteResult(
diff --git 
a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightPreparedStatementTest.java
 
b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightPreparedStatementTest.java
index 774ad008..0369c3a1 100644
--- 
a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightPreparedStatementTest.java
+++ 
b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightPreparedStatementTest.java
@@ -20,6 +20,8 @@ import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertAll;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.nio.charset.StandardCharsets;
 import java.sql.Connection;
@@ -83,6 +85,19 @@ public class ArrowFlightPreparedStatementTest {
     }
   }
 
+  @Test
+  public void testSimpleQueryNoParameterBindingWithExecute() throws 
SQLException {
+    final String query = CoreMockedSqlProducers.LEGACY_REGULAR_SQL_CMD;
+    try (final PreparedStatement preparedStatement = 
connection.prepareStatement(query)) {
+      boolean isResultSet = preparedStatement.execute();
+      assertTrue(isResultSet);
+      final ResultSet resultSet = preparedStatement.getResultSet();
+      CoreMockedSqlProducers.assertLegacyRegularSqlResultSet(resultSet);
+      assertFalse(preparedStatement.getMoreResults());
+      assertEquals(-1, preparedStatement.getUpdateCount());
+    }
+  }
+
   @Test
   public void testQueryWithParameterBinding() throws SQLException {
     final String query = "Fake query with parameters";
@@ -174,6 +189,20 @@ public class ArrowFlightPreparedStatementTest {
     }
   }
 
+  @Test
+  public void testUpdateQueryWithExecute() throws SQLException {
+    String query = "Fake update with execute";
+    PRODUCER.addUpdateQuery(query, /*updatedRows*/ 42);
+    try (final PreparedStatement stmt = connection.prepareStatement(query)) {
+      boolean isResultSet = stmt.execute();
+      assertFalse(isResultSet);
+      int updated = stmt.getUpdateCount();
+      assertEquals(42, updated);
+      assertFalse(stmt.getMoreResults());
+      assertEquals(-1, stmt.getUpdateCount());
+    }
+  }
+
   @Test
   public void testUpdateQueryWithParameters() throws SQLException {
     String query = "Fake update with parameters";

Reply via email to