Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
ethe committed Dec 10, 2024
2 parents a2ba1f2 + 65106f4 commit d356bba
Show file tree
Hide file tree
Showing 15 changed files with 218 additions and 103 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ collation = []
# sqlite3_create_function_v2: 3.7.3 (2010-10-08)
functions = []
# sqlite3_log: 3.6.23 (2010-03-09)
trace = []
# sqlite3_db_release_memory: 3.7.10 (2012-01-16)
buildtime_bindgen = ["libsqlite3-sys/buildtime_bindgen"]
bundled = ["libsqlite3-sys/bundled", "modern_sqlite"]
bundled-sqlcipher = ["bundled", "libsqlite3-sys/bundled-sqlcipher"]
Expand All @@ -58,6 +56,7 @@ loadable_extension = ["libsqlite3-sys/loadable_extension"]
preupdate_hook = ["hooks", "libsqlite3-sys/preupdate_hook"]
release_memory = []
sqlcipher = ["libsqlite3-sys/sqlcipher"]
trace = []
unlock_notify = ["libsqlite3-sys/unlock_notify"]
# xSavepoint, xRelease and xRollbackTo: 3.7.7 (2011-06-23)
csvtab = ["csv", "vtab"]
Expand Down Expand Up @@ -142,7 +141,9 @@ uuid = { version = "1.0", optional = true }

[dev-dependencies]
doc-comment = "0.3"
ouroboros = "0.18"
regex = "1.5.5"
self_cell = "1.1.0"
tempfile = "3.1.0"
unicase = "2.6.0"
uuid = { version = "1.0", features = ["v4"] }
Expand Down
1 change: 1 addition & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ignore:
- "examples"
- "libsqlite3-sys/bindgen-bindings"
- "libsqlite3-sys/sqlite3"
coverage:
Expand Down
29 changes: 29 additions & 0 deletions examples/owning_rows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
extern crate rusqlite;

use ouroboros::self_referencing;
use rusqlite::{CachedStatement, Connection, Result, Rows};

#[self_referencing]
struct OwningRows<'conn> {
stmt: CachedStatement<'conn>,
#[borrows(mut stmt)]
#[covariant]
rows: Rows<'this>,
}

fn main() -> Result<()> {
let conn = Connection::open_in_memory()?;
let stmt = conn.prepare_cached("SELECT 1")?;
let mut or = OwningRowsTryBuilder {
stmt,
rows_builder: |s| s.query([]),
}
.try_build()?;
or.with_rows_mut(|rows| -> Result<()> {
while let Some(row) = rows.next()? {
assert_eq!(Ok(1), row.get(0));
}
Ok(())
})?;
Ok(())
}
27 changes: 27 additions & 0 deletions examples/owning_rows_self_cell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
extern crate rusqlite;

use rusqlite::{CachedStatement, Connection, Result, Rows};
use self_cell::{self_cell, MutBorrow};

type RowsRef<'a> = Rows<'a>;

self_cell!(
struct OwningRows<'conn> {
owner: MutBorrow<CachedStatement<'conn>>,
#[covariant]
dependent: RowsRef,
}
);

fn main() -> Result<()> {
let conn = Connection::open_in_memory()?;
let stmt = conn.prepare_cached("SELECT 1")?;
let mut or = OwningRows::try_new(MutBorrow::new(stmt), |s| s.borrow_mut().query([]))?;
or.with_dependent_mut(|_stmt, rows| -> Result<()> {
while let Some(row) = rows.next()? {
assert_eq!(Ok(1), row.get(0));
}
Ok(())
})?;
Ok(())
}
30 changes: 30 additions & 0 deletions examples/owning_statement.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
extern crate rusqlite;
use ouroboros::self_referencing;
use rusqlite::{CachedStatement, Connection, Result, Rows};

/// Caveat: single statement at a time for one connection.
/// But if you need multiple statements, you can still create your own struct
/// with multiple fields (one for each statement).
#[self_referencing]
struct OwningStatement {
conn: Connection,
#[borrows(conn)]
#[covariant]
stmt: CachedStatement<'this>,
}

