From d9ce608b3b2aac3826593a007995a357c581a10b Mon Sep 17 00:00:00 2001 From: Alf Hellmund <281968230+alfhellmund@users.noreply.github.com> Date: Thu, 5 Nov 2026 07:31:51 +0100 Subject: [PATCH] feat: Connection::is_autocommit and Connection::transaction_capable Adds two read accessors to `Connection`, as discussed in #959: - `is_autocommit()` reads `SQL_ATTR_AUTOCOMMIT` via `SQLGetConnectAttr`. Co-Authored-By: Claude Opus 5.5 --- odbc-api/src/connection.rs | 10 ++++++++++ odbc-api/src/handles/connection.rs | 20 +++++++++++++++++++- odbc-api/tests/integration/main.rs | 21 +++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/odbc-api/src/connection.rs b/odbc-api/src/connection.rs index 3a88a399..9c6ca794 100644 --- a/odbc-api/src/connection.rs +++ b/odbc-api/src/connection.rs @@ -478,6 +478,16 @@ impl<'env> Connection<'env> { .into_result(&self.connection) } + /// `true` if the connection is in autocommit mode, `false` if it is in manual-commit mode. New + /// connections start in autocommit mode. See [`Connection::set_autocommit`]. + /// + /// This corresponds to the `SQL_ATTR_AUTOCOMMIT` attribute in the ODBC specification. + pub fn is_autocommit(&self) -> Result { + self.connection + .is_autocommit() + .into_result(&self.connection) + } + /// To commit a transaction in manual-commit mode. pub fn commit(&self) -> Result<(), Error> { self.connection.commit().into_result(&self.connection) diff --git a/odbc-api/src/handles/connection.rs b/odbc-api/src/handles/connection.rs index 28670b26..912154c2 100644 --- a/odbc-api/src/handles/connection.rs +++ b/odbc-api/src/handles/connection.rs @@ -399,7 +399,25 @@ impl Connection<'_> { .map(|v| match v { 0 => false, 1 => true, - other => panic!("Unexpected result value from SQLGetConnectAttr: {other}"), + other => panic!( + "Unexpected result value retrieving SQL_ATTR_CONNECTION_DEAD via \ + SQLGetConnectAttr: {other}" + ), + }) + } + } + + /// `true` if the connection is in autocommit mode, `false` if it is in manual-commit mode. + pub fn is_autocommit(&self) -> SqlResult { + unsafe { + self.attribute_u32(ConnectionAttribute::AUTOCOMMIT) + .map(|v| match v { + 0 => false, + 1 => true, + other => panic!( + "Unexpected result value retrieving SQL_ATTR_AUTOCOMMIT via \ + SQLGetConnectAttr: {other}" + ), }) } } diff --git a/odbc-api/tests/integration/main.rs b/odbc-api/tests/integration/main.rs index 782677c0..ebc1b361 100644 --- a/odbc-api/tests/integration/main.rs +++ b/odbc-api/tests/integration/main.rs @@ -1919,6 +1919,27 @@ fn manual_commit_mode(profile: &Profile) { conn.commit().unwrap(); } +#[test_case(MSSQL; "Microsoft SQL Server")] +#[test_case(MARIADB; "Maria DB")] +#[test_case(SQLITE_3; "SQLite 3")] +#[test_case(POSTGRES; "PostgreSQL")] +fn is_autocommit_is_true_for_new_connection(profile: &Profile) { + let conn = profile.connection().unwrap(); + + assert!(conn.is_autocommit().unwrap()); +} + +#[test_case(MSSQL; "Microsoft SQL Server")] +#[test_case(MARIADB; "Maria DB")] +#[test_case(SQLITE_3; "SQLite 3")] +#[test_case(POSTGRES; "PostgreSQL")] +fn is_autocommit_is_false_after_disabling_autocommit(profile: &Profile) { + let conn = profile.connection().unwrap(); + conn.set_autocommit(false).unwrap(); + + assert!(!conn.is_autocommit().unwrap()); +} + /// This test checks the behaviour if a connections goes out of scope with a transaction still /// open. #[test_case(MSSQL; "Microsoft SQL Server")]