From 7eee86a124f2d0665970ff3c688e96540dda168e Mon Sep 17 00:00:00 2001
From: David Li
Date: Mon, 13 Apr 2026 13:22:14 +0900
Subject: [PATCH] feat(java/driver/jni): implement get/set option
Closes #3868
---
.../org/apache/arrow/adbc/core/TypedKey.java | 8 +
java/driver/jni/src/main/cpp/jni_wrapper.cc | 484 +++++++++++++++++-
.../arrow/adbc/driver/jni/JniConnection.java | 60 ++-
.../arrow/adbc/driver/jni/JniDatabase.java | 56 ++
.../arrow/adbc/driver/jni/JniStatement.java | 56 ++
.../arrow/adbc/driver/jni/impl/JniLoader.java | 122 ++++-
.../adbc/driver/jni/impl/NativeAdbc.java | 62 ++-
.../arrow/adbc/driver/jni/JniDriverTest.java | 145 +++++-
8 files changed, 974 insertions(+), 19 deletions(-)
diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/TypedKey.java b/java/core/src/main/java/org/apache/arrow/adbc/core/TypedKey.java
index 1f1dda2f4b..957664ce48 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/TypedKey.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/TypedKey.java
@@ -42,6 +42,14 @@ public String getKey() {
return key;
}
+ public Class getType() {
+ return type;
+ }
+
+ public T cast(Object value) {
+ return type.cast(value);
+ }
+
/**
* Get the option value (if it was set) and check the type.
*
diff --git a/java/driver/jni/src/main/cpp/jni_wrapper.cc b/java/driver/jni/src/main/cpp/jni_wrapper.cc
index 080a310aec..7a1e2c6702 100644
--- a/java/driver/jni/src/main/cpp/jni_wrapper.cc
+++ b/java/driver/jni/src/main/cpp/jni_wrapper.cc
@@ -456,15 +456,163 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementExecuteSchema(
return nullptr;
}
+JNIEXPORT jbyteArray JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionBytes(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+
+ std::vector buf(1024, '\0');
+ size_t length = buf.size();
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(
+ AdbcStatementGetOptionBytes(db, key_str.value, const_cast(buf.data()),
+ &length, &error),
+ error);
+ while (length > buf.size()) {
+ // Buffer was too small, resize and try again
+ buf.resize(length);
+ CHECK_ADBC_ERROR(
+ AdbcStatementGetOptionBytes(db, key_str.value, const_cast(buf.data()),
+ &length, &error),
+ error);
+ }
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return nullptr;
+ }
+ jbyteArray result = env->NewByteArray(static_cast(length));
+ env->SetByteArrayRegion(result, 0, static_cast(length),
+ reinterpret_cast(buf.data()));
+ return result;
+}
+
+JNIEXPORT jdouble JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionDouble(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ double value = 0.0;
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(AdbcStatementGetOptionDouble(db, key_str.value, &value, &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return 0.0;
+ }
+ return static_cast(value);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionLong(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ int64_t value = 0;
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(AdbcStatementGetOptionInt(db, key_str.value, &value, &error), error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return 0;
+ }
+ return static_cast(value);
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionString(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+
+ std::vector buf(1024, '\0');
+ size_t length = buf.size();
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(
+ AdbcStatementGetOption(db, key_str.value, const_cast(buf.data()), &length,
+ &error),
+ error);
+ while (length > buf.size()) {
+ // Buffer was too small, resize and try again
+ buf.resize(length);
+ CHECK_ADBC_ERROR(
+ AdbcStatementGetOption(db, key_str.value, const_cast(buf.data()),
+ &length, &error),
+ error);
+ }
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return nullptr;
+ }
+ return env->NewStringUTF(buf.data());
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionBytes(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key,
+ jbyteArray value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ jsize value_length = env->GetArrayLength(value);
+ std::vector value_buf(static_cast(value_length));
+ env->GetByteArrayRegion(value, 0, value_length,
+ reinterpret_cast(value_buf.data()));
+ CHECK_ADBC_ERROR(AdbcStatementSetOptionBytes(db, key_str.value, value_buf.data(),
+ value_buf.size(), &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
JNIEXPORT void JNICALL
-Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOption(
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionDouble(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key, jdouble value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(AdbcStatementSetOptionDouble(db, key_str.value,
+ static_cast(value), &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionLong(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key, jlong value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(
+ AdbcStatementSetOptionInt(db, key_str.value, static_cast(value), &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionString(
JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key, jstring value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
try {
- struct AdbcError error = ADBC_ERROR_INIT;
- auto* ptr = reinterpret_cast(static_cast(handle));
JniStringView key_str(env, key);
+ if (value == nullptr) {
+ CHECK_ADBC_ERROR(AdbcStatementSetOption(db, key_str.value, nullptr, &error), error);
+ return;
+ }
JniStringView value_str(env, value);
- CHECK_ADBC_ERROR(AdbcStatementSetOption(ptr, key_str.value, value_str.value, &error),
+ CHECK_ADBC_ERROR(AdbcStatementSetOption(db, key_str.value, value_str.value, &error),
error);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
@@ -598,4 +746,332 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetTableTypes(
}
return nullptr;
}
+
+JNIEXPORT jbyteArray JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionBytes(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+
+ std::vector buf(1024, '\0');
+ size_t length = buf.size();
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(
+ AdbcConnectionGetOptionBytes(db, key_str.value, const_cast(buf.data()),
+ &length, &error),
+ error);
+ while (length > buf.size()) {
+ // Buffer was too small, resize and try again
+ buf.resize(length);
+ CHECK_ADBC_ERROR(
+ AdbcConnectionGetOptionBytes(db, key_str.value,
+ const_cast(buf.data()), &length, &error),
+ error);
+ }
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return nullptr;
+ }
+ jbyteArray result = env->NewByteArray(static_cast(length));
+ env->SetByteArrayRegion(result, 0, static_cast(length),
+ reinterpret_cast(buf.data()));
+ return result;
+}
+
+JNIEXPORT jdouble JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionDouble(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ double value = 0.0;
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(AdbcConnectionGetOptionDouble(db, key_str.value, &value, &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return 0.0;
+ }
+ return static_cast(value);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionLong(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ int64_t value = 0;
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(AdbcConnectionGetOptionInt(db, key_str.value, &value, &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return 0;
+ }
+ return static_cast(value);
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionString(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+
+ std::vector buf(1024, '\0');
+ size_t length = buf.size();
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(
+ AdbcConnectionGetOption(db, key_str.value, const_cast(buf.data()), &length,
+ &error),
+ error);
+ while (length > buf.size()) {
+ // Buffer was too small, resize and try again
+ buf.resize(length);
+ CHECK_ADBC_ERROR(
+ AdbcConnectionGetOption(db, key_str.value, const_cast(buf.data()),
+ &length, &error),
+ error);
+ }
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return nullptr;
+ }
+ return env->NewStringUTF(buf.data());
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionBytes(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key,
+ jbyteArray value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ jsize value_length = env->GetArrayLength(value);
+ std::vector value_buf(static_cast(value_length));
+ env->GetByteArrayRegion(value, 0, value_length,
+ reinterpret_cast(value_buf.data()));
+ CHECK_ADBC_ERROR(AdbcConnectionSetOptionBytes(db, key_str.value, value_buf.data(),
+ value_buf.size(), &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionDouble(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key, jdouble value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(AdbcConnectionSetOptionDouble(db, key_str.value,
+ static_cast(value), &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionLong(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key, jlong value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(AdbcConnectionSetOptionInt(db, key_str.value,
+ static_cast(value), &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionString(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key, jstring value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ if (value == nullptr) {
+ CHECK_ADBC_ERROR(AdbcConnectionSetOption(db, key_str.value, nullptr, &error),
+ error);
+ return;
+ }
+ JniStringView value_str(env, value);
+ CHECK_ADBC_ERROR(AdbcConnectionSetOption(db, key_str.value, value_str.value, &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionBytes(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+
+ std::vector buf(1024, '\0');
+ size_t length = buf.size();
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(
+ AdbcDatabaseGetOptionBytes(db, key_str.value, const_cast(buf.data()),
+ &length, &error),
+ error);
+ while (length > buf.size()) {
+ // Buffer was too small, resize and try again
+ buf.resize(length);
+ CHECK_ADBC_ERROR(
+ AdbcDatabaseGetOptionBytes(db, key_str.value, const_cast(buf.data()),
+ &length, &error),
+ error);
+ }
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return nullptr;
+ }
+ jbyteArray result = env->NewByteArray(static_cast(length));
+ env->SetByteArrayRegion(result, 0, static_cast(length),
+ reinterpret_cast(buf.data()));
+ return result;
+}
+
+JNIEXPORT jdouble JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionDouble(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ double value = 0.0;
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(AdbcDatabaseGetOptionDouble(db, key_str.value, &value, &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return 0.0;
+ }
+ return static_cast(value);
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionLong(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ int64_t value = 0;
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(AdbcDatabaseGetOptionInt(db, key_str.value, &value, &error), error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return 0;
+ }
+ return static_cast(value);
+}
+
+JNIEXPORT jstring JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionString(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+
+ std::vector buf(1024, '\0');
+ size_t length = buf.size();
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(
+ AdbcDatabaseGetOption(db, key_str.value, const_cast(buf.data()), &length,
+ &error),
+ error);
+ while (length > buf.size()) {
+ // Buffer was too small, resize and try again
+ buf.resize(length);
+ CHECK_ADBC_ERROR(
+ AdbcDatabaseGetOption(db, key_str.value, const_cast(buf.data()), &length,
+ &error),
+ error);
+ }
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ return nullptr;
+ }
+ return env->NewStringUTF(buf.data());
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseSetOptionBytes(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key,
+ jbyteArray value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ jsize value_length = env->GetArrayLength(value);
+ std::vector value_buf(static_cast(value_length));
+ env->GetByteArrayRegion(value, 0, value_length,
+ reinterpret_cast(value_buf.data()));
+ CHECK_ADBC_ERROR(AdbcDatabaseSetOptionBytes(db, key_str.value, value_buf.data(),
+ value_buf.size(), &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseSetOptionDouble(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key, jdouble value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(AdbcDatabaseSetOptionDouble(db, key_str.value,
+ static_cast(value), &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseSetOptionLong(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key, jlong value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ CHECK_ADBC_ERROR(
+ AdbcDatabaseSetOptionInt(db, key_str.value, static_cast(value), &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseSetOptionString(
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key, jstring value) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ auto* db = reinterpret_cast(static_cast(handle));
+ try {
+ JniStringView key_str(env, key);
+ if (value == nullptr) {
+ CHECK_ADBC_ERROR(AdbcDatabaseSetOption(db, key_str.value, nullptr, &error), error);
+ return;
+ }
+ JniStringView value_str(env, value);
+ CHECK_ADBC_ERROR(AdbcDatabaseSetOption(db, key_str.value, value_str.value, &error),
+ error);
+ } catch (const AdbcException& e) {
+ e.ThrowJavaException(env);
+ }
+}
}
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 ef214eea32..008aeec427 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
@@ -21,6 +21,7 @@
import org.apache.arrow.adbc.core.AdbcException;
import org.apache.arrow.adbc.core.AdbcStatement;
import org.apache.arrow.adbc.core.BulkIngestMode;
+import org.apache.arrow.adbc.core.TypedKey;
import org.apache.arrow.adbc.driver.jni.impl.JniLoader;
import org.apache.arrow.adbc.driver.jni.impl.NativeConnectionHandle;
import org.apache.arrow.adbc.driver.jni.impl.NativeStatementHandle;
@@ -66,9 +67,9 @@ public AdbcStatement bulkIngest(String targetTableName, BulkIngestMode mode)
throw new IllegalArgumentException("Unknown bulk ingest mode: " + mode);
}
- JniLoader.INSTANCE.statementSetOption(
+ JniLoader.INSTANCE.statementSetOptionString(
stmtHandle, "adbc.ingest.target_table", targetTableName);
- JniLoader.INSTANCE.statementSetOption(stmtHandle, "adbc.ingest.mode", modeValue);
+ JniLoader.INSTANCE.statementSetOptionString(stmtHandle, "adbc.ingest.mode", modeValue);
return new JniStatement(allocator, stmtHandle);
} catch (Exception e) {
@@ -120,4 +121,59 @@ public ArrowReader getTableTypes() throws AdbcException {
public void close() {
handle.close();
}
+
+ @Override
+ public T getOption(TypedKey key) throws AdbcException {
+ if (key.getType() == String.class) {
+ return key.cast(JniLoader.INSTANCE.connectionGetOptionString(handle, key.getKey()));
+ } else if (key.getType() == Integer.class) {
+ return key.cast((int) JniLoader.INSTANCE.connectionGetOptionLong(handle, key.getKey()));
+ } else if (key.getType() == Long.class) {
+ return key.cast(JniLoader.INSTANCE.connectionGetOptionLong(handle, key.getKey()));
+ } else if (key.getType() == Float.class) {
+ return key.cast((float) JniLoader.INSTANCE.connectionGetOptionDouble(handle, key.getKey()));
+ } else if (key.getType() == Double.class) {
+ return key.cast(JniLoader.INSTANCE.connectionGetOptionDouble(handle, key.getKey()));
+ } else if (key.getType() == Boolean.class) {
+ String value = JniLoader.INSTANCE.connectionGetOptionString(handle, key.getKey());
+ if (value == null) {
+ return null;
+ } else if ("true".equalsIgnoreCase(value)) {
+ return key.cast(Boolean.TRUE);
+ } else if ("false".equalsIgnoreCase(value)) {
+ return key.cast(Boolean.FALSE);
+ } else {
+ throw AdbcException.invalidArgument(
+ "[jni] invalid boolean value for option " + key.getKey() + ": " + value);
+ }
+ } else if (key.getType() == byte[].class) {
+ return key.cast(JniLoader.INSTANCE.connectionGetOptionBytes(handle, key.getKey()));
+ }
+ return AdbcConnection.super.getOption(key);
+ }
+
+ @Override
+ public void setOption(TypedKey key, T value) throws AdbcException {
+ if (value instanceof String) {
+ JniLoader.INSTANCE.connectionSetOptionString(handle, key.getKey(), (String) value);
+ } else if (value == null) {
+ JniLoader.INSTANCE.connectionSetOptionString(handle, key.getKey(), null);
+ } else if (value instanceof Integer) {
+ JniLoader.INSTANCE.connectionSetOptionLong(handle, key.getKey(), (Integer) value);
+ } else if (value instanceof Long) {
+ JniLoader.INSTANCE.connectionSetOptionLong(handle, key.getKey(), (Long) value);
+ } else if (value instanceof Float) {
+ JniLoader.INSTANCE.connectionSetOptionDouble(handle, key.getKey(), (Float) value);
+ } else if (value instanceof Double) {
+ JniLoader.INSTANCE.connectionSetOptionDouble(handle, key.getKey(), (Double) value);
+ } else if (value instanceof Boolean) {
+ JniLoader.INSTANCE.connectionSetOptionString(
+ handle, key.getKey(), ((Boolean) value) ? "true" : "false");
+ } else if (value instanceof byte[]) {
+ JniLoader.INSTANCE.connectionSetOptionBytes(handle, key.getKey(), (byte[]) value);
+ } else {
+ throw AdbcException.invalidArgument(
+ "[jni] unsupported connection option type " + value.getClass());
+ }
+ }
}
diff --git a/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniDatabase.java b/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniDatabase.java
index 1eaea0c5a0..9468107056 100644
--- a/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniDatabase.java
+++ b/java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniDatabase.java
@@ -20,6 +20,7 @@
import org.apache.arrow.adbc.core.AdbcConnection;
import org.apache.arrow.adbc.core.AdbcDatabase;
import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.adbc.core.TypedKey;
import org.apache.arrow.adbc.driver.jni.impl.JniLoader;
import org.apache.arrow.adbc.driver.jni.impl.NativeDatabaseHandle;
import org.apache.arrow.memory.BufferAllocator;
@@ -42,4 +43,59 @@ public AdbcConnection connect() throws AdbcException {
public void close() {
handle.close();
}
+
+ @Override
+ public T getOption(TypedKey key) throws AdbcException {
+ if (key.getType() == String.class) {
+ return key.cast(JniLoader.INSTANCE.databaseGetOptionString(handle, key.getKey()));
+ } else if (key.getType() == Integer.class) {
+ return key.cast((int) JniLoader.INSTANCE.databaseGetOptionLong(handle, key.getKey()));
+ } else if (key.getType() == Long.class) {
+ return key.cast(JniLoader.INSTANCE.databaseGetOptionLong(handle, key.getKey()));
+ } else if (key.getType() == Float.class) {
+ return key.cast((float) JniLoader.INSTANCE.databaseGetOptionDouble(handle, key.getKey()));
+ } else if (key.getType() == Double.class) {
+ return key.cast(JniLoader.INSTANCE.databaseGetOptionDouble(handle, key.getKey()));
+ } else if (key.getType() == Boolean.class) {
+ String value = JniLoader.INSTANCE.databaseGetOptionString(handle, key.getKey());
+ if (value == null) {
+ return null;
+ } else if ("true".equalsIgnoreCase(value)) {
+ return key.cast(Boolean.TRUE);
+ } else if ("false".equalsIgnoreCase(value)) {
+ return key.cast(Boolean.FALSE);
+ } else {
+ throw AdbcException.invalidArgument(
+ "[jni] invalid boolean value for option " + key.getKey() + ": " + value);
+ }
+ } else if (key.getType() == byte[].class) {
+ return key.cast(JniLoader.INSTANCE.databaseGetOptionBytes(handle, key.getKey()));
+ }
+ return AdbcDatabase.super.getOption(key);
+ }
+
+ @Override
+ public void setOption(TypedKey key, T value) throws AdbcException {
+ if (value instanceof String) {
+ JniLoader.INSTANCE.databaseSetOptionString(handle, key.getKey(), (String) value);
+ } else if (value == null) {
+ JniLoader.INSTANCE.databaseSetOptionString(handle, key.getKey(), null);
+ } else if (value instanceof Integer) {
+ JniLoader.INSTANCE.databaseSetOptionLong(handle, key.getKey(), (Integer) value);
+ } else if (value instanceof Long) {
+ JniLoader.INSTANCE.databaseSetOptionLong(handle, key.getKey(), (Long) value);
+ } else if (value instanceof Float) {
+ JniLoader.INSTANCE.databaseSetOptionDouble(handle, key.getKey(), (Float) value);
+ } else if (value instanceof Double) {
+ JniLoader.INSTANCE.databaseSetOptionDouble(handle, key.getKey(), (Double) value);
+ } else if (value instanceof Boolean) {
+ JniLoader.INSTANCE.databaseSetOptionString(
+ handle, key.getKey(), ((Boolean) value) ? "true" : "false");
+ } else if (value instanceof byte[]) {
+ JniLoader.INSTANCE.databaseSetOptionBytes(handle, key.getKey(), (byte[]) value);
+ } else {
+ throw AdbcException.invalidArgument(
+ "[jni] unsupported database option type " + value.getClass());
+ }
+ }
}
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 2f98c3aa02..40a1eeec15 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
@@ -19,6 +19,7 @@
import org.apache.arrow.adbc.core.AdbcException;
import org.apache.arrow.adbc.core.AdbcStatement;
+import org.apache.arrow.adbc.core.TypedKey;
import org.apache.arrow.adbc.driver.jni.impl.JniLoader;
import org.apache.arrow.adbc.driver.jni.impl.NativeQueryResult;
import org.apache.arrow.adbc.driver.jni.impl.NativeStatementHandle;
@@ -95,4 +96,59 @@ public void prepare() throws AdbcException {
public void close() {
handle.close();
}
+
+ @Override
+ public T getOption(TypedKey key) throws AdbcException {
+ if (key.getType() == String.class) {
+ return key.cast(JniLoader.INSTANCE.statementGetOptionString(handle, key.getKey()));
+ } else if (key.getType() == Integer.class) {
+ return key.cast((int) JniLoader.INSTANCE.statementGetOptionLong(handle, key.getKey()));
+ } else if (key.getType() == Long.class) {
+ return key.cast(JniLoader.INSTANCE.statementGetOptionLong(handle, key.getKey()));
+ } else if (key.getType() == Float.class) {
+ return key.cast((float) JniLoader.INSTANCE.statementGetOptionDouble(handle, key.getKey()));
+ } else if (key.getType() == Double.class) {
+ return key.cast(JniLoader.INSTANCE.statementGetOptionDouble(handle, key.getKey()));
+ } else if (key.getType() == Boolean.class) {
+ String value = JniLoader.INSTANCE.statementGetOptionString(handle, key.getKey());
+ if (value == null) {
+ return null;
+ } else if ("true".equalsIgnoreCase(value)) {
+ return key.cast(Boolean.TRUE);
+ } else if ("false".equalsIgnoreCase(value)) {
+ return key.cast(Boolean.FALSE);
+ } else {
+ throw AdbcException.invalidArgument(
+ "[jni] invalid boolean value for option " + key.getKey() + ": " + value);
+ }
+ } else if (key.getType() == byte[].class) {
+ return key.cast(JniLoader.INSTANCE.statementGetOptionBytes(handle, key.getKey()));
+ }
+ return AdbcStatement.super.getOption(key);
+ }
+
+ @Override
+ public void setOption(TypedKey key, T value) throws AdbcException {
+ if (value instanceof String) {
+ JniLoader.INSTANCE.statementSetOptionString(handle, key.getKey(), (String) value);
+ } else if (value == null) {
+ JniLoader.INSTANCE.statementSetOptionString(handle, key.getKey(), null);
+ } else if (value instanceof Integer) {
+ JniLoader.INSTANCE.statementSetOptionLong(handle, key.getKey(), (Integer) value);
+ } else if (value instanceof Long) {
+ JniLoader.INSTANCE.statementSetOptionLong(handle, key.getKey(), (Long) value);
+ } else if (value instanceof Float) {
+ JniLoader.INSTANCE.statementSetOptionDouble(handle, key.getKey(), (Float) value);
+ } else if (value instanceof Double) {
+ JniLoader.INSTANCE.statementSetOptionDouble(handle, key.getKey(), (Double) value);
+ } else if (value instanceof Boolean) {
+ JniLoader.INSTANCE.statementSetOptionString(
+ handle, key.getKey(), ((Boolean) value) ? "true" : "false");
+ } else if (value instanceof byte[]) {
+ JniLoader.INSTANCE.statementSetOptionBytes(handle, key.getKey(), (byte[]) value);
+ } else {
+ throw AdbcException.invalidArgument(
+ "[jni] unsupported statement option type " + value.getClass());
+ }
+ }
}
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 8102af7a88..f1aa978d99 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
@@ -114,14 +114,49 @@ public void statementPrepare(NativeStatementHandle statement) throws AdbcExcepti
NativeAdbc.statementPrepare(statement.getStatementHandle());
}
- public void statementSetOption(NativeStatementHandle statement, String key, String value)
+ public NativeSchemaResult statementExecuteSchema(NativeStatementHandle statement)
throws AdbcException {
- NativeAdbc.statementSetOption(statement.getStatementHandle(), key, value);
+ return NativeAdbc.statementExecuteSchema(statement.getStatementHandle());
}
- public NativeSchemaResult statementExecuteSchema(NativeStatementHandle statement)
+ public byte[] statementGetOptionBytes(NativeStatementHandle handle, String key)
throws AdbcException {
- return NativeAdbc.statementExecuteSchema(statement.getStatementHandle());
+ return NativeAdbc.statementGetOptionBytes(handle.getStatementHandle(), key);
+ }
+
+ public double statementGetOptionDouble(NativeStatementHandle handle, String key)
+ throws AdbcException {
+ return NativeAdbc.statementGetOptionDouble(handle.getStatementHandle(), key);
+ }
+
+ public long statementGetOptionLong(NativeStatementHandle handle, String key)
+ throws AdbcException {
+ return NativeAdbc.statementGetOptionLong(handle.getStatementHandle(), key);
+ }
+
+ public String statementGetOptionString(NativeStatementHandle handle, String key)
+ throws AdbcException {
+ return NativeAdbc.statementGetOptionString(handle.getStatementHandle(), key);
+ }
+
+ public void statementSetOptionBytes(NativeStatementHandle handle, String key, byte[] value)
+ throws AdbcException {
+ NativeAdbc.statementSetOptionBytes(handle.getStatementHandle(), key, value);
+ }
+
+ public void statementSetOptionDouble(NativeStatementHandle handle, String key, double value)
+ throws AdbcException {
+ NativeAdbc.statementSetOptionDouble(handle.getStatementHandle(), key, value);
+ }
+
+ public void statementSetOptionLong(NativeStatementHandle handle, String key, long value)
+ throws AdbcException {
+ NativeAdbc.statementSetOptionLong(handle.getStatementHandle(), key, value);
+ }
+
+ public void statementSetOptionString(NativeStatementHandle statement, String key, String value)
+ throws AdbcException {
+ NativeAdbc.statementSetOptionString(statement.getStatementHandle(), key, value);
}
public NativeQueryResult connectionGetObjects(
@@ -159,4 +194,83 @@ public NativeQueryResult connectionGetTableTypes(NativeConnectionHandle connecti
throws AdbcException {
return NativeAdbc.connectionGetTableTypes(connection.getConnectionHandle());
}
+
+ public byte[] connectionGetOptionBytes(NativeConnectionHandle handle, String key)
+ throws AdbcException {
+ return NativeAdbc.connectionGetOptionBytes(handle.getConnectionHandle(), key);
+ }
+
+ public double connectionGetOptionDouble(NativeConnectionHandle handle, String key)
+ throws AdbcException {
+ return NativeAdbc.connectionGetOptionDouble(handle.getConnectionHandle(), key);
+ }
+
+ public long connectionGetOptionLong(NativeConnectionHandle handle, String key)
+ throws AdbcException {
+ return NativeAdbc.connectionGetOptionLong(handle.getConnectionHandle(), key);
+ }
+
+ public String connectionGetOptionString(NativeConnectionHandle handle, String key)
+ throws AdbcException {
+ return NativeAdbc.connectionGetOptionString(handle.getConnectionHandle(), key);
+ }
+
+ public void connectionSetOptionBytes(NativeConnectionHandle handle, String key, byte[] value)
+ throws AdbcException {
+ NativeAdbc.connectionSetOptionBytes(handle.getConnectionHandle(), key, value);
+ }
+
+ public void connectionSetOptionDouble(NativeConnectionHandle handle, String key, double value)
+ throws AdbcException {
+ NativeAdbc.connectionSetOptionDouble(handle.getConnectionHandle(), key, value);
+ }
+
+ public void connectionSetOptionLong(NativeConnectionHandle handle, String key, long value)
+ throws AdbcException {
+ NativeAdbc.connectionSetOptionLong(handle.getConnectionHandle(), key, value);
+ }
+
+ public void connectionSetOptionString(NativeConnectionHandle connection, String key, String value)
+ throws AdbcException {
+ NativeAdbc.connectionSetOptionString(connection.getConnectionHandle(), key, value);
+ }
+
+ public byte[] databaseGetOptionBytes(NativeDatabaseHandle handle, String key)
+ throws AdbcException {
+ return NativeAdbc.databaseGetOptionBytes(handle.getDatabaseHandle(), key);
+ }
+
+ public double databaseGetOptionDouble(NativeDatabaseHandle handle, String key)
+ throws AdbcException {
+ return NativeAdbc.databaseGetOptionDouble(handle.getDatabaseHandle(), key);
+ }
+
+ public long databaseGetOptionLong(NativeDatabaseHandle handle, String key) throws AdbcException {
+ return NativeAdbc.databaseGetOptionLong(handle.getDatabaseHandle(), key);
+ }
+
+ public String databaseGetOptionString(NativeDatabaseHandle handle, String key)
+ throws AdbcException {
+ return NativeAdbc.databaseGetOptionString(handle.getDatabaseHandle(), key);
+ }
+
+ public void databaseSetOptionBytes(NativeDatabaseHandle handle, String key, byte[] value)
+ throws AdbcException {
+ NativeAdbc.databaseSetOptionBytes(handle.getDatabaseHandle(), key, value);
+ }
+
+ public void databaseSetOptionDouble(NativeDatabaseHandle handle, String key, double value)
+ throws AdbcException {
+ NativeAdbc.databaseSetOptionDouble(handle.getDatabaseHandle(), key, value);
+ }
+
+ public void databaseSetOptionLong(NativeDatabaseHandle handle, String key, long value)
+ throws AdbcException {
+ NativeAdbc.databaseSetOptionLong(handle.getDatabaseHandle(), key, value);
+ }
+
+ public void databaseSetOptionString(NativeDatabaseHandle handle, String key, String value)
+ throws AdbcException {
+ NativeAdbc.databaseSetOptionString(handle.getDatabaseHandle(), key, value);
+ }
}
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 2dcf70f625..3a6d09c8ce 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
@@ -50,10 +50,28 @@ static native NativeDatabaseHandle openDatabase(int version, String[] parameters
static native void statementPrepare(long handle) throws AdbcException;
- static native void statementSetOption(long handle, String key, String value) throws AdbcException;
-
static native NativeSchemaResult statementExecuteSchema(long handle) throws AdbcException;
+ static native byte[] statementGetOptionBytes(long handle, String key) throws AdbcException;
+
+ static native double statementGetOptionDouble(long handle, String key) throws AdbcException;
+
+ static native long statementGetOptionLong(long handle, String key) throws AdbcException;
+
+ static native String statementGetOptionString(long handle, String key) throws AdbcException;
+
+ static native void statementSetOptionBytes(long handle, String key, byte[] value)
+ throws AdbcException;
+
+ static native void statementSetOptionDouble(long handle, String key, double value)
+ throws AdbcException;
+
+ static native void statementSetOptionLong(long handle, String key, long value)
+ throws AdbcException;
+
+ static native void statementSetOptionString(long handle, String key, String value)
+ throws AdbcException;
+
static native NativeQueryResult connectionGetObjects(
long handle,
int depth,
@@ -71,4 +89,44 @@ static native NativeSchemaResult connectionGetTableSchema(
long handle, String catalog, String dbSchema, String tableName) throws AdbcException;
static native NativeQueryResult connectionGetTableTypes(long handle) throws AdbcException;
+
+ static native byte[] connectionGetOptionBytes(long handle, String key) throws AdbcException;
+
+ static native double connectionGetOptionDouble(long handle, String key) throws AdbcException;
+
+ static native long connectionGetOptionLong(long handle, String key) throws AdbcException;
+
+ static native String connectionGetOptionString(long handle, String key) throws AdbcException;
+
+ static native void connectionSetOptionBytes(long handle, String key, byte[] value)
+ throws AdbcException;
+
+ static native void connectionSetOptionDouble(long handle, String key, double value)
+ throws AdbcException;
+
+ static native void connectionSetOptionLong(long handle, String key, long value)
+ throws AdbcException;
+
+ static native void connectionSetOptionString(long handle, String key, String value)
+ throws AdbcException;
+
+ static native byte[] databaseGetOptionBytes(long handle, String key) throws AdbcException;
+
+ static native double databaseGetOptionDouble(long handle, String key) throws AdbcException;
+
+ static native long databaseGetOptionLong(long handle, String key) throws AdbcException;
+
+ static native String databaseGetOptionString(long handle, String key) throws AdbcException;
+
+ static native void databaseSetOptionBytes(long handle, String key, byte[] value)
+ throws AdbcException;
+
+ static native void databaseSetOptionDouble(long handle, String key, double value)
+ throws AdbcException;
+
+ static native void databaseSetOptionLong(long handle, String key, long value)
+ throws AdbcException;
+
+ static native void databaseSetOptionString(long handle, String key, String value)
+ throws AdbcException;
}
diff --git a/java/driver/jni/src/test/java/org/apache/arrow/adbc/driver/jni/JniDriverTest.java b/java/driver/jni/src/test/java/org/apache/arrow/adbc/driver/jni/JniDriverTest.java
index c61fa8d2b9..c9a0922210 100644
--- a/java/driver/jni/src/test/java/org/apache/arrow/adbc/driver/jni/JniDriverTest.java
+++ b/java/driver/jni/src/test/java/org/apache/arrow/adbc/driver/jni/JniDriverTest.java
@@ -25,12 +25,14 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
+import java.util.stream.Stream;
import org.apache.arrow.adbc.core.AdbcConnection;
import org.apache.arrow.adbc.core.AdbcDatabase;
import org.apache.arrow.adbc.core.AdbcDriver;
@@ -50,6 +52,8 @@
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
class JniDriverTest {
@Test
@@ -91,7 +95,7 @@ void loadProfile(@TempDir Path tempDir) throws Exception {
"profile_version = 1",
"driver = \"adbc_driver_sqlite\"",
"[Options]",
- "adbc.sqlite.query.batch_rows = 1024")
+ "adbc.sqlite.query.batch_rows = 4242")
.getBytes(StandardCharsets.UTF_8));
try (final BufferAllocator allocator = new RootAllocator()) {
JniDriver driver = new JniDriver(allocator);
@@ -99,12 +103,8 @@ void loadProfile(@TempDir Path tempDir) throws Exception {
JniDriver.PARAM_PROFILE.set(parameters, "myprofile");
JniDriver.PARAM_PROFILE_SEARCH_PATH.set(parameters, tempDir.toString());
try (final AdbcDatabase db = driver.open(parameters)) {
- // TODO(lidavidm): getOption not implemented
- AdbcException e =
- assertThrows(
- AdbcException.class,
- () -> db.getOption(new TypedKey<>("adbc.sqlite.query.batch_rows", Long.class)));
- assertThat(e).hasMessageContaining("Unsupported option");
+ assertThat(db.getOption(new TypedKey<>("adbc.sqlite.query.batch_rows", Long.class)))
+ .isEqualTo(4242L);
}
}
}
@@ -398,4 +398,135 @@ void bulkIngest() throws Exception {
}
}
}
+
+ @Test
+ void getSetOption() throws Exception {
+ TypedKey batchRowsInt = new TypedKey<>("adbc.sqlite.query.batch_rows", Integer.class);
+ TypedKey batchRowsLong = new TypedKey<>("adbc.sqlite.query.batch_rows", Long.class);
+ TypedKey bindByName = new TypedKey<>("adbc.statement.bind_by_name", Boolean.class);
+ TypedKey bindByNameString = new TypedKey<>("adbc.statement.bind_by_name", String.class);
+ try (final BufferAllocator allocator = new RootAllocator()) {
+ JniDriver driver = new JniDriver(allocator);
+ Map parameters = new HashMap<>();
+ JniDriver.PARAM_DRIVER.set(parameters, "adbc_driver_sqlite");
+ try (final AdbcDatabase db = driver.open(parameters)) {
+ assertThat(db.getOption(batchRowsInt)).isEqualTo(1024);
+ assertThat(db.getOption(batchRowsLong)).isEqualTo(1024L);
+ assertThat(db.getOption(AdbcDriver.PARAM_URI))
+ .isEqualTo("file:adbc_driver_sqlite?mode=memory&cache=shared");
+
+ try (final AdbcConnection conn = db.connect();
+ final AdbcStatement stmt = conn.createStatement()) {
+ assertThat(conn.getOption(batchRowsInt)).isEqualTo(1024);
+ assertThat(conn.getOption(batchRowsLong)).isEqualTo(1024L);
+
+ assertThat(stmt.getOption(batchRowsInt)).isEqualTo(1024);
+ assertThat(stmt.getOption(batchRowsLong)).isEqualTo(1024L);
+ stmt.setOption(batchRowsLong, 42L);
+ assertThat(stmt.getOption(batchRowsLong)).isEqualTo(42L);
+ assertThat(stmt.getOption(bindByName)).isFalse();
+ assertThat(stmt.getOption(bindByNameString)).isEqualTo("false");
+ stmt.setOption(bindByName, true);
+ assertThat(stmt.getOption(bindByName)).isTrue();
+ assertThat(stmt.getOption(bindByNameString)).isEqualTo("true");
+ }
+ }
+ }
+ }
+
+ static class GetSetOptionFailCase {
+ @SuppressWarnings("rawtypes")
+ final TypedKey key;
+
+ final Object value;
+ final String message;
+
+ GetSetOptionFailCase(TypedKey> key, Object value, String message) {
+ this.key = key;
+ this.value = value;
+ this.message = message;
+ }
+
+ @Override
+ public String toString() {
+ String v;
+ if (value == null) {
+ v = "(NULL)";
+ } else if (value instanceof byte[]) {
+ v = Arrays.toString((byte[]) value);
+ } else {
+ v = value.toString();
+ }
+ return "key=" + key.getKey() + ", value=" + v;
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("getSetOptionFailProvider")
+ void getSetOptionFailDatabase(GetSetOptionFailCase testCase) throws Exception {
+ // These will fail; we don't have a driver that supports an example of every type
+ try (final BufferAllocator allocator = new RootAllocator()) {
+ JniDriver driver = new JniDriver(allocator);
+ Map parameters = new HashMap<>();
+ JniDriver.PARAM_DRIVER.set(parameters, "adbc_driver_sqlite");
+ try (final AdbcDatabase db = driver.open(parameters)) {
+ AdbcException e;
+ //noinspection unchecked
+ e = assertThrows(AdbcException.class, () -> db.setOption(testCase.key, testCase.value));
+ assertThat(e).hasMessageContaining(testCase.message);
+ }
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("getSetOptionFailProvider")
+ void getSetOptionFailConnection(GetSetOptionFailCase testCase) throws Exception {
+ try (final BufferAllocator allocator = new RootAllocator()) {
+ JniDriver driver = new JniDriver(allocator);
+ Map parameters = new HashMap<>();
+ JniDriver.PARAM_DRIVER.set(parameters, "adbc_driver_sqlite");
+ try (final AdbcDatabase db = driver.open(parameters);
+ final AdbcConnection conn = db.connect()) {
+ AdbcException e;
+ //noinspection unchecked
+ e = assertThrows(AdbcException.class, () -> conn.setOption(testCase.key, testCase.value));
+ assertThat(e).hasMessageContaining(testCase.message);
+ }
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("getSetOptionFailProvider")
+ void getSetOptionFailStatement(GetSetOptionFailCase testCase) throws Exception {
+ try (final BufferAllocator allocator = new RootAllocator()) {
+ JniDriver driver = new JniDriver(allocator);
+ Map parameters = new HashMap<>();
+ JniDriver.PARAM_DRIVER.set(parameters, "adbc_driver_sqlite");
+ try (final AdbcDatabase db = driver.open(parameters);
+ final AdbcConnection conn = db.connect();
+ final AdbcStatement stmt = conn.createStatement()) {
+ AdbcException e;
+ //noinspection unchecked
+ e = assertThrows(AdbcException.class, () -> stmt.setOption(testCase.key, testCase.value));
+ assertThat(e).hasMessageContaining(testCase.message);
+ }
+ }
+ }
+
+ static Stream getSetOptionFailProvider() {
+ return Stream.of(
+ new GetSetOptionFailCase(new TypedKey<>("unknown", Integer.class), 2048, "unknown=2048"),
+ new GetSetOptionFailCase(new TypedKey<>("unknown", Long.class), 2048L, "unknown=2048"),
+ new GetSetOptionFailCase(new TypedKey<>("unknown", Float.class), 2048f, "unknown=2048.0"),
+ new GetSetOptionFailCase(new TypedKey<>("unknown", Double.class), 2048d, "unknown=2048.0"),
+ new GetSetOptionFailCase(
+ new TypedKey<>("unknown", String.class), "foobar", "unknown='foobar'"),
+ new GetSetOptionFailCase(new TypedKey<>("unknown", String.class), null, "unknown=(NULL)"),
+ new GetSetOptionFailCase(
+ new TypedKey<>("unknown", Boolean.class), false, "unknown='false'"),
+ new GetSetOptionFailCase(new TypedKey<>("unknown", Boolean.class), true, "unknown='true'"),
+ new GetSetOptionFailCase(
+ new TypedKey<>("unknown", byte[].class), new byte[] {0, 42, 0}, "unknown=(3 bytes)"),
+ new GetSetOptionFailCase(new TypedKey<>("unknown", byte[].class), null, "unknown=(NULL)"));
+ }
}