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 bca1bc8f9 fix(java/driver/jni): release AdbcError in 
RaiseAdbcException (#4391)
bca1bc8f9 is described below

commit bca1bc8f9219df71a9f321e77e784aa92465a437
Author: David Li <[email protected]>
AuthorDate: Sun Jun 14 15:07:02 2026 -0700

    fix(java/driver/jni): release AdbcError in RaiseAdbcException (#4391)
    
    We were simply leaking any errors before.
    
    ---------
    
    Assisted-by: Claude Opus 4.8 <[email protected]>
    Assisted-by: Copilot Autofix powered by AI 
<[email protected]>
---
 java/driver/jni/src/main/cpp/jni_wrapper.cc | 403 ++++++++++++++++------------
 1 file changed, 231 insertions(+), 172 deletions(-)

diff --git a/java/driver/jni/src/main/cpp/jni_wrapper.cc 
b/java/driver/jni/src/main/cpp/jni_wrapper.cc
index 385a65ae1..6af1a247c 100644
--- a/java/driver/jni/src/main/cpp/jni_wrapper.cc
+++ b/java/driver/jni/src/main/cpp/jni_wrapper.cc
@@ -35,6 +35,23 @@
 
 namespace {
 
+struct AdbcErrorGuard {
+  AdbcErrorGuard() = default;
+  AdbcErrorGuard(const AdbcErrorGuard&) = delete;
+  AdbcErrorGuard& operator=(const AdbcErrorGuard&) = delete;
+  AdbcErrorGuard(AdbcErrorGuard&&) = delete;
+  AdbcErrorGuard& operator=(AdbcErrorGuard&&) = delete;
+
+  struct AdbcError error = ADBC_ERROR_INIT;
+
+  ~AdbcErrorGuard() {
+    if (error.release != nullptr) {
+      error.release(&error);
+      error.release = nullptr;
+    }
+  }
+};
+
 void ThrowJavaException(JNIEnv* env, const std::string& klass,
                         const std::string& message) {
   jclass exception_klass = env->FindClass(klass.c_str());
@@ -107,13 +124,18 @@ struct AdbcException {
 };
 
 /// Signal an error to Java.
-void RaiseAdbcException(AdbcStatusCode code, const AdbcError& error) {
+void RaiseAdbcException(AdbcStatusCode code, AdbcError& error) {
   assert(code != ADBC_STATUS_OK);
-  throw AdbcException{
+  AdbcException exception{
       .code = code,
       .message =
           error.message ? std::string(error.message) : std::string("(unknown 
error)"),
   };
+  if (error.release != nullptr) {
+    error.release(&error);
+    error.release = nullptr;
+  }
+  throw exception;
 }
 
 /// Check the result of an ADBC call and raise an exception to Java if it 
failed.
@@ -304,15 +326,15 @@ JNIEXPORT jobject JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openDatabase(
     JNIEnv* env, [[maybe_unused]] jclass self, [[maybe_unused]] jint version,
     jobjectArray parameters) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto db = std::make_unique<struct AdbcDatabase>();
     std::memset(db.get(), 0, sizeof(struct AdbcDatabase));
 
-    CHECK_ADBC_ERROR(AdbcDatabaseNew(db.get(), &error), error);
-    CHECK_ADBC_ERROR(
-        AdbcDriverManagerDatabaseSetLoadFlags(db.get(), 
ADBC_LOAD_FLAG_DEFAULT, &error),
-        error);
+    CHECK_ADBC_ERROR(AdbcDatabaseNew(db.get(), &error_guard.error), 
error_guard.error);
+    CHECK_ADBC_ERROR(AdbcDriverManagerDatabaseSetLoadFlags(
+                         db.get(), ADBC_LOAD_FLAG_DEFAULT, &error_guard.error),
+                     error_guard.error);
 
     const jsize num_params = env->GetArrayLength(parameters);
     if (num_params % 2 != 0) {
@@ -329,11 +351,12 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openDatabase(
 
       JniStringView key_str(env, key);
       JniStringView value_str(env, value);
-      CHECK_ADBC_ERROR(
-          AdbcDatabaseSetOption(db.get(), key_str.value, value_str.value, 
&error), error);
+      CHECK_ADBC_ERROR(AdbcDatabaseSetOption(db.get(), key_str.value, 
value_str.value,
+                                             &error_guard.error),
+                       error_guard.error);
     }
 
-    CHECK_ADBC_ERROR(AdbcDatabaseInit(db.get(), &error), error);
+    CHECK_ADBC_ERROR(AdbcDatabaseInit(db.get(), &error_guard.error), 
error_guard.error);
 
     jclass nativeHandleKlass = RequireImplClass(env, "NativeDatabaseHandle");
     jmethodID nativeHandleCtor = RequireMethod(env, nativeHandleKlass, 
"<init>", "(J)V");
@@ -352,10 +375,10 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openDatabase(
 JNIEXPORT void JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_closeDatabase(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* ptr = reinterpret_cast<struct 
AdbcDatabase*>(static_cast<uintptr_t>(handle));
-    CHECK_ADBC_ERROR(AdbcDatabaseRelease(ptr, &error), error);
+    CHECK_ADBC_ERROR(AdbcDatabaseRelease(ptr, &error_guard.error), 
error_guard.error);
     delete ptr;
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -365,16 +388,18 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_closeDatabase(
 JNIEXPORT jobject JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openConnection(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong database_handle) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto conn = std::make_unique<struct AdbcConnection>();
     std::memset(conn.get(), 0, sizeof(struct AdbcConnection));
 
     auto* db =
         reinterpret_cast<struct 
AdbcDatabase*>(static_cast<uintptr_t>(database_handle));
 
-    CHECK_ADBC_ERROR(AdbcConnectionNew(conn.get(), &error), error);
-    CHECK_ADBC_ERROR(AdbcConnectionInit(conn.get(), db, &error), error);
+    CHECK_ADBC_ERROR(AdbcConnectionNew(conn.get(), &error_guard.error),
+                     error_guard.error);
+    CHECK_ADBC_ERROR(AdbcConnectionInit(conn.get(), db, &error_guard.error),
+                     error_guard.error);
 
     jclass native_handle_class = RequireImplClass(env, 
"NativeConnectionHandle");
     jmethodID native_handle_ctor =
@@ -394,10 +419,10 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openConnection(
 JNIEXPORT void JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_closeConnection(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* ptr = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
-    CHECK_ADBC_ERROR(AdbcConnectionRelease(ptr, &error), error);
+    CHECK_ADBC_ERROR(AdbcConnectionRelease(ptr, &error_guard.error), 
error_guard.error);
     delete ptr;
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -407,15 +432,16 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_closeConnection(
 JNIEXPORT jobject JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openStatement(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong connection_handle) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto stmt = std::make_unique<struct AdbcStatement>();
     std::memset(stmt.get(), 0, sizeof(struct AdbcStatement));
 
     auto* conn = reinterpret_cast<struct AdbcConnection*>(
         static_cast<uintptr_t>(connection_handle));
 
-    CHECK_ADBC_ERROR(AdbcStatementNew(conn, stmt.get(), &error), error);
+    CHECK_ADBC_ERROR(AdbcStatementNew(conn, stmt.get(), &error_guard.error),
+                     error_guard.error);
 
     jclass native_handle_class = RequireImplClass(env, 
"NativeStatementHandle");
     jmethodID native_handle_ctor =
@@ -435,10 +461,10 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openStatement(
 JNIEXPORT void JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_closeStatement(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
-    CHECK_ADBC_ERROR(AdbcStatementRelease(ptr, &error), error);
+    CHECK_ADBC_ERROR(AdbcStatementRelease(ptr, &error_guard.error), 
error_guard.error);
     delete ptr;
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -465,10 +491,10 @@ jobject MakeNativeSchemaResult(JNIEnv* env, struct 
ArrowSchema* schema) {
 JNIEXPORT void JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementCancel(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
   try {
-    CHECK_ADBC_ERROR(AdbcStatementCancel(ptr, &error), error);
+    CHECK_ADBC_ERROR(AdbcStatementCancel(ptr, &error_guard.error), 
error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -477,11 +503,12 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementCancel(
 JNIEXPORT jobject JNICALL
 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetParameterSchema(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
   struct ArrowSchema schema = {};
   try {
-    CHECK_ADBC_ERROR(AdbcStatementGetParameterSchema(ptr, &schema, &error), 
error);
+    CHECK_ADBC_ERROR(AdbcStatementGetParameterSchema(ptr, &schema, 
&error_guard.error),
+                     error_guard.error);
     return MakeNativeSchemaResult(env, &schema);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -492,7 +519,7 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetParameterSchem
 JNIEXPORT jobject JNICALL
 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementExecutePartitions(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
   struct ArrowSchema schema = {};
   struct AdbcPartitions partitions = {};
@@ -506,9 +533,9 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementExecutePartitions
     jmethodID native_result_add_partition =
         RequireMethod(env, native_result_class, "addPartition", "([B)V");
 
-    CHECK_ADBC_ERROR(
-        AdbcStatementExecutePartitions(ptr, &schema, &partitions, 
&rows_affected, &error),
-        error);
+    CHECK_ADBC_ERROR(AdbcStatementExecutePartitions(ptr, &schema, &partitions,
+                                                    &rows_affected, 
&error_guard.error),
+                     error_guard.error);
 
     result = env->NewObject(native_result_class, native_result_ctor, 
rows_affected,
                             
static_cast<jlong>(reinterpret_cast<uintptr_t>(&schema)));
@@ -546,12 +573,14 @@ cleanupall:
 JNIEXPORT jobject JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementExecuteQuery(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
     struct ArrowArrayStream out = {};
     int64_t rows_affected = 0;
-    CHECK_ADBC_ERROR(AdbcStatementExecuteQuery(ptr, &out, &rows_affected, 
&error), error);
+    CHECK_ADBC_ERROR(
+        AdbcStatementExecuteQuery(ptr, &out, &rows_affected, 
&error_guard.error),
+        error_guard.error);
 
     return MakeNativeQueryResult(env, rows_affected, &out);
   } catch (const AdbcException& e) {
@@ -563,11 +592,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard 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), 
error);
+    CHECK_ADBC_ERROR(AdbcStatementSetSqlQuery(ptr, query_str.value, 
&error_guard.error),
+                     error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -576,7 +606,7 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetSqlQuery(
 JNIEXPORT void JNICALL
 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetSubstraitPlan(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jobject plan) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
   std::vector<uint8_t> allocated_plan;
   size_t plan_length = 0;
@@ -586,8 +616,9 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetSubstraitPlan(
       return;  // GetJniByteBuffer failed
     }
     assert(plan_ptr != nullptr);
-    CHECK_ADBC_ERROR(AdbcStatementSetSubstraitPlan(ptr, plan_ptr, plan_length, 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcStatementSetSubstraitPlan(ptr, plan_ptr, plan_length, 
&error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -596,13 +627,14 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetSubstraitPlan(
 JNIEXPORT void JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementBind(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jlong values, 
jlong schema) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
     auto* c_batch = reinterpret_cast<struct 
ArrowArray*>(static_cast<uintptr_t>(values));
     auto* c_schema =
         reinterpret_cast<struct ArrowSchema*>(static_cast<uintptr_t>(schema));
-    CHECK_ADBC_ERROR(AdbcStatementBind(ptr, c_batch, c_schema, &error), error);
+    CHECK_ADBC_ERROR(AdbcStatementBind(ptr, c_batch, c_schema, 
&error_guard.error),
+                     error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -611,12 +643,13 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementBind(
 JNIEXPORT void JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementBindStream(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jlong stream) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
     auto* c_stream =
         reinterpret_cast<struct 
ArrowArrayStream*>(static_cast<uintptr_t>(stream));
-    CHECK_ADBC_ERROR(AdbcStatementBindStream(ptr, c_stream, &error), error);
+    CHECK_ADBC_ERROR(AdbcStatementBindStream(ptr, c_stream, 
&error_guard.error),
+                     error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -625,12 +658,13 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementBindStream(
 JNIEXPORT jlong JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementExecuteUpdate(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
     int64_t rows_affected = 0;
-    CHECK_ADBC_ERROR(
-        AdbcStatementExecuteQuery(ptr, /*out=*/nullptr, &rows_affected, 
&error), error);
+    CHECK_ADBC_ERROR(AdbcStatementExecuteQuery(ptr, /*out=*/nullptr, 
&rows_affected,
+                                               &error_guard.error),
+                     error_guard.error);
     return static_cast<jlong>(rows_affected);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -641,10 +675,10 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementExecuteUpdate(
 JNIEXPORT void JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementPrepare(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
-    CHECK_ADBC_ERROR(AdbcStatementPrepare(ptr, &error), error);
+    CHECK_ADBC_ERROR(AdbcStatementPrepare(ptr, &error_guard.error), 
error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -653,11 +687,12 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementPrepare(
 JNIEXPORT jobject JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementExecuteSchema(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* ptr = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
     struct ArrowSchema schema = {};
-    CHECK_ADBC_ERROR(AdbcStatementExecuteSchema(ptr, &schema, &error), error);
+    CHECK_ADBC_ERROR(AdbcStatementExecuteSchema(ptr, &schema, 
&error_guard.error),
+                     error_guard.error);
 
     return MakeNativeSchemaResult(env, &schema);
   } catch (const AdbcException& e) {
@@ -669,7 +704,7 @@ 
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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* stmt = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
 
   std::vector<uint8_t> buf(1024, '\0');
@@ -678,15 +713,15 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionBytes(
     JniStringView key_str(env, key);
     CHECK_ADBC_ERROR(
         AdbcStatementGetOptionBytes(stmt, key_str.value, 
const_cast<uint8_t*>(buf.data()),
-                                    &length, &error),
-        error);
+                                    &length, &error_guard.error),
+        error_guard.error);
     while (length > buf.size()) {
       // Buffer was too small, resize and try again
       buf.resize(length);
-      CHECK_ADBC_ERROR(
-          AdbcStatementGetOptionBytes(stmt, key_str.value,
-                                      const_cast<uint8_t*>(buf.data()), 
&length, &error),
-          error);
+      CHECK_ADBC_ERROR(AdbcStatementGetOptionBytes(stmt, key_str.value,
+                                                   
const_cast<uint8_t*>(buf.data()),
+                                                   &length, 
&error_guard.error),
+                       error_guard.error);
     }
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -701,13 +736,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* stmt = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
   double value = 0.0;
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcStatementGetOptionDouble(stmt, key_str.value, &value, 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcStatementGetOptionDouble(stmt, key_str.value, &value, 
&error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
     return 0.0;
@@ -718,13 +754,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* stmt = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
   int64_t value = 0;
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcStatementGetOptionInt(stmt, key_str.value, &value, 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcStatementGetOptionInt(stmt, key_str.value, &value, 
&error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
     return 0;
@@ -735,7 +772,7 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionLong(
 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;
+  AdbcErrorGuard error_guard;
   auto* stmt = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
 
   std::vector<char> buf(1024, '\0');
@@ -744,15 +781,15 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionString(
     JniStringView key_str(env, key);
     CHECK_ADBC_ERROR(
         AdbcStatementGetOption(stmt, key_str.value, 
const_cast<char*>(buf.data()),
-                               &length, &error),
-        error);
+                               &length, &error_guard.error),
+        error_guard.error);
     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()),
-                                 &length, &error),
-          error);
+                                 &length, &error_guard.error),
+          error_guard.error);
     }
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -765,7 +802,7 @@ 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;
+  AdbcErrorGuard error_guard;
   auto* stmt = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
@@ -774,8 +811,8 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionBytes(
     env->GetByteArrayRegion(value, 0, value_length,
                             reinterpret_cast<jbyte*>(value_buf.data()));
     CHECK_ADBC_ERROR(AdbcStatementSetOptionBytes(stmt, key_str.value, 
value_buf.data(),
-                                                 value_buf.size(), &error),
-                     error);
+                                                 value_buf.size(), 
&error_guard.error),
+                     error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -784,13 +821,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* stmt = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcStatementSetOptionDouble(stmt, key_str.value,
-                                                  static_cast<double>(value), 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcStatementSetOptionDouble(stmt, key_str.value, 
static_cast<double>(value),
+                                     &error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -799,13 +837,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* stmt = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcStatementSetOptionInt(stmt, key_str.value,
-                                               static_cast<int64_t>(value), 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcStatementSetOptionInt(stmt, key_str.value, 
static_cast<int64_t>(value),
+                                  &error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -814,18 +853,20 @@ 
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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* stmt = reinterpret_cast<struct 
AdbcStatement*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
     if (value == nullptr) {
-      CHECK_ADBC_ERROR(AdbcStatementSetOption(stmt, key_str.value, nullptr, 
&error),
-                       error);
+      CHECK_ADBC_ERROR(
+          AdbcStatementSetOption(stmt, key_str.value, nullptr, 
&error_guard.error),
+          error_guard.error);
       return;
     }
     JniStringView value_str(env, value);
-    CHECK_ADBC_ERROR(AdbcStatementSetOption(stmt, key_str.value, 
value_str.value, &error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcStatementSetOption(stmt, key_str.value, value_str.value, 
&error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -834,10 +875,10 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionString(
 JNIEXPORT void JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionCancel(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* ptr = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   try {
-    CHECK_ADBC_ERROR(AdbcConnectionCancel(ptr, &error), error);
+    CHECK_ADBC_ERROR(AdbcConnectionCancel(ptr, &error_guard.error), 
error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -848,8 +889,8 @@ 
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) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
 
     // Nullable string parameters: null jstring → NULL for C API (meaning "no 
filter")
@@ -883,8 +924,9 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetObjects(
             conn, static_cast<int>(depth), catalog_str ? catalog_str->c_str() 
: nullptr,
             db_schema_str ? db_schema_str->c_str() : nullptr,
             table_name_str ? table_name_str->c_str() : nullptr, c_table_types,
-            column_name_str ? column_name_str->c_str() : nullptr, &out, 
&error),
-        error);
+            column_name_str ? column_name_str->c_str() : nullptr, &out,
+            &error_guard.error),
+        error_guard.error);
 
     return MakeNativeQueryResult(env, -1, &out);
   } catch (const AdbcException& e) {
@@ -896,8 +938,8 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetObjects(
 JNIEXPORT jobject JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetInfo(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jintArray 
info_codes) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
 
     // Convert jintArray to uint32_t* + length (or NULL + 0 if array is null)
@@ -915,9 +957,9 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetInfo(
 
     struct ArrowArrayStream out = {};
 
-    CHECK_ADBC_ERROR(
-        AdbcConnectionGetInfo(conn, c_info_codes, info_codes_length, &out, 
&error),
-        error);
+    CHECK_ADBC_ERROR(AdbcConnectionGetInfo(conn, c_info_codes, 
info_codes_length, &out,
+                                           &error_guard.error),
+                     error_guard.error);
 
     return MakeNativeQueryResult(env, -1, &out);
   } catch (const AdbcException& e) {
@@ -930,8 +972,8 @@ 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) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
 
     auto catalog_str = MaybeGetJniString(env, catalog);
@@ -943,8 +985,8 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetTableSchema(
     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),
-        error);
+                                     table_name_str.value, &schema, 
&error_guard.error),
+        error_guard.error);
 
     return MakeNativeSchemaResult(env, &schema);
   } catch (const AdbcException& e) {
@@ -956,13 +998,14 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetTableSchema(
 JNIEXPORT jobject JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetTableTypes(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
+  AdbcErrorGuard error_guard;
   try {
-    struct AdbcError error = ADBC_ERROR_INIT;
     auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
 
     struct ArrowArrayStream out = {};
 
-    CHECK_ADBC_ERROR(AdbcConnectionGetTableTypes(conn, &out, &error), error);
+    CHECK_ADBC_ERROR(AdbcConnectionGetTableTypes(conn, &out, 
&error_guard.error),
+                     error_guard.error);
 
     return MakeNativeQueryResult(env, -1, &out);
   } catch (const AdbcException& e) {
@@ -974,24 +1017,24 @@ 
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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard 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,
-                                     const_cast<uint8_t*>(buf.data()), 
&length, &error),
-        error);
+    CHECK_ADBC_ERROR(AdbcConnectionGetOptionBytes(conn, key_str.value,
+                                                  
const_cast<uint8_t*>(buf.data()),
+                                                  &length, &error_guard.error),
+                     error_guard.error);
     while (length > buf.size()) {
       // Buffer was too small, resize and try again
       buf.resize(length);
-      CHECK_ADBC_ERROR(
-          AdbcConnectionGetOptionBytes(conn, key_str.value,
-                                       const_cast<uint8_t*>(buf.data()), 
&length, &error),
-          error);
+      CHECK_ADBC_ERROR(AdbcConnectionGetOptionBytes(conn, key_str.value,
+                                                    
const_cast<uint8_t*>(buf.data()),
+                                                    &length, 
&error_guard.error),
+                       error_guard.error);
     }
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -1006,13 +1049,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   double value = 0.0;
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcConnectionGetOptionDouble(conn, key_str.value, 
&value, &error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcConnectionGetOptionDouble(conn, key_str.value, &value, 
&error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
     return 0.0;
@@ -1023,13 +1067,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   int64_t value = 0;
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcConnectionGetOptionInt(conn, key_str.value, &value, 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcConnectionGetOptionInt(conn, key_str.value, &value, 
&error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
     return 0;
@@ -1040,7 +1085,7 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionLong(
 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;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
 
   std::vector<char> buf(1024, '\0');
@@ -1049,15 +1094,15 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionString(
     JniStringView key_str(env, key);
     CHECK_ADBC_ERROR(
         AdbcConnectionGetOption(conn, key_str.value, 
const_cast<char*>(buf.data()),
-                                &length, &error),
-        error);
+                                &length, &error_guard.error),
+        error_guard.error);
     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()),
-                                  &length, &error),
-          error);
+                                  &length, &error_guard.error),
+          error_guard.error);
     }
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -1070,7 +1115,7 @@ 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;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
@@ -1079,8 +1124,8 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionBytes(
     env->GetByteArrayRegion(value, 0, value_length,
                             reinterpret_cast<jbyte*>(value_buf.data()));
     CHECK_ADBC_ERROR(AdbcConnectionSetOptionBytes(conn, key_str.value, 
value_buf.data(),
-                                                  value_buf.size(), &error),
-                     error);
+                                                  value_buf.size(), 
&error_guard.error),
+                     error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -1089,13 +1134,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcConnectionSetOptionDouble(conn, key_str.value,
-                                                   static_cast<double>(value), 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcConnectionSetOptionDouble(conn, key_str.value, 
static_cast<double>(value),
+                                      &error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -1104,13 +1150,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcConnectionSetOptionInt(conn, key_str.value,
-                                                static_cast<int64_t>(value), 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcConnectionSetOptionInt(conn, key_str.value, 
static_cast<int64_t>(value),
+                                   &error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -1119,18 +1166,20 @@ 
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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
     if (value == nullptr) {
-      CHECK_ADBC_ERROR(AdbcConnectionSetOption(conn, key_str.value, nullptr, 
&error),
-                       error);
+      CHECK_ADBC_ERROR(
+          AdbcConnectionSetOption(conn, key_str.value, nullptr, 
&error_guard.error),
+          error_guard.error);
       return;
     }
     JniStringView value_str(env, value);
     CHECK_ADBC_ERROR(
-        AdbcConnectionSetOption(conn, key_str.value, value_str.value, &error), 
error);
+        AdbcConnectionSetOption(conn, key_str.value, value_str.value, 
&error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -1139,10 +1188,10 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionString(
 JNIEXPORT void JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionCommit(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   try {
-    CHECK_ADBC_ERROR(AdbcConnectionCommit(conn, &error), error);
+    CHECK_ADBC_ERROR(AdbcConnectionCommit(conn, &error_guard.error), 
error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -1151,10 +1200,10 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionCommit(
 JNIEXPORT void JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionRollback(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   try {
-    CHECK_ADBC_ERROR(AdbcConnectionRollback(conn, &error), error);
+    CHECK_ADBC_ERROR(AdbcConnectionRollback(conn, &error_guard.error), 
error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -1163,7 +1212,7 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionRollback(
 JNIEXPORT jobject JNICALL
 Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionReadPartition(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle, jobject 
partition) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   struct ArrowArrayStream out = {};
   size_t serialized_length = 0;
@@ -1176,9 +1225,10 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionReadPartition(
       return nullptr;  // GetJniByteBuffer failed
     }
     assert(serialized_partition != nullptr);
-    CHECK_ADBC_ERROR(AdbcConnectionReadPartition(conn, serialized_partition,
-                                                 serialized_length, &out, 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcConnectionReadPartition(conn, serialized_partition, 
serialized_length, &out,
+                                    &error_guard.error),
+        error_guard.error);
     return MakeNativeQueryResult(env, -1, &out);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -1189,11 +1239,12 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionReadPartition(
 JNIEXPORT jobject JNICALL
 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetStatisticNames(
     JNIEnv* env, [[maybe_unused]] jclass self, jlong handle) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   struct ArrowArrayStream out = {};
   try {
-    CHECK_ADBC_ERROR(AdbcConnectionGetStatisticNames(conn, &out, &error), 
error);
+    CHECK_ADBC_ERROR(AdbcConnectionGetStatisticNames(conn, &out, 
&error_guard.error),
+                     error_guard.error);
     return MakeNativeQueryResult(env, -1, &out);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -1205,7 +1256,7 @@ 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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* conn = reinterpret_cast<struct 
AdbcConnection*>(static_cast<uintptr_t>(handle));
   struct ArrowArrayStream out = {};
   try {
@@ -1216,8 +1267,8 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetStatistics(
         AdbcConnectionGetStatistics(conn, catalog_str ? catalog_str->c_str() : 
nullptr,
                                     schema_str ? schema_str->c_str() : nullptr,
                                     table_str ? table_str->c_str() : nullptr, 
approximate,
-                                    &out, &error),
-        error);
+                                    &out, &error_guard.error),
+        error_guard.error);
     return MakeNativeQueryResult(env, -1, &out);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -1228,7 +1279,7 @@ 
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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* db = reinterpret_cast<struct 
AdbcDatabase*>(static_cast<uintptr_t>(handle));
 
   std::vector<uint8_t> buf(1024, '\0');
@@ -1237,15 +1288,15 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionBytes(
     JniStringView key_str(env, key);
     CHECK_ADBC_ERROR(
         AdbcDatabaseGetOptionBytes(db, key_str.value, 
const_cast<uint8_t*>(buf.data()),
-                                   &length, &error),
-        error);
+                                   &length, &error_guard.error),
+        error_guard.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<uint8_t*>(buf.data()),
-                                     &length, &error),
-          error);
+                                     &length, &error_guard.error),
+          error_guard.error);
     }
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -1260,13 +1311,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* db = reinterpret_cast<struct 
AdbcDatabase*>(static_cast<uintptr_t>(handle));
   double value = 0.0;
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcDatabaseGetOptionDouble(db, key_str.value, &value, 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcDatabaseGetOptionDouble(db, key_str.value, &value, 
&error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
     return 0.0;
@@ -1277,12 +1329,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* db = reinterpret_cast<struct 
AdbcDatabase*>(static_cast<uintptr_t>(handle));
   int64_t value = 0;
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcDatabaseGetOptionInt(db, key_str.value, &value, 
&error), error);
+    CHECK_ADBC_ERROR(
+        AdbcDatabaseGetOptionInt(db, key_str.value, &value, 
&error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
     return 0;
@@ -1293,7 +1347,7 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionLong(
 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;
+  AdbcErrorGuard error_guard;
   auto* db = reinterpret_cast<struct 
AdbcDatabase*>(static_cast<uintptr_t>(handle));
 
   std::vector<char> buf(1024, '\0');
@@ -1302,15 +1356,15 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionString(
     JniStringView key_str(env, key);
     CHECK_ADBC_ERROR(
         AdbcDatabaseGetOption(db, key_str.value, 
const_cast<char*>(buf.data()), &length,
-                              &error),
-        error);
+                              &error_guard.error),
+        error_guard.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<char*>(buf.data()), &length,
-                                &error),
-          error);
+                                &error_guard.error),
+          error_guard.error);
     }
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
@@ -1323,7 +1377,7 @@ 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;
+  AdbcErrorGuard error_guard;
   auto* db = reinterpret_cast<struct 
AdbcDatabase*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
@@ -1332,8 +1386,8 @@ 
Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseSetOptionBytes(
     env->GetByteArrayRegion(value, 0, value_length,
                             reinterpret_cast<jbyte*>(value_buf.data()));
     CHECK_ADBC_ERROR(AdbcDatabaseSetOptionBytes(db, key_str.value, 
value_buf.data(),
-                                                value_buf.size(), &error),
-                     error);
+                                                value_buf.size(), 
&error_guard.error),
+                     error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -1342,13 +1396,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* db = reinterpret_cast<struct 
AdbcDatabase*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
-    CHECK_ADBC_ERROR(AdbcDatabaseSetOptionDouble(db, key_str.value,
-                                                 static_cast<double>(value), 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcDatabaseSetOptionDouble(db, key_str.value, 
static_cast<double>(value),
+                                    &error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -1357,13 +1412,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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* db = reinterpret_cast<struct 
AdbcDatabase*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
     CHECK_ADBC_ERROR(
-        AdbcDatabaseSetOptionInt(db, key_str.value, 
static_cast<int64_t>(value), &error),
-        error);
+        AdbcDatabaseSetOptionInt(db, key_str.value, 
static_cast<int64_t>(value),
+                                 &error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }
@@ -1372,17 +1428,20 @@ 
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) {
-  struct AdbcError error = ADBC_ERROR_INIT;
+  AdbcErrorGuard error_guard;
   auto* db = reinterpret_cast<struct 
AdbcDatabase*>(static_cast<uintptr_t>(handle));
   try {
     JniStringView key_str(env, key);
     if (value == nullptr) {
-      CHECK_ADBC_ERROR(AdbcDatabaseSetOption(db, key_str.value, nullptr, 
&error), error);
+      CHECK_ADBC_ERROR(
+          AdbcDatabaseSetOption(db, key_str.value, nullptr, 
&error_guard.error),
+          error_guard.error);
       return;
     }
     JniStringView value_str(env, value);
-    CHECK_ADBC_ERROR(AdbcDatabaseSetOption(db, key_str.value, value_str.value, 
&error),
-                     error);
+    CHECK_ADBC_ERROR(
+        AdbcDatabaseSetOption(db, key_str.value, value_str.value, 
&error_guard.error),
+        error_guard.error);
   } catch (const AdbcException& e) {
     e.ThrowJavaException(env);
   }

Reply via email to