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 5672c879c feat!(rust/ffi): catch panics at FFI boundary (#3819)
5672c879c is described below

commit 5672c879c35b7f5e86d30481bf3ef3c8fd12c0e5
Author: David Li <[email protected]>
AuthorDate: Tue Jan 6 09:05:55 2026 +0900

    feat!(rust/ffi): catch panics at FFI boundary (#3819)
    
    This gives a slightly nicer experience than unconditionally crashing the
    entire program. As with the Go FFI scaffolding, once a driver panics,
    all further calls to the driver will fail. (Albeit, this is not true for
    exported readers. We also need our own C Data Interface export shim so
    we can handle things like exporting ADBC errors through the C Data
    Interface boundary. Currently, C++ and Go-based drivers can do this.)
    
    ---------
    
    Co-authored-by: eitsupi <[email protected]>
    Co-authored-by: Bryce Mecum <[email protected]>
---
 .github/workflows/native-unix.yml                |    6 +
 python/adbc_driver_manager/tests/test_panic.py   |   70 +-
 rust/driver/dummy/src/lib.rs                     |   21 +-
 rust/driver/dummy/tests/driver_exporter_dummy.rs |    2 +-
 rust/ffi/src/driver_exporter.rs                  | 1412 +++++++++++++---------
 5 files changed, 941 insertions(+), 570 deletions(-)

diff --git a/.github/workflows/native-unix.yml 
b/.github/workflows/native-unix.yml
index 814e17654..d4d7632d8 100644
--- a/.github/workflows/native-unix.yml
+++ b/.github/workflows/native-unix.yml
@@ -598,12 +598,18 @@ jobs:
           else
             make -C ./go/adbc/pkg libadbc_driver_panicdummy.so
           fi
+      - name: Build Panic Dummy (Rust)
+        working-directory: rust
+        run: |
+          cargo build -padbc_dummy
       - name: Test Python Driver Manager
         run: |
           if [[ $(uname) = "Darwin" ]]; then
             export 
PANICDUMMY_LIBRARY_PATH=$(pwd)/go/adbc/pkg/libadbc_driver_panicdummy.dylib
+            export 
PANICDUMMY_RUST_LIBRARY_PATH=$(pwd)/rust/target/debug/libadbc_dummy.dylib
           else
             export 
PANICDUMMY_LIBRARY_PATH=$(pwd)/go/adbc/pkg/libadbc_driver_panicdummy.so
+            export 
PANICDUMMY_RUST_LIBRARY_PATH=$(pwd)/rust/target/debug/libadbc_dummy.so
           fi
           export PATH=$RUNNER_TOOL_CACHE/go/${GO_VERSION}/x64/bin:$PATH
           env BUILD_ALL=0 BUILD_DRIVER_MANAGER=1 ./ci/scripts/python_test.sh 
"$(pwd)" "$(pwd)/build" "$HOME/local"
diff --git a/python/adbc_driver_manager/tests/test_panic.py 
b/python/adbc_driver_manager/tests/test_panic.py
index d0aef2b85..9963c7a8a 100644
--- a/python/adbc_driver_manager/tests/test_panic.py
+++ b/python/adbc_driver_manager/tests/test_panic.py
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-"""Tests for the panic behavior of the Go driver FFI wrapper."""
+"""Tests for the panic behavior of the Go/Rust FFI wrappers."""
 
 import os
 import subprocess
@@ -26,17 +26,25 @@ import pytest
 
 pytestmark = pytest.mark.panicdummy
 
-_LIB_ENV_VAR = "PANICDUMMY_LIBRARY_PATH"
+_GO_LIB_ENV_VAR = "PANICDUMMY_LIBRARY_PATH"
+_RUST_LIB_ENV_VAR = "PANICDUMMY_RUST_LIBRARY_PATH"
 
 
 @pytest.fixture(scope="module")
-def libpath() -> str:
-    if _LIB_ENV_VAR not in os.environ:
-        pytest.skip(f"{_LIB_ENV_VAR} not specified", allow_module_level=True)
-    return os.environ[_LIB_ENV_VAR]
+def go_driver() -> str:
+    if _GO_LIB_ENV_VAR not in os.environ:
+        pytest.skip(f"{_GO_LIB_ENV_VAR} not specified", 
allow_module_level=True)
+    return os.environ[_GO_LIB_ENV_VAR]
 
 
-def test_panic_close(libpath) -> None:
[email protected](scope="module")
+def rust_driver() -> str:
+    if _RUST_LIB_ENV_VAR not in os.environ:
+        pytest.skip(f"{_RUST_LIB_ENV_VAR} not specified", 
allow_module_level=True)
+    return os.environ[_RUST_LIB_ENV_VAR]
+
+
+def test_panic_close_go(go_driver) -> None:
     env = os.environ.copy()
     env["PANICDUMMY_FUNC"] = "StatementClose"
     env["PANICDUMMY_MESSAGE"] = "Boo!"
@@ -44,7 +52,7 @@ def test_panic_close(libpath) -> None:
         [
             sys.executable,
             Path(__file__).parent / "panictest.py",
-            libpath,
+            go_driver,
         ],
         stdout=subprocess.PIPE,
         stderr=subprocess.PIPE,
@@ -57,7 +65,7 @@ def test_panic_close(libpath) -> None:
     assert "Go panicked, driver is in unknown state" in output.stderr
 
 
-def test_panic_execute(libpath) -> None:
+def test_panic_execute_go(go_driver) -> None:
     env = os.environ.copy()
     env["PANICDUMMY_FUNC"] = "StatementExecuteQuery"
     env["PANICDUMMY_MESSAGE"] = "Boo!"
@@ -65,7 +73,7 @@ def test_panic_execute(libpath) -> None:
         [
             sys.executable,
             Path(__file__).parent / "panictest.py",
-            libpath,
+            go_driver,
         ],
         stdout=subprocess.PIPE,
         stderr=subprocess.PIPE,
@@ -76,3 +84,45 @@ def test_panic_execute(libpath) -> None:
     assert "Go panic in PanicDummy driver" in output.stderr
     assert "Boo!" in output.stderr
     assert "Go panicked, driver is in unknown state" in output.stderr
+
+
+def test_panic_close_rust(rust_driver) -> None:
+    env = os.environ.copy()
+    env["PANICDUMMY_FUNC"] = "StatementClose"
+    env["PANICDUMMY_MESSAGE"] = "Boo!"
+    output = subprocess.run(
+        [
+            sys.executable,
+            Path(__file__).parent / "panictest.py",
+            rust_driver,
+        ],
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        env=env,
+        encoding="utf-8",
+    )
+    assert output.returncode != 0
+    assert "Uncaught panic in driver" in output.stderr
+    assert "Boo!" in output.stderr
+    assert "Driver panicked and is in unknown state" in output.stderr
+
+
+def test_panic_execute_rust(rust_driver) -> None:
+    env = os.environ.copy()
+    env["PANICDUMMY_FUNC"] = "StatementExecuteQuery"
+    env["PANICDUMMY_MESSAGE"] = "Boo!"
+    output = subprocess.run(
+        [
+            sys.executable,
+            Path(__file__).parent / "panictest.py",
+            rust_driver,
+        ],
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        env=env,
+        encoding="utf-8",
+    )
+    assert output.returncode != 0
+    assert "Uncaught panic in driver" in output.stderr
+    assert "Boo!" in output.stderr
+    assert "Driver panicked and is in unknown state" in output.stderr
diff --git a/rust/driver/dummy/src/lib.rs b/rust/driver/dummy/src/lib.rs
index 4ab708afd..451b89594 100644
--- a/rust/driver/dummy/src/lib.rs
+++ b/rust/driver/dummy/src/lib.rs
@@ -175,6 +175,18 @@ where
     }
 }
 
