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 d6cdd4dc0 fix(java/driver/jni): handle "modified UTF-8" encoding
(#4423)
d6cdd4dc0 is described below
commit d6cdd4dc044d2ef110dc7bc1b78b1526dd3dc60b
Author: David Li <[email protected]>
AuthorDate: Tue Jun 23 17:32:18 2026 -0700
fix(java/driver/jni): handle "modified UTF-8" encoding (#4423)
Assisted-by: GPT-5.5 <[email protected]>
---
java/driver/jni/src/main/cpp/jni_wrapper.cc | 339 +++++++++++----------
.../arrow/adbc/driver/jni/impl/JniLoader.java | 103 ++++---
.../arrow/adbc/driver/jni/impl/NativeAdbc.java | 70 ++---
.../arrow/adbc/driver/jni/JniDriverTest.java | 23 ++
4 files changed, 296 insertions(+), 239 deletions(-)
diff --git a/java/driver/jni/src/main/cpp/jni_wrapper.cc
b/java/driver/jni/src/main/cpp/jni_wrapper.cc
index 56e5e4718..f39e3538b 100644
--- a/java/driver/jni/src/main/cpp/jni_wrapper.cc
+++ b/java/driver/jni/src/main/cpp/jni_wrapper.cc
@@ -216,51 +216,47 @@ jmethodID RequireMethod(JNIEnv* env, jclass klass,
std::string_view name,
return method;
}
-struct JniStringView {
- JNIEnv* env;
- jstring jni_string;
- const char* value;
-
- explicit JniStringView(JNIEnv* env, jstring jni_string)
- : env(env), jni_string(jni_string), value(nullptr) {
- if (jni_string == nullptr) {
- throw AdbcException{ADBC_STATUS_INTERNAL, "Java string was nullptr"};
- }
- value = env->GetStringUTFChars(jni_string, nullptr);
- if (value == nullptr) {
- throw AdbcException{ADBC_STATUS_INTERNAL,
- "Java string was nullptr (could not get string
contents)"};
- }
+std::string GetJniUtf8String(JNIEnv* env, jbyteArray jni_string) {
+ if (jni_string == nullptr) {
+ throw AdbcException{ADBC_STATUS_INTERNAL, "Java byte array was nullptr"};
}
- ~JniStringView() {
- if (jni_string == nullptr) {
- return;
- }
-
- env->ReleaseStringUTFChars(jni_string, value);
- env->DeleteLocalRef(jni_string);
- jni_string = nullptr;
+ jsize length = env->GetArrayLength(jni_string);
+ if (env->ExceptionCheck()) {
+ throw AdbcException{ADBC_STATUS_INTERNAL, "Could not get byte array
length"};
}
-};
-std::string GetJniString(JNIEnv* env, jstring jni_string) {
- JniStringView view(env, jni_string);
- return std::string(view.value);
+ std::string result(static_cast<size_t>(length), '\0');
+ if (length > 0) {
+ env->GetByteArrayRegion(jni_string, 0, length,
+ reinterpret_cast<jbyte*>(result.data()));
+ if (env->ExceptionCheck()) {
+ throw AdbcException{ADBC_STATUS_INTERNAL, "Could not get byte array
contents"};
+ }
+ }
+ return result;
}
-std::optional<std::string> MaybeGetJniString(JNIEnv* env, jstring jni_string) {
+std::optional<std::string> MaybeGetJniUtf8String(JNIEnv* env, jbyteArray
jni_string) {
if (jni_string == nullptr) {
return std::nullopt;
}
- JniStringView view(env, jni_string);
- return std::string(view.value);
+ return GetJniUtf8String(env, jni_string);
}
-template <typename Callable>
-auto WithJniString(JNIEnv* env, jstring jni_string, Callable&& callable) {
- JniStringView view(env, jni_string);
- return callable(view.value);
+jbyteArray MakeJniUtf8String(JNIEnv* env, const char* value, size_t length) {
+ if (length > 0 && value[length - 1] == '\0') {
+ length--;
+ }
+
+ jbyteArray result = env->NewByteArray(static_cast<jsize>(length));
+ if (result == nullptr || env->ExceptionCheck()) return nullptr;
+ if (length > 0) {
+ env->SetByteArrayRegion(result, 0, static_cast<jsize>(length),
+ reinterpret_cast<const jbyte*>(value));
+ if (env->ExceptionCheck()) return nullptr;
+ }
+ return result;
}
// Get the contents of a ByteBuffer. We may have to copy, so also take a
@@ -430,17 +426,18 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openDatabase(
error_guard.value);
for (jsize i = 0; i < num_params; i += 2) {
- // N.B. assuming String because Java side is typed as String[]
- auto key =
reinterpret_cast<jstring>(env->GetObjectArrayElement(parameters, i));
+ auto key =
reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(parameters, i));
if (env->ExceptionCheck()) return nullptr;
auto value =
- reinterpret_cast<jstring>(env->GetObjectArrayElement(parameters, i +
1));
+ reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(parameters,
i + 1));
if (env->ExceptionCheck()) return nullptr;
- JniStringView key_str(env, key);
- JniStringView value_str(env, value);
- CHECK_ADBC_ERROR(AdbcDatabaseSetOption(&db.value, key_str.value,
value_str.value,
- &error_guard.value),
+ std::string key_str = GetJniUtf8String(env, key);
+ std::string value_str = GetJniUtf8String(env, value);
+ env->DeleteLocalRef(key);
+ env->DeleteLocalRef(value);
+ CHECK_ADBC_ERROR(AdbcDatabaseSetOption(&db.value, key_str.c_str(),
+ value_str.c_str(),
&error_guard.value),
error_guard.value);
}
CHECK_ADBC_ERROR(AdbcDatabaseInit(&db.value, &error_guard.value),
error_guard.value);
@@ -686,12 +683,12 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementExecuteQuery(
JNIEXPORT void JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetSqlQuery(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring query) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray query)
{
AdbcGuard<struct AdbcError> error_guard;
auto* ptr = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
try {
- JniStringView query_str(env, query);
- CHECK_ADBC_ERROR(AdbcStatementSetSqlQuery(ptr, query_str.value,
&error_guard.value),
+ std::string query_str = GetJniUtf8String(env, query);
+ CHECK_ADBC_ERROR(AdbcStatementSetSqlQuery(ptr, query_str.c_str(),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
@@ -798,22 +795,22 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementExecuteSchema(
JNIEXPORT jbyteArray JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionBytes(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* stmt = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
std::vector<uint8_t> buf(1024, '\0');
size_t length = buf.size();
try {
- JniStringView key_str(env, key);
- CHECK_ADBC_ERROR(
- AdbcStatementGetOptionBytes(stmt, key_str.value,
const_cast<uint8_t*>(buf.data()),
- &length, &error_guard.value),
- error_guard.value);
+ std::string key_str = GetJniUtf8String(env, key);
+ CHECK_ADBC_ERROR(AdbcStatementGetOptionBytes(stmt, key_str.c_str(),
+
const_cast<uint8_t*>(buf.data()),
+ &length, &error_guard.value),
+ error_guard.value);
while (length > buf.size()) {
// Buffer was too small, resize and try again
buf.resize(length);
- CHECK_ADBC_ERROR(AdbcStatementGetOptionBytes(stmt, key_str.value,
+ CHECK_ADBC_ERROR(AdbcStatementGetOptionBytes(stmt, key_str.c_str(),
const_cast<uint8_t*>(buf.data()),
&length,
&error_guard.value),
error_guard.value);
@@ -832,14 +829,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionBytes(
JNIEXPORT jdouble JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionDouble(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* stmt = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
double value = 0.0;
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcStatementGetOptionDouble(stmt, key_str.value, &value,
&error_guard.value),
+ AdbcStatementGetOptionDouble(stmt, key_str.c_str(), &value,
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
@@ -850,14 +847,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionDouble(
JNIEXPORT jlong JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionLong(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* stmt = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
int64_t value = 0;
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcStatementGetOptionInt(stmt, key_str.value, &value,
&error_guard.value),
+ AdbcStatementGetOptionInt(stmt, key_str.c_str(), &value,
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
@@ -866,25 +863,25 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionLong(
return static_cast<jlong>(value);
}
-JNIEXPORT jstring JNICALL
+JNIEXPORT jbyteArray JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionString(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* stmt = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
std::vector<char> buf(1024, '\0');
size_t length = buf.size();
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcStatementGetOption(stmt, key_str.value,
const_cast<char*>(buf.data()),
+ AdbcStatementGetOption(stmt, key_str.c_str(),
const_cast<char*>(buf.data()),
&length, &error_guard.value),
error_guard.value);
while (length > buf.size()) {
// Buffer was too small, resize and try again
buf.resize(length);
CHECK_ADBC_ERROR(
- AdbcStatementGetOption(stmt, key_str.value,
const_cast<char*>(buf.data()),
+ AdbcStatementGetOption(stmt, key_str.c_str(),
const_cast<char*>(buf.data()),
&length, &error_guard.value),
error_guard.value);
}
@@ -892,24 +889,24 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionString(
e.ThrowJavaException(env);
return nullptr;
}
- return env->NewStringUTF(buf.data());
+ return MakeJniUtf8String(env, buf.data(), length);
}
JNIEXPORT void JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionBytes(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key,
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
jbyteArray value) {
AdbcGuard<struct AdbcError> error_guard;
auto* stmt = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
jsize value_length = env->GetArrayLength(value);
if (env->ExceptionCheck()) return;
std::vector<uint8_t> value_buf(static_cast<size_t>(value_length));
env->GetByteArrayRegion(value, 0, value_length,
reinterpret_cast<jbyte*>(value_buf.data()));
if (env->ExceptionCheck()) return;
- CHECK_ADBC_ERROR(AdbcStatementSetOptionBytes(stmt, key_str.value,
value_buf.data(),
+ CHECK_ADBC_ERROR(AdbcStatementSetOptionBytes(stmt, key_str.c_str(),
value_buf.data(),
value_buf.size(),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
@@ -919,13 +916,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionBytes(
JNIEXPORT void JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionDouble(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key,
jdouble value) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
+ jdouble value) {
AdbcGuard<struct AdbcError> error_guard;
auto* stmt = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcStatementSetOptionDouble(stmt, key_str.value,
static_cast<double>(value),
+ AdbcStatementSetOptionDouble(stmt, key_str.c_str(),
static_cast<double>(value),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
@@ -935,13 +933,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionDouble(
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) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
+ jlong value) {
AdbcGuard<struct AdbcError> error_guard;
auto* stmt = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcStatementSetOptionInt(stmt, key_str.value,
static_cast<int64_t>(value),
+ AdbcStatementSetOptionInt(stmt, key_str.c_str(),
static_cast<int64_t>(value),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
@@ -951,21 +950,22 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionLong(
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) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
+ jbyteArray value) {
AdbcGuard<struct AdbcError> error_guard;
auto* stmt = reinterpret_cast<struct
AdbcStatement*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
if (value == nullptr) {
CHECK_ADBC_ERROR(
- AdbcStatementSetOption(stmt, key_str.value, nullptr,
&error_guard.value),
+ AdbcStatementSetOption(stmt, key_str.c_str(), nullptr,
&error_guard.value),
error_guard.value);
return;
}
- JniStringView value_str(env, value);
- CHECK_ADBC_ERROR(
- AdbcStatementSetOption(stmt, key_str.value, value_str.value,
&error_guard.value),
- error_guard.value);
+ std::string value_str = GetJniUtf8String(env, value);
+ CHECK_ADBC_ERROR(AdbcStatementSetOption(stmt, key_str.c_str(),
value_str.c_str(),
+ &error_guard.value),
+ error_guard.value);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
}
@@ -985,20 +985,18 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionCancel(
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,
- jstring db_schema, jstring table_name, jobjectArray table_types,
- jstring column_name) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jint depth,
+ jbyteArray catalog, jbyteArray db_schema, jbyteArray table_name,
+ jobjectArray table_types, jbyteArray column_name) {
AdbcGuard<struct AdbcError> error_guard;
try {
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
- // Nullable string parameters: null jstring → NULL for C API (meaning "no
filter")
- auto catalog_str = MaybeGetJniString(env, catalog);
- auto db_schema_str = MaybeGetJniString(env, db_schema);
- auto table_name_str = MaybeGetJniString(env, table_name);
- auto column_name_str = MaybeGetJniString(env, column_name);
+ auto catalog_str = MaybeGetJniUtf8String(env, catalog);
+ auto db_schema_str = MaybeGetJniUtf8String(env, db_schema);
+ auto table_name_str = MaybeGetJniUtf8String(env, table_name);
+ auto column_name_str = MaybeGetJniUtf8String(env, column_name);
- // Convert String[] table_types to const char** (NULL-terminated) or NULL
std::vector<std::string> table_type_strings;
std::vector<const char*> table_type_ptrs;
const char** c_table_types = nullptr;
@@ -1009,9 +1007,10 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetObjects(
table_type_ptrs.reserve(len + 1);
for (jsize i = 0; i < len; i++) {
auto element =
- reinterpret_cast<jstring>(env->GetObjectArrayElement(table_types,
i));
+
reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(table_types, i));
if (env->ExceptionCheck()) return nullptr;
- table_type_strings.push_back(GetJniString(env, element));
+ table_type_strings.push_back(GetJniUtf8String(env, element));
+ env->DeleteLocalRef(element);
table_type_ptrs.push_back(table_type_strings.back().c_str());
}
table_type_ptrs.push_back(nullptr); // NULL terminator
@@ -1073,22 +1072,22 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetInfo(
JNIEXPORT jobject JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetTableSchema(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring catalog,
- jstring db_schema, jstring table_name) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray
catalog,
+ jbyteArray db_schema, jbyteArray table_name) {
AdbcGuard<struct AdbcError> error_guard;
try {
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
- auto catalog_str = MaybeGetJniString(env, catalog);
- auto db_schema_str = MaybeGetJniString(env, db_schema);
- JniStringView table_name_str(env, table_name);
+ auto catalog_str = MaybeGetJniUtf8String(env, catalog);
+ auto db_schema_str = MaybeGetJniUtf8String(env, db_schema);
+ std::string table_name_str = GetJniUtf8String(env, table_name);
struct ArrowSchema schema = {};
CHECK_ADBC_ERROR(
AdbcConnectionGetTableSchema(conn, catalog_str ? catalog_str->c_str()
: nullptr,
db_schema_str ? db_schema_str->c_str() :
nullptr,
- table_name_str.value, &schema,
&error_guard.value),
+ table_name_str.c_str(), &schema,
&error_guard.value),
error_guard.value);
return MakeNativeSchemaResult(env, &schema);
@@ -1119,22 +1118,22 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetTableTypes(
JNIEXPORT jbyteArray JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionBytes(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
std::vector<uint8_t> buf(1024, '\0');
size_t length = buf.size();
try {
- JniStringView key_str(env, key);
- CHECK_ADBC_ERROR(AdbcConnectionGetOptionBytes(conn, key_str.value,
+ std::string key_str = GetJniUtf8String(env, key);
+ CHECK_ADBC_ERROR(AdbcConnectionGetOptionBytes(conn, key_str.c_str(),
const_cast<uint8_t*>(buf.data()),
&length, &error_guard.value),
error_guard.value);
while (length > buf.size()) {
// Buffer was too small, resize and try again
buf.resize(length);
- CHECK_ADBC_ERROR(AdbcConnectionGetOptionBytes(conn, key_str.value,
+ CHECK_ADBC_ERROR(AdbcConnectionGetOptionBytes(conn, key_str.c_str(),
const_cast<uint8_t*>(buf.data()),
&length,
&error_guard.value),
error_guard.value);
@@ -1153,14 +1152,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionBytes(
JNIEXPORT jdouble JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionDouble(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
double value = 0.0;
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcConnectionGetOptionDouble(conn, key_str.value, &value,
&error_guard.value),
+ AdbcConnectionGetOptionDouble(conn, key_str.c_str(), &value,
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
@@ -1171,14 +1170,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionDouble(
JNIEXPORT jlong JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionLong(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
int64_t value = 0;
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcConnectionGetOptionInt(conn, key_str.value, &value,
&error_guard.value),
+ AdbcConnectionGetOptionInt(conn, key_str.c_str(), &value,
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
@@ -1187,25 +1186,25 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionLong(
return static_cast<jlong>(value);
}
-JNIEXPORT jstring JNICALL
+JNIEXPORT jbyteArray JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionString(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
std::vector<char> buf(1024, '\0');
size_t length = buf.size();
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcConnectionGetOption(conn, key_str.value,
const_cast<char*>(buf.data()),
+ AdbcConnectionGetOption(conn, key_str.c_str(),
const_cast<char*>(buf.data()),
&length, &error_guard.value),
error_guard.value);
while (length > buf.size()) {
// Buffer was too small, resize and try again
buf.resize(length);
CHECK_ADBC_ERROR(
- AdbcConnectionGetOption(conn, key_str.value,
const_cast<char*>(buf.data()),
+ AdbcConnectionGetOption(conn, key_str.c_str(),
const_cast<char*>(buf.data()),
&length, &error_guard.value),
error_guard.value);
}
@@ -1213,24 +1212,24 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionString(
e.ThrowJavaException(env);
return nullptr;
}
- return env->NewStringUTF(buf.data());
+ return MakeJniUtf8String(env, buf.data(), length);
}
JNIEXPORT void JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionBytes(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key,
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
jbyteArray value) {
AdbcGuard<struct AdbcError> error_guard;
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
jsize value_length = env->GetArrayLength(value);
if (env->ExceptionCheck()) return;
std::vector<uint8_t> value_buf(static_cast<size_t>(value_length));
env->GetByteArrayRegion(value, 0, value_length,
reinterpret_cast<jbyte*>(value_buf.data()));
if (env->ExceptionCheck()) return;
- CHECK_ADBC_ERROR(AdbcConnectionSetOptionBytes(conn, key_str.value,
value_buf.data(),
+ CHECK_ADBC_ERROR(AdbcConnectionSetOptionBytes(conn, key_str.c_str(),
value_buf.data(),
value_buf.size(),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
@@ -1240,13 +1239,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionBytes(
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) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
+ jdouble value) {
AdbcGuard<struct AdbcError> error_guard;
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcConnectionSetOptionDouble(conn, key_str.value,
static_cast<double>(value),
+ AdbcConnectionSetOptionDouble(conn, key_str.c_str(),
static_cast<double>(value),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
@@ -1256,13 +1256,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionDouble(
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) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
+ jlong value) {
AdbcGuard<struct AdbcError> error_guard;
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcConnectionSetOptionInt(conn, key_str.value,
static_cast<int64_t>(value),
+ AdbcConnectionSetOptionInt(conn, key_str.c_str(),
static_cast<int64_t>(value),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
@@ -1272,21 +1273,22 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionLong(
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) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
+ jbyteArray value) {
AdbcGuard<struct AdbcError> error_guard;
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
if (value == nullptr) {
CHECK_ADBC_ERROR(
- AdbcConnectionSetOption(conn, key_str.value, nullptr,
&error_guard.value),
+ AdbcConnectionSetOption(conn, key_str.c_str(), nullptr,
&error_guard.value),
error_guard.value);
return;
}
- JniStringView value_str(env, value);
- CHECK_ADBC_ERROR(
- AdbcConnectionSetOption(conn, key_str.value, value_str.value,
&error_guard.value),
- error_guard.value);
+ std::string value_str = GetJniUtf8String(env, value);
+ CHECK_ADBC_ERROR(AdbcConnectionSetOption(conn, key_str.c_str(),
value_str.c_str(),
+ &error_guard.value),
+ error_guard.value);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
}
@@ -1361,15 +1363,15 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetStatisticName
JNIEXPORT jobject JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetStatistics(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring catalog,
- jstring schema, jstring table, jboolean approximate) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray
catalog,
+ jbyteArray schema, jbyteArray table, jboolean approximate) {
AdbcGuard<struct AdbcError> error_guard;
auto* conn = reinterpret_cast<struct
AdbcConnection*>(static_cast<uintptr_t>(handle));
struct ArrowArrayStream out = {};
try {
- std::optional<std::string> catalog_str = MaybeGetJniString(env, catalog);
- std::optional<std::string> schema_str = MaybeGetJniString(env, schema);
- std::optional<std::string> table_str = MaybeGetJniString(env, table);
+ std::optional<std::string> catalog_str = MaybeGetJniUtf8String(env,
catalog);
+ std::optional<std::string> schema_str = MaybeGetJniUtf8String(env, schema);
+ std::optional<std::string> table_str = MaybeGetJniUtf8String(env, table);
CHECK_ADBC_ERROR(
AdbcConnectionGetStatistics(conn, catalog_str ? catalog_str->c_str() :
nullptr,
schema_str ? schema_str->c_str() : nullptr,
@@ -1385,25 +1387,25 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetStatistics(
JNIEXPORT jbyteArray JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionBytes(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* db = reinterpret_cast<struct
AdbcDatabase*>(static_cast<uintptr_t>(handle));
std::vector<uint8_t> buf(1024, '\0');
size_t length = buf.size();
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcDatabaseGetOptionBytes(db, key_str.value,
const_cast<uint8_t*>(buf.data()),
+ AdbcDatabaseGetOptionBytes(db, key_str.c_str(),
const_cast<uint8_t*>(buf.data()),
&length, &error_guard.value),
error_guard.value);
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<uint8_t*>(buf.data()),
- &length, &error_guard.value),
- error_guard.value);
+ CHECK_ADBC_ERROR(AdbcDatabaseGetOptionBytes(db, key_str.c_str(),
+
const_cast<uint8_t*>(buf.data()),
+ &length, &error_guard.value),
+ error_guard.value);
}
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
@@ -1419,14 +1421,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionBytes(
JNIEXPORT jdouble JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionDouble(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* db = reinterpret_cast<struct
AdbcDatabase*>(static_cast<uintptr_t>(handle));
double value = 0.0;
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcDatabaseGetOptionDouble(db, key_str.value, &value,
&error_guard.value),
+ AdbcDatabaseGetOptionDouble(db, key_str.c_str(), &value,
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
@@ -1437,14 +1439,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionDouble(
JNIEXPORT jlong JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionLong(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* db = reinterpret_cast<struct
AdbcDatabase*>(static_cast<uintptr_t>(handle));
int64_t value = 0;
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcDatabaseGetOptionInt(db, key_str.value, &value,
&error_guard.value),
+ AdbcDatabaseGetOptionInt(db, key_str.c_str(), &value,
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
@@ -1453,50 +1455,50 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionLong(
return static_cast<jlong>(value);
}
-JNIEXPORT jstring JNICALL
+JNIEXPORT jbyteArray JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionString(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key) {
AdbcGuard<struct AdbcError> error_guard;
auto* db = reinterpret_cast<struct
AdbcDatabase*>(static_cast<uintptr_t>(handle));
std::vector<char> buf(1024, '\0');
size_t length = buf.size();
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcDatabaseGetOption(db, key_str.value,
const_cast<char*>(buf.data()), &length,
+ AdbcDatabaseGetOption(db, key_str.c_str(),
const_cast<char*>(buf.data()), &length,
&error_guard.value),
error_guard.value);
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<char*>(buf.data()), &length,
- &error_guard.value),
+ AdbcDatabaseGetOption(db, key_str.c_str(),
const_cast<char*>(buf.data()),
+ &length, &error_guard.value),
error_guard.value);
}
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
return nullptr;
}
- return env->NewStringUTF(buf.data());
+ return MakeJniUtf8String(env, buf.data(), length);
}
JNIEXPORT void JNICALL
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseSetOptionBytes(
- JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jstring key,
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
jbyteArray value) {
AdbcGuard<struct AdbcError> error_guard;
auto* db = reinterpret_cast<struct
AdbcDatabase*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
jsize value_length = env->GetArrayLength(value);
if (env->ExceptionCheck()) return;
std::vector<uint8_t> value_buf(static_cast<size_t>(value_length));
env->GetByteArrayRegion(value, 0, value_length,
reinterpret_cast<jbyte*>(value_buf.data()));
if (env->ExceptionCheck()) return;
- CHECK_ADBC_ERROR(AdbcDatabaseSetOptionBytes(db, key_str.value,
value_buf.data(),
+ CHECK_ADBC_ERROR(AdbcDatabaseSetOptionBytes(db, key_str.c_str(),
value_buf.data(),
value_buf.size(),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
@@ -1506,13 +1508,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseSetOptionBytes(
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) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
+ jdouble value) {
AdbcGuard<struct AdbcError> error_guard;
auto* db = reinterpret_cast<struct
AdbcDatabase*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcDatabaseSetOptionDouble(db, key_str.value,
static_cast<double>(value),
+ AdbcDatabaseSetOptionDouble(db, key_str.c_str(),
static_cast<double>(value),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
@@ -1522,13 +1525,14 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseSetOptionDouble(
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) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
+ jlong value) {
AdbcGuard<struct AdbcError> error_guard;
auto* db = reinterpret_cast<struct
AdbcDatabase*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
CHECK_ADBC_ERROR(
- AdbcDatabaseSetOptionInt(db, key_str.value,
static_cast<int64_t>(value),
+ AdbcDatabaseSetOptionInt(db, key_str.c_str(),
static_cast<int64_t>(value),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
@@ -1538,20 +1542,21 @@
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseSetOptionLong(
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) {
+ JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jbyteArray key,
+ jbyteArray value) {
AdbcGuard<struct AdbcError> error_guard;
auto* db = reinterpret_cast<struct
AdbcDatabase*>(static_cast<uintptr_t>(handle));
try {
- JniStringView key_str(env, key);
+ std::string key_str = GetJniUtf8String(env, key);
if (value == nullptr) {
CHECK_ADBC_ERROR(
- AdbcDatabaseSetOption(db, key_str.value, nullptr,
&error_guard.value),
+ AdbcDatabaseSetOption(db, key_str.c_str(), nullptr,
&error_guard.value),
error_guard.value);
return;
}
- JniStringView value_str(env, value);
+ std::string value_str = GetJniUtf8String(env, value);
CHECK_ADBC_ERROR(
- AdbcDatabaseSetOption(db, key_str.value, value_str.value,
&error_guard.value),
+ AdbcDatabaseSetOption(db, key_str.c_str(), value_str.c_str(),
&error_guard.value),
error_guard.value);
} catch (const AdbcException& e) {
e.ThrowJavaException(env);
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 3174655c5..e2934741c 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
@@ -22,6 +22,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Map;
@@ -65,11 +66,11 @@ public enum JniLoader {
}
public NativeDatabaseHandle openDatabase(Map<String, String> parameters)
throws AdbcException {
- String[] nativeParameters = new String[parameters.size() * 2];
+ byte[][] nativeParameters = new byte[parameters.size() * 2][];
int index = 0;
for (Map.Entry<String, String> parameter : parameters.entrySet()) {
- nativeParameters[index++] = parameter.getKey();
- nativeParameters[index++] = parameter.getValue();
+ nativeParameters[index++] = stringToUtf8(parameter.getKey());
+ nativeParameters[index++] = stringToUtf8(parameter.getValue());
}
return NativeAdbc.openDatabase(1001000, nativeParameters);
}
@@ -99,7 +100,7 @@ public enum JniLoader {
public void statementSetSqlQuery(NativeStatementHandle statement, String
query)
throws AdbcException {
- NativeAdbc.statementSetSqlQuery(statement.getStatementHandle(), query);
+ NativeAdbc.statementSetSqlQuery(statement.getStatementHandle(),
stringToUtf8(query));
}
public void statementSetSubstraitPlan(NativeStatementHandle statement,
ByteBuffer plan)
@@ -138,42 +139,44 @@ public enum JniLoader {
public byte[] statementGetOptionBytes(NativeStatementHandle handle, String
key)
throws AdbcException {
- return NativeAdbc.statementGetOptionBytes(handle.getStatementHandle(),
key);
+ return NativeAdbc.statementGetOptionBytes(handle.getStatementHandle(),
stringToUtf8(key));
}
public double statementGetOptionDouble(NativeStatementHandle handle, String
key)
throws AdbcException {
- return NativeAdbc.statementGetOptionDouble(handle.getStatementHandle(),
key);
+ return NativeAdbc.statementGetOptionDouble(handle.getStatementHandle(),
stringToUtf8(key));
}
public long statementGetOptionLong(NativeStatementHandle handle, String key)
throws AdbcException {
- return NativeAdbc.statementGetOptionLong(handle.getStatementHandle(), key);
+ return NativeAdbc.statementGetOptionLong(handle.getStatementHandle(),
stringToUtf8(key));
}
public String statementGetOptionString(NativeStatementHandle handle, String
key)
throws AdbcException {
- return NativeAdbc.statementGetOptionString(handle.getStatementHandle(),
key);
+ return utf8ToString(
+ NativeAdbc.statementGetOptionString(handle.getStatementHandle(),
stringToUtf8(key)));
}
public void statementSetOptionBytes(NativeStatementHandle handle, String
key, byte[] value)
throws AdbcException {
- NativeAdbc.statementSetOptionBytes(handle.getStatementHandle(), key,
value);
+ NativeAdbc.statementSetOptionBytes(handle.getStatementHandle(),
stringToUtf8(key), value);
}
public void statementSetOptionDouble(NativeStatementHandle handle, String
key, double value)
throws AdbcException {
- NativeAdbc.statementSetOptionDouble(handle.getStatementHandle(), key,
value);
+ NativeAdbc.statementSetOptionDouble(handle.getStatementHandle(),
stringToUtf8(key), value);
}
public void statementSetOptionLong(NativeStatementHandle handle, String key,
long value)
throws AdbcException {
- NativeAdbc.statementSetOptionLong(handle.getStatementHandle(), key, value);
+ NativeAdbc.statementSetOptionLong(handle.getStatementHandle(),
stringToUtf8(key), value);
}
public void statementSetOptionString(NativeStatementHandle statement, String
key, String value)
throws AdbcException {
- NativeAdbc.statementSetOptionString(statement.getStatementHandle(), key,
value);
+ NativeAdbc.statementSetOptionString(
+ statement.getStatementHandle(), stringToUtf8(key),
stringToUtf8(value));
}
public void connectionCancel(NativeConnectionHandle connection) throws
AdbcException {
@@ -192,11 +195,11 @@ public enum JniLoader {
return NativeAdbc.connectionGetObjects(
connection.getConnectionHandle(),
depth,
- catalog,
- dbSchema,
- tableName,
- tableTypes,
- columnName);
+ stringToUtf8(catalog),
+ stringToUtf8(dbSchema),
+ stringToUtf8(tableName),
+ stringArrayToUtf8(tableTypes),
+ stringToUtf8(columnName));
}
public NativeQueryResult connectionGetInfo(NativeConnectionHandle
connection, int[] infoCodes)
@@ -208,7 +211,10 @@ public enum JniLoader {
NativeConnectionHandle connection, String catalog, String dbSchema,
String tableName)
throws AdbcException {
return NativeAdbc.connectionGetTableSchema(
- connection.getConnectionHandle(), catalog, dbSchema, tableName);
+ connection.getConnectionHandle(),
+ stringToUtf8(catalog),
+ stringToUtf8(dbSchema),
+ stringToUtf8(tableName));
}
public NativeQueryResult connectionGetTableTypes(NativeConnectionHandle
connection)
@@ -231,42 +237,44 @@ public enum JniLoader {
public byte[] connectionGetOptionBytes(NativeConnectionHandle handle, String
key)
throws AdbcException {
- return NativeAdbc.connectionGetOptionBytes(handle.getConnectionHandle(),
key);
+ return NativeAdbc.connectionGetOptionBytes(handle.getConnectionHandle(),
stringToUtf8(key));
}
public double connectionGetOptionDouble(NativeConnectionHandle handle,
String key)
throws AdbcException {
- return NativeAdbc.connectionGetOptionDouble(handle.getConnectionHandle(),
key);
+ return NativeAdbc.connectionGetOptionDouble(handle.getConnectionHandle(),
stringToUtf8(key));
}
public long connectionGetOptionLong(NativeConnectionHandle handle, String
key)
throws AdbcException {
- return NativeAdbc.connectionGetOptionLong(handle.getConnectionHandle(),
key);
+ return NativeAdbc.connectionGetOptionLong(handle.getConnectionHandle(),
stringToUtf8(key));
}
public String connectionGetOptionString(NativeConnectionHandle handle,
String key)
throws AdbcException {
- return NativeAdbc.connectionGetOptionString(handle.getConnectionHandle(),
key);
+ return utf8ToString(
+ NativeAdbc.connectionGetOptionString(handle.getConnectionHandle(),
stringToUtf8(key)));
}
public void connectionSetOptionBytes(NativeConnectionHandle handle, String
key, byte[] value)
throws AdbcException {
- NativeAdbc.connectionSetOptionBytes(handle.getConnectionHandle(), key,
value);
+ NativeAdbc.connectionSetOptionBytes(handle.getConnectionHandle(),
stringToUtf8(key), value);
}
public void connectionSetOptionDouble(NativeConnectionHandle handle, String
key, double value)
throws AdbcException {
- NativeAdbc.connectionSetOptionDouble(handle.getConnectionHandle(), key,
value);
+ NativeAdbc.connectionSetOptionDouble(handle.getConnectionHandle(),
stringToUtf8(key), value);
}
public void connectionSetOptionLong(NativeConnectionHandle handle, String
key, long value)
throws AdbcException {
- NativeAdbc.connectionSetOptionLong(handle.getConnectionHandle(), key,
value);
+ NativeAdbc.connectionSetOptionLong(handle.getConnectionHandle(),
stringToUtf8(key), value);
}
public void connectionSetOptionString(NativeConnectionHandle connection,
String key, String value)
throws AdbcException {
- NativeAdbc.connectionSetOptionString(connection.getConnectionHandle(),
key, value);
+ NativeAdbc.connectionSetOptionString(
+ connection.getConnectionHandle(), stringToUtf8(key),
stringToUtf8(value));
}
public NativeQueryResult connectionGetStatistics(
@@ -278,9 +286,9 @@ public enum JniLoader {
throws AdbcException {
return NativeAdbc.connectionGetStatistics(
connection.getConnectionHandle(),
- catalogPattern,
- dbSchemaPattern,
- tableNamePattern,
+ stringToUtf8(catalogPattern),
+ stringToUtf8(dbSchemaPattern),
+ stringToUtf8(tableNamePattern),
approximate);
}
@@ -291,40 +299,61 @@ public enum JniLoader {
public byte[] databaseGetOptionBytes(NativeDatabaseHandle handle, String key)
throws AdbcException {
- return NativeAdbc.databaseGetOptionBytes(handle.getDatabaseHandle(), key);
+ return NativeAdbc.databaseGetOptionBytes(handle.getDatabaseHandle(),
stringToUtf8(key));
}
public double databaseGetOptionDouble(NativeDatabaseHandle handle, String
key)
throws AdbcException {
- return NativeAdbc.databaseGetOptionDouble(handle.getDatabaseHandle(), key);
+ return NativeAdbc.databaseGetOptionDouble(handle.getDatabaseHandle(),
stringToUtf8(key));
}
public long databaseGetOptionLong(NativeDatabaseHandle handle, String key)
throws AdbcException {
- return NativeAdbc.databaseGetOptionLong(handle.getDatabaseHandle(), key);
+ return NativeAdbc.databaseGetOptionLong(handle.getDatabaseHandle(),
stringToUtf8(key));
}
public String databaseGetOptionString(NativeDatabaseHandle handle, String
key)
throws AdbcException {
- return NativeAdbc.databaseGetOptionString(handle.getDatabaseHandle(), key);
+ return utf8ToString(
+ NativeAdbc.databaseGetOptionString(handle.getDatabaseHandle(),
stringToUtf8(key)));
}
public void databaseSetOptionBytes(NativeDatabaseHandle handle, String key,
byte[] value)
throws AdbcException {
- NativeAdbc.databaseSetOptionBytes(handle.getDatabaseHandle(), key, value);
+ NativeAdbc.databaseSetOptionBytes(handle.getDatabaseHandle(),
stringToUtf8(key), value);
}
public void databaseSetOptionDouble(NativeDatabaseHandle handle, String key,
double value)
throws AdbcException {
- NativeAdbc.databaseSetOptionDouble(handle.getDatabaseHandle(), key, value);
+ NativeAdbc.databaseSetOptionDouble(handle.getDatabaseHandle(),
stringToUtf8(key), value);
}
public void databaseSetOptionLong(NativeDatabaseHandle handle, String key,
long value)
throws AdbcException {
- NativeAdbc.databaseSetOptionLong(handle.getDatabaseHandle(), key, value);
+ NativeAdbc.databaseSetOptionLong(handle.getDatabaseHandle(),
stringToUtf8(key), value);
}
public void databaseSetOptionString(NativeDatabaseHandle handle, String key,
String value)
throws AdbcException {
- NativeAdbc.databaseSetOptionString(handle.getDatabaseHandle(), key, value);
+ NativeAdbc.databaseSetOptionString(
+ handle.getDatabaseHandle(), stringToUtf8(key), stringToUtf8(value));
+ }
+
+ private static byte[] stringToUtf8(String value) {
+ return value == null ? null : value.getBytes(StandardCharsets.UTF_8);
+ }
+
+ private static byte[][] stringArrayToUtf8(String[] values) {
+ if (values == null) {
+ return null;
+ }
+ byte[][] result = new byte[values.length][];
+ for (int i = 0; i < values.length; i++) {
+ result[i] = stringToUtf8(values[i]);
+ }
+ return result;
+ }
+
+ private static String utf8ToString(byte[] value) {
+ return value == null ? null : new String(value, StandardCharsets.UTF_8);
}
}
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 c2059532f..b23245430 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
@@ -22,7 +22,7 @@ import org.apache.arrow.adbc.core.AdbcException;
/** All the JNI methods. Don't use this directly, prefer {@link JniLoader}. */
class NativeAdbc {
- static native NativeDatabaseHandle openDatabase(int version, String[]
parameters)
+ static native NativeDatabaseHandle openDatabase(int version, byte[][]
parameters)
throws AdbcException;
static native void closeDatabase(long handle) throws AdbcException;
@@ -57,28 +57,28 @@ class NativeAdbc {
static native NativeSchemaResult statementGetParameterSchema(long
statementHandle)
throws AdbcException;
- static native void statementSetSqlQuery(long handle, String query) throws
AdbcException;
+ static native void statementSetSqlQuery(long handle, byte[] query) throws
AdbcException;
static native void statementSetSubstraitPlan(long handle, ByteBuffer plan)
throws AdbcException;
- static native byte[] statementGetOptionBytes(long handle, String key) throws
AdbcException;
+ static native byte[] statementGetOptionBytes(long handle, byte[] key) throws
AdbcException;
- static native double statementGetOptionDouble(long handle, String key)
throws AdbcException;
+ static native double statementGetOptionDouble(long handle, byte[] key)
throws AdbcException;
- static native long statementGetOptionLong(long handle, String key) throws
AdbcException;
+ static native long statementGetOptionLong(long handle, byte[] key) throws
AdbcException;
- static native String statementGetOptionString(long handle, String key)
throws AdbcException;
+ static native byte[] statementGetOptionString(long handle, byte[] key)
throws AdbcException;
- static native void statementSetOptionBytes(long handle, String key, byte[]
value)
+ static native void statementSetOptionBytes(long handle, byte[] key, byte[]
value)
throws AdbcException;
- static native void statementSetOptionDouble(long handle, String key, double
value)
+ static native void statementSetOptionDouble(long handle, byte[] key, double
value)
throws AdbcException;
- static native void statementSetOptionLong(long handle, String key, long
value)
+ static native void statementSetOptionLong(long handle, byte[] key, long
value)
throws AdbcException;
- static native void statementSetOptionString(long handle, String key, String
value)
+ static native void statementSetOptionString(long handle, byte[] key, byte[]
value)
throws AdbcException;
static native void connectionCancel(long handle) throws AdbcException;
@@ -86,18 +86,18 @@ class NativeAdbc {
static native NativeQueryResult connectionGetObjects(
long handle,
int depth,
- String catalog,
- String dbSchema,
- String tableName,
- String[] tableTypes,
- String columnName)
+ byte[] catalog,
+ byte[] dbSchema,
+ byte[] tableName,
+ byte[][] tableTypes,
+ byte[] columnName)
throws AdbcException;
static native NativeQueryResult connectionGetInfo(long handle, int[]
infoCodes)
throws AdbcException;
static native NativeSchemaResult connectionGetTableSchema(
- long handle, String catalog, String dbSchema, String tableName) throws
AdbcException;
+ long handle, byte[] catalog, byte[] dbSchema, byte[] tableName) throws
AdbcException;
static native NativeQueryResult connectionGetTableTypes(long handle) throws
AdbcException;
@@ -108,53 +108,53 @@ class NativeAdbc {
static native NativeQueryResult connectionReadPartition(long handle,
ByteBuffer partition)
throws AdbcException;
- static native byte[] connectionGetOptionBytes(long handle, String key)
throws AdbcException;
+ static native byte[] connectionGetOptionBytes(long handle, byte[] key)
throws AdbcException;
- static native double connectionGetOptionDouble(long handle, String key)
throws AdbcException;
+ static native double connectionGetOptionDouble(long handle, byte[] key)
throws AdbcException;
- static native long connectionGetOptionLong(long handle, String key) throws
AdbcException;
+ static native long connectionGetOptionLong(long handle, byte[] key) throws
AdbcException;
- static native String connectionGetOptionString(long handle, String key)
throws AdbcException;
+ static native byte[] connectionGetOptionString(long handle, byte[] key)
throws AdbcException;
- static native void connectionSetOptionBytes(long handle, String key, byte[]
value)
+ static native void connectionSetOptionBytes(long handle, byte[] key, byte[]
value)
throws AdbcException;
- static native void connectionSetOptionDouble(long handle, String key, double
value)
+ static native void connectionSetOptionDouble(long handle, byte[] key, double
value)
throws AdbcException;
- static native void connectionSetOptionLong(long handle, String key, long
value)
+ static native void connectionSetOptionLong(long handle, byte[] key, long
value)
throws AdbcException;
- static native void connectionSetOptionString(long handle, String key, String
value)
+ static native void connectionSetOptionString(long handle, byte[] key, byte[]
value)
throws AdbcException;
static native NativeQueryResult connectionGetStatisticNames(long handle)
throws AdbcException;
static native NativeQueryResult connectionGetStatistics(
long handle,
- String catalogPattern,
- String dbSchemaPattern,
- String tableNamePattern,
+ byte[] catalogPattern,
+ byte[] dbSchemaPattern,
+ byte[] tableNamePattern,
boolean approximate)
throws AdbcException;
- static native byte[] databaseGetOptionBytes(long handle, String key) throws
AdbcException;
+ static native byte[] databaseGetOptionBytes(long handle, byte[] key) throws
AdbcException;
- static native double databaseGetOptionDouble(long handle, String key) throws
AdbcException;
+ static native double databaseGetOptionDouble(long handle, byte[] key) throws
AdbcException;
- static native long databaseGetOptionLong(long handle, String key) throws
AdbcException;
+ static native long databaseGetOptionLong(long handle, byte[] key) throws
AdbcException;
- static native String databaseGetOptionString(long handle, String key) throws
AdbcException;
+ static native byte[] databaseGetOptionString(long handle, byte[] key) throws
AdbcException;
- static native void databaseSetOptionBytes(long handle, String key, byte[]
value)
+ static native void databaseSetOptionBytes(long handle, byte[] key, byte[]
value)
throws AdbcException;
- static native void databaseSetOptionDouble(long handle, String key, double
value)
+ static native void databaseSetOptionDouble(long handle, byte[] key, double
value)
throws AdbcException;
- static native void databaseSetOptionLong(long handle, String key, long value)
+ static native void databaseSetOptionLong(long handle, byte[] key, long value)
throws AdbcException;
- static native void databaseSetOptionString(long handle, String key, String
value)
+ static native void databaseSetOptionString(long handle, byte[] key, byte[]
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 14adf62e0..94712c86f 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
@@ -144,6 +144,29 @@ class JniDriverTest {
}
}
+ // Ensure strings with characters that differ between UTF-8 and Java's
"modifiefd UTF-8" are
+ // properly serialized
+ @Test
+ void queryNonBmpUtf8() throws Exception {
+ try (final BufferAllocator allocator = new RootAllocator()) {
+ JniDriver driver = new JniDriver(allocator);
+ Map<String, Object> parameters = new HashMap<>();
+ JniDriver.PARAM_DRIVER.set(parameters, "adbc_driver_sqlite");
+ String expected = "\uD83D\uDE00";
+
+ try (final AdbcDatabase db = driver.open(parameters);
+ final AdbcConnection conn = db.connect();
+ final AdbcStatement stmt = conn.createStatement()) {
+ stmt.setSqlQuery("SELECT '" + expected + "'");
+ try (final AdbcStatement.QueryResult result = stmt.executeQuery()) {
+ assertThat(result.getReader().loadNextBatch()).isTrue();
+
assertThat(result.getReader().getVectorSchemaRoot().getVector(0).getObject(0))
+ .hasToString(expected);
+ }
+ }
+ }
+ }
+
@Test
void statementThrowsAfterClose() throws Exception {
try (final BufferAllocator allocator = new RootAllocator()) {