Use C string literal for database name

No alloc for "main" and "temp".
No alloc possible when the attached database name is known at compile time / a C
string literal can be usd.
No alloc when the database name is given by SQLite (`sqlite3_wal_hook`).
This commit is contained in:
gwenn 2024-11-10 16:56:03 +01:00
parent 0af8bfc603
commit 3d85c79891
6 changed files with 28 additions and 19 deletions

View File

@ -207,8 +207,8 @@ impl Backup<'_, '_> {
to: &'b mut Connection,
to_name: DatabaseName<'_>,
) -> Result<Backup<'a, 'b>> {
let to_name = to_name.as_cstring()?;
let from_name = from_name.as_cstring()?;
let to_name = to_name.as_cstr()?;
let from_name = from_name.as_cstr()?;
let to_db = to.db.borrow_mut().db;

View File

@ -346,7 +346,7 @@ impl InnerConnection {
fn remove_preupdate_hook(&mut self) {}
pub fn db_readonly(&self, db_name: super::DatabaseName<'_>) -> Result<bool> {
let name = db_name.as_cstring()?;
let name = db_name.as_cstr()?;
let r = unsafe { ffi::sqlite3_db_readonly(self.db, name.as_ptr()) };
match r {
0 => Ok(false),
@ -368,7 +368,7 @@ impl InnerConnection {
db_name: Option<super::DatabaseName<'_>>,
) -> Result<super::transaction::TransactionState> {
let r = if let Some(ref name) = db_name {
let name = name.as_cstring()?;
let name = name.as_cstr()?;
unsafe { ffi::sqlite3_txn_state(self.db, name.as_ptr()) }
} else {
unsafe { ffi::sqlite3_txn_state(self.db, ptr::null()) }

View File

@ -347,12 +347,12 @@ fn path_to_cstring(p: &Path) -> Result<CString> {
pub enum DatabaseName<'a> {
/// The main database.
Main,
/// The temporary database (e.g., any "CREATE TEMPORARY TABLE" tables).
Temp,
/// A database that has been attached via "ATTACH DATABASE ...".
Attached(&'a str),
/// Optim
C(&'a CStr),
}
/// Shorthand for [`DatabaseName::Main`].
@ -361,16 +361,24 @@ pub const MAIN_DB: DatabaseName<'static> = DatabaseName::Main;
/// Shorthand for [`DatabaseName::Temp`].
pub const TEMP_DB: DatabaseName<'static> = DatabaseName::Temp;
// Currently DatabaseName is only used by the backup and blob mods, so hide
// this (private) impl to avoid dead code warnings.
impl DatabaseName<'_> {
#[inline]
fn as_cstring(&self) -> Result<SmallCString> {
use self::DatabaseName::{Attached, Main, Temp};
match *self {
Main => str_to_cstring("main"), // TODO C-string literals
Temp => str_to_cstring("temp"),
Attached(s) => str_to_cstring(s),
fn as_cstr(&self) -> Result<std::borrow::Cow<'_, CStr>> {
Ok(match *self {
DatabaseName::Main => std::borrow::Cow::Borrowed(c"main"),
DatabaseName::Temp => std::borrow::Cow::Borrowed(c"temp"),
DatabaseName::Attached(s) => std::borrow::Cow::Owned(CString::new(s)?),
DatabaseName::C(s) => std::borrow::Cow::Borrowed(s),
})
}
#[cfg(feature = "hooks")]
pub(crate) fn from_cstr(cs: &std::ffi::CStr) -> DatabaseName<'_> {
if cs == c"main" {
DatabaseName::Main
} else if cs == c"temp" {
DatabaseName::Temp
} else {
DatabaseName::C(cs)
}
}
#[cfg(feature = "hooks")]
@ -647,7 +655,7 @@ impl Connection {
pub fn path(&self) -> Option<&str> {
unsafe {
let db = self.handle();
let db_name = DatabaseName::Main.as_cstring().unwrap();
let db_name = DatabaseName::Main.as_cstr().unwrap();
let db_filename = ffi::sqlite3_db_filename(db, db_name.as_ptr());
if db_filename.is_null() {
None

View File

@ -47,6 +47,7 @@ impl Sql {
DatabaseName::Main => self.buf.push_str("main"),
DatabaseName::Temp => self.buf.push_str("temp"),
DatabaseName::Attached(s) => self.push_identifier(s),
DatabaseName::C(s) => self.push_identifier(s.to_str().expect("invalid database name")),
};
}

View File

@ -66,7 +66,7 @@ impl Deref for Data<'_> {
impl Connection {
/// Serialize a database.
pub fn serialize(&self, schema: DatabaseName) -> Result<Data> {
let schema = schema.as_cstring()?;
let schema = schema.as_cstr()?;
let mut sz = 0;
let mut ptr: *mut u8 = unsafe {
ffi::sqlite3_serialize(
@ -102,7 +102,7 @@ impl Connection {
data: OwnedData,
read_only: bool,
) -> Result<()> {
let schema = schema.as_cstring()?;
let schema = schema.as_cstr()?;
let (data, sz) = data.into_raw();
let sz = sz.try_into().unwrap();
let flags = if read_only {

View File

@ -42,7 +42,7 @@ impl Session<'_> {
db: &'conn Connection,
name: DatabaseName<'_>,
) -> Result<Session<'conn>> {
let name = name.as_cstring()?;
let name = name.as_cstr()?;
let db = db.db.borrow_mut().db;
@ -154,7 +154,7 @@ impl Session<'_> {
/// Load the difference between tables.
pub fn diff(&mut self, from: DatabaseName<'_>, table: &str) -> Result<()> {
let from = from.as_cstring()?;
let from = from.as_cstr()?;
let table = str_to_cstring(table)?;
let table = table.as_ptr();
unsafe {