+fn maybe_panic(fnname: impl AsRef<str>) {
+    if let Some(func) = std::env::var_os("PANICDUMMY_FUNC").map(|x| 
x.to_string_lossy().to_string())
+    {
+        if fnname.as_ref() == func {
+            let message = std::env::var_os("PANICDUMMY_MESSAGE")
+                .map(|x| x.to_string_lossy().to_string())
+                .unwrap_or_else(|| format!("We panicked in {}!", 
fnname.as_ref()));
+            panic!("{}", message);
+        }
+    }
+}
+
 /// A dummy driver used for testing purposes.
 #[derive(Default)]
 pub struct DummyDriver {}
@@ -837,6 +849,7 @@ impl Statement for DummyStatement {
     }
 
     fn execute(&mut self) -> Result<impl RecordBatchReader> {
+        maybe_panic("StatementExecuteQuery");
         let batch = get_table_data();
         let reader = SingleBatchReader::new(batch);
         Ok(reader)
@@ -875,4 +888,10 @@ impl Statement for DummyStatement {
     }
 }
 
-adbc_ffi::export_driver!(DummyDriverInit, DummyDriver);
+impl Drop for DummyStatement {
+    fn drop(&mut self) {
+        maybe_panic("StatementClose");
+    }
+}
+
+adbc_ffi::export_driver!(AdbcDummyInit, DummyDriver);
diff --git a/rust/driver/dummy/tests/driver_exporter_dummy.rs 
b/rust/driver/dummy/tests/driver_exporter_dummy.rs
index a5869c055..6d1445a45 100644
--- a/rust/driver/dummy/tests/driver_exporter_dummy.rs
+++ b/rust/driver/dummy/tests/driver_exporter_dummy.rs
@@ -67,7 +67,7 @@ fn get_exported() -> (
 ) {
     let mut driver = ManagedDriver::load_dynamic_from_name(
         "adbc_dummy",
-        Some(b"DummyDriverInit"),
+        Some(b"AdbcDummyInit"),
         AdbcVersion::V110,
     )
     .unwrap();
diff --git a/rust/ffi/src/driver_exporter.rs b/rust/ffi/src/driver_exporter.rs
index c142121bf..e24d9b473 100644
--- a/rust/ffi/src/driver_exporter.rs
+++ b/rust/ffi/src/driver_exporter.rs
@@ -167,11 +167,11 @@ impl<DriverType: Driver + Default + 'static> FFIDriver 
for DriverType {
 ///
 /// # Parameters
 ///
-/// - `$func_name` - Driver's initialization function name. The recommended 
name
-///   is `AdbcDriverInit`, or a name derived from the name of the driver's 
shared
-///   library as follows: remove the `lib` prefix (on Unix systems) and all 
file
-///   extensions, then `PascalCase` the driver name, append `Init`, and prepend
-///   `Adbc` (if not already there). For example:
+/// - `$func_name` - Driver's initialization function name. The recommended
+///   name should be derived from the name of the driver's shared library as
+///   follows: remove the `lib` prefix (on Unix systems) and all file
+///   extensions, then `PascalCase` the driver name, append `Init`, and
+///   prepend `Adbc` (if not already there). For example:
 ///     - `libadbc_driver_sqlite.so.2.0.0` -> `AdbcDriverSqliteInit`
 ///     - `adbc_driver_sqlite.dll` -> `AdbcDriverSqliteInit`
 ///     - `proprietary_driver.dll` -> `AdbcProprietaryDriverInit`
@@ -180,6 +180,7 @@ impl<DriverType: Driver + Default + 'static> FFIDriver for 
DriverType {
 #[macro_export]
 macro_rules! export_driver {
     ($func_name:ident, $driver_type:ty) => {
+        #[allow(non_snake_case)]
         #[no_mangle]
         pub unsafe extern "C" fn $func_name(
             version: std::os::raw::c_int,
@@ -207,6 +208,17 @@ macro_rules! export_driver {
             }
             adbc_core::constants::ADBC_STATUS_OK
         }
+
+        // Fallback symbol, if the driver manager does not find the init above
+        #[allow(non_snake_case)]
+        #[no_mangle]
+        pub unsafe extern "C" fn AdbcDriverInit(
+            version: std::os::raw::c_int,
+            driver: *mut std::os::raw::c_void,
+            error: *mut $crate::FFI_AdbcError,
+        ) -> adbc_core::error::AdbcStatusCode {
+            unsafe { $func_name(version, driver, error) }
+        }
     };
 }
 
@@ -229,7 +241,7 @@ macro_rules! check_err {
                 if !$err_out.is_null() {
                     let mut ffi_error =
                         
$crate::FFI_AdbcError::try_from(error).unwrap_or_else(Into::into);
-                    ffi_error.private_driver = (*$err_out).private_driver;
+                    ffi_error.private_driver = unsafe { 
(*$err_out).private_driver };
                     unsafe { std::ptr::write_unaligned($err_out, ffi_error) };
                 }
                 return status;
@@ -258,6 +270,32 @@ macro_rules! check_not_null {
     };
 }
 
+/// Check that the given raw pointer is not null, then return it as a mutable 
reference.
+///
+/// If null, an error is returned from the enclosing function.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! pointer_as_mut {
+    ($ptr:ident, $err_out:expr) => {
+        match unsafe { $ptr.as_mut() } {
+            Some(p) => p,
+            None => {
+                if !$err_out.is_null() {
+                    let error = 
adbc_core::error::Error::with_message_and_status(
+                        format!("Passed null pointer for argument {:?}", 
stringify!($ptr)),
+                        adbc_core::error::Status::InvalidArguments,
+                    );
+                    let mut ffi_error =
+                        
$crate::FFI_AdbcError::try_from(error).unwrap_or_else(Into::into);
+                    ffi_error.private_driver = unsafe { 
(*$err_out).private_driver };
+                    unsafe { std::ptr::write_unaligned($err_out, ffi_error) };
+                }
+                return adbc_core::error::Status::InvalidArguments.into();
+            }
+        }
+    };
+}
+
 unsafe extern "C" fn release_ffi_driver(
     driver: *mut FFI_AdbcDriver,
     error: *mut FFI_AdbcError,
@@ -456,14 +494,57 @@ where
     }
 }
 
+static POISON: std::sync::atomic::AtomicBool = 
std::sync::atomic::AtomicBool::new(false);
+
+fn catch_panic<F: FnOnce() -> AdbcStatusCode + std::panic::UnwindSafe>(
+    error: *mut FFI_AdbcError,
+    f: F,
+) -> AdbcStatusCode {
+    check_err!(check_poison(), error);
+
+    match std::panic::catch_unwind(f) {
+        Ok(status) => status,
+        Err(cause) => {
+            POISON.store(true, std::sync::atomic::Ordering::Release);
+
+            if !error.is_null() {
+                let message = if let Some(s) = cause.downcast_ref::<&str>() {
+                    s.to_string()
+                } else if let Some(s) = cause.downcast_ref::<String>() {
+                    s.clone()
+                } else {
+                    "Unknown panic".to_string()
+                };
+                let err = Error::with_message_and_status(
+                    format!("Uncaught panic in driver: {message}"),
+                    Status::Internal,
+                );
+                let mut ffi_error = 
FFI_AdbcError::try_from(err).unwrap_or_else(Into::into);
+                ffi_error.private_driver = unsafe { (*error).private_driver };
+                unsafe { std::ptr::write_unaligned(error, ffi_error) };
+            }
+            Status::Internal.into()
+        }
+    }
+}
+
+fn check_poison() -> Result<()> {
+    if POISON.load(std::sync::atomic::Ordering::Acquire) {
+        Err(Error::with_message_and_status(
+            "Driver panicked and is in unknown state",
+            Status::Internal,
+        ))
+    } else {
+        Ok(())
+    }
+}
+
 // Database
 
-// SAFETY: Will panic if `database` is null.
 unsafe fn database_private_data<'a, DriverType: Driver>(
-    database: *mut FFI_AdbcDatabase,
+    database: &mut FFI_AdbcDatabase,
 ) -> Result<&'a mut ExportedDatabase<DriverType>> {
