From ea2192c332a1ae1e4814ac111e203b6422aacf3d Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 24 Aug 2025 14:05:48 +0300 Subject: [PATCH] sqlite3: Implement sqlite3_get_autocommit() --- sqlite3/src/lib.rs | 13 +++++- sqlite3/tests/compat/mod.rs | 80 +++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/sqlite3/src/lib.rs b/sqlite3/src/lib.rs index 32a2976e3..2fbf464c6 100644 --- a/sqlite3/src/lib.rs +++ b/sqlite3/src/lib.rs @@ -378,8 +378,17 @@ pub unsafe extern "C" fn sqlite3_deserialize( } #[no_mangle] -pub unsafe extern "C" fn sqlite3_get_autocommit(_db: *mut sqlite3) -> ffi::c_int { - stub!(); +pub unsafe extern "C" fn sqlite3_get_autocommit(db: *mut sqlite3) -> ffi::c_int { + if db.is_null() { + return 1; + } + let db: &mut sqlite3 = &mut *db; + let inner = db.inner.lock().unwrap(); + if inner.conn.get_auto_commit() { + 1 + } else { + 0 + } } #[no_mangle] diff --git a/sqlite3/tests/compat/mod.rs b/sqlite3/tests/compat/mod.rs index 2192a89f9..df5fca2b0 100644 --- a/sqlite3/tests/compat/mod.rs +++ b/sqlite3/tests/compat/mod.rs @@ -71,6 +71,7 @@ extern "C" { fn sqlite3_column_blob(stmt: *mut sqlite3_stmt, idx: i32) -> *const libc::c_void; fn sqlite3_column_type(stmt: *mut sqlite3_stmt, idx: i32) -> i32; fn sqlite3_column_decltype(stmt: *mut sqlite3_stmt, idx: i32) -> *const libc::c_char; + fn sqlite3_get_autocommit(db: *mut sqlite3) -> i32; } const SQLITE_OK: i32 = 0; @@ -986,6 +987,85 @@ mod tests { } } + #[test] + fn test_get_autocommit() { + unsafe { + let temp_file = tempfile::NamedTempFile::with_suffix(".db").unwrap(); + let path = std::ffi::CString::new(temp_file.path().to_str().unwrap()).unwrap(); + let mut db = ptr::null_mut(); + assert_eq!(sqlite3_open(path.as_ptr(), &mut db), SQLITE_OK); + + // Should be in autocommit mode by default + assert_eq!(sqlite3_get_autocommit(db), 1); + + // Begin a transaction + let mut stmt = ptr::null_mut(); + assert_eq!( + sqlite3_prepare_v2(db, c"BEGIN".as_ptr(), -1, &mut stmt, ptr::null_mut()), + SQLITE_OK + ); + assert_eq!(sqlite3_step(stmt), SQLITE_DONE); + assert_eq!(sqlite3_finalize(stmt), SQLITE_OK); + + // Should NOT be in autocommit mode during transaction + assert_eq!(sqlite3_get_autocommit(db), 0); + + // Create a table within the transaction + let mut stmt = ptr::null_mut(); + assert_eq!( + sqlite3_prepare_v2( + db, + c"CREATE TABLE test (id INTEGER PRIMARY KEY)".as_ptr(), + -1, + &mut stmt, + ptr::null_mut() + ), + SQLITE_OK + ); + assert_eq!(sqlite3_step(stmt), SQLITE_DONE); + assert_eq!(sqlite3_finalize(stmt), SQLITE_OK); + + // Still not in autocommit mode + assert_eq!(sqlite3_get_autocommit(db), 0); + + // Commit the transaction + let mut stmt = ptr::null_mut(); + assert_eq!( + sqlite3_prepare_v2(db, c"COMMIT".as_ptr(), -1, &mut stmt, ptr::null_mut()), + SQLITE_OK + ); + assert_eq!(sqlite3_step(stmt), SQLITE_DONE); + assert_eq!(sqlite3_finalize(stmt), SQLITE_OK); + + // Should be back in autocommit mode after commit + assert_eq!(sqlite3_get_autocommit(db), 1); + + // Test with ROLLBACK + let mut stmt = ptr::null_mut(); + assert_eq!( + sqlite3_prepare_v2(db, c"BEGIN".as_ptr(), -1, &mut stmt, ptr::null_mut()), + SQLITE_OK + ); + assert_eq!(sqlite3_step(stmt), SQLITE_DONE); + assert_eq!(sqlite3_finalize(stmt), SQLITE_OK); + + assert_eq!(sqlite3_get_autocommit(db), 0); + + let mut stmt = ptr::null_mut(); + assert_eq!( + sqlite3_prepare_v2(db, c"ROLLBACK".as_ptr(), -1, &mut stmt, ptr::null_mut()), + SQLITE_OK + ); + assert_eq!(sqlite3_step(stmt), SQLITE_DONE); + assert_eq!(sqlite3_finalize(stmt), SQLITE_OK); + + // Should be back in autocommit mode after rollback + assert_eq!(sqlite3_get_autocommit(db), 1); + + assert_eq!(sqlite3_close(db), SQLITE_OK); + } + } + #[test] fn test_wal_checkpoint() { let temp_file = tempfile::NamedTempFile::with_suffix(".db").unwrap();