Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions rust/driver/dummy/tests/driver_exporter_dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,24 @@
/// directly using the Rust API (native) and through the exported driver via the
/// driver manager (exported). That allows us to test that data correctly round-trip
/// between C and Rust.
use std::ffi::CString;
use std::ops::Deref;
use std::sync::Arc;

use arrow_array::ffi_stream::FFI_ArrowArrayStream;
use arrow_array::{Array, Float64Array, Int64Array, RecordBatch, RecordBatchReader, StringArray};
use arrow_schema::{DataType, Field, Schema};
use arrow_select::concat::concat_batches;

use adbc_core::Statement;
use adbc_core::constants::ADBC_STATUS_OK;
use adbc_core::options::{
AdbcVersion, InfoCode, IngestMode, IsolationLevel, ObjectDepth, OptionConnection,
OptionDatabase, OptionStatement,
};
use adbc_core::{Connection, Database, Driver, Optionable, schemas};
use adbc_driver_manager::{ManagedConnection, ManagedDatabase, ManagedDriver, ManagedStatement};
use adbc_ffi::{FFI_AdbcConnection, FFI_AdbcDatabase, FFI_AdbcError, FFI_AdbcStatement, FFIDriver};

use adbc_dummy::{DummyConnection, DummyDatabase, DummyDriver, DummyStatement, SingleBatchReader};

Expand Down Expand Up @@ -590,6 +594,70 @@ fn test_statement_execute_query() {
assert_eq!(exported_data, native_data);
}

// Driven at the C ABI (unlike the other tests): the driver manager passes a NULL
// `rows_affected` on the query path, so the -1 the exporter must write there is not
// observable through the high-level `Statement::execute`.
#[test]
fn test_statement_execute_query_sets_rows_affected() {
let driver = DummyDriver::ffi_driver();
let mut error = FFI_AdbcError::default();
let err = &mut error as *mut FFI_AdbcError;

unsafe {
let mut database = FFI_AdbcDatabase::default();
assert_eq!(
driver.DatabaseNew.unwrap()(&mut database, err),
ADBC_STATUS_OK
);
assert_eq!(
driver.DatabaseInit.unwrap()(&mut database, err),
ADBC_STATUS_OK
);

let mut connection = FFI_AdbcConnection::default();
assert_eq!(
driver.ConnectionNew.unwrap()(&mut connection, err),
ADBC_STATUS_OK
);
assert_eq!(
driver.ConnectionInit.unwrap()(&mut connection, &mut database, err),
ADBC_STATUS_OK
);

let mut statement = FFI_AdbcStatement::default();
assert_eq!(
driver.StatementNew.unwrap()(&mut connection, &mut statement, err),
ADBC_STATUS_OK
);
let query = CString::new("SELECT 1").unwrap();
assert_eq!(
driver.StatementSetSqlQuery.unwrap()(&mut statement, query.as_ptr(), err),
ADBC_STATUS_OK
);

// Seed `rows_affected` with a value the exporter must overwrite with -1.
let mut stream = FFI_ArrowArrayStream::empty();
let mut rows_affected: i64 = 42;
assert_eq!(
driver.StatementExecuteQuery.unwrap()(
&mut statement,
&mut stream,
&mut rows_affected,
err,
),
ADBC_STATUS_OK
);
assert_eq!(
rows_affected, -1,
"a query must report rows_affected = -1 (not known), not a stale value"
);

driver.StatementRelease.unwrap()(&mut statement, err);
driver.ConnectionRelease.unwrap()(&mut connection, err);
driver.DatabaseRelease.unwrap()(&mut database, err);
}
}

#[test]
fn test_statement_execute_schema() {
let (_, _, _, mut exported_statement) = get_exported();
Expand Down
3 changes: 3 additions & 0 deletions rust/ffi/src/driver_exporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1728,6 +1728,9 @@ extern "C" fn statement_execute_query<DriverType: Driver + 'static>(
let reader = Box::new(reader);
let reader = FFI_ArrowArrayStream::new(reader);
unsafe { std::ptr::write_unaligned(out, reader) };
if !rows_affected.is_null() {
unsafe { std::ptr::write_unaligned(rows_affected, -1) };
}
} else {
let rows_affected_value = check_err!(statement.execute_update(), error).unwrap_or(-1);
if !rows_affected.is_null() {
Expand Down
Loading