fn main() -> Result<()> {
let conn = Connection::open_in_memory()?;

let mut os = OwningStatementTryBuilder {
conn,
stmt_builder: |c| c.prepare_cached("SELECT 1"),
}
.try_build()?;

let mut rows = os.with_stmt_mut(|stmt| -> Result<Rows<'_>> { stmt.query([]) })?;
while let Some(row) = rows.next()? {
assert_eq!(Ok(1), row.get(0));
}
Ok(())
}
2 changes: 1 addition & 1 deletion libsqlite3-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ js-sys = "0.3"
wasm32-unknown-unknown-openbsd-libc = "0.2"

[build-dependencies]
bindgen = { version = "0.70", optional = true, default-features = false, features = [
bindgen = { version = "0.71", optional = true, default-features = false, features = [
"runtime",
] }
cc = { version = "1.1.6", optional = true }
Expand Down
37 changes: 30 additions & 7 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,14 +412,37 @@ pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
Error::SqliteFailure(ffi::Error::new(code), message)
}

macro_rules! err {
($code:expr $(,)?) => {
$crate::error::error_from_sqlite_code($code, None)
};
($code:expr, $msg:literal $(,)?) => {
$crate::error::error_from_sqlite_code($code, Some(format!($msg)))
};
($code:expr, $err:expr $(,)?) => {
$crate::error::error_from_sqlite_code($code, Some(format!($err)))
};
($code:expr, $fmt:expr, $($arg:tt)*) => {
$crate::error::error_from_sqlite_code($code, Some(format!($fmt, $($arg)*)))
};
}

#[cold]
pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
let message = if db.is_null() {
None
error_from_sqlite_code(code, error_msg(db, code))
}

unsafe fn error_msg(db: *mut ffi::sqlite3, code: c_int) -> Option<String> {
if db.is_null() || ffi::sqlite3_errcode(db) != code {
let err_str = ffi::sqlite3_errstr(code);
if err_str.is_null() {
None
} else {
Some(errmsg_to_string(err_str))
}
} else {
Some(errmsg_to_string(ffi::sqlite3_errmsg(db)))
};
error_from_sqlite_code(code, message)
}
}

pub unsafe fn decode_result_raw(db: *mut ffi::sqlite3, code: c_int) -> Result<()> {
Expand All @@ -443,19 +466,19 @@ pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -
error_from_sqlite_code(code, None)
} else {
let error = ffi::Error::new(code);
let msg = errmsg_to_string(ffi::sqlite3_errmsg(db));
let msg = error_msg(db, code);
if ffi::ErrorCode::Unknown == error.code {
let offset = ffi::sqlite3_error_offset(db);
if offset >= 0 {
return Error::SqlInputError {
error,
msg,
msg: msg.unwrap_or("error".to_owned()),
sql: sql.to_owned(),
offset,
};
}
}
Error::SqliteFailure(error, Some(msg))
Error::SqliteFailure(error, msg)
}
}

