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";