let z_vfs = match vfs {
Some(c_vfs) => c_vfs.as_ptr(),
None => ptr::null(),
};
// turn on extended results code before opening database to have a better diagnostic if a failure happens let exrescode = if version_number() >= 3_037_000 {
flags |= OpenFlags::SQLITE_OPEN_EXRESCODE; true
} else { false// flag SQLITE_OPEN_EXRESCODE is ignored by SQLite version < 3.37.0
};
unsafe { letmut db: *mut ffi::sqlite3 = ptr::null_mut(); let r = ffi::sqlite3_open_v2(c_path.as_ptr(), &mut db, flags.bits(), z_vfs); if r != ffi::SQLITE_OK { let e = if db.is_null() {
err!(r, "{}", c_path.to_string_lossy())
} else { letmut e = error_from_handle(db, r); iflet Error::SqliteFailure(
ffi::Error {
code: ffi::ErrorCode::CannotOpen,
..
},
Some(msg),
) = e
{
e = err!(r, "{msg}: {}", c_path.to_string_lossy());
}
ffi::sqlite3_close(db);
e
};
return Err(e);
}
// attempt to turn on extended results code; don't fail if we can't. if !exrescode {
ffi::sqlite3_extended_result_codes(db, 1);
}
let r = ffi::sqlite3_busy_timeout(db, 5000); if r != ffi::SQLITE_OK { let e = error_from_handle(db, r);
ffi::sqlite3_close(db); return Err(e);
}
pubfn close(&mutself) -> Result<()> { ifself.db.is_null() { return Ok(());
} self.remove_hooks(); self.remove_preupdate_hook(); letmut shared_handle = self.interrupt_lock.lock().unwrap();
assert!(
!self.owned || !shared_handle.is_null(), "Bug: Somehow interrupt_lock was cleared before the DB was closed"
); if !self.owned { self.db = ptr::null_mut(); return Ok(());
} unsafe { let r = ffi::sqlite3_close(self.db); // Need to use _raw because _guard has a reference out, and // decode_result takes &mut self. let r = decode_result_raw(self.db, r); if r.is_ok() {
*shared_handle = ptr::null_mut(); self.db = ptr::null_mut();
}
r
}
}
pubfn prepare<'a>(
&mutself,
conn: &'a Connection,
sql: &str,
flags: PrepFlags,
) -> Result<(Statement<'a>, usize)> { letmut c_stmt: *mut ffi::sqlite3_stmt = ptr::null_mut(); let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?; letmut c_tail: *const c_char = ptr::null(); #[cfg(not(feature = "unlock_notify"))] let r = unsafe { self.prepare_(c_sql, len, flags, &mut c_stmt, &style='color:red'>mut c_tail) }; #[cfg(feature = "unlock_notify")] let r = unsafe { usecrate::unlock_notify; letmut rc; loop {
rc = self.prepare_(c_sql, len, flags, &mut c_stmt, &mut c_tail); if !unlock_notify::is_locked(self.db, rc) { break;
}
rc = unlock_notify::wait_for_unlock_notify(self.db); if rc != ffi::SQLITE_OK { break;
}
}
rc
}; // If there is an error, *ppStmt is set to NULL. if r != ffi::SQLITE_OK { return Err(unsafe { error_with_offset(self.db, r, sql) });
} // If the input text contains no SQL (if the input is an empty string or a // comment) then *ppStmt is set to NULL. let tail = if c_tail.is_null() { 0
} else { let n = (c_tail as isize) - (c_sql as isize); if n <= 0 || n >= len as isize { 0
} else {
n as usize
}
};
Ok((
Statement::new(conn, unsafe { RawStatement::new(c_stmt) }),
tail,
))
}
pubfn db_readonly<N: Name>(&self, db_name: N) -> Result<bool> { let name = db_name.as_cstr()?; let r = unsafe { ffi::sqlite3_db_readonly(self.db, name.as_ptr()) }; match r { 0 => Ok(false), 1 => Ok(true),
-1 => Err(err!(
ffi::SQLITE_MISUSE, "{db_name:?} is not the name of a database"
)),
_ => Err(err!(r, "Unexpected result")),
}
}
#[cfg(feature = "modern_sqlite")] // 3.37.0 pubfn txn_state<N: Name>(
&self,
db_name: Option<N>,
) -> Result<super::transaction::TransactionState> { let cs = db_name.as_ref().map(N::as_cstr).transpose()?; let name = cs.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()); let r = unsafe { ffi::sqlite3_txn_state(self.db, name) }; match r { 0 => Ok(super::transaction::TransactionState::None), 1 => Ok(super::transaction::TransactionState::Read), 2 => Ok(super::transaction::TransactionState::Write),
-1 => Err(err!(
ffi::SQLITE_MISUSE, "{db_name:?} is not the name of a valid schema"
)),
_ => Err(err!(r, "Unexpected result")),
}
}
#[inline] pub(crate) unsafefn db_filename<N: Name>(
_: std::marker::PhantomData<&()>,
ptr: *mut ffi::sqlite3,
db_name: N,
) -> Option<&str> { let db_name = db_name.as_cstr().unwrap(); let db_filename = ffi::sqlite3_db_filename(ptr, db_name.as_ptr()); if db_filename.is_null() {
None
} else {
CStr::from_ptr(db_filename).to_str().ok()
}
}
impl Drop for InnerConnection { #[expect(unused_must_use)] #[inline] fn drop(&mutself) { self.close();
}
}
// threading mode checks are not necessary (and do not work) on target // platforms that do not have threading (such as webassembly) #[cfg(target_arch = "wasm32")] fn ensure_safe_sqlite_threading_mode() -> Result<()> {
Ok(())
}
// Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode, // but it's possible someone configured it to be in Single-thread mode // before calling into us. That would mean we're exposing an unsafe API via // a safe one (in Rust terminology). // // We can ask SQLite for a mutex and check for // the magic value 8. This isn't documented, but it's what SQLite // returns for its mutex allocation function in Single-thread mode. const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8; let is_singlethreaded = unsafe { let mutex_ptr = ffi::sqlite3_mutex_alloc(0); let is_singlethreaded = mutex_ptr as usize == SQLITE_SINGLETHREADED_MUTEX_MAGIC;
ffi::sqlite3_mutex_free(mutex_ptr);
is_singlethreaded
}; if is_singlethreaded {
Err(Error::SqliteSingleThreadedMode)
} else {
Ok(())
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.