-    assert!(!database.is_null());
-    let exported = (*database).private_data as *mut 
ExportedDatabase<DriverType>;
+    let exported = database.private_data as *mut ExportedDatabase<DriverType>;
     let exported = exported.as_mut().ok_or(Error::with_message_and_status(
         "Uninitialized database",
         Status::InvalidState,
@@ -471,14 +552,13 @@ unsafe fn database_private_data<'a, DriverType: Driver>(
     exported
 }
 
-// SAFETY: Will panic if `database` or `key` is null.
+// SAFETY: Will panic if `key` is null.
 unsafe fn database_set_option_impl<DriverType: Driver, Value: 
Into<OptionValue>>(
-    database: *mut FFI_AdbcDatabase,
+    database: &mut FFI_AdbcDatabase,
     key: *const c_char,
     value: Value,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    assert!(!database.is_null());
     assert!(!key.is_null());
 
     let exported = check_err!(database_private_data::<DriverType>(database), 
error);
@@ -496,200 +576,234 @@ unsafe fn database_set_option_impl<DriverType: Driver, 
Value: Into<OptionValue>>
     ADBC_STATUS_OK
 }
 
-unsafe extern "C" fn database_new<DriverType: Driver>(
+extern "C" fn database_new<DriverType: Driver>(
     database: *mut FFI_AdbcDatabase,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
+        let exported = 
Box::new(ExportedDatabase::<DriverType>::Options(HashMap::new()));
+        database.private_data = Box::into_raw(exported) as *mut c_void;
 
-    let database = database.as_mut().unwrap();
-    let exported = 
Box::new(ExportedDatabase::<DriverType>::Options(HashMap::new()));
-    database.private_data = Box::into_raw(exported) as *mut c_void;
-
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn database_init<DriverType: Driver + Default>(
+extern "C" fn database_init<DriverType: Driver + Default>(
     database: *mut FFI_AdbcDatabase,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
 
-    let exported = check_err!(database_private_data::<DriverType>(database), 
error);
-
-    if let ExportedDatabase::Options(options) = exported {
-        let mut driver = DriverType::default();
-        let database = 
check_err!(driver.new_database_with_opts(options.clone()), error);
-        *exported = ExportedDatabase::Database(database);
-    } else {
-        check_err!(
-            Err(Error::with_message_and_status(
-                "Database already initialized",
-                Status::InvalidState
-            )),
+        let exported = check_err!(
+            unsafe { database_private_data::<DriverType>(database) },
             error
         );
-    }
 
-    ADBC_STATUS_OK
+        if let ExportedDatabase::Options(options) = exported {
+            let mut driver = DriverType::default();
+            let database = 
check_err!(driver.new_database_with_opts(options.clone()), error);
+            *exported = ExportedDatabase::Database(database);
+        } else {
+            check_err!(
+                Err(Error::with_message_and_status(
+                    "Database already initialized",
+                    Status::InvalidState
+                )),
+                error
+            );
+        }
+
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn database_release<DriverType: Driver>(
+extern "C" fn database_release<DriverType: Driver>(
     database: *mut FFI_AdbcDatabase,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
-
-    let database = database.as_mut().unwrap();
-    if database.private_data.is_null() {
-        check_err!(
-            Err(Error::with_message_and_status(
-                "Database already released",
-                Status::InvalidState
-            )),
-            error
-        );
-    }
-    let exported = Box::from_raw(database.private_data as *mut 
ExportedDatabase<DriverType>);
-    drop(exported);
-    database.private_data = std::ptr::null_mut();
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
+        if database.private_data.is_null() {
+            check_err!(
+                Err(Error::with_message_and_status(
+                    "Database already released",
+                    Status::InvalidState
+                )),
+                error
+            );
+        }
+        let exported =
+            unsafe { Box::from_raw(database.private_data as *mut 
ExportedDatabase<DriverType>) };
+        drop(exported);
+        database.private_data = std::ptr::null_mut();
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn database_set_option<DriverType: Driver>(
+extern "C" fn database_set_option<DriverType: Driver>(
     database: *mut FFI_AdbcDatabase,
     key: *const c_char,
     value: *const c_char,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let value = check_err!(CStr::from_ptr(value).to_str(), error);
-    database_set_option_impl::<DriverType, &str>(database, key, value, error)
+        let value = check_err!(unsafe { CStr::from_ptr(value).to_str() }, 
error);
+        unsafe { database_set_option_impl::<DriverType, &str>(database, key, 
value, error) }
+    })
 }
 
-unsafe extern "C" fn database_set_option_int<DriverType: Driver>(
+extern "C" fn database_set_option_int<DriverType: Driver>(
     database: *mut FFI_AdbcDatabase,
     key: *const c_char,
     value: i64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
-    check_not_null!(key, error);
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
+        check_not_null!(key, error);
 
-    database_set_option_impl::<DriverType, i64>(database, key, value, error)
+        unsafe { database_set_option_impl::<DriverType, i64>(database, key, 
value, error) }
+    })
 }
 
-unsafe extern "C" fn database_set_option_double<DriverType: Driver>(
+extern "C" fn database_set_option_double<DriverType: Driver>(
     database: *mut FFI_AdbcDatabase,
     key: *const c_char,
     value: f64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
-    check_not_null!(key, error);
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
+        check_not_null!(key, error);
 
-    database_set_option_impl::<DriverType, f64>(database, key, value, error)
+        unsafe { database_set_option_impl::<DriverType, f64>(database, key, 
value, error) }
+    })
 }
 
-unsafe extern "C" fn database_set_option_bytes<DriverType: Driver>(
+extern "C" fn database_set_option_bytes<DriverType: Driver>(
     database: *mut FFI_AdbcDatabase,
     key: *const c_char,
     value: *const u8,
     length: usize,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let value = std::slice::from_raw_parts(value, length);
-    database_set_option_impl::<DriverType, &[u8]>(database, key, value, error)
+        let value = unsafe { std::slice::from_raw_parts(value, length) };
+        unsafe { database_set_option_impl::<DriverType, &[u8]>(database, key, 
value, error) }
+    })
 }
 
-unsafe extern "C" fn database_get_option<DriverType: Driver>(
+extern "C" fn database_get_option<DriverType: Driver>(
     database: *mut FFI_AdbcDatabase,
     key: *const c_char,
     value: *mut c_char,
     length: *mut usize,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
-    check_not_null!(length, error);
-
-    let exported = check_err!(database_private_data::<DriverType>(database), 
error);
-    let (options, database) = exported.tuple();
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
+        check_not_null!(length, error);
+
+        let exported = check_err!(
+            unsafe { database_private_data::<DriverType>(database) },
+            error
+        );
+        let (options, database) = exported.tuple();
 
-    let optvalue = get_option(database, options, key);
-    let optvalue = check_err!(optvalue, error);
-    check_err!(copy_string(&optvalue, value, length), error);
+        let optvalue = unsafe { get_option(database, options, key) };
+        let optvalue = check_err!(optvalue, error);
+        check_err!(unsafe { copy_string(&optvalue, value, length) }, error);
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn database_get_option_int<DriverType: Driver>(
+extern "C" fn database_get_option_int<DriverType: Driver>(
     database: *mut FFI_AdbcDatabase,
     key: *const c_char,
     value: *mut i64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let exported = check_err!(database_private_data::<DriverType>(database), 
error);
-    let (options, database) = exported.tuple();
+        let exported = check_err!(
+            unsafe { database_private_data::<DriverType>(database) },
+            error
+        );
+        let (options, database) = exported.tuple();
 
-    let optvalue = check_err!(get_option_int(database, options, key), error);
-    std::ptr::write_unaligned(value, optvalue);
+        let optvalue = check_err!(unsafe { get_option_int(database, options, 
key) }, error);
+        unsafe { std::ptr::write_unaligned(value, optvalue) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn database_get_option_double<DriverType: Driver>(
+extern "C" fn database_get_option_double<DriverType: Driver>(
     database: *mut FFI_AdbcDatabase,
     key: *const c_char,
     value: *mut f64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let exported = check_err!(database_private_data::<DriverType>(database), 
error);
-    let (options, database) = exported.tuple();
+        let exported = check_err!(
+            unsafe { database_private_data::<DriverType>(database) },
+            error
+        );
+        let (options, database) = exported.tuple();
 
-    let optvalue = check_err!(get_option_double(database, options, key), 
error);
-    std::ptr::write_unaligned(value, optvalue);
+        let optvalue = check_err!(unsafe { get_option_double(database, 
options, key) }, error);
+        unsafe { std::ptr::write_unaligned(value, optvalue) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn database_get_option_bytes<DriverType: Driver>(
+extern "C" fn database_get_option_bytes<DriverType: Driver>(
     database: *mut FFI_AdbcDatabase,
     key: *const c_char,
     value: *mut u8,
     length: *mut usize,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(database, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
-    check_not_null!(length, error);
-
-    let exported = check_err!(database_private_data::<DriverType>(database), 
error);
-    let (options, database) = exported.tuple();
+    catch_panic(error, || {
+        let database = pointer_as_mut!(database, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
+        check_not_null!(length, error);
+
+        let exported = check_err!(
+            unsafe { database_private_data::<DriverType>(database) },
+            error
+        );
+        let (options, database) = exported.tuple();
 
-    let optvalue = get_option_bytes(database, options, key);
-    let optvalue = check_err!(optvalue, error);
-    copy_bytes(&optvalue, value, length);
+        let optvalue = unsafe { get_option_bytes(database, options, key) };
+        let optvalue = check_err!(optvalue, error);
+        unsafe { copy_bytes(&optvalue, value, length) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
 unsafe fn maybe_str<'a>(str: *const c_char) -> Result<Option<&'a str>> {
@@ -701,12 +815,10 @@ unsafe fn maybe_str<'a>(str: *const c_char) -> 
Result<Option<&'a str>> {
 
 // Connection
 
-// SAFETY: Will panic if `connection` is null.
 unsafe fn connection_private_data<'a, DriverType: Driver>(
-    connection: *mut FFI_AdbcConnection,
+    connection: &mut FFI_AdbcConnection,
 ) -> Result<&'a mut ExportedConnection<DriverType>> {
-    assert!(!connection.is_null());
-    let exported = (*connection).private_data as *mut 
ExportedConnection<DriverType>;
+    let exported = connection.private_data as *mut 
ExportedConnection<DriverType>;
     let exported = exported.as_mut().ok_or(Error::with_message_and_status(
         "Uninitialized connection",
         Status::InvalidState,
@@ -721,7 +833,7 @@ unsafe fn connection_set_option_impl<DriverType: Driver, 
Value: Into<OptionValue
     value: Value,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    assert!(!connection.is_null());
+    let connection = pointer_as_mut!(connection, error);
     assert!(!key.is_null());
 
     let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
@@ -739,233 +851,282 @@ unsafe fn connection_set_option_impl<DriverType: 
Driver, Value: Into<OptionValue
     ADBC_STATUS_OK
 }
 
-unsafe extern "C" fn connection_new<DriverType: Driver>(
+extern "C" fn connection_new<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
 
-    let connection = connection.as_mut().unwrap();
-    let exported = 
Box::new(ExportedConnection::<DriverType>::Options(HashMap::new()));
-    connection.private_data = Box::into_raw(exported) as *mut c_void;
+        let exported = 
Box::new(ExportedConnection::<DriverType>::Options(HashMap::new()));
+        connection.private_data = Box::into_raw(exported) as *mut c_void;
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_init<DriverType: Driver>(
+extern "C" fn connection_init<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     database: *mut FFI_AdbcDatabase,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(database, error);
-
-    let exported_connection = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let exported_database = 
check_err!(database_private_data::<DriverType>(database), error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        let database = pointer_as_mut!(database, error);
 
-    if let ExportedConnection::Options(options) = exported_connection {
-        let connection = match exported_database {
-            ExportedDatabase::Database(database) => {
-                database.new_connection_with_opts(options.clone())
-            }
-            _ => Err(Error::with_message_and_status(
-                "You must call DatabaseInit before ConnectionInit",
-                Status::InvalidState,
-            )),
-        };
-        let connection = check_err!(connection, error);
-        *exported_connection = ExportedConnection::Connection(connection);
-    } else {
-        check_err!(
-            Err(Error::with_message_and_status(
-                "Connection already initialized",
-                Status::InvalidState
-            )),
+        let exported_connection = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let exported_database = check_err!(
+            unsafe { database_private_data::<DriverType>(database) },
             error
         );
-    }
 
-    ADBC_STATUS_OK
+        if let ExportedConnection::Options(options) = exported_connection {
+            let connection = match exported_database {
+                ExportedDatabase::Database(database) => {
+                    database.new_connection_with_opts(options.clone())
+                }
+                _ => Err(Error::with_message_and_status(
+                    "You must call DatabaseInit before ConnectionInit",
+                    Status::InvalidState,
+                )),
+            };
+            let connection = check_err!(connection, error);
+            *exported_connection = ExportedConnection::Connection(connection);
+        } else {
+            check_err!(
+                Err(Error::with_message_and_status(
+                    "Connection already initialized",
+                    Status::InvalidState
+                )),
+                error
+            );
+        }
+
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_release<DriverType: Driver>(
+extern "C" fn connection_release<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-
-    let connection = connection.as_mut().unwrap();
-    if connection.private_data.is_null() {
-        check_err!(
-            Err(Error::with_message_and_status(
-                "Connection already released",
-                Status::InvalidState
-            )),
-            error
-        );
-    }
-    let exported = Box::from_raw(connection.private_data as *mut 
ExportedConnection<DriverType>);
-    drop(exported);
-    connection.private_data = std::ptr::null_mut();
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
 
-    ADBC_STATUS_OK
+        if connection.private_data.is_null() {
+            check_err!(
+                Err(Error::with_message_and_status(
+                    "Connection already released",
+                    Status::InvalidState
+                )),
+                error
+            );
+        }
+
+        let exported = unsafe {
+            Box::from_raw(connection.private_data as *mut 
ExportedConnection<DriverType>)
+        };
+        drop(exported);
+        connection.private_data = std::ptr::null_mut();
+
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_set_option<DriverType: Driver>(
+extern "C" fn connection_set_option<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     key: *const c_char,
     value: *const c_char,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        check_not_null!(connection, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let value = check_err!(CStr::from_ptr(value).to_str(), error);
-    connection_set_option_impl::<DriverType, &str>(connection, key, value, 
error)
+        let value = check_err!(unsafe { CStr::from_ptr(value).to_str() }, 
error);
+        unsafe { connection_set_option_impl::<DriverType, &str>(connection, 
key, value, error) }
+    })
 }
 
-unsafe extern "C" fn connection_set_option_int<DriverType: Driver>(
+extern "C" fn connection_set_option_int<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     key: *const c_char,
     value: i64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(key, error);
+    catch_panic(error, || {
+        check_not_null!(connection, error);
+        check_not_null!(key, error);
 
-    connection_set_option_impl::<DriverType, i64>(connection, key, value, 
error)
+        unsafe { connection_set_option_impl::<DriverType, i64>(connection, 
key, value, error) }
+    })
 }
 
-unsafe extern "C" fn connection_set_option_double<DriverType: Driver>(
+extern "C" fn connection_set_option_double<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     key: *const c_char,
     value: f64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(key, error);
+    catch_panic(error, || {
+        check_not_null!(connection, error);
+        check_not_null!(key, error);
 
-    connection_set_option_impl::<DriverType, f64>(connection, key, value, 
error)
+        unsafe { connection_set_option_impl::<DriverType, f64>(connection, 
key, value, error) }
+    })
 }
 
-unsafe extern "C" fn connection_set_option_bytes<DriverType: Driver>(
+extern "C" fn connection_set_option_bytes<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     key: *const c_char,
     value: *const u8,
     length: usize,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        check_not_null!(connection, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let value = std::slice::from_raw_parts(value, length);
-    connection_set_option_impl::<DriverType, &[u8]>(connection, key, value, 
error)
+        let value = unsafe { std::slice::from_raw_parts(value, length) };
+        unsafe { connection_set_option_impl::<DriverType, &[u8]>(connection, 
key, value, error) }
+    })
 }
 
-unsafe extern "C" fn connection_get_option<DriverType: Driver>(
+extern "C" fn connection_get_option<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     key: *const c_char,
     value: *mut c_char,
     length: *mut usize,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
-    check_not_null!(length, error);
-
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let (options, connection) = exported.tuple();
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
+        check_not_null!(length, error);
+
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let (options, connection) = exported.tuple();
 
-    let optvalue = get_option(connection, options, key);
-    let optvalue = check_err!(optvalue, error);
-    check_err!(copy_string(&optvalue, value, length), error);
+        let optvalue = unsafe { get_option(connection, options, key) };
+        let optvalue = check_err!(optvalue, error);
+        check_err!(unsafe { copy_string(&optvalue, value, length) }, error);
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_get_option_int<DriverType: Driver>(
+extern "C" fn connection_get_option_int<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     key: *const c_char,
     value: *mut i64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let (options, connection) = exported.tuple();
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let (options, connection) = exported.tuple();
 
-    let optvalue = check_err!(get_option_int(connection, options, key), error);
-    std::ptr::write_unaligned(value, optvalue);
+        let optvalue = check_err!(unsafe { get_option_int(connection, options, 
key) }, error);
+        unsafe { std::ptr::write_unaligned(value, optvalue) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_get_option_double<DriverType: Driver>(
+extern "C" fn connection_get_option_double<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     key: *const c_char,
     value: *mut f64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let (options, connection) = exported.tuple();
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let (options, connection) = exported.tuple();
 
-    let optvalue = check_err!(get_option_double(connection, options, key), 
error);
-    std::ptr::write_unaligned(value, optvalue);
+        let optvalue = check_err!(
+            unsafe { get_option_double(connection, options, key) },
+            error
+        );
+        unsafe { std::ptr::write_unaligned(value, optvalue) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_get_option_bytes<DriverType: Driver>(
+extern "C" fn connection_get_option_bytes<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     key: *const c_char,
     value: *mut u8,
     length: *mut usize,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
-    check_not_null!(length, error);
-
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let (options, connection) = exported.tuple();
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
+        check_not_null!(length, error);
+
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let (options, connection) = exported.tuple();
 
-    let optvalue = get_option_bytes(connection, options, key);
-    let optvalue = check_err!(optvalue, error);
-    copy_bytes(&optvalue, value, length);
+        let optvalue = unsafe { get_option_bytes(connection, options, key) };
+        let optvalue = check_err!(optvalue, error);
+        unsafe { copy_bytes(&optvalue, value, length) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_get_table_types<DriverType: Driver + 'static>(
+extern "C" fn connection_get_table_types<DriverType: Driver + 'static>(
     connection: *mut FFI_AdbcConnection,
     out: *mut FFI_ArrowArrayStream,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(out, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(out, error);
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let connection = check_err!(exported.try_connection(), error);
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let connection = check_err!(exported.try_connection(), error);
 
-    let reader = check_err!(connection.get_table_types(), error);
-    let reader = Box::new(reader);
-    let reader = FFI_ArrowArrayStream::new(reader);
-    std::ptr::write_unaligned(out, reader);
+        let reader = check_err!(connection.get_table_types(), error);
+        let reader = Box::new(reader);
+        let reader = FFI_ArrowArrayStream::new(reader);
+        unsafe { std::ptr::write_unaligned(out, reader) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_get_table_schema<DriverType: Driver>(
+extern "C" fn connection_get_table_schema<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     catalog: *const c_char,
     db_schema: *const c_char,
@@ -973,138 +1134,174 @@ unsafe extern "C" fn 
connection_get_table_schema<DriverType: Driver>(
     schema: *mut FFI_ArrowSchema,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(table_name, error);
-    check_not_null!(schema, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(table_name, error);
+        check_not_null!(schema, error);
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let connection = check_err!(exported.try_connection(), error);
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let connection = check_err!(exported.try_connection(), error);
 
-    let catalog = check_err!(maybe_str(catalog), error);
-    let db_schema = check_err!(maybe_str(db_schema), error);
-    let table_name = check_err!(maybe_str(table_name), error);
+        let catalog = check_err!(unsafe { maybe_str(catalog) }, error);
+        let db_schema = check_err!(unsafe { maybe_str(db_schema) }, error);
+        let table_name = check_err!(unsafe { maybe_str(table_name) }, error);
 
-    let schema_value = connection.get_table_schema(catalog, db_schema, 
table_name.unwrap());
-    let schema_value = check_err!(schema_value, error);
-    let schema_value: FFI_ArrowSchema = check_err!(schema_value.try_into(), 
error);
-    std::ptr::write_unaligned(schema, schema_value);
+        let schema_value = connection.get_table_schema(catalog, db_schema, 
table_name.unwrap());
+        let schema_value = check_err!(schema_value, error);
+        let schema_value: FFI_ArrowSchema = 
check_err!(schema_value.try_into(), error);
+        unsafe { std::ptr::write_unaligned(schema, schema_value) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_get_info<DriverType: Driver + 'static>(
+extern "C" fn connection_get_info<DriverType: Driver + 'static>(
     connection: *mut FFI_AdbcConnection,
     info_codes: *const u32,
     info_codes_length: usize,
     out: *mut FFI_ArrowArrayStream,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(out, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(out, error);
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let connection = check_err!(exported.try_connection(), error);
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let connection = check_err!(exported.try_connection(), error);
 
-    let info_codes = if info_codes.is_null() {
-        None
-    } else {
-        let info_codes = std::slice::from_raw_parts(info_codes, 
info_codes_length);
-        let info_codes: Result<HashSet<InfoCode>> =
-            info_codes.iter().map(|c| InfoCode::try_from(*c)).collect();
-        let info_codes = check_err!(info_codes, error);
-        Some(info_codes)
-    };
+        let info_codes = if info_codes.is_null() {
+            None
+        } else {
+            let info_codes = unsafe { std::slice::from_raw_parts(info_codes, 
info_codes_length) };
+            let info_codes: Result<HashSet<InfoCode>> =
+                info_codes.iter().map(|c| InfoCode::try_from(*c)).collect();
+            let info_codes = check_err!(info_codes, error);
+            Some(info_codes)
+        };
 
-    let reader = check_err!(connection.get_info(info_codes), error);
-    let reader = Box::new(reader);
-    let reader = FFI_ArrowArrayStream::new(reader);
-    std::ptr::write_unaligned(out, reader);
+        let reader = check_err!(connection.get_info(info_codes), error);
+        let reader = Box::new(reader);
+        let reader = FFI_ArrowArrayStream::new(reader);
+        unsafe { std::ptr::write_unaligned(out, reader) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_commit<DriverType: Driver>(
+extern "C" fn connection_commit<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let connection = check_err!(exported.try_connection(), error);
-    check_err!(connection.commit(), error);
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let connection = check_err!(exported.try_connection(), error);
+        check_err!(connection.commit(), error);
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_rollback<DriverType: Driver>(
+extern "C" fn connection_rollback<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let connection = check_err!(exported.try_connection(), error);
-    check_err!(connection.rollback(), error);
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let connection = check_err!(exported.try_connection(), error);
+        check_err!(connection.rollback(), error);
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_cancel<DriverType: Driver>(
+extern "C" fn connection_cancel<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let connection = check_err!(exported.try_connection(), error);
-    check_err!(connection.cancel(), error);
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let connection = check_err!(exported.try_connection(), error);
+        check_err!(connection.cancel(), error);
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_get_statistic_names<DriverType: Driver + 
'static>(
+extern "C" fn connection_get_statistic_names<DriverType: Driver + 'static>(
     connection: *mut FFI_AdbcConnection,
     out: *mut FFI_ArrowArrayStream,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(out, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(out, error);
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let connection = check_err!(exported.try_connection(), error);
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let connection = check_err!(exported.try_connection(), error);
 
-    let reader = check_err!(connection.get_statistic_names(), error);
-    let reader = Box::new(reader);
-    let reader = FFI_ArrowArrayStream::new(reader);
-    std::ptr::write_unaligned(out, reader);
+        let reader = check_err!(connection.get_statistic_names(), error);
+        let reader = Box::new(reader);
+        let reader = FFI_ArrowArrayStream::new(reader);
+        unsafe { std::ptr::write_unaligned(out, reader) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_read_partition<DriverType: Driver + 'static>(
+extern "C" fn connection_read_partition<DriverType: Driver + 'static>(
     connection: *mut FFI_AdbcConnection,
     serialized_partition: *const u8,
     serialized_length: usize,
     out: *mut FFI_ArrowArrayStream,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(serialized_partition, error);
-    check_not_null!(out, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(serialized_partition, error);
+        check_not_null!(out, error);
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let connection = check_err!(exported.try_connection(), error);
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let connection = check_err!(exported.try_connection(), error);
 
-    let partition = std::slice::from_raw_parts(serialized_partition, 
serialized_length);
-    let reader = check_err!(connection.read_partition(partition), error);
-    let reader = Box::new(reader);
-    let reader = FFI_ArrowArrayStream::new(reader);
-    std::ptr::write_unaligned(out, reader);
+        let partition =
+            unsafe { std::slice::from_raw_parts(serialized_partition, 
serialized_length) };
+        let reader = check_err!(connection.read_partition(partition), error);
+        let reader = Box::new(reader);
+        let reader = FFI_ArrowArrayStream::new(reader);
+        unsafe { std::ptr::write_unaligned(out, reader) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_get_statistics<DriverType: Driver + 'static>(
+extern "C" fn connection_get_statistics<DriverType: Driver + 'static>(
     connection: *mut FFI_AdbcConnection,
     catalog: *const c_char,
     db_schema: *const c_char,
@@ -1113,27 +1310,32 @@ unsafe extern "C" fn 
connection_get_statistics<DriverType: Driver + 'static>(
     out: *mut FFI_ArrowArrayStream,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(out, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(out, error);
 
-    let catalog = check_err!(maybe_str(catalog), error);
-    let db_schema = check_err!(maybe_str(db_schema), error);
-    let table_name = check_err!(maybe_str(table_name), error);
-    let approximate = approximate != 0;
+        let catalog = check_err!(unsafe { maybe_str(catalog) }, error);
+        let db_schema = check_err!(unsafe { maybe_str(db_schema) }, error);
+        let table_name = check_err!(unsafe { maybe_str(table_name) }, error);
+        let approximate = approximate != 0;
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let connection = check_err!(exported.try_connection(), error);
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let connection = check_err!(exported.try_connection(), error);
 
-    let reader = connection.get_statistics(catalog, db_schema, table_name, 
approximate);
-    let reader = check_err!(reader, error);
-    let reader = Box::new(reader);
-    let reader = FFI_ArrowArrayStream::new(reader);
-    std::ptr::write_unaligned(out, reader);
+        let reader = connection.get_statistics(catalog, db_schema, table_name, 
approximate);
+        let reader = check_err!(reader, error);
+        let reader = Box::new(reader);
+        let reader = FFI_ArrowArrayStream::new(reader);
+        unsafe { std::ptr::write_unaligned(out, reader) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn connection_get_objects<DriverType: Driver + 'static>(
+extern "C" fn connection_get_objects<DriverType: Driver + 'static>(
     connection: *mut FFI_AdbcConnection,
     depth: c_int,
     catalog: *const c_char,
@@ -1144,45 +1346,50 @@ unsafe extern "C" fn connection_get_objects<DriverType: 
Driver + 'static>(
     out: *mut FFI_ArrowArrayStream,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(out, error);
-
-    let depth = check_err!(ObjectDepth::try_from(depth), error);
-    let catalog = check_err!(maybe_str(catalog), error);
-    let db_schema = check_err!(maybe_str(db_schema), error);
-    let table_name = check_err!(maybe_str(table_name), error);
-    let column_name = check_err!(maybe_str(column_name), error);
-    let table_type = if !table_type.is_null() {
-        let mut strs = Vec::new();
-        let mut ptr = table_type;
-        // Iteration over an array of C-strings that ends with a null pointer.
-        while !(*ptr).is_null() {
-            let str = check_err!(CStr::from_ptr(*ptr).to_str(), error);
-            strs.push(str);
-            ptr = ptr.add(1);
-        }
-        Some(strs)
-    } else {
-        None
-    };
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        check_not_null!(out, error);
+
+        let depth = check_err!(ObjectDepth::try_from(depth), error);
+        let catalog = check_err!(unsafe { maybe_str(catalog) }, error);
+        let db_schema = check_err!(unsafe { maybe_str(db_schema) }, error);
+        let table_name = check_err!(unsafe { maybe_str(table_name) }, error);
+        let column_name = check_err!(unsafe { maybe_str(column_name) }, error);
+        let table_type = if !table_type.is_null() {
+            let mut strs = Vec::new();
+            let mut ptr = table_type;
+            // Iteration over an array of C-strings that ends with a null 
pointer.
+            while !unsafe { *ptr }.is_null() {
+                let str = check_err!(unsafe { CStr::from_ptr(*ptr) }.to_str(), 
error);
+                strs.push(str);
+                ptr = unsafe { ptr.add(1) };
+            }
+            Some(strs)
+        } else {
+            None
+        };
 
-    let exported = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let connection = check_err!(exported.try_connection(), error);
-
-    let reader = connection.get_objects(
-        depth,
-        catalog,
-        db_schema,
-        table_name,
-        table_type,
-        column_name,
-    );
-    let reader = check_err!(reader, error);
-    let reader = Box::new(reader);
-    let reader = FFI_ArrowArrayStream::new(reader);
-    std::ptr::write_unaligned(out, reader);
+        let exported = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let connection = check_err!(exported.try_connection(), error);
+
+        let reader = connection.get_objects(
+            depth,
+            catalog,
+            db_schema,
+            table_name,
+            table_type,
+            column_name,
+        );
+        let reader = check_err!(reader, error);
+        let reader = Box::new(reader);
+        let reader = FFI_ArrowArrayStream::new(reader);
+        unsafe { std::ptr::write_unaligned(out, reader) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
 // Statement
@@ -1216,376 +1423,465 @@ unsafe fn statement_set_option_impl<DriverType: 
Driver, Value: Into<OptionValue>
     ADBC_STATUS_OK
 }
 
-unsafe extern "C" fn statement_new<DriverType: Driver>(
+extern "C" fn statement_new<DriverType: Driver>(
     connection: *mut FFI_AdbcConnection,
     statement: *mut FFI_AdbcStatement,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(connection, error);
-    check_not_null!(statement, error);
+    catch_panic(error, || {
+        let connection = pointer_as_mut!(connection, error);
+        let statement = pointer_as_mut!(statement, error);
 
-    let exported_connection = 
check_err!(connection_private_data::<DriverType>(connection), error);
-    let inner_connection = check_err!(exported_connection.try_connection(), 
error);
+        let exported_connection = check_err!(
+            unsafe { connection_private_data::<DriverType>(connection) },
+            error
+        );
+        let inner_connection = 
check_err!(exported_connection.try_connection(), error);
 
-    let statement = statement.as_mut().unwrap();
-    let inner_statement = check_err!(inner_connection.new_statement(), error);
+        let inner_statement = check_err!(inner_connection.new_statement(), 
error);
 
-    let exported = Box::new(ExportedStatement::<DriverType>(inner_statement));
-    statement.private_data = Box::into_raw(exported) as *mut c_void;
+        let exported = 
Box::new(ExportedStatement::<DriverType>(inner_statement));
+        statement.private_data = Box::into_raw(exported) as *mut c_void;
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_release<DriverType: Driver>(
+extern "C" fn statement_release<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-
-    let statement = statement.as_mut().unwrap();
-    if statement.private_data.is_null() {
-        check_err!(
-            Err(Error::with_message_and_status(
-                "Statement already released",
-                Status::InvalidState
-            )),
-            error
-        );
-    }
-    let exported = Box::from_raw(statement.private_data as *mut 
ExportedStatement<DriverType>);
-    drop(exported);
-    statement.private_data = std::ptr::null_mut();
+    catch_panic(error, || {
+        let statement = pointer_as_mut!(statement, error);
+        if statement.private_data.is_null() {
+            check_err!(
+                Err(Error::with_message_and_status(
+                    "Statement already released",
+                    Status::InvalidState
+                )),
+                error
+            );
+        }
+        let exported =
+            unsafe { Box::from_raw(statement.private_data as *mut 
ExportedStatement<DriverType>) };
+        drop(exported);
+        statement.private_data = std::ptr::null_mut();
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_set_option<DriverType: Driver>(
+extern "C" fn statement_set_option<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     key: *const c_char,
     value: *const c_char,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let value = check_err!(CStr::from_ptr(value).to_str(), error);
-    statement_set_option_impl::<DriverType, &str>(statement, key, value, error)
+        let value = check_err!(unsafe { CStr::from_ptr(value).to_str() }, 
error);
+        unsafe { statement_set_option_impl::<DriverType, &str>(statement, key, 
value, error) }
+    })
 }
 
-unsafe extern "C" fn statement_set_option_int<DriverType: Driver>(
+extern "C" fn statement_set_option_int<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     key: *const c_char,
     value: i64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(key, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(key, error);
 
-    statement_set_option_impl::<DriverType, i64>(statement, key, value, error)
+        unsafe { statement_set_option_impl::<DriverType, i64>(statement, key, 
value, error) }
+    })
 }
 
-unsafe extern "C" fn statement_set_option_double<DriverType: Driver>(
+extern "C" fn statement_set_option_double<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     key: *const c_char,
     value: f64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(key, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(key, error);
 
-    statement_set_option_impl::<DriverType, f64>(statement, key, value, error)
+        unsafe { statement_set_option_impl::<DriverType, f64>(statement, key, 
value, error) }
+    })
 }
 
-unsafe extern "C" fn statement_set_option_bytes<DriverType: Driver>(
+extern "C" fn statement_set_option_bytes<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     key: *const c_char,
     value: *const u8,
     length: usize,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let value = std::slice::from_raw_parts(value, length);
-    statement_set_option_impl::<DriverType, &[u8]>(statement, key, value, 
error)
+        let value = unsafe { std::slice::from_raw_parts(value, length) };
+        unsafe { statement_set_option_impl::<DriverType, &[u8]>(statement, 
key, value, error) }
+    })
 }
 
-unsafe extern "C" fn statement_get_option<DriverType: Driver>(
+extern "C" fn statement_get_option<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     key: *const c_char,
     value: *mut c_char,
     length: *mut usize,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
-    check_not_null!(length, error);
-
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let optvalue = get_option(Some(&mut exported.0), None, key);
-    let optvalue = check_err!(optvalue, error);
-    check_err!(copy_string(&optvalue, value, length), error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
+        check_not_null!(length, error);
+
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let optvalue = unsafe { get_option(Some(&mut exported.0), None, key) };
+        let optvalue = check_err!(optvalue, error);
+        check_err!(unsafe { copy_string(&optvalue, value, length) }, error);
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_get_option_int<DriverType: Driver>(
+extern "C" fn statement_get_option_int<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     key: *const c_char,
     value: *mut i64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let optvalue = check_err!(get_option_int(Some(&mut exported.0), None, 
key), error);
-    std::ptr::write_unaligned(value, optvalue);
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let optvalue = check_err!(
+            unsafe { get_option_int(Some(&mut exported.0), None, key) },
+            error
+        );
+        unsafe { std::ptr::write_unaligned(value, optvalue) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_get_option_double<DriverType: Driver>(
+extern "C" fn statement_get_option_double<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     key: *const c_char,
     value: *mut f64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let optvalue = check_err!(get_option_double(Some(&mut exported.0), None, 
key), error);
-    std::ptr::write_unaligned(value, optvalue);
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let optvalue = check_err!(
+            unsafe { get_option_double(Some(&mut exported.0), None, key) },
+            error
+        );
+        unsafe { std::ptr::write_unaligned(value, optvalue) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_get_option_bytes<DriverType: Driver>(
+extern "C" fn statement_get_option_bytes<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     key: *const c_char,
     value: *mut u8,
     length: *mut usize,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(key, error);
-    check_not_null!(value, error);
-    check_not_null!(length, error);
-
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let optvalue = get_option_bytes(Some(&mut exported.0), None, key);
-    let optvalue = check_err!(optvalue, error);
-    copy_bytes(&optvalue, value, length);
-    ADBC_STATUS_OK
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(key, error);
+        check_not_null!(value, error);
+        check_not_null!(length, error);
+
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let optvalue = unsafe { get_option_bytes(Some(&mut exported.0), None, 
key) };
+        let optvalue = check_err!(optvalue, error);
+        unsafe { copy_bytes(&optvalue, value, length) };
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_bind<DriverType: Driver>(
+extern "C" fn statement_bind<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     values: *mut FFI_ArrowArray,
     schema: *mut FFI_ArrowSchema,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(values, error);
-    check_not_null!(schema, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(values, error);
+        check_not_null!(schema, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let statement = &mut exported.0;
-
-    let schema = schema.as_ref().unwrap();
-    let data = FFI_ArrowArray::from_raw(values);
-    let array = check_err!(from_ffi(data, schema), error);
-
-    if !matches!(array.data_type(), DataType::Struct(_)) {
-        check_err!(
-            Err(Error::with_message_and_status(
-                "You must pass a struct array to StatementBind",
-                Status::InvalidArguments
-            )),
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
             error
         );
-    }
+        let statement = &mut exported.0;
 
-    let array: StructArray = array.into();
-    check_err!(statement.bind(array.into()), error);
+        let schema = unsafe { schema.as_ref().unwrap() };
+        let data = unsafe { FFI_ArrowArray::from_raw(values) };
+        let array = check_err!(unsafe { from_ffi(data, schema) }, error);
 
-    ADBC_STATUS_OK
+        if !matches!(array.data_type(), DataType::Struct(_)) {
+            check_err!(
+                Err(Error::with_message_and_status(
+                    "You must pass a struct array to StatementBind",
+                    Status::InvalidArguments
+                )),
+                error
+            );
+        }
+
+        let array: StructArray = array.into();
+        check_err!(statement.bind(array.into()), error);
+
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_bind_stream<DriverType: Driver>(
+extern "C" fn statement_bind_stream<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     stream: *mut FFI_ArrowArrayStream,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(stream, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(stream, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let statement = &mut exported.0;
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let statement = &mut exported.0;
 
-    let reader = check_err!(ArrowArrayStreamReader::from_raw(stream), error);
-    let reader = Box::new(reader);
-    check_err!(statement.bind_stream(reader), error);
+        let reader = check_err!(unsafe { 
ArrowArrayStreamReader::from_raw(stream) }, error);
+        let reader = Box::new(reader);
+        check_err!(statement.bind_stream(reader), error);
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_cancel<DriverType: Driver>(
+extern "C" fn statement_cancel<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let statement = &mut exported.0;
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let statement = &mut exported.0;
 
-    check_err!(statement.cancel(), error);
+        check_err!(statement.cancel(), error);
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_execute_query<DriverType: Driver + 'static>(
+extern "C" fn statement_execute_query<DriverType: Driver + 'static>(
     statement: *mut FFI_AdbcStatement,
     out: *mut FFI_ArrowArrayStream,
     rows_affected: *mut i64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let statement = &mut exported.0;
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let statement = &mut exported.0;
 
-    if !out.is_null() {
-        let reader = check_err!(statement.execute(), error);
-        let reader = Box::new(reader);
-        let reader = FFI_ArrowArrayStream::new(reader);
-        std::ptr::write_unaligned(out, reader);
-    } else {
-        let rows_affected_value = check_err!(statement.execute_update(), 
error).unwrap_or(-1);
-        if !rows_affected.is_null() {
-            std::ptr::write_unaligned(rows_affected, rows_affected_value);
+        if !out.is_null() {
+            let reader = check_err!(statement.execute(), error);
+            let reader = Box::new(reader);
+            let reader = FFI_ArrowArrayStream::new(reader);
+            unsafe { std::ptr::write_unaligned(out, reader) };
+        } else {
+            let rows_affected_value = check_err!(statement.execute_update(), 
error).unwrap_or(-1);
+            if !rows_affected.is_null() {
+                unsafe { std::ptr::write_unaligned(rows_affected, 
rows_affected_value) };
+            }
         }
-    }
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_execute_schema<DriverType: Driver>(
+extern "C" fn statement_execute_schema<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     schema: *mut FFI_ArrowSchema,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(schema, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(schema, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let statement = &mut exported.0;
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let statement = &mut exported.0;
 
-    let schema_value = check_err!(statement.execute_schema(), error);
-    let schema_value: FFI_ArrowSchema = check_err!(schema_value.try_into(), 
error);
-    std::ptr::write_unaligned(schema, schema_value);
+        let schema_value = check_err!(statement.execute_schema(), error);
+        let schema_value: FFI_ArrowSchema = 
check_err!(schema_value.try_into(), error);
+        unsafe { std::ptr::write_unaligned(schema, schema_value) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_execute_partitions<DriverType: Driver>(
+extern "C" fn statement_execute_partitions<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     schema: *mut FFI_ArrowSchema,
     partitions: *mut FFI_AdbcPartitions,
     rows_affected: *mut i64,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(schema, error);
-    check_not_null!(partitions, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(schema, error);
+        check_not_null!(partitions, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let statement = &mut exported.0;
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let statement = &mut exported.0;
 
-    let result = check_err!(statement.execute_partitions(), error);
+        let result = check_err!(statement.execute_partitions(), error);
 
-    if !rows_affected.is_null() {
-        std::ptr::write_unaligned(rows_affected, result.rows_affected);
-    }
+        if !rows_affected.is_null() {
+            unsafe { std::ptr::write_unaligned(rows_affected, 
result.rows_affected) };
+        }
 
-    let schema_value: FFI_ArrowSchema = 
check_err!((&result.schema).try_into(), error);
-    std::ptr::write_unaligned(schema, schema_value);
+        let schema_value: FFI_ArrowSchema = 
check_err!((&result.schema).try_into(), error);
+        unsafe { std::ptr::write_unaligned(schema, schema_value) };
 
-    let partitions_value: FFI_AdbcPartitions = result.partitions.into();
-    std::ptr::write_unaligned(partitions, partitions_value);
+        let partitions_value: FFI_AdbcPartitions = result.partitions.into();
+        unsafe { std::ptr::write_unaligned(partitions, partitions_value) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_prepare<DriverType: Driver>(
+extern "C" fn statement_prepare<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let statement = &mut exported.0;
-    check_err!(statement.prepare(), error);
-    ADBC_STATUS_OK
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let statement = &mut exported.0;
+        check_err!(statement.prepare(), error);
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_set_sql_query<DriverType: Driver>(
+extern "C" fn statement_set_sql_query<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     query: *const c_char,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(query, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(query, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let statement = &mut exported.0;
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let statement = &mut exported.0;
 
-    let query = check_err!(CStr::from_ptr(query).to_str(), error);
-    check_err!(statement.set_sql_query(query), error);
+        let query = check_err!(unsafe { CStr::from_ptr(query).to_str() }, 
error);
+        check_err!(statement.set_sql_query(query), error);
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_set_substrait_plan<DriverType: Driver>(
+extern "C" fn statement_set_substrait_plan<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     plan: *const u8,
     length: usize,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(plan, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(plan, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let statement = &mut exported.0;
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let statement = &mut exported.0;
 
-    let plan = std::slice::from_raw_parts(plan, length);
-    check_err!(statement.set_substrait_plan(plan), error);
+        let plan = unsafe { std::slice::from_raw_parts(plan, length) };
+        check_err!(statement.set_substrait_plan(plan), error);
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
-unsafe extern "C" fn statement_get_parameter_schema<DriverType: Driver>(
+extern "C" fn statement_get_parameter_schema<DriverType: Driver>(
     statement: *mut FFI_AdbcStatement,
     schema: *mut FFI_ArrowSchema,
     error: *mut FFI_AdbcError,
 ) -> AdbcStatusCode {
-    check_not_null!(statement, error);
-    check_not_null!(schema, error);
+    catch_panic(error, || {
+        check_not_null!(statement, error);
+        check_not_null!(schema, error);
 
-    let exported = check_err!(statement_private_data::<DriverType>(statement), 
error);
-    let statement = &exported.0;
+        let exported = check_err!(
+            unsafe { statement_private_data::<DriverType>(statement) },
+            error
+        );
+        let statement = &exported.0;
 
-    let schema_value = check_err!(statement.get_parameter_schema(), error);
-    let schema_value: FFI_ArrowSchema = check_err!(schema_value.try_into(), 
error);
-    std::ptr::write_unaligned(schema, schema_value);
+        let schema_value = check_err!(statement.get_parameter_schema(), error);
+        let schema_value: FFI_ArrowSchema = 
check_err!(schema_value.try_into(), error);
+        unsafe { std::ptr::write_unaligned(schema, schema_value) };
 
-    ADBC_STATUS_OK
+        ADBC_STATUS_OK
+    })
 }
 
 // Error

Reply via email to