Expand Down
17 changes: 17 additions & 0 deletions src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ impl Context<'_> {
///
/// See `https://www.sqlite.org/c3ref/get_auxdata.html` for a discussion of
/// this feature, or the unit tests of this module for an example.
///
/// # Failure
///
/// Will panic if `arg` is greater than or equal to
/// [`self.len()`](Context::len).
pub fn get_or_create_aux<T, E, F>(&self, arg: c_int, func: F) -> Result<Arc<T>>
where
T: Send + Sync + 'static,
Expand All @@ -196,7 +201,13 @@ impl Context<'_> {
/// Sets the auxiliary data associated with a particular parameter. See
/// `https://www.sqlite.org/c3ref/get_auxdata.html` for a discussion of
/// this feature, or the unit tests of this module for an example.
///
/// # Failure
///
/// Will panic if `arg` is greater than or equal to
/// [`self.len()`](Context::len).
pub fn set_aux<T: Send + Sync + 'static>(&self, arg: c_int, value: T) -> Result<Arc<T>> {
assert!(arg < self.len() as i32);
let orig: Arc<T> = Arc::new(value);
let inner: AuxInner = orig.clone();
let outer = Box::new(inner);
Expand All @@ -216,7 +227,13 @@ impl Context<'_> {
/// [`set_aux`](Context::set_aux). Returns `Ok(None)` if no data has been
/// associated, and Ok(Some(v)) if it has. Returns an error if the
/// requested type does not match.
///
/// # Failure
///
/// Will panic if `arg` is greater than or equal to
/// [`self.len()`](Context::len).
pub fn get_aux<T: Send + Sync + 'static>(&self, arg: c_int) -> Result<Option<Arc<T>>> {
assert!(arg < self.len() as i32);
let p = unsafe { ffi::sqlite3_get_auxdata(self.ctx, arg) as *const AuxInner };
if p.is_null() {
Ok(None)
Expand Down
36 changes: 12 additions & 24 deletions src/inner_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ use std::sync::{Arc, Mutex};
use super::ffi;
use super::str_for_sqlite;
use super::{Connection, InterruptHandle, OpenFlags, PrepFlags, Result};
use crate::error::{
decode_result_raw, error_from_handle, error_from_sqlite_code, error_with_offset, Error,
};
use crate::error::{decode_result_raw, error_from_handle, error_with_offset, Error};
use crate::raw_statement::RawStatement;
use crate::statement::Statement;
use crate::version_number;
Expand Down Expand Up @@ -90,7 +88,7 @@ impl InnerConnection {
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() {
error_from_sqlite_code(r, Some(c_path.to_string_lossy().to_string()))
err!(r, "{}", c_path.to_string_lossy())
} else {
let mut e = error_from_handle(db, r);
if let Error::SqliteFailure(
Expand All @@ -101,10 +99,7 @@ impl InnerConnection {
Some(msg),
) = e
{
e = Error::SqliteFailure(
ffi::Error::new(r),
Some(format!("{msg}: {}", c_path.to_string_lossy())),
);
e = err!(r, "{msg}: {}", c_path.to_string_lossy());
}
ffi::sqlite3_close(db);
e
Expand Down Expand Up @@ -200,7 +195,7 @@ impl InnerConnection {
} else {
let message = super::errmsg_to_string(errmsg);
ffi::sqlite3_free(errmsg.cast::<std::os::raw::c_void>());
Err(error_from_sqlite_code(r, Some(message)))
Err(crate::error::error_from_sqlite_code(r, Some(message)))
}
}

Expand Down Expand Up @@ -344,14 +339,11 @@ impl InnerConnection {
match r {
0 => Ok(false),
1 => Ok(true),
-1 => Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("{db_name:?} is not the name of a database")),
)),
_ => Err(error_from_sqlite_code(
r,
Some("Unexpected result".to_owned()),
-1 => Err(err!(
ffi::SQLITE_MISUSE,
"{db_name:?} is not the name of a database"
)),
_ => Err(err!(r, "Unexpected result")),
}
}

Expand All @@ -370,19 +362,15 @@ impl InnerConnection {
0 => Ok(super::transaction::TransactionState::None),
1 => Ok(super::transaction::TransactionState::Read),
2 => Ok(super::transaction::TransactionState::Write),
-1 => Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_MISUSE),
Some(format!("{db_name:?} is not the name of a valid schema")),
)),
_ => Err(error_from_sqlite_code(
r,
Some("Unexpected result".to_owned()),
-1 => Err(err!(
ffi::SQLITE_MISUSE,
"{db_name:?} is not the name of a valid schema"
)),
_ => Err(err!(r, "Unexpected result")),
}
}

#[inline]
#[cfg(feature = "release_memory")]
pub fn release_memory(&self) -> Result<()> {
self.decode_result(unsafe { ffi::sqlite3_db_release_memory(self.db) })
}
Expand Down
13 changes: 8 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub use crate::version::*;
#[doc(hidden)]
pub use rusqlite_macros::__bind;

#[macro_use]
mod error;

#[cfg(not(feature = "loadable_extension"))]
Expand Down Expand Up @@ -321,10 +322,7 @@ fn str_for_sqlite(s: &[u8]) -> Result<(*const c_char, c_int, ffi::sqlite3_destru
// failed.
fn len_as_c_int(len: usize) -> Result<c_int> {
if len >= (c_int::MAX as usize) {
Err(Error::SqliteFailure(
ffi::Error::new(ffi::SQLITE_TOOBIG),
None,
))
Err(err!(ffi::SQLITE_TOOBIG))
} else {
Ok(len as c_int)
}
Expand Down Expand Up @@ -652,7 +650,6 @@ impl Connection {
///
/// This calls [`sqlite3_db_release_memory`](https://www.sqlite.org/c3ref/db_release_memory.html).
#[inline]
#[cfg(feature = "release_memory")]
pub fn release_memory(&self) -> Result<()> {
self.db.borrow_mut().release_memory()
}
Expand Down Expand Up @@ -2288,4 +2285,10 @@ mod test {
assert!(db.is_interrupted());
Ok(())
}

#[test]
fn release_memory() -> Result<()> {
let db = Connection::open_in_memory()?;
db.release_memory()
}
}
Loading

0 comments on commit d356bba

Please sign in to comment.