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-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new 6f5b5fc56 feat(java/driver/jni): wire up cancel, getParameterSchema
(#4249)
6f5b5fc56 is described below
commit 6f5b5fc5691f57a8e0e546b68194c99dc82ffb50
Author: David Li <[email protected]>
AuthorDate: Mon Apr 27 09:50:54 2026 +0900
feat(java/driver/jni): wire up cancel, getParameterSchema (#4249)
Closes #4239.
---
.../org/apache/arrow/adbc/core/AdbcConnection.java | 2 +-
.../adbc/driver/jni/PostgresIntegrationTest.java | 37 +++++++++++++++++++-
.../adbc/driver/jni/SqlServerIntegrationTest.java | 37 +++++++++++++++++++-
java/driver/jni/src/main/cpp/jni_wrapper.cc | 39 ++++++++++++++++++++++
.../arrow/adbc/driver/jni/JniConnection.java | 5 +++
.../apache/arrow/adbc/driver/jni/JniStatement.java | 12 ++++++-
.../arrow/adbc/driver/jni/impl/JniLoader.java | 13 ++++++++
.../arrow/adbc/driver/jni/impl/NativeAdbc.java | 15 ++++++---
8 files changed, 152 insertions(+), 8 deletions(-)
diff --git
a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java
b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java
index 060c65e81..0b39a3d6a 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java
@@ -40,7 +40,7 @@ public interface AdbcConnection extends AutoCloseable,
AdbcOptions {
* @since ADBC API revision 1.1.0
*/
default void cancel() throws AdbcException {
- throw AdbcException.notImplemented("Statement does not support cancel");
+ throw AdbcException.notImplemented("Connection does not support cancel");
}
/** Commit the pending transaction. */
diff --git
a/java/driver/jni-validation/src/test/java/org/apache/arrow/adbc/driver/jni/PostgresIntegrationTest.java
b/java/driver/jni-validation/src/test/java/org/apache/arrow/adbc/driver/jni/PostgresIntegrationTest.java
index b805a420d..125644041 100644
---
a/java/driver/jni-validation/src/test/java/org/apache/arrow/adbc/driver/jni/PostgresIntegrationTest.java
+++
b/java/driver/jni-validation/src/test/java/org/apache/arrow/adbc/driver/jni/PostgresIntegrationTest.java
@@ -316,8 +316,43 @@ class PostgresIntegrationTest {
assertThat(result.getReader().loadNextBatch()).isTrue();
assertThat(result.getReader().loadNextBatch()).isFalse();
}
+
+ assertThat(stmt.getParameterSchema().getFields()).isEmpty();
}
- // TODO(https://github.com/apache/arrow-adbc/issues/4239): test get
parameter schema
+
+ try (var stmt = conn.createStatement()) {
+ stmt.setSqlQuery("SELECT $1 || 'foo'");
+ assertSchema(stmt.getParameterSchema())
+ .isEqualTo(new Schema(List.of(Field.nullable("$1",
Types.MinorType.VARCHAR.getType()))));
+ }
+ }
+
+ @Test
+ void cancelQuery() throws Exception {
+ // There's nothing really we can test reliably; it is wired up but we'd
need a long-running
+ // query and a reliable way to start the cancel at the right time
+ Schema schema = new Schema(List.of(Field.nullable("$1",
Types.MinorType.VARCHAR.getType())));
+ try (var stmt = conn.createStatement();
+ var vsr = VectorSchemaRoot.create(schema, allocator)) {
+ var vcv = (VarCharVector) vsr.getVector(0);
+ vcv.setSafe(0, "test".getBytes(StandardCharsets.UTF_8));
+ vcv.setSafe(1, "bar".getBytes(StandardCharsets.UTF_8));
+
+ stmt.setSqlQuery("SELECT CAST($1 AS VARCHAR) || 'foo'");
+ stmt.bind(vsr);
+
+ try (AdbcStatement.QueryResult result = stmt.executeQuery()) {
+ stmt.cancel();
+ //noinspection StatementWithEmptyBody
+ while (result.getReader().loadNextBatch()) {}
+ }
+ }
+ }
+
+ @Test
+ void cancelConnection() throws Exception {
+ // There's nothing really we can test reliably
+ conn.cancel();
}
@Test
diff --git
a/java/driver/jni-validation/src/test/java/org/apache/arrow/adbc/driver/jni/SqlServerIntegrationTest.java
b/java/driver/jni-validation/src/test/java/org/apache/arrow/adbc/driver/jni/SqlServerIntegrationTest.java
index 8a6737816..0b4bfd452 100644
---
a/java/driver/jni-validation/src/test/java/org/apache/arrow/adbc/driver/jni/SqlServerIntegrationTest.java
+++
b/java/driver/jni-validation/src/test/java/org/apache/arrow/adbc/driver/jni/SqlServerIntegrationTest.java
@@ -322,8 +322,43 @@ class SqlServerIntegrationTest {
assertThat(result.getReader().loadNextBatch()).isTrue();
assertThat(result.getReader().loadNextBatch()).isFalse();
}
+
+ assertThat(stmt.getParameterSchema().getFields()).isEmpty();
}
- // TODO(https://github.com/apache/arrow-adbc/issues/4239): test get
parameter schema
+
+ try (var stmt = conn.createStatement()) {
+ stmt.setSqlQuery("SELECT CONCAT(CAST(@p1 AS NVARCHAR), 'foo')");
+ assertSchema(stmt.getParameterSchema())
+ .isEqualTo(new Schema(List.of(Field.nullable("@p1",
Types.MinorType.VARCHAR.getType()))));
+ }
+ }
+
+ @Test
+ void cancelQuery() throws Exception {
+ // There's nothing really we can test reliably (MSSQL driver doesn't react
to cancel)
+ Schema schema = new Schema(List.of(Field.nullable("$1",
Types.MinorType.VARCHAR.getType())));
+ try (var stmt = conn.createStatement();
+ var vsr = VectorSchemaRoot.create(schema, allocator)) {
+ var vcv = (VarCharVector) vsr.getVector(0);
+ vcv.setSafe(0, "test".getBytes(StandardCharsets.UTF_8));
+ vcv.setSafe(1, "bar".getBytes(StandardCharsets.UTF_8));
+
+ stmt.setSqlQuery("SELECT CAST(@p1 AS NVARCHAR) || 'foo'");
+ stmt.bind(vsr);
+
+ // N.B. the MSSQL driver doesn't appear to react
+ try (AdbcStatement.QueryResult result = stmt.executeQuery()) {
+ stmt.cancel();
+ //noinspection StatementWithEmptyBody
+ while (result.getReader().loadNextBatch()) {}
+ }
+ }
+ }
+
+ @Test
+ void cancelConnection() throws Exception {
+ // There's nothing really we can test reliably
+ conn.cancel();
}
@Test
diff --git a/java/driver/jni/src/main/cpp/jni_wrapper.cc
b/java/driver/jni/src/main/cpp/jni_wrapper.cc
index a830e7304..0cb128f84 100644
--- a/java/driver/jni/src/main/cpp/jni_wrapper.cc
+++ b/java/driver/jni/src/main/cpp/jni_wrapper.cc
@@ -353,6 +353,33 @@ jobject MakeNativeSchemaResult(JNIEnv* env, struct
ArrowSchema* schema) {
static_cast<jlong>(reinterpret_cast<uintptr_t>(schema)));
}
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementCancel(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* ptr = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
+ try {
+ CHECK_ADBC_ERROR(AdbcStatementCancel(ptr, &error), error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetParameterSchema(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* ptr = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
+ struct ArrowSchema schema = {};
+ try {
+ CHECK_ADBC_ERROR(AdbcStatementGetParameterSchema(ptr, &schema, &error),
error);
+ return MakeNativeSchemaResult(env, &schema);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+ return nullptr;
+}
+
JNIEXPORT jobject JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementExecuteQuery(
JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
@@ -621,6 +648,18 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionString(
}
}
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionCancel(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* ptr = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
+ try {
+ CHECK_ADBC_ERROR(AdbcConnectionCancel(ptr, &error), error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
JNIEXPORT jobject JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetObjects(
JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jint depth,
jstring catalog,
diff --git
a/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniConnection.java
b/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniConnection.java
index 563420fa3..ebfd75957 100644
---
a/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniConnection.java
+++
b/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniConnection.java
@@ -45,6 +45,11 @@ public class JniConnection implements AdbcConnection {
return new JniStatement(allocator,
JniLoader.INSTANCE.openStatement(handle));
}
+ @Override
+ public void cancel() throws AdbcException {
+ JniLoader.INSTANCE.connectionCancel(handle);
+ }
+
@Override
public AdbcStatement bulkIngest(String targetTableName, BulkIngestMode mode)
throws AdbcException {
diff --git
a/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniStatement.java
b/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniStatement.java
index 40a1eeec1..ec8fd46b2 100644
---
a/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniStatement.java
+++
b/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniStatement.java
@@ -40,6 +40,11 @@ public class JniStatement implements AdbcStatement {
this.handle = handle;
}
+ @Override
+ public void cancel() throws AdbcException {
+ JniLoader.INSTANCE.statementCancel(handle);
+ }
+
@Override
public void setSqlQuery(String query) throws AdbcException {
JniLoader.INSTANCE.statementSetSqlQuery(handle, query);
@@ -87,6 +92,11 @@ public class JniStatement implements AdbcStatement {
return
JniLoader.INSTANCE.statementExecuteSchema(handle).importSchema(allocator);
}
+ @Override
+ public Schema getParameterSchema() throws AdbcException {
+ return
JniLoader.INSTANCE.statementGetParameterSchema(handle).importSchema(allocator);
+ }
+
@Override
public void prepare() throws AdbcException {
JniLoader.INSTANCE.statementPrepare(handle);
@@ -143,7 +153,7 @@ public class JniStatement implements AdbcStatement {
JniLoader.INSTANCE.statementSetOptionDouble(handle, key.getKey(),
(Double) value);
} else if (value instanceof Boolean) {
JniLoader.INSTANCE.statementSetOptionString(
- handle, key.getKey(), ((Boolean) value) ? "true" : "false");
+ handle, key.getKey(), ((Boolean) value).toString());
} else if (value instanceof byte[]) {
JniLoader.INSTANCE.statementSetOptionBytes(handle, key.getKey(),
(byte[]) value);
} else {
diff --git
a/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/JniLoader.java
b/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/JniLoader.java
index 5b1adaa0d..ebfc3c51c 100644
---
a/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/JniLoader.java
+++
b/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/JniLoader.java
@@ -81,6 +81,10 @@ public enum JniLoader {
return NativeAdbc.openStatement(connection.getConnectionHandle());
}
+ public void statementCancel(NativeStatementHandle statement) throws
AdbcException {
+ NativeAdbc.statementCancel(statement.getStatementHandle());
+ }
+
public NativeQueryResult statementExecuteQuery(NativeStatementHandle
statement)
throws AdbcException {
return NativeAdbc.statementExecuteQuery(statement.getStatementHandle());
@@ -110,6 +114,11 @@ public enum JniLoader {
return NativeAdbc.statementExecuteSchema(statement.getStatementHandle());
}
+ public NativeSchemaResult statementGetParameterSchema(NativeStatementHandle
statement)
+ throws AdbcException {
+ return
NativeAdbc.statementGetParameterSchema(statement.getStatementHandle());
+ }
+
public byte[] statementGetOptionBytes(NativeStatementHandle handle, String
key)
throws AdbcException {
return NativeAdbc.statementGetOptionBytes(handle.getStatementHandle(),
key);
@@ -150,6 +159,10 @@ public enum JniLoader {
NativeAdbc.statementSetOptionString(statement.getStatementHandle(), key,
value);
}
+ public void connectionCancel(NativeConnectionHandle connection) throws
AdbcException {
+ NativeAdbc.connectionCancel(connection.getConnectionHandle());
+ }
+
public NativeQueryResult connectionGetObjects(
NativeConnectionHandle connection,
int depth,
diff --git
a/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/NativeAdbc.java
b/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/NativeAdbc.java
index 601a4716b..fb93dacc8 100644
---
a/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/NativeAdbc.java
+++
b/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/NativeAdbc.java
@@ -34,10 +34,6 @@ class NativeAdbc {
static native void closeStatement(long handle) throws AdbcException;
- static native NativeQueryResult statementExecuteQuery(long handle) throws
AdbcException;
-
- static native void statementSetSqlQuery(long handle, String query) throws
AdbcException;
-
static native void statementBind(long handle, long values, long schema)
throws AdbcException;
// TODO(lidavidm): we need a way to bind an ArrowReader (or some other
suitable interface that
@@ -46,12 +42,21 @@ class NativeAdbc {
@SuppressWarnings("unused")
static native void statementBindStream(long handle, long stream) throws
AdbcException;
+ static native void statementCancel(long handle) throws AdbcException;
+
static native long statementExecuteUpdate(long handle) throws AdbcException;
static native void statementPrepare(long handle) throws AdbcException;
+ static native NativeQueryResult statementExecuteQuery(long handle) throws
AdbcException;
+
static native NativeSchemaResult statementExecuteSchema(long handle) throws
AdbcException;
+ static native NativeSchemaResult statementGetParameterSchema(long
statementHandle)
+ throws AdbcException;
+
+ static native void statementSetSqlQuery(long handle, String query) throws
AdbcException;
+
static native byte[] statementGetOptionBytes(long handle, String key) throws
AdbcException;
static native double statementGetOptionDouble(long handle, String key)
throws AdbcException;
@@ -72,6 +77,8 @@ class NativeAdbc {
static native void statementSetOptionString(long handle, String key, String
value)
throws AdbcException;
+ static native void connectionCancel(long handle) throws AdbcException;
+
static native NativeQueryResult connectionGetObjects(
long handle,
int depth,