From d24318f7c9aacba882fa6bb76044dd99a8dcf6e1 Mon Sep 17 00:00:00 2001 From: gwenn Date: Tue, 8 Nov 2022 20:44:12 +0100 Subject: [PATCH] Remove Connection path field Use sqlite3_db_filename instead. Pros: memory footprint, absolute path Cons: one cannot make the disctinction between multiple memory databases anymore (like file:one.db?mode=memory and file:another.db?mode=memory). --- src/lib.rs | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5ec8eec..112ca54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ use std::ffi::{CStr, CString}; use std::fmt; use std::os::raw::{c_char, c_int}; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::result; use std::str; use std::sync::atomic::Ordering; @@ -330,7 +330,6 @@ impl DatabaseName<'_> { pub struct Connection { db: RefCell, cache: StatementCache, - path: Option, } unsafe impl Send for Connection {} @@ -427,7 +426,6 @@ impl Connection { InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Connection { db: RefCell::new(db), cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), - path: Some(path.as_ref().to_path_buf()), }) } @@ -452,7 +450,6 @@ impl Connection { InnerConnection::open_with_flags(&c_path, flags, Some(&c_vfs)).map(|db| Connection { db: RefCell::new(db), cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), - path: Some(path.as_ref().to_path_buf()), }) } @@ -580,12 +577,23 @@ impl Connection { /// Returns the path to the database file, if one exists and is known. /// + /// Returns `Some("")` for a temporary or in-memory database. + /// /// Note that in some cases [PRAGMA /// database_list](https://sqlite.org/pragma.html#pragma_database_list) is /// likely to be more robust. #[inline] - pub fn path(&self) -> Option<&Path> { - self.path.as_deref() + pub fn path(&self) -> Option<&str> { + unsafe { + let db = self.handle(); + let db_name = DatabaseName::Main.as_cstring().unwrap(); + let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr()); + if db_filename.is_null() { + None + } else { + CStr::from_ptr(db_filename).to_str().ok() + } + } } /// Attempts to free as much heap memory as possible from the database @@ -915,12 +923,10 @@ impl Connection { /// This function is unsafe because improper use may impact the Connection. #[inline] pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result { - let db_path = db_filename(db); let db = InnerConnection::new(db, false); Ok(Connection { db: RefCell::new(db), cache: StatementCache::with_capacity(STATEMENT_CACHE_DEFAULT_CAPACITY), - path: db_path, }) } @@ -973,7 +979,7 @@ impl Connection { impl fmt::Debug for Connection { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Connection") - .field("path", &self.path) + .field("path", &self.path()) .finish() } } @@ -1164,16 +1170,6 @@ impl InterruptHandle { } } -unsafe fn db_filename(db: *mut ffi::sqlite3) -> Option { - let db_name = DatabaseName::Main.as_cstring().unwrap(); - let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr()); - if db_filename.is_null() { - None - } else { - CStr::from_ptr(db_filename).to_str().ok().map(PathBuf::from) - } -} - #[cfg(doctest)] doc_comment::doctest!("../README.md"); @@ -1275,6 +1271,21 @@ mod test { db.close().unwrap(); } + #[test] + fn test_path() -> Result<()> { + let tmp = tempfile::tempdir().unwrap(); + let db = Connection::open("")?; + assert_eq!(Some(""), db.path()); + let db = Connection::open_in_memory()?; + assert_eq!(Some(""), db.path()); + let db = Connection::open("file:dummy.db?mode=memory&cache=shared")?; + assert_eq!(Some(""), db.path()); + let path = tmp.path().join("file.db"); + let db = Connection::open(path)?; + assert!(db.path().map(|p| p.ends_with("file.db")).unwrap_or(false)); + Ok(()) + } + #[test] fn test_open_failure() { let filename = "no_such_file.db";