alexandreyc commented on code in PR #1742:
URL: https://github.com/apache/arrow-adbc/pull/1742#discussion_r1574625991
##########
rust/core/src/ffi/types.rs:
##########
@@ -17,4 +17,606 @@
#![allow(non_camel_case_types, non_snake_case)]
+use std::ffi::{CStr, CString};
+use std::mem::ManuallyDrop;
+use std::os::raw::{c_char, c_int, c_void};
+use std::ptr::{null, null_mut};
+
+use super::{check_status, constants, methods};
+use crate::{
+ error::{Error, Status},
+ Partitions,
+};
+
pub type FFI_AdbcStatusCode = u8;
+
+/// A driver initialization function.
+pub type FFI_AdbcDriverInitFunc =
+ unsafe extern "C" fn(c_int, *mut c_void, *mut FFI_AdbcError) ->
FFI_AdbcStatusCode;
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcError {
+ message: *mut c_char,
+ vendor_code: i32,
+ sqlstate: [c_char; 5],
+ release: Option<unsafe extern "C" fn(*mut Self)>,
+ /// Added in ADBC 1.1.0.
+ pub(crate) private_data: *mut c_void,
+ /// Added in ADBC 1.1.0.
+ pub private_driver: *const FFI_AdbcDriver,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcErrorDetail {
+ /// The metadata key.
+ pub(crate) key: *const c_char,
+ /// The binary metadata value.
+ pub(crate) value: *const u8,
+ /// The length of the metadata value.
+ pub(crate) value_length: usize,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcDatabase {
+ /// Opaque implementation-defined state.
+ /// This field is NULLPTR iff the connection is unintialized/freed.
+ pub(crate) private_data: *mut c_void,
+ /// The associated driver (used by the driver manager to help track state).
+ pub(crate) private_driver: *const FFI_AdbcDriver,
+}
+
+unsafe impl Send for FFI_AdbcDatabase {}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcConnection {
+ /// Opaque implementation-defined state.
+ /// This field is NULLPTR iff the connection is unintialized/freed.
+ pub(crate) private_data: *mut c_void,
+ /// The associated driver (used by the driver manager to help track state).
+ pub(crate) private_driver: *const FFI_AdbcDriver,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcStatement {
+ /// Opaque implementation-defined state.
+ /// This field is NULLPTR iff the connection is unintialized/freed.
+ pub(crate) private_data: *mut c_void,
+ /// The associated driver (used by the driver manager to help track state).
+ pub(crate) private_driver: *const FFI_AdbcDriver,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcPartitions {
+ /// The number of partitions.
+ num_partitions: usize,
+
+ /// The partitions of the result set, where each entry (up to
+ /// num_partitions entries) is an opaque identifier that can be
+ /// passed to AdbcConnectionReadPartition.
+ // It's defined as a const const pointer in C but we need to release it so
it
+ // probably needs to be mutable.
+ partitions: *mut *mut u8,
+
+ /// The length of each corresponding entry in partitions.
+ // It's defined as a const pointer in C but we need to release it so it
+ // probably needs to be mutable.
+ partition_lengths: *mut usize,
+
+ /// Opaque implementation-defined state.
+ /// This field is NULLPTR iff the connection is unintialized/freed.
+ pub(crate) private_data: *mut c_void,
+
+ /// Release the contained partitions.
+ /// Unlike other structures, this is an embedded callback to make it
+ /// easier for the driver manager and driver to cooperate.
+ release: Option<unsafe extern "C" fn(*mut Self)>,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcDriver {
+ /// Opaque driver-defined state.
+ /// This field is NULL if the driver is unintialized/freed (but
+ /// it need not have a value even if the driver is initialized).
+ pub(crate) private_data: *mut c_void,
+ /// Opaque driver manager-defined state.
+ /// This field is NULL if the driver is unintialized/freed (but
+ /// it need not have a value even if the driver is initialized).
+ pub(crate) private_manager: *const c_void,
+ pub(crate) release: Option<
+ unsafe extern "C" fn(driver: *mut Self, error: *mut FFI_AdbcError) ->
FFI_AdbcStatusCode,
+ >,
+ pub(crate) DatabaseInit: Option<methods::FuncDatabaseInit>,
+ pub(crate) DatabaseNew: Option<methods::FuncDatabaseNew>,
+ pub(crate) DatabaseSetOption: Option<methods::FuncDatabaseSetOption>,
+ pub(crate) DatabaseRelease: Option<methods::FuncDatabaseRelease>,
+ pub(crate) ConnectionCommit: Option<methods::FuncConnectionCommit>,
+ pub(crate) ConnectionGetInfo: Option<methods::FuncConnectionGetInfo>,
+ pub(crate) ConnectionGetObjects: Option<methods::FuncConnectionGetObjects>,
+ pub(crate) ConnectionGetTableSchema:
Option<methods::FuncConnectionGetTableSchema>,
+ pub(crate) ConnectionGetTableTypes:
Option<methods::FuncConnectionGetTableTypes>,
+ pub(crate) ConnectionInit: Option<methods::FuncConnectionInit>,
+ pub(crate) ConnectionNew: Option<methods::FuncConnectionNew>,
+ pub(crate) ConnectionSetOption: Option<methods::FuncConnectionSetOption>,
+ pub(crate) ConnectionReadPartition:
Option<methods::FuncConnectionReadPartition>,
+ pub(crate) ConnectionRelease: Option<methods::FuncConnectionRelease>,
+ pub(crate) ConnectionRollback: Option<methods::FuncConnectionRollback>,
+ pub(crate) StatementBind: Option<methods::FuncStatementBind>,
+ pub(crate) StatementBindStream: Option<methods::FuncStatementBindStream>,
+ pub(crate) StatementExecuteQuery:
Option<methods::FuncStatementExecuteQuery>,
+ pub(crate) StatementExecutePartitions:
Option<methods::FuncStatementExecutePartitions>,
+ pub(crate) StatementGetParameterSchema:
Option<methods::FuncStatementGetParameterSchema>,
+ pub(crate) StatementNew: Option<methods::FuncStatementNew>,
+ pub(crate) StatementPrepare: Option<methods::FuncStatementPrepare>,
+ pub(crate) StatementRelease: Option<methods::FuncStatementRelease>,
+ pub(crate) StatementSetOption: Option<methods::FuncStatementSetOption>,
+ pub(crate) StatementSetSqlQuery: Option<methods::FuncStatementSetSqlQuery>,
+ pub(crate) StatementSetSubstraitPlan:
Option<methods::FuncStatementSetSubstraitPlan>,
+ pub(crate) ErrorGetDetailCount: Option<methods::FuncErrorGetDetailCount>,
+ pub(crate) ErrorGetDetail: Option<methods::FuncErrorGetDetail>,
+ pub(crate) ErrorFromArrayStream: Option<methods::FuncErrorFromArrayStream>,
+ pub(crate) DatabaseGetOption: Option<methods::FuncDatabaseGetOption>,
+ pub(crate) DatabaseGetOptionBytes:
Option<methods::FuncDatabaseGetOptionBytes>,
+ pub(crate) DatabaseGetOptionDouble:
Option<methods::FuncDatabaseGetOptionDouble>,
+ pub(crate) DatabaseGetOptionInt: Option<methods::FuncDatabaseGetOptionInt>,
+ pub(crate) DatabaseSetOptionBytes:
Option<methods::FuncDatabaseSetOptionBytes>,
+ pub(crate) DatabaseSetOptionDouble:
Option<methods::FuncDatabaseSetOptionDouble>,
+ pub(crate) DatabaseSetOptionInt: Option<methods::FuncDatabaseSetOptionInt>,
+ pub(crate) ConnectionCancel: Option<methods::FuncConnectionCancel>,
+ pub(crate) ConnectionGetOption: Option<methods::FuncConnectionGetOption>,
+ pub(crate) ConnectionGetOptionBytes:
Option<methods::FuncConnectionGetOptionBytes>,
+ pub(crate) ConnectionGetOptionDouble:
Option<methods::FuncConnectionGetOptionDouble>,
+ pub(crate) ConnectionGetOptionInt:
Option<methods::FuncConnectionGetOptionInt>,
+ pub(crate) ConnectionGetStatistics:
Option<methods::FuncConnectionGetStatistics>,
+ pub(crate) ConnectionGetStatisticNames:
Option<methods::FuncConnectionGetStatisticNames>,
+ pub(crate) ConnectionSetOptionBytes:
Option<methods::FuncConnectionSetOptionBytes>,
+ pub(crate) ConnectionSetOptionDouble:
Option<methods::FuncConnectionSetOptionDouble>,
+ pub(crate) ConnectionSetOptionInt:
Option<methods::FuncConnectionSetOptionInt>,
+ pub(crate) StatementCancel: Option<methods::FuncStatementCancel>,
+ pub(crate) StatementExecuteSchema:
Option<methods::FuncStatementExecuteSchema>,
+ pub(crate) StatementGetOption: Option<methods::FuncStatementGetOption>,
+ pub(crate) StatementGetOptionBytes:
Option<methods::FuncStatementGetOptionBytes>,
+ pub(crate) StatementGetOptionDouble:
Option<methods::FuncStatementGetOptionDouble>,
+ pub(crate) StatementGetOptionInt:
Option<methods::FuncStatementGetOptionInt>,
+ pub(crate) StatementSetOptionBytes:
Option<methods::FuncStatementSetOptionBytes>,
+ pub(crate) StatementSetOptionDouble:
Option<methods::FuncStatementSetOptionDouble>,
+ pub(crate) StatementSetOptionInt:
Option<methods::FuncStatementSetOptionInt>,
+}
+
+unsafe impl Send for FFI_AdbcDriver {}
+unsafe impl Sync for FFI_AdbcDriver {}
+
+macro_rules! driver_method {
+ ($driver:expr, $method:ident) => {
+ $driver.$method.unwrap_or(crate::ffi::methods::$method)
+ };
+}
+
+pub(crate) use driver_method;
+
+impl TryFrom<FFI_AdbcStatusCode> for Status {
+ type Error = Error;
+
+ fn try_from(value: FFI_AdbcStatusCode) -> Result<Self, Error> {
+ match value {
+ constants::ADBC_STATUS_OK => Ok(Status::Ok),
+ constants::ADBC_STATUS_UNKNOWN => Ok(Status::Unknown),
+ constants::ADBC_STATUS_NOT_IMPLEMENTED =>
Ok(Status::NotImplemented),
+ constants::ADBC_STATUS_NOT_FOUND => Ok(Status::NotFound),
+ constants::ADBC_STATUS_ALREADY_EXISTS => Ok(Status::AlreadyExists),
+ constants::ADBC_STATUS_INVALID_ARGUMENT =>
Ok(Status::InvalidArguments),
+ constants::ADBC_STATUS_INVALID_STATE => Ok(Status::InvalidState),
+ constants::ADBC_STATUS_INVALID_DATA => Ok(Status::InvalidData),
+ constants::ADBC_STATUS_INTEGRITY => Ok(Status::Integrity),
+ constants::ADBC_STATUS_INTERNAL => Ok(Status::Internal),
+ constants::ADBC_STATUS_IO => Ok(Status::IO),
+ constants::ADBC_STATUS_CANCELLED => Ok(Status::Cancelled),
+ constants::ADBC_STATUS_TIMEOUT => Ok(Status::Timeout),
+ constants::ADBC_STATUS_UNAUTHENTICATED =>
Ok(Status::Unauthenticated),
+ constants::ADBC_STATUS_UNAUTHORIZED => Ok(Status::Unauthorized),
+ v => Err(Error::with_message_and_status(
+ format!("Unknown status code: {v}"),
+ Status::InvalidData,
+ )),
+ }
+ }
+}
+
+impl From<Status> for FFI_AdbcStatusCode {
+ fn from(value: Status) -> Self {
+ match value {
+ Status::Ok => constants::ADBC_STATUS_OK,
+ Status::Unknown => constants::ADBC_STATUS_UNKNOWN,
+ Status::NotImplemented => constants::ADBC_STATUS_NOT_IMPLEMENTED,
+ Status::NotFound => constants::ADBC_STATUS_NOT_FOUND,
+ Status::AlreadyExists => constants::ADBC_STATUS_ALREADY_EXISTS,
+ Status::InvalidArguments =>
constants::ADBC_STATUS_INVALID_ARGUMENT,
+ Status::InvalidState => constants::ADBC_STATUS_INVALID_STATE,
+ Status::InvalidData => constants::ADBC_STATUS_INVALID_DATA,
+ Status::Integrity => constants::ADBC_STATUS_INTEGRITY,
+ Status::Internal => constants::ADBC_STATUS_INTERNAL,
+ Status::IO => constants::ADBC_STATUS_IO,
+ Status::Cancelled => constants::ADBC_STATUS_CANCELLED,
+ Status::Timeout => constants::ADBC_STATUS_TIMEOUT,
+ Status::Unauthenticated => constants::ADBC_STATUS_UNAUTHENTICATED,
+ Status::Unauthorized => constants::ADBC_STATUS_UNAUTHORIZED,
+ }
+ }
+}
+
+impl From<&Status> for FFI_AdbcStatusCode {
+ fn from(value: &Status) -> Self {
+ (*value).into()
+ }
+}
+
+impl From<FFI_AdbcPartitions> for Partitions {
+ fn from(value: FFI_AdbcPartitions) -> Self {
+ let mut partitions = Vec::with_capacity(value.num_partitions);
+ for p in 0..value.num_partitions {
+ let partition = unsafe {
+ let ptr = *value.partitions.add(p);
+ let len = *value.partition_lengths.add(p);
+ std::slice::from_raw_parts(ptr, len)
+ };
+ partitions.push(partition.to_vec());
+ }
+ partitions
+ }
+}
+
+// Taken from `Vec::into_raw_parts` which is currently nightly-only.
+fn vec_into_raw_parts<T>(data: Vec<T>) -> (*mut T, usize, usize) {
+ let mut md = ManuallyDrop::new(data);
+ (md.as_mut_ptr(), md.len(), md.capacity())
+}
+
+// We need to store capacities to correctly release memory because the C API
+// only stores lengths and so capacties are lost in translation.
+struct PartitionsPrivateData {
+ partitions_capacity: usize,
+ partition_lengths_capacity: usize,
+ partition_capacities: Vec<usize>,
+}
+
+impl From<Partitions> for FFI_AdbcPartitions {
+ fn from(value: Partitions) -> Self {
+ let num_partitions = value.len();
+ let mut partition_lengths = Vec::with_capacity(num_partitions);
+ let mut partition_capacities = Vec::with_capacity(num_partitions);
+ let mut partition_ptrs = Vec::with_capacity(num_partitions);
+
+ for partition in value.into_iter() {
+ let (partition_ptr, partition_len, partition_cap) =
vec_into_raw_parts(partition);
+ partition_lengths.push(partition_len);
+ partition_capacities.push(partition_cap);
+ partition_ptrs.push(partition_ptr);
+ }
+
+ let (partition_lengths_ptr, _, partition_lengths_cap) =
+ vec_into_raw_parts(partition_lengths);
+ let (partitions_ptr, _, partitions_cap) =
vec_into_raw_parts(partition_ptrs);
+ let private_data = Box::new(PartitionsPrivateData {
+ partitions_capacity: partitions_cap,
+ partition_lengths_capacity: partition_lengths_cap,
+ partition_capacities,
+ });
+
+ FFI_AdbcPartitions {
+ num_partitions,
+ partition_lengths: partition_lengths_ptr,
+ partitions: partitions_ptr,
+ private_data: Box::into_raw(private_data) as *mut c_void,
+ release: Some(release_ffi_partitions),
+ }
+ }
+}
+
+unsafe extern "C" fn release_ffi_partitions(partitions: *mut
FFI_AdbcPartitions) {
+ match partitions.as_mut() {
+ None => (),
+ Some(partitions) => {
+ let private_data = Box::from_raw(partitions.private_data as *mut
PartitionsPrivateData);
+
+ let partition_lengths = Vec::from_raw_parts(
+ partitions.partition_lengths,
+ partitions.num_partitions,
+ private_data.partition_lengths_capacity,
+ );
+ drop(partition_lengths);
+
+ for p in 0..partitions.num_partitions {
+ let partition_ptr = *partitions.partitions.add(p);
Review Comment:
There is probably a use-after-free here. I'm working on it.
##########
rust/core/src/ffi/types.rs:
##########
@@ -17,4 +17,606 @@
#![allow(non_camel_case_types, non_snake_case)]
+use std::ffi::{CStr, CString};
+use std::mem::ManuallyDrop;
+use std::os::raw::{c_char, c_int, c_void};
+use std::ptr::{null, null_mut};
+
+use super::{check_status, constants, methods};
+use crate::{
+ error::{Error, Status},
+ Partitions,
+};
+
pub type FFI_AdbcStatusCode = u8;
+
+/// A driver initialization function.
+pub type FFI_AdbcDriverInitFunc =
+ unsafe extern "C" fn(c_int, *mut c_void, *mut FFI_AdbcError) ->
FFI_AdbcStatusCode;
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcError {
+ message: *mut c_char,
+ vendor_code: i32,
+ sqlstate: [c_char; 5],
+ release: Option<unsafe extern "C" fn(*mut Self)>,
+ /// Added in ADBC 1.1.0.
+ pub(crate) private_data: *mut c_void,
+ /// Added in ADBC 1.1.0.
+ pub private_driver: *const FFI_AdbcDriver,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcErrorDetail {
+ /// The metadata key.
+ pub(crate) key: *const c_char,
+ /// The binary metadata value.
+ pub(crate) value: *const u8,
+ /// The length of the metadata value.
+ pub(crate) value_length: usize,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcDatabase {
+ /// Opaque implementation-defined state.
+ /// This field is NULLPTR iff the connection is unintialized/freed.
+ pub(crate) private_data: *mut c_void,
+ /// The associated driver (used by the driver manager to help track state).
+ pub(crate) private_driver: *const FFI_AdbcDriver,
+}
+
+unsafe impl Send for FFI_AdbcDatabase {}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcConnection {
+ /// Opaque implementation-defined state.
+ /// This field is NULLPTR iff the connection is unintialized/freed.
+ pub(crate) private_data: *mut c_void,
+ /// The associated driver (used by the driver manager to help track state).
+ pub(crate) private_driver: *const FFI_AdbcDriver,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcStatement {
+ /// Opaque implementation-defined state.
+ /// This field is NULLPTR iff the connection is unintialized/freed.
+ pub(crate) private_data: *mut c_void,
+ /// The associated driver (used by the driver manager to help track state).
+ pub(crate) private_driver: *const FFI_AdbcDriver,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcPartitions {
+ /// The number of partitions.
+ num_partitions: usize,
+
+ /// The partitions of the result set, where each entry (up to
+ /// num_partitions entries) is an opaque identifier that can be
+ /// passed to AdbcConnectionReadPartition.
+ // It's defined as a const const pointer in C but we need to release it so
it
+ // probably needs to be mutable.
+ partitions: *mut *mut u8,
+
+ /// The length of each corresponding entry in partitions.
+ // It's defined as a const pointer in C but we need to release it so it
+ // probably needs to be mutable.
+ partition_lengths: *mut usize,
+
+ /// Opaque implementation-defined state.
+ /// This field is NULLPTR iff the connection is unintialized/freed.
+ pub(crate) private_data: *mut c_void,
+
+ /// Release the contained partitions.
+ /// Unlike other structures, this is an embedded callback to make it
+ /// easier for the driver manager and driver to cooperate.
+ release: Option<unsafe extern "C" fn(*mut Self)>,
+}
+
+#[repr(C)]
+#[derive(Debug)]
+pub struct FFI_AdbcDriver {
+ /// Opaque driver-defined state.
+ /// This field is NULL if the driver is unintialized/freed (but
+ /// it need not have a value even if the driver is initialized).
+ pub(crate) private_data: *mut c_void,
+ /// Opaque driver manager-defined state.
+ /// This field is NULL if the driver is unintialized/freed (but
+ /// it need not have a value even if the driver is initialized).
+ pub(crate) private_manager: *const c_void,
+ pub(crate) release: Option<
+ unsafe extern "C" fn(driver: *mut Self, error: *mut FFI_AdbcError) ->
FFI_AdbcStatusCode,
+ >,
+ pub(crate) DatabaseInit: Option<methods::FuncDatabaseInit>,
+ pub(crate) DatabaseNew: Option<methods::FuncDatabaseNew>,
+ pub(crate) DatabaseSetOption: Option<methods::FuncDatabaseSetOption>,
+ pub(crate) DatabaseRelease: Option<methods::FuncDatabaseRelease>,
+ pub(crate) ConnectionCommit: Option<methods::FuncConnectionCommit>,
+ pub(crate) ConnectionGetInfo: Option<methods::FuncConnectionGetInfo>,
+ pub(crate) ConnectionGetObjects: Option<methods::FuncConnectionGetObjects>,
+ pub(crate) ConnectionGetTableSchema:
Option<methods::FuncConnectionGetTableSchema>,
+ pub(crate) ConnectionGetTableTypes:
Option<methods::FuncConnectionGetTableTypes>,
+ pub(crate) ConnectionInit: Option<methods::FuncConnectionInit>,
+ pub(crate) ConnectionNew: Option<methods::FuncConnectionNew>,
+ pub(crate) ConnectionSetOption: Option<methods::FuncConnectionSetOption>,
+ pub(crate) ConnectionReadPartition:
Option<methods::FuncConnectionReadPartition>,
+ pub(crate) ConnectionRelease: Option<methods::FuncConnectionRelease>,
+ pub(crate) ConnectionRollback: Option<methods::FuncConnectionRollback>,
+ pub(crate) StatementBind: Option<methods::FuncStatementBind>,
+ pub(crate) StatementBindStream: Option<methods::FuncStatementBindStream>,
+ pub(crate) StatementExecuteQuery:
Option<methods::FuncStatementExecuteQuery>,
+ pub(crate) StatementExecutePartitions:
Option<methods::FuncStatementExecutePartitions>,
+ pub(crate) StatementGetParameterSchema:
Option<methods::FuncStatementGetParameterSchema>,
+ pub(crate) StatementNew: Option<methods::FuncStatementNew>,
+ pub(crate) StatementPrepare: Option<methods::FuncStatementPrepare>,
+ pub(crate) StatementRelease: Option<methods::FuncStatementRelease>,
+ pub(crate) StatementSetOption: Option<methods::FuncStatementSetOption>,
+ pub(crate) StatementSetSqlQuery: Option<methods::FuncStatementSetSqlQuery>,
+ pub(crate) StatementSetSubstraitPlan:
Option<methods::FuncStatementSetSubstraitPlan>,
+ pub(crate) ErrorGetDetailCount: Option<methods::FuncErrorGetDetailCount>,
+ pub(crate) ErrorGetDetail: Option<methods::FuncErrorGetDetail>,
+ pub(crate) ErrorFromArrayStream: Option<methods::FuncErrorFromArrayStream>,
+ pub(crate) DatabaseGetOption: Option<methods::FuncDatabaseGetOption>,
+ pub(crate) DatabaseGetOptionBytes:
Option<methods::FuncDatabaseGetOptionBytes>,
+ pub(crate) DatabaseGetOptionDouble:
Option<methods::FuncDatabaseGetOptionDouble>,
+ pub(crate) DatabaseGetOptionInt: Option<methods::FuncDatabaseGetOptionInt>,
+ pub(crate) DatabaseSetOptionBytes:
Option<methods::FuncDatabaseSetOptionBytes>,
+ pub(crate) DatabaseSetOptionDouble:
Option<methods::FuncDatabaseSetOptionDouble>,
+ pub(crate) DatabaseSetOptionInt: Option<methods::FuncDatabaseSetOptionInt>,
+ pub(crate) ConnectionCancel: Option<methods::FuncConnectionCancel>,
+ pub(crate) ConnectionGetOption: Option<methods::FuncConnectionGetOption>,
+ pub(crate) ConnectionGetOptionBytes:
Option<methods::FuncConnectionGetOptionBytes>,
+ pub(crate) ConnectionGetOptionDouble:
Option<methods::FuncConnectionGetOptionDouble>,
+ pub(crate) ConnectionGetOptionInt:
Option<methods::FuncConnectionGetOptionInt>,
+ pub(crate) ConnectionGetStatistics:
Option<methods::FuncConnectionGetStatistics>,
+ pub(crate) ConnectionGetStatisticNames:
Option<methods::FuncConnectionGetStatisticNames>,
+ pub(crate) ConnectionSetOptionBytes:
Option<methods::FuncConnectionSetOptionBytes>,
+ pub(crate) ConnectionSetOptionDouble:
Option<methods::FuncConnectionSetOptionDouble>,
+ pub(crate) ConnectionSetOptionInt:
Option<methods::FuncConnectionSetOptionInt>,
+ pub(crate) StatementCancel: Option<methods::FuncStatementCancel>,
+ pub(crate) StatementExecuteSchema:
Option<methods::FuncStatementExecuteSchema>,
+ pub(crate) StatementGetOption: Option<methods::FuncStatementGetOption>,
+ pub(crate) StatementGetOptionBytes:
Option<methods::FuncStatementGetOptionBytes>,
+ pub(crate) StatementGetOptionDouble:
Option<methods::FuncStatementGetOptionDouble>,
+ pub(crate) StatementGetOptionInt:
Option<methods::FuncStatementGetOptionInt>,
+ pub(crate) StatementSetOptionBytes:
Option<methods::FuncStatementSetOptionBytes>,
+ pub(crate) StatementSetOptionDouble:
Option<methods::FuncStatementSetOptionDouble>,
+ pub(crate) StatementSetOptionInt:
Option<methods::FuncStatementSetOptionInt>,
+}
+
+unsafe impl Send for FFI_AdbcDriver {}
+unsafe impl Sync for FFI_AdbcDriver {}
+
+macro_rules! driver_method {
+ ($driver:expr, $method:ident) => {
+ $driver.$method.unwrap_or(crate::ffi::methods::$method)
+ };
+}
+
+pub(crate) use driver_method;
+
+impl TryFrom<FFI_AdbcStatusCode> for Status {
+ type Error = Error;
+
+ fn try_from(value: FFI_AdbcStatusCode) -> Result<Self, Error> {
+ match value {
+ constants::ADBC_STATUS_OK => Ok(Status::Ok),
+ constants::ADBC_STATUS_UNKNOWN => Ok(Status::Unknown),
+ constants::ADBC_STATUS_NOT_IMPLEMENTED =>
Ok(Status::NotImplemented),
+ constants::ADBC_STATUS_NOT_FOUND => Ok(Status::NotFound),
+ constants::ADBC_STATUS_ALREADY_EXISTS => Ok(Status::AlreadyExists),
+ constants::ADBC_STATUS_INVALID_ARGUMENT =>
Ok(Status::InvalidArguments),
+ constants::ADBC_STATUS_INVALID_STATE => Ok(Status::InvalidState),
+ constants::ADBC_STATUS_INVALID_DATA => Ok(Status::InvalidData),
+ constants::ADBC_STATUS_INTEGRITY => Ok(Status::Integrity),
+ constants::ADBC_STATUS_INTERNAL => Ok(Status::Internal),
+ constants::ADBC_STATUS_IO => Ok(Status::IO),
+ constants::ADBC_STATUS_CANCELLED => Ok(Status::Cancelled),
+ constants::ADBC_STATUS_TIMEOUT => Ok(Status::Timeout),
+ constants::ADBC_STATUS_UNAUTHENTICATED =>
Ok(Status::Unauthenticated),
+ constants::ADBC_STATUS_UNAUTHORIZED => Ok(Status::Unauthorized),
+ v => Err(Error::with_message_and_status(
+ format!("Unknown status code: {v}"),
+ Status::InvalidData,
+ )),
+ }
+ }
+}
+
+impl From<Status> for FFI_AdbcStatusCode {
+ fn from(value: Status) -> Self {
+ match value {
+ Status::Ok => constants::ADBC_STATUS_OK,
+ Status::Unknown => constants::ADBC_STATUS_UNKNOWN,
+ Status::NotImplemented => constants::ADBC_STATUS_NOT_IMPLEMENTED,
+ Status::NotFound => constants::ADBC_STATUS_NOT_FOUND,
+ Status::AlreadyExists => constants::ADBC_STATUS_ALREADY_EXISTS,
+ Status::InvalidArguments =>
constants::ADBC_STATUS_INVALID_ARGUMENT,
+ Status::InvalidState => constants::ADBC_STATUS_INVALID_STATE,
+ Status::InvalidData => constants::ADBC_STATUS_INVALID_DATA,
+ Status::Integrity => constants::ADBC_STATUS_INTEGRITY,
+ Status::Internal => constants::ADBC_STATUS_INTERNAL,
+ Status::IO => constants::ADBC_STATUS_IO,
+ Status::Cancelled => constants::ADBC_STATUS_CANCELLED,
+ Status::Timeout => constants::ADBC_STATUS_TIMEOUT,
+ Status::Unauthenticated => constants::ADBC_STATUS_UNAUTHENTICATED,
+ Status::Unauthorized => constants::ADBC_STATUS_UNAUTHORIZED,
+ }
+ }
+}
+
+impl From<&Status> for FFI_AdbcStatusCode {
+ fn from(value: &Status) -> Self {
+ (*value).into()
+ }
+}
+
+impl From<FFI_AdbcPartitions> for Partitions {
+ fn from(value: FFI_AdbcPartitions) -> Self {
+ let mut partitions = Vec::with_capacity(value.num_partitions);
+ for p in 0..value.num_partitions {
+ let partition = unsafe {
+ let ptr = *value.partitions.add(p);
+ let len = *value.partition_lengths.add(p);
+ std::slice::from_raw_parts(ptr, len)
+ };
+ partitions.push(partition.to_vec());
+ }
+ partitions
+ }
+}
+
+// Taken from `Vec::into_raw_parts` which is currently nightly-only.
+fn vec_into_raw_parts<T>(data: Vec<T>) -> (*mut T, usize, usize) {
+ let mut md = ManuallyDrop::new(data);
+ (md.as_mut_ptr(), md.len(), md.capacity())
+}
+
+// We need to store capacities to correctly release memory because the C API
+// only stores lengths and so capacties are lost in translation.
+struct PartitionsPrivateData {
+ partitions_capacity: usize,
+ partition_lengths_capacity: usize,
+ partition_capacities: Vec<usize>,
+}
+
+impl From<Partitions> for FFI_AdbcPartitions {
+ fn from(value: Partitions) -> Self {
+ let num_partitions = value.len();
+ let mut partition_lengths = Vec::with_capacity(num_partitions);
+ let mut partition_capacities = Vec::with_capacity(num_partitions);
+ let mut partition_ptrs = Vec::with_capacity(num_partitions);
+
+ for partition in value.into_iter() {
+ let (partition_ptr, partition_len, partition_cap) =
vec_into_raw_parts(partition);
+ partition_lengths.push(partition_len);
+ partition_capacities.push(partition_cap);
+ partition_ptrs.push(partition_ptr);
+ }
+
+ let (partition_lengths_ptr, _, partition_lengths_cap) =
+ vec_into_raw_parts(partition_lengths);
+ let (partitions_ptr, _, partitions_cap) =
vec_into_raw_parts(partition_ptrs);
+ let private_data = Box::new(PartitionsPrivateData {
+ partitions_capacity: partitions_cap,
+ partition_lengths_capacity: partition_lengths_cap,
+ partition_capacities,
+ });
+
+ FFI_AdbcPartitions {
+ num_partitions,
+ partition_lengths: partition_lengths_ptr,
+ partitions: partitions_ptr,
+ private_data: Box::into_raw(private_data) as *mut c_void,
+ release: Some(release_ffi_partitions),
+ }
+ }
+}
+
+unsafe extern "C" fn release_ffi_partitions(partitions: *mut
FFI_AdbcPartitions) {
+ match partitions.as_mut() {
+ None => (),
+ Some(partitions) => {
+ let private_data = Box::from_raw(partitions.private_data as *mut
PartitionsPrivateData);
+
+ let partition_lengths = Vec::from_raw_parts(
+ partitions.partition_lengths,
+ partitions.num_partitions,
+ private_data.partition_lengths_capacity,
+ );
+ drop(partition_lengths);
+
+ for p in 0..partitions.num_partitions {
+ let partition_ptr = *partitions.partitions.add(p);
+ let partition_len = *partitions.partition_lengths.add(p);
Review Comment:
There is probably a use-after-free here. I'm working on it.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]