From c0dff0cf2e2371b45520fb09a8d78656662e612b Mon Sep 17 00:00:00 2001 From: Felipe Oliveira Carvalho Date: Sat, 7 Nov 2026 15:45:53 -0300 Subject: [PATCH 1/2] fix(rust): require arrow >= 59 so FFI imports realign buffers Drivers may export buffers that only meet the C Data Interface's recommended 8-byte alignment, but arrow-rs requires 16-byte alignment for i128 (e.g. Decimal128). With arrow 58, importing such data through `from_ffi` or `ArrowArrayStreamReader` panics. arrow 59 realigns under-aligned buffers on import (apache/arrow-rs#10030), so raise the minimum arrow version to 59 and add a regression test that imports an 8-byte-aligned Decimal128 buffer. Closes #2526. Co-Authored-By: Claude Opus 5.5 --- rust/Cargo.lock | 2 ++ rust/Cargo.toml | 12 +++++--- rust/ffi/Cargo.toml | 4 +++ rust/ffi/src/driver_exporter.rs | 49 +++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 4 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 69c984ab54..1bd9047a2e 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -49,6 +49,8 @@ version = "0.26.0" dependencies = [ "adbc_core", "arrow-array", + "arrow-buffer", + "arrow-data", "arrow-schema", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index acca282d0b..c885dfde0c 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -36,9 +36,13 @@ categories = ["database"] adbc_core = { path = "./core", version = "0.26.0" } adbc_driver_manager = { path = "./driver_manager", version = "0.26.0" } adbc_ffi = { path = "./ffi", version = "0.26.0" } -arrow-array = { version = ">=58, <61", default-features = false, features = [ +# arrow >= 59 realigns under-aligned buffers imported through the C Data +# Interface (arrow-rs#10030). Older versions panic on buffers that are only +# 8-byte aligned (e.g. Decimal128 from JVM-based drivers). +arrow-array = { version = ">=59, <61", default-features = false, features = [ "ffi", ] } -arrow-buffer = { version = ">=58, <61", default-features = false } -arrow-schema = { version = ">=58, <61", default-features = false } -arrow-select = { version = ">=58, <61", default-features = false } +arrow-buffer = { version = ">=59, <61", default-features = false } +arrow-data = { version = ">=59, <61", default-features = false } +arrow-schema = { version = ">=59, <61", default-features = false } +arrow-select = { version = ">=59, <61", default-features = false } diff --git a/rust/ffi/Cargo.toml b/rust/ffi/Cargo.toml index 553a51cf6e..197f63cda5 100644 --- a/rust/ffi/Cargo.toml +++ b/rust/ffi/Cargo.toml @@ -38,5 +38,9 @@ adbc_core.workspace = true arrow-array.workspace = true arrow-schema.workspace = true +[dev-dependencies] +arrow-buffer.workspace = true +arrow-data.workspace = true + [package.metadata.docs.rs] all-features = true diff --git a/rust/ffi/src/driver_exporter.rs b/rust/ffi/src/driver_exporter.rs index 72aa43add2..2d6ff35a47 100644 --- a/rust/ffi/src/driver_exporter.rs +++ b/rust/ffi/src/driver_exporter.rs @@ -2079,6 +2079,55 @@ mod tests { use crate::types::FFI_AdbcErrorV100; use std::ptr::{null, null_mut}; + /// Drivers may export buffers that only meet the C Data Interface's + /// recommended 8-byte alignment, while arrow-rs requires 16 bytes for + /// i128. Importing such data must realign it instead of panicking. + /// See https://github.com/apache/arrow-adbc/issues/2526. + #[test] + fn test_import_under_aligned_buffers() { + use arrow_array::{Array, Decimal128Array, RecordBatch}; + use arrow_buffer::Buffer; + use arrow_data::ArrayData; + use arrow_schema::{Field, Fields}; + + let decimal_type = DataType::Decimal128(10, 2); + let aligned = Buffer::from_vec(vec![0_i128, 1, 2]); + let under_aligned = aligned.slice(8); + assert_eq!(under_aligned.as_ptr().align_offset(8), 0); + assert_ne!(under_aligned.as_ptr().align_offset(16), 0); + + let child = unsafe { + ArrayData::builder(decimal_type.clone()) + .len(2) + .add_buffer(under_aligned) + .build_unchecked() + }; + let struct_type = + DataType::Struct(Fields::from(vec![Field::new("d", decimal_type, false)])); + let data = unsafe { + ArrayData::builder(struct_type.clone()) + .len(2) + .add_child_data(child) + .build_unchecked() + }; + + // Same import path as `statement_bind`; `ArrowArrayStreamReader` + // (used by `statement_bind_stream` and the driver manager) goes + // through `from_ffi_and_data_type`, which aligns the same way. + let schema = FFI_ArrowSchema::try_from(&struct_type).unwrap(); + let imported = unsafe { from_ffi(FFI_ArrowArray::new(&data), &schema) }.unwrap(); + let batch = RecordBatch::from(StructArray::from(imported)); + + let column = batch + .column(0) + .as_any() + .downcast_ref::() + .unwrap(); + assert_eq!(column.values().inner().as_ptr().align_offset(16), 0); + assert_eq!(column.value(0), 1_i128 << 64); + assert_eq!(column.value(1), 2_i128 << 64); + } + #[test] fn test_error_details_null() { unsafe { From 7cde14913d820fb238c782c3f2f25d66bb0ba824 Mon Sep 17 00:00:00 2001 From: Felipe Oliveira Carvalho Date: Tue, 10 Nov 2026 18:40:30 -0300 Subject: [PATCH 2/2] Remove noisy comments from Cargo.toml Co-authored-by: David Li --- rust/Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index c885dfde0c..799d0a24ad 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -36,9 +36,6 @@ categories = ["database"] adbc_core = { path = "./core", version = "0.26.0" } adbc_driver_manager = { path = "./driver_manager", version = "0.26.0" } adbc_ffi = { path = "./ffi", version = "0.26.0" } -# arrow >= 59 realigns under-aligned buffers imported through the C Data -# Interface (arrow-rs#10030). Older versions panic on buffers that are only -# 8-byte aligned (e.g. Decimal128 from JVM-based drivers). arrow-array = { version = ">=59, <61", default-features = false, features = [ "ffi", ] }