Add #[inline] and #[cold] in far more places

This commit is contained in:
Thom Chiovoloni 2020-11-03 19:10:23 -08:00
parent 7574124233
commit 65c38bf813
36 changed files with 366 additions and 32 deletions

View File

@ -180,6 +180,7 @@ impl Backup<'_, '_> {
///
/// Will return `Err` if the underlying `sqlite3_backup_init` call returns
/// `NULL`.
#[inline]
pub fn new<'a, 'b>(from: &'a Connection, to: &'b mut Connection) -> Result<Backup<'a, 'b>> {
Backup::new_with_names(from, DatabaseName::Main, to, DatabaseName::Main)
}
@ -225,6 +226,7 @@ impl Backup<'_, '_> {
}
/// Gets the progress of the backup as of the last call to `step`.
#[inline]
pub fn progress(&self) -> Progress {
unsafe {
Progress {
@ -246,6 +248,7 @@ impl Backup<'_, '_> {
/// an error code other than `DONE`, `OK`, `BUSY`, or `LOCKED`. `BUSY` and
/// `LOCKED` are transient errors and are therefore returned as possible
/// `Ok` values.
#[inline]
pub fn step(&self, num_pages: c_int) -> Result<StepResult> {
use self::StepResult::{Busy, Done, Locked, More};
@ -298,6 +301,7 @@ impl Backup<'_, '_> {
}
impl Drop for Backup<'_, '_> {
#[inline]
fn drop(&mut self) {
unsafe { ffi::sqlite3_backup_finish(self.b) };
}

View File

@ -214,6 +214,7 @@ impl Connection {
/// Will return `Err` if `db`/`table`/`column` cannot be converted to a
/// C-compatible string or if the underlying SQLite BLOB open call
/// fails.
#[inline]
pub fn blob_open<'a>(
&'a self,
db: DatabaseName<'_>,
@ -252,6 +253,7 @@ impl Blob<'_> {
/// # Failure
///
/// Will return `Err` if the underlying SQLite BLOB reopen call fails.
#[inline]
pub fn reopen(&mut self, row: i64) -> Result<()> {
let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
if rc != ffi::SQLITE_OK {
@ -262,17 +264,20 @@ impl Blob<'_> {
}
/// Return the size in bytes of the BLOB.
#[inline]
pub fn size(&self) -> i32 {
unsafe { ffi::sqlite3_blob_bytes(self.blob) }
}
/// Return the current size in bytes of the BLOB.
#[inline]
pub fn len(&self) -> usize {
use std::convert::TryInto;
self.size().try_into().unwrap()
}
/// Return true if the BLOB is empty.
#[inline]
pub fn is_empty(&self) -> bool {
self.size() == 0
}
@ -286,10 +291,12 @@ impl Blob<'_> {
/// # Failure
///
/// Will return `Err` if the underlying SQLite close call fails.
#[inline]
pub fn close(mut self) -> Result<()> {
self.close_()
}
#[inline]
fn close_(&mut self) -> Result<()> {
let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
self.blob = ptr::null_mut();
@ -304,6 +311,7 @@ impl io::Read for Blob<'_> {
/// # Failure
///
/// Will return `Err` if the underlying SQLite read call fails.
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let max_allowed_len = (self.size() - self.pos) as usize;
let n = min(buf.len(), max_allowed_len) as i32;
@ -334,6 +342,7 @@ impl io::Write for Blob<'_> {
/// # Failure
///
/// Will return `Err` if the underlying SQLite write call fails.
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let max_allowed_len = (self.size() - self.pos) as usize;
let n = min(buf.len(), max_allowed_len) as i32;
@ -350,6 +359,7 @@ impl io::Write for Blob<'_> {
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
@ -357,6 +367,7 @@ impl io::Write for Blob<'_> {
impl io::Seek for Blob<'_> {
/// Seek to an offset, in bytes, in BLOB.
#[inline]
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
let pos = match pos {
io::SeekFrom::Start(offset) => offset as i64,
@ -383,6 +394,7 @@ impl io::Seek for Blob<'_> {
#[allow(unused_must_use)]
impl Drop for Blob<'_> {
#[inline]
fn drop(&mut self) {
self.close_();
}
@ -398,6 +410,7 @@ impl Drop for Blob<'_> {
pub struct ZeroBlob(pub i32);
impl ToSql for ZeroBlob {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let ZeroBlob(length) = *self;
Ok(ToSqlOutput::ZeroBlob(length))

View File

@ -69,6 +69,7 @@ impl Connection {
}
impl InnerConnection {
#[inline]
fn busy_timeout(&mut self, timeout: c_int) -> Result<()> {
let r = unsafe { ffi::sqlite3_busy_timeout(self.db, timeout) };
self.decode_result(r)

View File

@ -34,6 +34,7 @@ impl Connection {
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
#[inline]
pub fn prepare_cached(&self, sql: &str) -> Result<CachedStatement<'_>> {
self.cache.get(self, sql)
}
@ -43,11 +44,13 @@ impl Connection {
/// number of cached statements. If you need more, or know that you
/// will not use cached statements, you
/// can set the capacity manually using this method.
#[inline]
pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) {
self.cache.set_capacity(capacity)
}
/// Remove/finalize all prepared statements currently in the cache.
#[inline]
pub fn flush_prepared_statement_cache(&self) {
self.cache.flush()
}
@ -69,12 +72,14 @@ pub struct CachedStatement<'conn> {
impl<'conn> Deref for CachedStatement<'conn> {
type Target = Statement<'conn>;
#[inline]
fn deref(&self) -> &Statement<'conn> {
self.stmt.as_ref().unwrap()
}
}
impl<'conn> DerefMut for CachedStatement<'conn> {
#[inline]
fn deref_mut(&mut self) -> &mut Statement<'conn> {
self.stmt.as_mut().unwrap()
}
@ -82,6 +87,7 @@ impl<'conn> DerefMut for CachedStatement<'conn> {
impl Drop for CachedStatement<'_> {
#[allow(unused_must_use)]
#[inline]
fn drop(&mut self) {
if let Some(stmt) = self.stmt.take() {
self.cache.cache_stmt(unsafe { stmt.into_raw() });
@ -90,6 +96,7 @@ impl Drop for CachedStatement<'_> {
}
impl CachedStatement<'_> {
#[inline]
fn new<'conn>(stmt: Statement<'conn>, cache: &'conn StatementCache) -> CachedStatement<'conn> {
CachedStatement {
stmt: Some(stmt),
@ -99,6 +106,7 @@ impl CachedStatement<'_> {
/// Discard the statement, preventing it from being returned to its
/// `Connection`'s collection of cached statements.
#[inline]
pub fn discard(mut self) {
self.stmt = None;
}
@ -106,10 +114,12 @@ impl CachedStatement<'_> {
impl StatementCache {
/// Create a statement cache.
#[inline]
pub fn with_capacity(capacity: usize) -> StatementCache {
StatementCache(RefCell::new(LruCache::new(capacity)))
}
#[inline]
fn set_capacity(&self, capacity: usize) {
self.0.borrow_mut().set_capacity(capacity)
}
@ -155,6 +165,7 @@ impl StatementCache {
}
}
#[inline]
fn flush(&self) {
let mut cache = self.0.borrow_mut();
cache.clear()

View File

@ -15,6 +15,7 @@ unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
impl Connection {
/// `feature = "collation"` Add or modify a collation.
#[inline]
pub fn create_collation<'c, C>(&'c self, collation_name: &str, x_compare: C) -> Result<()>
where
C: Fn(&str, &str) -> Ordering + Send + UnwindSafe + 'c,
@ -25,6 +26,7 @@ impl Connection {
}
/// `feature = "collation"` Collation needed callback
#[inline]
pub fn collation_needed(
&self,
x_coll_needed: fn(&Connection, &str) -> Result<()>,
@ -33,6 +35,7 @@ impl Connection {
}
/// `feature = "collation"` Remove collation.
#[inline]
pub fn remove_collation(&self, collation_name: &str) -> Result<()> {
self.db.borrow_mut().remove_collation(collation_name)
}
@ -139,6 +142,7 @@ impl InnerConnection {
self.decode_result(r)
}
#[inline]
fn remove_collation(&mut self, collation_name: &str) -> Result<()> {
let c_name = str_to_cstring(collation_name)?;
let r = unsafe {

View File

@ -11,11 +11,13 @@ pub struct Column<'stmt> {
impl Column<'_> {
/// Returns the name of the column.
#[inline]
pub fn name(&self) -> &str {
self.name
}
/// Returns the type of the column (`None` for expression).
#[inline]
pub fn decl_type(&self) -> Option<&str> {
self.decl_type
}
@ -35,10 +37,12 @@ impl Statement<'_> {
/// Return the number of columns in the result set returned by the prepared
/// statement.
#[inline]
pub fn column_count(&self) -> usize {
self.stmt.column_count()
}
#[inline]
pub(super) fn column_name_unwrap(&self, col: usize) -> &str {
// Just panic if the bounds are wrong for now, we never call this
// without checking first.
@ -54,6 +58,7 @@ impl Statement<'_> {
/// column range for this row.
///
/// Panics when column name is not valid UTF-8.
#[inline]
pub fn column_name(&self, col: usize) -> Result<&str> {
self.stmt
.column_name(col)
@ -72,6 +77,7 @@ impl Statement<'_> {
///
/// Will return an `Error::InvalidColumnName` when there is no column with
/// the specified `name`.
#[inline]
pub fn column_index(&self, name: &str) -> Result<usize> {
let bytes = name.as_bytes();
let n = self.column_count();
@ -104,26 +110,31 @@ impl Statement<'_> {
impl<'stmt> Rows<'stmt> {
/// Get all the column names.
#[inline]
pub fn column_names(&self) -> Option<Vec<&str>> {
self.stmt.map(Statement::column_names)
}
/// Return the number of columns.
#[inline]
pub fn column_count(&self) -> Option<usize> {
self.stmt.map(Statement::column_count)
}
/// Return the name of the column.
#[inline]
pub fn column_name(&self, col: usize) -> Option<Result<&str>> {
self.stmt.map(|stmt| stmt.column_name(col))
}
/// Return the index of the column.
#[inline]
pub fn column_index(&self, name: &str) -> Option<Result<usize>> {
self.stmt.map(|stmt| stmt.column_index(name))
}
/// Returns a slice describing the columns of the Rows.
#[inline]
#[cfg(feature = "column_decltype")]
pub fn columns(&self) -> Option<Vec<Column>> {
self.stmt.map(Statement::columns)
@ -132,26 +143,31 @@ impl<'stmt> Rows<'stmt> {
impl<'stmt> Row<'stmt> {
/// Get all the column names of the Row.
#[inline]
pub fn column_names(&self) -> Vec<&str> {
self.stmt.column_names()
}
/// Return the number of columns in the current row.
#[inline]
pub fn column_count(&self) -> usize {
self.stmt.column_count()
}
/// Return the name of the column.
#[inline]
pub fn column_name(&self, col: usize) -> Result<&str> {
self.stmt.column_name(col)
}
/// Return the index of the column.
#[inline]
pub fn column_index(&self, name: &str) -> Result<usize> {
self.stmt.column_index(name)
}
/// Returns a slice describing the columns of the Row.
#[inline]
#[cfg(feature = "column_decltype")]
pub fn columns(&self) -> Vec<Column> {
self.stmt.columns()

View File

@ -74,6 +74,7 @@ impl Connection {
/// whether the QPSG is disabled or enabled
/// - SQLITE_DBCONFIG_TRIGGER_EQP: return `false` to indicate
/// output-for-trigger are not disabled or `true` if it is
#[inline]
pub fn db_config(&self, config: DbConfig) -> Result<bool> {
let c = self.db.borrow();
unsafe {
@ -102,6 +103,7 @@ impl Connection {
/// enable QPSG
/// - SQLITE_DBCONFIG_TRIGGER_EQP: `false` to disable output for trigger
/// programs, `true` to enable it
#[inline]
pub fn set_db_config(&self, config: DbConfig, new_val: bool) -> Result<bool> {
let c = self.db.borrow_mut();
unsafe {

View File

@ -12,6 +12,10 @@ use crate::types::{ToSqlOutput, ValueRef};
#[cfg(feature = "array")]
use crate::vtab::array::{free_array, ARRAY_TYPE};
// This function is inline despite it's size because what's in the ToSqlOutput
// is often known to the compiler, and thus const prop/DCE can substantially
// simplify the function.
#[inline]
pub(super) unsafe fn set_result(ctx: *mut sqlite3_context, result: &ToSqlOutput<'_>) {
let value = match *result {
ToSqlOutput::Borrowed(v) => v,

View File

@ -166,12 +166,14 @@ impl PartialEq for Error {
}
impl From<str::Utf8Error> for Error {
#[cold]
fn from(err: str::Utf8Error) -> Error {
Error::Utf8Error(err)
}
}
impl From<::std::ffi::NulError> for Error {
#[cold]
fn from(err: ::std::ffi::NulError) -> Error {
Error::NulError(err)
}
@ -182,6 +184,7 @@ const UNKNOWN_COLUMN: usize = std::usize::MAX;
/// The conversion isn't precise, but it's convenient to have it
/// to allow use of `get_raw(…).as_…()?` in callbacks that take `Error`.
impl From<FromSqlError> for Error {
#[cold]
fn from(err: FromSqlError) -> Error {
// The error type requires index and type fields, but they aren't known in this
// context.
@ -327,10 +330,12 @@ impl error::Error for Error {
// These are public but not re-exported by lib.rs, so only visible within crate.
#[cold]
pub fn error_from_sqlite_code(code: c_int, message: Option<String>) -> Error {
Error::SqliteFailure(ffi::Error::new(code), message)
}
#[cold]
pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
let message = if db.is_null() {
None

View File

@ -111,11 +111,13 @@ pub struct Context<'a> {
impl Context<'_> {
/// Returns the number of arguments to the function.
#[inline]
pub fn len(&self) -> usize {
self.args.len()
}
/// Returns `true` when there is no argument.
#[inline]
pub fn is_empty(&self) -> bool {
self.args.is_empty()
}
@ -155,6 +157,7 @@ impl Context<'_> {
/// # Failure
///
/// Will panic if `idx` is greater than or equal to `self.len()`.
#[inline]
pub fn get_raw(&self, idx: usize) -> ValueRef<'_> {
let arg = self.args[idx];
unsafe { ValueRef::from_value(arg) }
@ -290,6 +293,7 @@ bitflags::bitflags! {
}
impl Default for FunctionFlags {
#[inline]
fn default() -> FunctionFlags {
FunctionFlags::SQLITE_UTF8
}
@ -332,6 +336,7 @@ impl Connection {
/// # Failure
///
/// Will return Err if the function could not be attached to the connection.
#[inline]
pub fn create_scalar_function<'c, F, T>(
&'c self,
fn_name: &str,
@ -354,6 +359,7 @@ impl Connection {
/// # Failure
///
/// Will return Err if the function could not be attached to the connection.
#[inline]
pub fn create_aggregate_function<A, D, T>(
&self,
fn_name: &str,
@ -377,6 +383,7 @@ impl Connection {
/// See https://sqlite.org/windowfunctions.html#udfwinfunc for more
/// information.
#[cfg(feature = "window")]
#[inline]
pub fn create_window_function<A, W, T>(
&self,
fn_name: &str,
@ -403,6 +410,7 @@ impl Connection {
/// # Failure
///
/// Will return Err if the function could not be removed.
#[inline]
pub fn remove_function(&self, fn_name: &str, n_arg: c_int) -> Result<()> {
self.db.borrow_mut().remove_function(fn_name, n_arg)
}

View File

@ -25,6 +25,7 @@ pub enum Action {
}
impl From<i32> for Action {
#[inline]
fn from(code: i32) -> Action {
match code {
ffi::SQLITE_DELETE => Action::SQLITE_DELETE,
@ -40,6 +41,7 @@ impl Connection {
/// a transaction is committed.
///
/// The callback returns `true` to rollback.
#[inline]
pub fn commit_hook<'c, F>(&'c self, hook: Option<F>)
where
F: FnMut() -> bool + Send + 'c,
@ -51,6 +53,7 @@ impl Connection {
/// a transaction is committed.
///
/// The callback returns `true` to rollback.
#[inline]
pub fn rollback_hook<'c, F>(&'c self, hook: Option<F>)
where
F: FnMut() + Send + 'c,
@ -68,6 +71,7 @@ impl Connection {
/// - the name of the database ("main", "temp", ...),
/// - the name of the table that is updated,
/// - the ROWID of the row that is updated.
#[inline]
pub fn update_hook<'c, F>(&'c self, hook: Option<F>)
where
F: FnMut(Action, &str, &str, i64) + Send + 'c,
@ -92,6 +96,7 @@ impl Connection {
}
impl InnerConnection {
#[inline]
pub fn remove_hooks(&mut self) {
self.update_hook(None::<fn(Action, &str, &str, i64)>);
self.commit_hook(None::<fn() -> bool>);

View File

@ -38,6 +38,7 @@ pub struct InnerConnection {
impl InnerConnection {
#[allow(clippy::mutex_atomic)]
#[inline]
pub unsafe fn new(db: *mut ffi::sqlite3, owned: bool) -> InnerConnection {
InnerConnection {
db,
@ -125,14 +126,17 @@ impl InnerConnection {
}
}
#[inline]
pub fn db(&self) -> *mut ffi::sqlite3 {
self.db
}
#[inline]
pub fn decode_result(&mut self, code: c_int) -> Result<()> {
unsafe { InnerConnection::decode_result_raw(self.db(), code) }
}
#[inline]
unsafe fn decode_result_raw(db: *mut ffi::sqlite3, code: c_int) -> Result<()> {
if code == ffi::SQLITE_OK {
Ok(())
@ -169,12 +173,14 @@ impl InnerConnection {
}
}
#[inline]
pub fn get_interrupt_handle(&self) -> InterruptHandle {
InterruptHandle {
db_lock: Arc::clone(&self.interrupt_lock),
}
}
#[inline]
#[cfg(feature = "load_extension")]
pub fn enable_load_extension(&mut self, onoff: c_int) -> Result<()> {
let r = unsafe { ffi::sqlite3_enable_load_extension(self.db, onoff) };
@ -207,6 +213,7 @@ impl InnerConnection {
}
}
#[inline]
pub fn last_insert_rowid(&self) -> i64 {
unsafe { ffi::sqlite3_last_insert_rowid(self.db()) }
}
@ -266,10 +273,12 @@ impl InnerConnection {
}))
}
#[inline]
pub fn changes(&mut self) -> usize {
unsafe { ffi::sqlite3_changes(self.db()) as usize }
}
#[inline]
pub fn is_autocommit(&self) -> bool {
unsafe { ffi::sqlite3_get_autocommit(self.db()) != 0 }
}
@ -290,11 +299,13 @@ impl InnerConnection {
}
#[cfg(not(feature = "hooks"))]
#[inline]
fn remove_hooks(&mut self) {}
}
impl Drop for InnerConnection {
#[allow(unused_must_use)]
#[inline]
fn drop(&mut self) {
use std::thread::panicking;

View File

@ -282,7 +282,7 @@ fn path_to_cstring(p: &Path) -> Result<CString> {
}
/// Name for a database within a SQLite connection.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum DatabaseName<'a> {
/// The main database.
Main,
@ -294,6 +294,12 @@ pub enum DatabaseName<'a> {
Attached(&'a str),
}
/// Shorthand for [`DatabaseName::Main`].
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.
#[cfg(any(
@ -303,6 +309,7 @@ pub enum DatabaseName<'a> {
feature = "modern_sqlite"
))]
impl DatabaseName<'_> {
#[inline]
fn to_cstring(&self) -> Result<util::SmallCString> {
use self::DatabaseName::{Attached, Main, Temp};
match *self {
@ -323,6 +330,7 @@ pub struct Connection {
unsafe impl Send for Connection {}
impl Drop for Connection {
#[inline]
fn drop(&mut self) {
self.flush_prepared_statement_cache();
}
@ -350,6 +358,7 @@ impl Connection {
///
/// Will return `Err` if `path` cannot be converted to a C-compatible
/// string or if the underlying SQLite open call fails.
#[inline]
pub fn open<P: AsRef<Path>>(path: P) -> Result<Connection> {
let flags = OpenFlags::default();
Connection::open_with_flags(path, flags)
@ -360,6 +369,7 @@ impl Connection {
/// # Failure
///
/// Will return `Err` if the underlying SQLite open call fails.
#[inline]
pub fn open_in_memory() -> Result<Connection> {
let flags = OpenFlags::default();
Connection::open_in_memory_with_flags(flags)
@ -374,6 +384,7 @@ impl Connection {
///
/// Will return `Err` if `path` cannot be converted to a C-compatible
/// string or if the underlying SQLite open call fails.
#[inline]
pub fn open_with_flags<P: AsRef<Path>>(path: P, flags: OpenFlags) -> Result<Connection> {
let c_path = path_to_cstring(path.as_ref())?;
InnerConnection::open_with_flags(&c_path, flags, None).map(|db| Connection {
@ -393,6 +404,7 @@ impl Connection {
///
/// Will return `Err` if either `path` or `vfs` cannot be converted to a
/// C-compatible string or if the underlying SQLite open call fails.
#[inline]
pub fn open_with_flags_and_vfs<P: AsRef<Path>>(
path: P,
flags: OpenFlags,
@ -415,6 +427,7 @@ impl Connection {
/// # Failure
///
/// Will return `Err` if the underlying SQLite open call fails.
#[inline]
pub fn open_in_memory_with_flags(flags: OpenFlags) -> Result<Connection> {
Connection::open_with_flags(":memory:", flags)
}
@ -429,6 +442,7 @@ impl Connection {
///
/// Will return `Err` if vfs` cannot be converted to a C-compatible
/// string or if the underlying SQLite open call fails.
#[inline]
pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Connection> {
Connection::open_with_flags_and_vfs(":memory:", flags, vfs)
}
@ -518,6 +532,7 @@ impl Connection {
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
#[inline]
pub fn execute<P: Params>(&self, sql: &str, params: P) -> Result<usize> {
self.prepare(sql)
.and_then(|mut stmt| stmt.check_no_tail().and_then(|_| stmt.execute(params)))
@ -547,6 +562,7 @@ impl Connection {
///
/// Uses [sqlite3_last_insert_rowid](https://www.sqlite.org/c3ref/last_insert_rowid.html) under
/// the hood.
#[inline]
pub fn last_insert_rowid(&self) -> i64 {
self.db.borrow_mut().last_insert_rowid()
}
@ -578,6 +594,7 @@ impl Connection {
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
#[inline]
pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
where
P: Params,
@ -635,6 +652,7 @@ impl Connection {
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
#[inline]
pub fn query_row_and_then<T, E, P, F>(&self, sql: &str, params: P, f: F) -> Result<T, E>
where
P: Params,
@ -666,6 +684,7 @@ impl Connection {
///
/// Will return `Err` if `sql` cannot be converted to a C-compatible string
/// or if the underlying SQLite call fails.
#[inline]
pub fn prepare(&self, sql: &str) -> Result<Statement<'_>> {
self.db.borrow_mut().prepare(self, sql)
}
@ -679,6 +698,7 @@ impl Connection {
/// # Failure
///
/// Will return `Err` if the underlying SQLite call fails.
#[inline]
pub fn close(self) -> Result<(), (Connection, Error)> {
self.flush_prepared_statement_cache();
let r = self.db.borrow_mut().close();
@ -704,6 +724,7 @@ impl Connection {
///
/// Will return `Err` if the underlying SQLite call fails.
#[cfg(feature = "load_extension")]
#[inline]
pub fn load_extension_enable(&self) -> Result<()> {
self.db.borrow_mut().enable_load_extension(1)
}
@ -716,6 +737,7 @@ impl Connection {
///
/// Will return `Err` if the underlying SQLite call fails.
#[cfg(feature = "load_extension")]
#[inline]
pub fn load_extension_disable(&self) -> Result<()> {
self.db.borrow_mut().enable_load_extension(0)
}
@ -744,6 +766,7 @@ impl Connection {
///
/// Will return `Err` if the underlying SQLite call fails.
#[cfg(feature = "load_extension")]
#[inline]
pub fn load_extension<P: AsRef<Path>>(
&self,
dylib_path: P,
@ -767,6 +790,7 @@ impl Connection {
/// This function is unsafe because it gives you raw access
/// to the SQLite connection, and what you do with it could impact the
/// safety of this `Connection`.
#[inline]
pub unsafe fn handle(&self) -> *mut ffi::sqlite3 {
self.db.borrow().db()
}
@ -779,6 +803,7 @@ impl Connection {
/// # Safety
///
/// This function is unsafe because improper use may impact the Connection.
#[inline]
pub unsafe fn from_handle(db: *mut ffi::sqlite3) -> Result<Connection> {
let db_path = db_filename(db);
let db = InnerConnection::new(db, false);
@ -791,10 +816,12 @@ impl Connection {
/// Get access to a handle that can be used to interrupt long running
/// queries from another thread.
#[inline]
pub fn get_interrupt_handle(&self) -> InterruptHandle {
self.db.borrow().get_interrupt_handle()
}
#[inline]
fn decode_result(&self, code: c_int) -> Result<()> {
self.db.borrow_mut().decode_result(code)
}
@ -802,17 +829,20 @@ impl Connection {
/// Return the number of rows modified, inserted or deleted by the most
/// recently completed INSERT, UPDATE or DELETE statement on the database
/// connection.
#[inline]
fn changes(&self) -> usize {
self.db.borrow_mut().changes()
}
/// Test for auto-commit mode.
/// Autocommit mode is on by default.
#[inline]
pub fn is_autocommit(&self) -> bool {
self.db.borrow().is_autocommit()
}
/// Determine if all associated prepared statements have been reset.
#[inline]
#[cfg(feature = "modern_sqlite")] // 3.8.6
pub fn is_busy(&self) -> bool {
self.db.borrow().is_busy()

View File

@ -9,6 +9,7 @@ use crate::Connection;
impl Connection {
/// `feature = "limits"` Returns the current value of a limit.
#[inline]
pub fn limit(&self, limit: Limit) -> i32 {
let c = self.db.borrow();
unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, -1) }
@ -16,6 +17,7 @@ impl Connection {
/// `feature = "limits"` Changes the limit to `new_val`, returning the prior
/// value of the limit.
#[inline]
pub fn set_limit(&self, limit: Limit, new_val: i32) -> i32 {
let c = self.db.borrow_mut();
unsafe { ffi::sqlite3_limit(c.db(), limit as c_int, new_val) }

View File

@ -22,6 +22,7 @@ impl LoadExtensionGuard<'_> {
/// Attempt to enable loading extensions. Loading extensions will be
/// disabled when this guard goes out of scope. Cannot be meaningfully
/// nested.
#[inline]
pub fn new(conn: &Connection) -> Result<LoadExtensionGuard<'_>> {
conn.load_extension_enable()
.map(|_| LoadExtensionGuard { conn })
@ -30,6 +31,7 @@ impl LoadExtensionGuard<'_> {
#[allow(unused_must_use)]
impl Drop for LoadExtensionGuard<'_> {
#[inline]
fn drop(&mut self) {
self.conn.load_extension_disable();
}

View File

@ -198,6 +198,8 @@ impl Params for &[(&str, &dyn ToSql)] {
macro_rules! impl_for_array_ref {
($($N:literal)+) => {$(
// These are already generic, and theres a shitload of them, so lets
// avoid the compile time hit from making them all inline for now.
impl<T: ToSql + ?Sized> Sealed for &[&T; $N] {}
impl<T: ToSql + ?Sized> Params for &[&T; $N] {
fn bind_in(self, stmt: &mut Statement<'_>) -> Result<()> {

View File

@ -29,6 +29,7 @@ pub struct RawStatement {
}
impl RawStatement {
#[inline]
pub unsafe fn new(stmt: *mut ffi::sqlite3_stmt, tail: usize) -> RawStatement {
RawStatement {
ptr: stmt,
@ -38,31 +39,38 @@ impl RawStatement {
}
}
#[inline]
pub fn is_null(&self) -> bool {
self.ptr.is_null()
}
#[inline]
pub(crate) fn set_statement_cache_key(&mut self, p: impl Into<Arc<str>>) {
self.statement_cache_key = Some(p.into());
}
#[inline]
pub(crate) fn statement_cache_key(&self) -> Option<Arc<str>> {
self.statement_cache_key.clone()
}
#[inline]
pub unsafe fn ptr(&self) -> *mut ffi::sqlite3_stmt {
self.ptr
}
#[inline]
pub fn column_count(&self) -> usize {
// Note: Can't cache this as it changes if the schema is altered.
unsafe { ffi::sqlite3_column_count(self.ptr) as usize }
}
#[inline]
pub fn column_type(&self, idx: usize) -> c_int {
unsafe { ffi::sqlite3_column_type(self.ptr, idx as c_int) }
}
#[inline]
#[cfg(feature = "column_decltype")]
pub fn column_decltype(&self, idx: usize) -> Option<&CStr> {
unsafe {
@ -75,6 +83,7 @@ impl RawStatement {
}
}
#[inline]
pub fn column_name(&self, idx: usize) -> Option<&CStr> {
let idx = idx as c_int;
if idx < 0 || idx >= self.column_count() as c_int {
@ -92,6 +101,7 @@ impl RawStatement {
}
}
#[cfg_attr(not(feature = "unlock_notify"), inline)]
pub fn step(&self) -> c_int {
if cfg!(feature = "unlock_notify") {
let db = unsafe { ffi::sqlite3_db_handle(self.ptr) };
@ -113,14 +123,17 @@ impl RawStatement {
}
}
#[inline]
pub fn reset(&self) -> c_int {
unsafe { ffi::sqlite3_reset(self.ptr) }
}
#[inline]
pub fn bind_parameter_count(&self) -> usize {
unsafe { ffi::sqlite3_bind_parameter_count(self.ptr) as usize }
}
#[inline]
pub fn bind_parameter_index(&self, name: &str) -> Option<usize> {
self.cache.get_or_insert_with(name, |param_cstr| {
let r = unsafe { ffi::sqlite3_bind_parameter_index(self.ptr, param_cstr.as_ptr()) };
@ -131,10 +144,12 @@ impl RawStatement {
})
}
#[inline]
pub fn clear_bindings(&self) -> c_int {
unsafe { ffi::sqlite3_clear_bindings(self.ptr) }
}
#[inline]
pub fn sql(&self) -> Option<&CStr> {
if self.ptr.is_null() {
None
@ -143,36 +158,43 @@ impl RawStatement {
}
}
#[inline]
pub fn finalize(mut self) -> c_int {
self.finalize_()
}
#[inline]
fn finalize_(&mut self) -> c_int {
let r = unsafe { ffi::sqlite3_finalize(self.ptr) };
self.ptr = ptr::null_mut();
r
}
#[inline]
#[cfg(all(feature = "extra_check", feature = "modern_sqlite"))] // 3.7.4
pub fn readonly(&self) -> bool {
unsafe { ffi::sqlite3_stmt_readonly(self.ptr) != 0 }
}
#[inline]
#[cfg(feature = "modern_sqlite")] // 3.14.0
pub(crate) fn expanded_sql(&self) -> Option<SqliteMallocString> {
unsafe { SqliteMallocString::from_raw(ffi::sqlite3_expanded_sql(self.ptr)) }
}
#[inline]
pub fn get_status(&self, status: StatementStatus, reset: bool) -> i32 {
assert!(!self.ptr.is_null());
unsafe { ffi::sqlite3_stmt_status(self.ptr, status as i32, reset as i32) }
}
#[inline]
#[cfg(feature = "extra_check")]
pub fn has_tail(&self) -> bool {
self.tail != 0
}
#[inline]
pub fn tail(&self) -> usize {
self.tail
}

View File

@ -13,6 +13,7 @@ pub struct Rows<'stmt> {
}
impl<'stmt> Rows<'stmt> {
#[inline]
fn reset(&mut self) {
if let Some(stmt) = self.stmt.take() {
stmt.reset();
@ -31,6 +32,7 @@ impl<'stmt> Rows<'stmt> {
/// consider using `query_map` or `query_and_then` instead, which
/// return types that implement `Iterator`.
#[allow(clippy::should_implement_trait)] // cannot implement Iterator
#[inline]
pub fn next(&mut self) -> Result<Option<&Row<'stmt>>> {
self.advance()?;
Ok((*self).get())
@ -47,6 +49,7 @@ impl<'stmt> Rows<'stmt> {
/// }
/// ```
// FIXME Hide FallibleStreamingIterator::map
#[inline]
pub fn map<F, B>(self, f: F) -> Map<'stmt, F>
where
F: FnMut(&Row<'_>) -> Result<B>,
@ -56,6 +59,7 @@ impl<'stmt> Rows<'stmt> {
/// Map over this `Rows`, converting it to a [`MappedRows`], which
/// implements `Iterator`.
#[inline]
pub fn mapped<F, B>(self, f: F) -> MappedRows<'stmt, F>
where
F: FnMut(&Row<'_>) -> Result<B>,
@ -66,6 +70,7 @@ impl<'stmt> Rows<'stmt> {
/// Map over this `Rows` with a fallible function, converting it to a
/// [`AndThenRows`], which implements `Iterator` (instead of
/// `FallibleStreamingIterator`).
#[inline]
pub fn and_then<F, T, E>(self, f: F) -> AndThenRows<'stmt, F>
where
F: FnMut(&Row<'_>) -> Result<T, E>,
@ -75,6 +80,7 @@ impl<'stmt> Rows<'stmt> {
}
impl<'stmt> Rows<'stmt> {
#[inline]
pub(crate) fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> {
Rows {
stmt: Some(stmt),
@ -82,6 +88,7 @@ impl<'stmt> Rows<'stmt> {
}
}
#[inline]
pub(crate) fn get_expected_row(&mut self) -> Result<&Row<'stmt>> {
match self.next()? {
Some(row) => Ok(row),
@ -91,6 +98,7 @@ impl<'stmt> Rows<'stmt> {
}
impl Drop for Rows<'_> {
#[inline]
fn drop(&mut self) {
self.reset();
}
@ -110,6 +118,7 @@ where
type Error = Error;
type Item = B;
#[inline]
fn next(&mut self) -> Result<Option<B>> {
match self.rows.next()? {
Some(v) => Ok(Some((self.f)(v)?)),
@ -127,21 +136,13 @@ pub struct MappedRows<'stmt, F> {
map: F,
}
impl<'stmt, T, F> MappedRows<'stmt, F>
where
F: FnMut(&Row<'_>) -> Result<T>,
{
pub(crate) fn new(rows: Rows<'stmt>, f: F) -> MappedRows<'stmt, F> {
MappedRows { rows, map: f }
}
}
impl<T, F> Iterator for MappedRows<'_, F>
where
F: FnMut(&Row<'_>) -> Result<T>,
{
type Item = Result<T>;
#[inline]
fn next(&mut self) -> Option<Result<T>> {
let map = &mut self.map;
self.rows
@ -159,15 +160,6 @@ pub struct AndThenRows<'stmt, F> {
map: F,
}
impl<'stmt, T, E, F> AndThenRows<'stmt, F>
where
F: FnMut(&Row<'_>) -> Result<T, E>,
{
pub(crate) fn new(rows: Rows<'stmt>, f: F) -> AndThenRows<'stmt, F> {
AndThenRows { rows, map: f }
}
}
impl<T, E, F> Iterator for AndThenRows<'_, F>
where
E: convert::From<Error>,
@ -175,6 +167,7 @@ where
{
type Item = Result<T, E>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let map = &mut self.map;
self.rows
@ -206,6 +199,7 @@ impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
type Error = Error;
type Item = Row<'stmt>;
#[inline]
fn advance(&mut self) -> Result<()> {
match self.stmt {
Some(ref stmt) => match stmt.step() {
@ -231,6 +225,7 @@ impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
}
}
#[inline]
fn get(&self) -> Option<&Row<'stmt>> {
self.row.as_ref()
}

View File

@ -29,11 +29,13 @@ pub struct Session<'conn> {
impl Session<'_> {
/// Create a new session object
#[inline]
pub fn new(db: &Connection) -> Result<Session<'_>> {
Session::new_with_name(db, DatabaseName::Main)
}
/// Create a new session object
#[inline]
pub fn new_with_name<'conn>(
db: &'conn Connection,
name: DatabaseName<'_>,
@ -120,6 +122,7 @@ impl Session<'_> {
}
/// Write the set of changes represented by this session to `output`.
#[inline]
pub fn changeset_strm(&mut self, output: &mut dyn Write) -> Result<()> {
let output_ref = &output;
check!(unsafe {
@ -133,6 +136,7 @@ impl Session<'_> {
}
/// Generate a Patchset
#[inline]
pub fn patchset(&mut self) -> Result<Changeset> {
let mut n = 0;
let mut ps: *mut c_void = ptr::null_mut();
@ -142,6 +146,7 @@ impl Session<'_> {
}
/// Write the set of patches represented by this session to `output`.
#[inline]
pub fn patchset_strm(&mut self, output: &mut dyn Write) -> Result<()> {
let output_ref = &output;
check!(unsafe {
@ -174,16 +179,19 @@ impl Session<'_> {
}
/// Test if a changeset has recorded any changes
#[inline]
pub fn is_empty(&self) -> bool {
unsafe { ffi::sqlite3session_isempty(self.s) != 0 }
}
/// Query the current state of the session
#[inline]
pub fn is_enabled(&self) -> bool {
unsafe { ffi::sqlite3session_enable(self.s, -1) != 0 }
}
/// Enable or disable the recording of changes
#[inline]
pub fn set_enabled(&mut self, enabled: bool) {
unsafe {
ffi::sqlite3session_enable(self.s, if enabled { 1 } else { 0 });
@ -191,11 +199,13 @@ impl Session<'_> {
}
/// Query the current state of the indirect flag
#[inline]
pub fn is_indirect(&self) -> bool {
unsafe { ffi::sqlite3session_indirect(self.s, -1) != 0 }
}
/// Set or clear the indirect change flag
#[inline]
pub fn set_indirect(&mut self, indirect: bool) {
unsafe {
ffi::sqlite3session_indirect(self.s, if indirect { 1 } else { 0 });
@ -204,6 +214,7 @@ impl Session<'_> {
}
impl Drop for Session<'_> {
#[inline]
fn drop(&mut self) {
if self.filter.is_some() {
self.table_filter(None::<fn(&str) -> bool>);
@ -213,6 +224,7 @@ impl Drop for Session<'_> {
}
/// `feature = "session"` Invert a changeset
#[inline]
pub fn invert_strm(input: &mut dyn Read, output: &mut dyn Write) -> Result<()> {
let input_ref = &input;
let output_ref = &output;
@ -228,6 +240,7 @@ pub fn invert_strm(input: &mut dyn Read, output: &mut dyn Write) -> Result<()> {
}
/// `feature = "session"` Combine two changesets
#[inline]
pub fn concat_strm(
input_a: &mut dyn Read,
input_b: &mut dyn Read,
@ -257,6 +270,7 @@ pub struct Changeset {
impl Changeset {
/// Invert a changeset
#[inline]
pub fn invert(&self) -> Result<Changeset> {
let mut n = 0;
let mut cs = ptr::null_mut();
@ -267,6 +281,7 @@ impl Changeset {
}
/// Create an iterator to traverse a changeset
#[inline]
pub fn iter(&self) -> Result<ChangesetIter<'_>> {
let mut it = ptr::null_mut();
check!(unsafe { ffi::sqlite3changeset_start(&mut it as *mut *mut _, self.n, self.cs) });
@ -278,6 +293,7 @@ impl Changeset {
}
/// Concatenate two changeset objects
#[inline]
pub fn concat(a: &Changeset, b: &Changeset) -> Result<Changeset> {
let mut n = 0;
let mut cs = ptr::null_mut();
@ -289,6 +305,7 @@ impl Changeset {
}
impl Drop for Changeset {
#[inline]
fn drop(&mut self) {
unsafe {
ffi::sqlite3_free(self.cs);
@ -306,6 +323,7 @@ pub struct ChangesetIter<'changeset> {
impl ChangesetIter<'_> {
/// Create an iterator on `input`
#[inline]
pub fn start_strm<'input>(input: &&'input mut dyn Read) -> Result<ChangesetIter<'input>> {
let mut it = ptr::null_mut();
check!(unsafe {
@ -327,6 +345,7 @@ impl FallibleStreamingIterator for ChangesetIter<'_> {
type Error = crate::error::Error;
type Item = ChangesetItem;
#[inline]
fn advance(&mut self) -> Result<()> {
let rc = unsafe { ffi::sqlite3changeset_next(self.it) };
match rc {
@ -342,6 +361,7 @@ impl FallibleStreamingIterator for ChangesetIter<'_> {
}
}
#[inline]
fn get(&self) -> Option<&ChangesetItem> {
self.item.as_ref()
}
@ -357,27 +377,32 @@ pub struct Operation<'item> {
impl Operation<'_> {
/// Returns the table name.
#[inline]
pub fn table_name(&self) -> &str {
self.table_name
}
/// Returns the number of columns in table
#[inline]
pub fn number_of_columns(&self) -> i32 {
self.number_of_columns
}
/// Returns the action code.
#[inline]
pub fn code(&self) -> Action {
self.code
}
/// Returns `true` for an 'indirect' change.
#[inline]
pub fn indirect(&self) -> bool {
self.indirect
}
}
impl Drop for ChangesetIter<'_> {
#[inline]
fn drop(&mut self) {
unsafe {
ffi::sqlite3changeset_finalize(self.it);
@ -397,6 +422,7 @@ impl ChangesetItem {
///
/// May only be called with an `SQLITE_CHANGESET_DATA` or
/// `SQLITE_CHANGESET_CONFLICT` conflict handler callback.
#[inline]
pub fn conflict(&self, col: usize) -> Result<ValueRef<'_>> {
unsafe {
let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
@ -413,6 +439,7 @@ impl ChangesetItem {
///
/// May only be called with an `SQLITE_CHANGESET_FOREIGN_KEY` conflict
/// handler callback.
#[inline]
pub fn fk_conflicts(&self) -> Result<i32> {
unsafe {
let mut p_out = 0;
@ -425,6 +452,7 @@ impl ChangesetItem {
///
/// May only be called if the type of change is either `SQLITE_UPDATE` or
/// `SQLITE_INSERT`.
#[inline]
pub fn new_value(&self, col: usize) -> Result<ValueRef<'_>> {
unsafe {
let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
@ -437,6 +465,7 @@ impl ChangesetItem {
///
/// May only be called if the type of change is either `SQLITE_DELETE` or
/// `SQLITE_UPDATE`.
#[inline]
pub fn old_value(&self, col: usize) -> Result<ValueRef<'_>> {
unsafe {
let mut p_value: *mut ffi::sqlite3_value = ptr::null_mut();
@ -446,6 +475,7 @@ impl ChangesetItem {
}
/// Obtain the current operation
#[inline]
pub fn op(&self) -> Result<Operation<'_>> {
let mut number_of_columns = 0;
let mut code = 0;
@ -471,6 +501,7 @@ impl ChangesetItem {
}
/// Obtain the primary key definition of a table
#[inline]
pub fn pk(&self) -> Result<&[u8]> {
let mut number_of_columns = 0;
unsafe {
@ -493,6 +524,7 @@ pub struct Changegroup {
impl Changegroup {
/// Create a new change group.
#[inline]
pub fn new() -> Result<Self> {
let mut cg = ptr::null_mut();
check!(unsafe { ffi::sqlite3changegroup_new(&mut cg) });
@ -500,12 +532,14 @@ impl Changegroup {
}
/// Add a changeset
#[inline]
pub fn add(&mut self, cs: &Changeset) -> Result<()> {
check!(unsafe { ffi::sqlite3changegroup_add(self.cg, cs.n, cs.cs) });
Ok(())
}
/// Add a changeset read from `input` to this change group.
#[inline]
pub fn add_stream(&mut self, input: &mut dyn Read) -> Result<()> {
let input_ref = &input;
check!(unsafe {
@ -519,6 +553,7 @@ impl Changegroup {
}
/// Obtain a composite Changeset
#[inline]
pub fn output(&mut self) -> Result<Changeset> {
let mut n = 0;
let mut output: *mut c_void = ptr::null_mut();
@ -527,6 +562,7 @@ impl Changegroup {
}
/// Write the combined set of changes to `output`.
#[inline]
pub fn output_strm(&mut self, output: &mut dyn Write) -> Result<()> {
let output_ref = &output;
check!(unsafe {
@ -541,6 +577,7 @@ impl Changegroup {
}
impl Drop for Changegroup {
#[inline]
fn drop(&mut self) {
unsafe {
ffi::sqlite3changegroup_delete(self.cg);

View File

@ -80,6 +80,7 @@ impl Statement<'_> {
/// Will return `Err` if binding parameters fails, the executed statement
/// returns rows (in which case `query` should be used instead), or the
/// underlying SQLite call fails.
#[inline]
pub fn execute<P: Params>(&mut self, params: P) -> Result<usize> {
params.bind_in(self)?;
self.execute_with_bound_parameters()
@ -104,6 +105,7 @@ impl Statement<'_> {
/// returns rows (in which case `query` should be used instead), or the
/// underlying SQLite call fails.
#[deprecated = "You can use `execute` with named params now."]
#[inline]
pub fn execute_named(&mut self, params: &[(&str, &dyn ToSql)]) -> Result<usize> {
self.execute(params)
}
@ -121,6 +123,7 @@ impl Statement<'_> {
/// # Failure
///
/// Will return `Err` if no row is inserted or many rows are inserted.
#[inline]
pub fn insert<P: Params>(&mut self, params: P) -> Result<i64> {
let changes = self.execute(params)?;
match changes {
@ -215,6 +218,7 @@ impl Statement<'_> {
/// ## Failure
///
/// Will return `Err` if binding parameters fails.
#[inline]
pub fn query<P: Params>(&mut self, params: P) -> Result<Rows<'_>> {
self.check_readonly()?;
params.bind_in(self)?;
@ -246,6 +250,8 @@ impl Statement<'_> {
/// `f` is used to tranform the _streaming_ iterator into a _standard_
/// iterator.
///
/// This is equivalent to `stmt.query(params)?.mapped(f)`.
///
/// ## Example
///
/// ### Use with positional params
@ -289,8 +295,7 @@ impl Statement<'_> {
P: Params,
F: FnMut(&Row<'_>) -> Result<T>,
{
let rows = self.query(params)?;
Ok(MappedRows::new(rows, f))
self.query(params).map(|rows| rows.mapped(f))
}
/// Execute the prepared statement with named parameter(s), returning an
@ -327,6 +332,8 @@ impl Statement<'_> {
/// rows, where the function returns a `Result` with `Error` type
/// implementing `std::convert::From<Error>` (so errors can be unified).
///
/// This is equivalent to `stmt.query(params)?.and_then(f)`.
///
/// ## Example
///
/// ### Use with named params
@ -376,14 +383,14 @@ impl Statement<'_> {
/// # Failure
///
/// Will return `Err` if binding parameters fails.
#[inline]
pub fn query_and_then<T, E, P, F>(&mut self, params: P, f: F) -> Result<AndThenRows<'_, F>>
where
P: Params,
E: convert::From<Error>,
F: FnMut(&Row<'_>) -> Result<T, E>,
{
let rows = self.query(params)?;
Ok(AndThenRows::new(rows, f))
self.query(params).map(|rows| rows.and_then(f))
}
/// Execute the prepared statement with named parameter(s), returning an
@ -416,6 +423,7 @@ impl Statement<'_> {
/// Return `true` if a query in the SQL statement it executes returns one
/// or more rows and `false` if the SQL returns an empty set.
#[inline]
pub fn exists<P: Params>(&mut self, params: P) -> Result<bool> {
let mut rows = self.query(params)?;
let exists = rows.next()?.is_some();
@ -478,6 +486,7 @@ impl Statement<'_> {
/// # Failure
///
/// Will return `Err` if the underlying SQLite call fails.
#[inline]
pub fn finalize(mut self) -> Result<()> {
self.finalize_()
}
@ -501,10 +510,12 @@ impl Statement<'_> {
///
/// Will return Err if `name` is invalid. Will return Ok(None) if the name
/// is valid but not a bound parameter of this statement.
#[inline]
pub fn parameter_index(&self, name: &str) -> Result<Option<usize>> {
Ok(self.stmt.bind_parameter_index(name))
}
#[inline]
pub(crate) fn bind_parameters<P>(&mut self, params: P) -> Result<()>
where
P: IntoIterator,
@ -526,6 +537,7 @@ impl Statement<'_> {
}
}
#[inline]
pub(crate) fn bind_parameters_named<T: ?Sized + ToSql>(
&mut self,
params: &[(&str, &T)],
@ -542,6 +554,7 @@ impl Statement<'_> {
}
/// Return the number of parameters that can be bound to this statement.
#[inline]
pub fn parameter_count(&self) -> usize {
self.stmt.bind_parameter_count()
}
@ -584,6 +597,7 @@ impl Statement<'_> {
/// Ok(())
/// }
/// ```
#[inline]
pub fn raw_bind_parameter<T: ToSql>(
&mut self,
one_based_col_index: usize,
@ -608,6 +622,7 @@ impl Statement<'_> {
///
/// Will return `Err` if the executed statement returns rows (in which case
/// `query` should be used instead), or the underlying SQLite call fails.
#[inline]
pub fn raw_execute(&mut self) -> Result<usize> {
self.execute_with_bound_parameters()
}
@ -624,11 +639,13 @@ impl Statement<'_> {
///
/// Note that if the SQL does not return results, [`Statement::raw_execute`]
/// should be used instead.
#[inline]
pub fn raw_query(&mut self) -> Rows<'_> {
Rows::new(self)
}
fn bind_parameter(&self, param: &dyn ToSql, col: usize) -> Result<()> {
// generic because many of these branches can constant fold away.
fn bind_parameter<P: ?Sized + ToSql>(&self, param: &P, col: usize) -> Result<()> {
let value = param.to_sql()?;
let ptr = unsafe { self.stmt.ptr() };
@ -680,6 +697,7 @@ impl Statement<'_> {
})
}
#[inline]
fn execute_with_bound_parameters(&mut self) -> Result<usize> {
self.check_update()?;
let r = self.stmt.step();
@ -691,6 +709,7 @@ impl Statement<'_> {
}
}
#[inline]
fn finalize_(&mut self) -> Result<()> {
let mut stmt = unsafe { RawStatement::new(ptr::null_mut(), 0) };
mem::swap(&mut stmt, &mut self.stmt);
@ -748,17 +767,20 @@ impl Statement<'_> {
}
/// Get the value for one of the status counters for this statement.
#[inline]
pub fn get_status(&self, status: StatementStatus) -> i32 {
self.stmt.get_status(status, false)
}
/// Reset the value of one of the status counters for this statement,
#[inline]
/// returning the value it had before resetting.
pub fn reset_status(&self, status: StatementStatus) -> i32 {
self.stmt.get_status(status, true)
}
#[cfg(feature = "extra_check")]
#[inline]
pub(crate) fn check_no_tail(&self) -> Result<()> {
if self.stmt.has_tail() {
Err(Error::MultipleStatement)
@ -776,6 +798,7 @@ impl Statement<'_> {
/// Safety: This is unsafe, because using `sqlite3_stmt` after the
/// connection has closed is illegal, but `RawStatement` does not enforce
/// this, as it loses our protective `'conn` lifetime bound.
#[inline]
pub(crate) unsafe fn into_raw(mut self) -> RawStatement {
let mut stmt = RawStatement::new(ptr::null_mut(), 0);
mem::swap(&mut stmt, &mut self.stmt);
@ -800,12 +823,14 @@ impl fmt::Debug for Statement<'_> {
impl Drop for Statement<'_> {
#[allow(unused_must_use)]
#[inline]
fn drop(&mut self) {
self.finalize_();
}
}
impl Statement<'_> {
#[inline]
pub(super) fn new(conn: &Connection, stmt: RawStatement) -> Statement<'_> {
Statement { conn, stmt }
}
@ -866,6 +891,7 @@ impl Statement<'_> {
}
}
#[inline]
pub(super) fn step(&self) -> Result<bool> {
match self.stmt.step() {
ffi::SQLITE_ROW => Ok(true),
@ -874,6 +900,7 @@ impl Statement<'_> {
}
}
#[inline]
pub(super) fn reset(&self) -> c_int {
self.stmt.reset()
}

View File

@ -55,6 +55,7 @@ pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> Result<()> {
/// `feature = "trace"` Write a message into the error log established by
/// `config_log`.
#[inline]
pub fn log(err_code: c_int, msg: &str) {
let msg = CString::new(msg).expect("SQLite log messages cannot contain embedded zeroes");
unsafe {

View File

@ -102,6 +102,7 @@ impl Transaction<'_> {
/// Even though we don't mutate the connection, we take a `&mut Connection`
/// so as to prevent nested transactions on the same connection. For cases
/// where this is unacceptable, [`Transaction::new_unchecked`] is available.
#[inline]
pub fn new(conn: &mut Connection, behavior: TransactionBehavior) -> Result<Transaction<'_>> {
Self::new_unchecked(conn, behavior)
}
@ -111,6 +112,7 @@ impl Transaction<'_> {
/// If a transaction is already open, this will return an error. Where
/// possible, [`Transaction::new`] should be preferred, as it provides a
/// compile-time guarantee that transactions are not nested.
#[inline]
pub fn new_unchecked(
conn: &Connection,
behavior: TransactionBehavior,
@ -153,42 +155,50 @@ impl Transaction<'_> {
/// tx.commit()
/// }
/// ```
#[inline]
pub fn savepoint(&mut self) -> Result<Savepoint<'_>> {
Savepoint::with_depth(self.conn, 1)
}
/// Create a new savepoint with a custom savepoint name. See `savepoint()`.
#[inline]
pub fn savepoint_with_name<T: Into<String>>(&mut self, name: T) -> Result<Savepoint<'_>> {
Savepoint::with_depth_and_name(self.conn, 1, name)
}
/// Get the current setting for what happens to the transaction when it is
/// dropped.
#[inline]
pub fn drop_behavior(&self) -> DropBehavior {
self.drop_behavior
}
/// Configure the transaction to perform the specified action when it is
/// dropped.
#[inline]
pub fn set_drop_behavior(&mut self, drop_behavior: DropBehavior) {
self.drop_behavior = drop_behavior
}
/// A convenience method which consumes and commits a transaction.
#[inline]
pub fn commit(mut self) -> Result<()> {
self.commit_()
}
#[inline]
fn commit_(&mut self) -> Result<()> {
self.conn.execute_batch("COMMIT")?;
Ok(())
}
/// A convenience method which consumes and rolls back a transaction.
#[inline]
pub fn rollback(mut self) -> Result<()> {
self.rollback_()
}
#[inline]
fn rollback_(&mut self) -> Result<()> {
self.conn.execute_batch("ROLLBACK")?;
Ok(())
@ -199,10 +209,12 @@ impl Transaction<'_> {
///
/// Functionally equivalent to the `Drop` implementation, but allows
/// callers to see any errors that occur.
#[inline]
pub fn finish(mut self) -> Result<()> {
self.finish_()
}
#[inline]
fn finish_(&mut self) -> Result<()> {
if self.conn.is_autocommit() {
return Ok(());
@ -219,6 +231,7 @@ impl Transaction<'_> {
impl Deref for Transaction<'_> {
type Target = Connection;
#[inline]
fn deref(&self) -> &Connection {
self.conn
}
@ -226,12 +239,14 @@ impl Deref for Transaction<'_> {
#[allow(unused_must_use)]
impl Drop for Transaction<'_> {
#[inline]
fn drop(&mut self) {
self.finish_();
}
}
impl Savepoint<'_> {
#[inline]
fn with_depth_and_name<T: Into<String>>(
conn: &Connection,
depth: u32,
@ -248,48 +263,57 @@ impl Savepoint<'_> {
})
}
#[inline]
fn with_depth(conn: &Connection, depth: u32) -> Result<Savepoint<'_>> {
let name = format!("_rusqlite_sp_{}", depth);
Savepoint::with_depth_and_name(conn, depth, name)
}
/// Begin a new savepoint. Can be nested.
#[inline]
pub fn new(conn: &mut Connection) -> Result<Savepoint<'_>> {
Savepoint::with_depth(conn, 0)
}
/// Begin a new savepoint with a user-provided savepoint name.
#[inline]
pub fn with_name<T: Into<String>>(conn: &mut Connection, name: T) -> Result<Savepoint<'_>> {
Savepoint::with_depth_and_name(conn, 0, name)
}
/// Begin a nested savepoint.
#[inline]
pub fn savepoint(&mut self) -> Result<Savepoint<'_>> {
Savepoint::with_depth(self.conn, self.depth + 1)
}
/// Begin a nested savepoint with a user-provided savepoint name.
#[inline]
pub fn savepoint_with_name<T: Into<String>>(&mut self, name: T) -> Result<Savepoint<'_>> {
Savepoint::with_depth_and_name(self.conn, self.depth + 1, name)
}
/// Get the current setting for what happens to the savepoint when it is
/// dropped.
#[inline]
pub fn drop_behavior(&self) -> DropBehavior {
self.drop_behavior
}
/// Configure the savepoint to perform the specified action when it is
/// dropped.
#[inline]
pub fn set_drop_behavior(&mut self, drop_behavior: DropBehavior) {
self.drop_behavior = drop_behavior
}
/// A convenience method which consumes and commits a savepoint.
#[inline]
pub fn commit(mut self) -> Result<()> {
self.commit_()
}
#[inline]
fn commit_(&mut self) -> Result<()> {
self.conn.execute_batch(&format!("RELEASE {}", self.name))?;
self.committed = true;
@ -302,6 +326,7 @@ impl Savepoint<'_> {
///
/// Unlike `Transaction`s, savepoints remain active after they have been
/// rolled back, and can be rolled back again or committed.
#[inline]
pub fn rollback(&mut self) -> Result<()> {
self.conn
.execute_batch(&format!("ROLLBACK TO {}", self.name))
@ -312,10 +337,12 @@ impl Savepoint<'_> {
///
/// Functionally equivalent to the `Drop` implementation, but allows
/// callers to see any errors that occur.
#[inline]
pub fn finish(mut self) -> Result<()> {
self.finish_()
}
#[inline]
fn finish_(&mut self) -> Result<()> {
if self.committed {
return Ok(());
@ -332,6 +359,7 @@ impl Savepoint<'_> {
impl Deref for Savepoint<'_> {
type Target = Connection;
#[inline]
fn deref(&self) -> &Connection {
self.conn
}
@ -339,6 +367,7 @@ impl Deref for Savepoint<'_> {
#[allow(unused_must_use)]
impl Drop for Savepoint<'_> {
#[inline]
fn drop(&mut self) {
self.finish_();
}
@ -370,6 +399,7 @@ impl Connection {
/// # Failure
///
/// Will return `Err` if the underlying SQLite call fails.
#[inline]
pub fn transaction(&mut self) -> Result<Transaction<'_>> {
Transaction::new(self, TransactionBehavior::Deferred)
}
@ -381,6 +411,7 @@ impl Connection {
/// # Failure
///
/// Will return `Err` if the underlying SQLite call fails.
#[inline]
pub fn transaction_with_behavior(
&mut self,
behavior: TransactionBehavior,
@ -448,6 +479,7 @@ impl Connection {
/// # Failure
///
/// Will return `Err` if the underlying SQLite call fails.
#[inline]
pub fn savepoint(&mut self) -> Result<Savepoint<'_>> {
Savepoint::new(self)
}
@ -459,6 +491,7 @@ impl Connection {
/// # Failure
///
/// Will return `Err` if the underlying SQLite call fails.
#[inline]
pub fn savepoint_with_name<T: Into<String>>(&mut self, name: T) -> Result<Savepoint<'_>> {
Savepoint::with_name(self, name)
}

View File

@ -9,6 +9,7 @@ use crate::Result;
/// ISO 8601 calendar date without timezone => "YYYY-MM-DD"
impl ToSql for NaiveDate {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let date_str = self.format("%Y-%m-%d").to_string();
Ok(ToSqlOutput::from(date_str))
@ -17,6 +18,7 @@ impl ToSql for NaiveDate {
/// "YYYY-MM-DD" => ISO 8601 calendar date without timezone.
impl FromSql for NaiveDate {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value
.as_str()
@ -29,6 +31,7 @@ impl FromSql for NaiveDate {
/// ISO 8601 time without timezone => "HH:MM:SS.SSS"
impl ToSql for NaiveTime {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let date_str = self.format("%H:%M:%S%.f").to_string();
Ok(ToSqlOutput::from(date_str))
@ -55,6 +58,7 @@ impl FromSql for NaiveTime {
/// ISO 8601 combined date and time without timezone =>
/// "YYYY-MM-DDTHH:MM:SS.SSS"
impl ToSql for NaiveDateTime {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let date_str = self.format("%Y-%m-%dT%H:%M:%S%.f").to_string();
Ok(ToSqlOutput::from(date_str))
@ -84,6 +88,7 @@ impl FromSql for NaiveDateTime {
/// Date and time with time zone => UTC RFC3339 timestamp
/// ("YYYY-MM-DDTHH:MM:SS.SSS+00:00").
impl<Tz: TimeZone> ToSql for DateTime<Tz> {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(self.with_timezone(&Utc).to_rfc3339()))
}
@ -120,6 +125,7 @@ impl FromSql for DateTime<Utc> {
/// RFC3339 ("YYYY-MM-DDTHH:MM:SS.SSS[+-]HH:MM") into `DateTime<Local>`.
impl FromSql for DateTime<Local> {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
let utc_dt = DateTime::<Utc>::column_result(value)?;
Ok(utc_dt.with_timezone(&Local))

View File

@ -94,6 +94,7 @@ pub trait FromSql: Sized {
macro_rules! from_sql_integral(
($t:ident) => (
impl FromSql for $t {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
let i = i64::column_result(value)?;
i.try_into().map_err(|_| FromSqlError::OutOfRange(i))
@ -114,12 +115,14 @@ from_sql_integral!(u64);
from_sql_integral!(usize);
impl FromSql for i64 {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_i64()
}
}
impl FromSql for f32 {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
match value {
ValueRef::Integer(i) => Ok(i as f32),
@ -130,6 +133,7 @@ impl FromSql for f32 {
}
impl FromSql for f64 {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
match value {
ValueRef::Integer(i) => Ok(i as f64),
@ -140,36 +144,42 @@ impl FromSql for f64 {
}
impl FromSql for bool {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
i64::column_result(value).map(|i| !matches!(i, 0))
}
}
impl FromSql for String {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().map(ToString::to_string)
}
}
impl FromSql for Box<str> {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().map(Into::into)
}
}
impl FromSql for std::rc::Rc<str> {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().map(Into::into)
}
}
impl FromSql for std::sync::Arc<str> {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().map(Into::into)
}
}
impl FromSql for Vec<u8> {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_blob().map(|b| b.to_vec())
}
@ -177,6 +187,7 @@ impl FromSql for Vec<u8> {
#[cfg(feature = "i128_blob")]
impl FromSql for i128 {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
use byteorder::{BigEndian, ByteOrder};
@ -192,6 +203,7 @@ impl FromSql for i128 {
#[cfg(feature = "uuid")]
impl FromSql for uuid::Uuid {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value
.as_blob()
@ -204,6 +216,7 @@ impl FromSql for uuid::Uuid {
}
impl<T: FromSql> FromSql for Option<T> {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
match value {
ValueRef::Null => Ok(None),
@ -213,6 +226,7 @@ impl<T: FromSql> FromSql for Option<T> {
}
impl FromSql for Value {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
Ok(value.into())
}

View File

@ -119,11 +119,11 @@ pub enum Type {
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Type::Null => write!(f, "Null"),
Type::Integer => write!(f, "Integer"),
Type::Real => write!(f, "Real"),
Type::Text => write!(f, "Text"),
Type::Blob => write!(f, "Blob"),
Type::Null => f.pad("Null"),
Type::Integer => f.pad("Integer"),
Type::Real => f.pad("Real"),
Type::Text => f.pad("Text"),
Type::Blob => f.pad("Blob"),
}
}
}
@ -260,9 +260,9 @@ mod test {
assert_eq!("text", row.get::<_, String>(1).unwrap());
assert_eq!(1, row.get::<_, c_int>(2).unwrap());
assert!((1.5 - row.get::<_, c_double>(3).unwrap()).abs() < EPSILON);
assert!(row.get::<_, Option<c_int>>(4).unwrap().is_none());
assert!(row.get::<_, Option<c_double>>(4).unwrap().is_none());
assert!(row.get::<_, Option<String>>(4).unwrap().is_none());
assert_eq!(row.get::<_, Option<c_int>>(4).unwrap(), None);
assert_eq!(row.get::<_, Option<c_double>>(4).unwrap(), None);
assert_eq!(row.get::<_, Option<String>>(4).unwrap(), None);
// check some invalid types

View File

@ -7,6 +7,7 @@ use crate::Result;
/// Serialize JSON `Value` to text.
impl ToSql for Value {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(serde_json::to_string(self).unwrap()))
}
@ -14,6 +15,7 @@ impl ToSql for Value {
/// Deserialize text/blob to JSON `Value`.
impl FromSql for Value {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
match value {
ValueRef::Text(s) => serde_json::from_slice(s),

View File

@ -8,6 +8,7 @@ const SQLITE_DATETIME_FMT: &str = "%Y-%m-%dT%H:%M:%S.%NZ";
const SQLITE_DATETIME_FMT_LEGACY: &str = "%Y-%m-%d %H:%M:%S:%N %z";
impl ToSql for OffsetDateTime {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
let time_string = self.to_offset(UtcOffset::UTC).format(SQLITE_DATETIME_FMT);
Ok(ToSqlOutput::from(time_string))

View File

@ -32,6 +32,7 @@ impl<'a, T: ?Sized> From<&'a T> for ToSqlOutput<'a>
where
&'a T: Into<ValueRef<'a>>,
{
#[inline]
fn from(t: &'a T) -> Self {
ToSqlOutput::Borrowed(t.into())
}
@ -45,6 +46,7 @@ where
macro_rules! from_value(
($t:ty) => (
impl From<$t> for ToSqlOutput<'_> {
#[inline]
fn from(t: $t) -> Self { ToSqlOutput::Owned(t.into())}
}
)
@ -74,6 +76,7 @@ from_value!(i128);
from_value!(uuid::Uuid);
impl ToSql for ToSqlOutput<'_> {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(match *self {
ToSqlOutput::Borrowed(v) => ToSqlOutput::Borrowed(v),
@ -95,24 +98,28 @@ pub trait ToSql {
}
impl<T: ToSql + ToOwned + ?Sized> ToSql for Cow<'_, T> {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
self.as_ref().to_sql()
}
}
impl<T: ToSql + ?Sized> ToSql for Box<T> {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
self.as_ref().to_sql()
}
}
impl<T: ToSql + ?Sized> ToSql for std::rc::Rc<T> {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
self.as_ref().to_sql()
}
}
impl<T: ToSql + ?Sized> ToSql for std::sync::Arc<T> {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
self.as_ref().to_sql()
}
@ -133,6 +140,7 @@ impl<T: ToSql + ?Sized> ToSql for std::sync::Arc<T> {
macro_rules! to_sql_self(
($t:ty) => (
impl ToSql for $t {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(*self))
}
@ -162,6 +170,7 @@ to_sql_self!(uuid::Uuid);
macro_rules! to_sql_self_fallible(
($t:ty) => (
impl ToSql for $t {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::Owned(Value::Integer(
i64::try_from(*self).map_err(
@ -182,42 +191,49 @@ impl<T: ?Sized> ToSql for &'_ T
where
T: ToSql,
{
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
(*self).to_sql()
}
}
impl ToSql for String {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(self.as_str()))
}
}
impl ToSql for str {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(self))
}
}
impl ToSql for Vec<u8> {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(self.as_slice()))
}
}
impl ToSql for [u8] {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(self))
}
}
impl ToSql for Value {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(self))
}
}
impl<T: ToSql> ToSql for Option<T> {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
match *self {
None => Ok(ToSqlOutput::from(Null)),

View File

@ -5,6 +5,7 @@ use url::Url;
/// Serialize `Url` to text.
impl ToSql for Url {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(self.as_str()))
}
@ -12,6 +13,7 @@ impl ToSql for Url {
/// Deserialize text to `Url`.
impl FromSql for Url {
#[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
match value {
ValueRef::Text(s) => {

View File

@ -19,18 +19,21 @@ pub enum Value {
}
impl From<Null> for Value {
#[inline]
fn from(_: Null) -> Value {
Value::Null
}
}
impl From<bool> for Value {
#[inline]
fn from(i: bool) -> Value {
Value::Integer(i as i64)
}
}
impl From<isize> for Value {
#[inline]
fn from(i: isize) -> Value {
Value::Integer(i as i64)
}
@ -38,6 +41,7 @@ impl From<isize> for Value {
#[cfg(feature = "i128_blob")]
impl From<i128> for Value {
#[inline]
fn from(i: i128) -> Value {
use byteorder::{BigEndian, ByteOrder};
let mut buf = vec![0u8; 16];
@ -50,6 +54,7 @@ impl From<i128> for Value {
#[cfg(feature = "uuid")]
impl From<uuid::Uuid> for Value {
#[inline]
fn from(id: uuid::Uuid) -> Value {
Value::Blob(id.as_bytes().to_vec())
}
@ -58,6 +63,7 @@ impl From<uuid::Uuid> for Value {
macro_rules! from_i64(
($t:ty) => (
impl From<$t> for Value {
#[inline]
fn from(i: $t) -> Value {
Value::Integer(i64::from(i))
}
@ -73,30 +79,35 @@ from_i64!(u16);
from_i64!(u32);
impl From<i64> for Value {
#[inline]
fn from(i: i64) -> Value {
Value::Integer(i)
}
}
impl From<f32> for Value {
#[inline]
fn from(f: f32) -> Value {
Value::Real(f.into())
}
}
impl From<f64> for Value {
#[inline]
fn from(f: f64) -> Value {
Value::Real(f)
}
}
impl From<String> for Value {
#[inline]
fn from(s: String) -> Value {
Value::Text(s)
}
}
impl From<Vec<u8>> for Value {
#[inline]
fn from(v: Vec<u8>) -> Value {
Value::Blob(v)
}
@ -106,6 +117,7 @@ impl<T> From<Option<T>> for Value
where
T: Into<Value>,
{
#[inline]
fn from(v: Option<T>) -> Value {
match v {
Some(x) => x.into(),
@ -116,6 +128,7 @@ where
impl Value {
/// Returns SQLite fundamental datatype.
#[inline]
pub fn data_type(&self) -> Type {
match *self {
Value::Null => Type::Null,

View File

@ -21,6 +21,7 @@ pub enum ValueRef<'a> {
impl ValueRef<'_> {
/// Returns SQLite fundamental datatype.
#[inline]
pub fn data_type(&self) -> Type {
match *self {
ValueRef::Null => Type::Null,
@ -35,6 +36,7 @@ impl ValueRef<'_> {
impl<'a> ValueRef<'a> {
/// If `self` is case `Integer`, returns the integral value. Otherwise,
/// returns `Err(Error::InvalidColumnType)`.
#[inline]
pub fn as_i64(&self) -> FromSqlResult<i64> {
match *self {
ValueRef::Integer(i) => Ok(i),
@ -44,6 +46,7 @@ impl<'a> ValueRef<'a> {
/// If `self` is case `Real`, returns the floating point value. Otherwise,
/// returns `Err(Error::InvalidColumnType)`.
#[inline]
pub fn as_f64(&self) -> FromSqlResult<f64> {
match *self {
ValueRef::Real(f) => Ok(f),
@ -53,6 +56,7 @@ impl<'a> ValueRef<'a> {
/// If `self` is case `Text`, returns the string value. Otherwise, returns
/// `Err(Error::InvalidColumnType)`.
#[inline]
pub fn as_str(&self) -> FromSqlResult<&'a str> {
match *self {
ValueRef::Text(t) => {
@ -64,6 +68,7 @@ impl<'a> ValueRef<'a> {
/// If `self` is case `Blob`, returns the byte slice. Otherwise, returns
/// `Err(Error::InvalidColumnType)`.
#[inline]
pub fn as_blob(&self) -> FromSqlResult<&'a [u8]> {
match *self {
ValueRef::Blob(b) => Ok(b),
@ -73,6 +78,7 @@ impl<'a> ValueRef<'a> {
}
impl From<ValueRef<'_>> for Value {
#[inline]
fn from(borrowed: ValueRef<'_>) -> Value {
match borrowed {
ValueRef::Null => Value::Null,
@ -88,18 +94,21 @@ impl From<ValueRef<'_>> for Value {
}
impl<'a> From<&'a str> for ValueRef<'a> {
#[inline]
fn from(s: &str) -> ValueRef<'_> {
ValueRef::Text(s.as_bytes())
}
}
impl<'a> From<&'a [u8]> for ValueRef<'a> {
#[inline]
fn from(s: &[u8]) -> ValueRef<'_> {
ValueRef::Blob(s)
}
}
impl<'a> From<&'a Value> for ValueRef<'a> {
#[inline]
fn from(value: &'a Value) -> ValueRef<'a> {
match *value {
Value::Null => ValueRef::Null,
@ -115,6 +124,7 @@ impl<'a, T> From<Option<T>> for ValueRef<'a>
where
T: Into<ValueRef<'a>>,
{
#[inline]
fn from(s: Option<T>) -> ValueRef<'a> {
match s {
Some(x) => x.into(),

View File

@ -155,6 +155,7 @@ fn make_nonnull(v: &str) -> String {
}
impl Drop for SqliteMallocString {
#[inline]
fn drop(&mut self) {
unsafe { ffi::sqlite3_free(self.ptr.as_ptr().cast()) };
}

View File

@ -5,6 +5,7 @@ use std::ffi::CStr;
/// 3.16.2.
///
/// See [`sqlite3_libversion_number()`](https://www.sqlite.org/c3ref/libversion.html).
#[inline]
pub fn version_number() -> i32 {
unsafe { ffi::sqlite3_libversion_number() }
}
@ -12,6 +13,7 @@ pub fn version_number() -> i32 {
/// Returns the SQLite version as a string; e.g., `"3.16.2"` for version 3.16.2.
///
/// See [`sqlite3_libversion()`](https://www.sqlite.org/c3ref/libversion.html).
#[inline]
pub fn version() -> &'static str {
let cstr = unsafe { CStr::from_ptr(ffi::sqlite3_libversion()) };
cstr.to_str()

View File

@ -51,6 +51,7 @@ pub(crate) unsafe extern "C" fn free_array(p: *mut c_void) {
pub type Array = Rc<Vec<Value>>;
impl ToSql for Array {
#[inline]
fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::Array(self.clone()))
}

View File

@ -354,6 +354,7 @@ unsafe impl VTabCursor for CSVTabCursor<'_> {
}
impl From<csv::Error> for Error {
#[cold]
fn from(err: csv::Error) -> Error {
Error::ModuleError(err.to_string())
}

View File

@ -310,6 +310,7 @@ pub struct IndexInfo(*mut ffi::sqlite3_index_info);
impl IndexInfo {
/// Record WHERE clause constraints.
#[inline]
pub fn constraints(&self) -> IndexConstraintIter<'_> {
let constraints =
unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
@ -319,6 +320,7 @@ impl IndexInfo {
}
/// Information about the ORDER BY clause.
#[inline]
pub fn order_bys(&self) -> OrderByIter<'_> {
let order_bys =
unsafe { slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize) };
@ -328,11 +330,13 @@ impl IndexInfo {
}
/// Number of terms in the ORDER BY clause
#[inline]
pub fn num_of_order_by(&self) -> usize {
unsafe { (*self.0).nOrderBy as usize }
}
/// Information about what parameters to pass to `VTabCursor.filter`.
#[inline]
pub fn constraint_usage(&mut self, constraint_idx: usize) -> IndexConstraintUsage<'_> {
let constraint_usages = unsafe {
slice::from_raw_parts_mut((*self.0).aConstraintUsage, (*self.0).nConstraint as usize)
@ -341,6 +345,7 @@ impl IndexInfo {
}
/// Number used to identify the index
#[inline]
pub fn set_idx_num(&mut self, idx_num: c_int) {
unsafe {
(*self.0).idxNum = idx_num;
@ -348,6 +353,7 @@ impl IndexInfo {
}
/// True if output is already ordered
#[inline]
pub fn set_order_by_consumed(&mut self, order_by_consumed: bool) {
unsafe {
(*self.0).orderByConsumed = if order_by_consumed { 1 } else { 0 };
@ -355,6 +361,7 @@ impl IndexInfo {
}
/// Estimated cost of using this index
#[inline]
pub fn set_estimated_cost(&mut self, estimated_ost: f64) {
unsafe {
(*self.0).estimatedCost = estimated_ost;
@ -363,6 +370,7 @@ impl IndexInfo {
/// Estimated number of rows returned.
#[cfg(feature = "modern_sqlite")] // SQLite >= 3.8.2
#[inline]
pub fn set_estimated_rows(&mut self, estimated_rows: i64) {
unsafe {
(*self.0).estimatedRows = estimated_rows;
@ -383,10 +391,12 @@ pub struct IndexConstraintIter<'a> {
impl<'a> Iterator for IndexConstraintIter<'a> {
type Item = IndexConstraint<'a>;
#[inline]
fn next(&mut self) -> Option<IndexConstraint<'a>> {
self.iter.next().map(|raw| IndexConstraint(raw))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
@ -397,16 +407,19 @@ pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
impl IndexConstraint<'_> {
/// Column constrained. -1 for ROWID
#[inline]
pub fn column(&self) -> c_int {
self.0.iColumn
}
/// Constraint operator
#[inline]
pub fn operator(&self) -> IndexConstraintOp {
IndexConstraintOp::from(self.0.op)
}
/// True if this constraint is usable
#[inline]
pub fn is_usable(&self) -> bool {
self.0.usable != 0
}
@ -418,11 +431,13 @@ pub struct IndexConstraintUsage<'a>(&'a mut ffi::sqlite3_index_constraint_usage)
impl IndexConstraintUsage<'_> {
/// if `argv_index` > 0, constraint is part of argv to `VTabCursor.filter`
#[inline]
pub fn set_argv_index(&mut self, argv_index: c_int) {
self.0.argvIndex = argv_index;
}
/// if `omit`, do not code a test for this constraint
#[inline]
pub fn set_omit(&mut self, omit: bool) {
self.0.omit = if omit { 1 } else { 0 };
}
@ -436,10 +451,12 @@ pub struct OrderByIter<'a> {
impl<'a> Iterator for OrderByIter<'a> {
type Item = OrderBy<'a>;
#[inline]
fn next(&mut self) -> Option<OrderBy<'a>> {
self.iter.next().map(|raw| OrderBy(raw))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
@ -450,11 +467,13 @@ pub struct OrderBy<'a>(&'a ffi::sqlite3_index_info_sqlite3_index_orderby);
impl OrderBy<'_> {
/// Column number
#[inline]
pub fn column(&self) -> c_int {
self.0.iColumn
}
/// True for DESC. False for ASC.
#[inline]
pub fn is_order_by_desc(&self) -> bool {
self.0.desc != 0
}
@ -500,6 +519,7 @@ pub struct Context(*mut ffi::sqlite3_context);
impl Context {
/// Set current cell value
#[inline]
pub fn set_result<T: ToSql>(&mut self, value: &T) -> Result<()> {
let t = value.to_sql()?;
unsafe { set_result(self.0, &t) };
@ -517,11 +537,13 @@ pub struct Values<'a> {
impl Values<'_> {
/// Returns the number of values.
#[inline]
pub fn len(&self) -> usize {
self.args.len()
}
/// Returns `true` if there is no value.
#[inline]
pub fn is_empty(&self) -> bool {
self.args.is_empty()
}
@ -567,6 +589,7 @@ impl Values<'_> {
}
/// Turns `Values` into an iterator.
#[inline]
pub fn iter(&self) -> ValueIter<'_> {
ValueIter {
iter: self.args.iter(),
@ -578,6 +601,7 @@ impl<'a> IntoIterator for &'a Values<'a> {
type IntoIter = ValueIter<'a>;
type Item = ValueRef<'a>;
#[inline]
fn into_iter(self) -> ValueIter<'a> {
self.iter()
}
@ -591,12 +615,14 @@ pub struct ValueIter<'a> {
impl<'a> Iterator for ValueIter<'a> {
type Item = ValueRef<'a>;
#[inline]
fn next(&mut self) -> Option<ValueRef<'a>> {
self.iter
.next()
.map(|&raw| unsafe { ValueRef::from_value(raw) })
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
@ -607,6 +633,7 @@ impl Connection {
///
/// Step 3 of [Creating New Virtual Table
/// Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
#[inline]
pub fn create_module<'vtab, T: VTab<'vtab>>(
&self,
module_name: &str,
@ -977,6 +1004,7 @@ where
/// Virtual table cursors can set an error message by assigning a string to
/// `zErrMsg`.
#[cold]
unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<T>) -> c_int {
match result {
Ok(_) => ffi::SQLITE_OK,
@ -995,6 +1023,7 @@ unsafe fn cursor_error<T>(cursor: *mut ffi::sqlite3_vtab_cursor, result: Result<
/// Virtual tables methods can set an error message by assigning a string to
/// `zErrMsg`.
#[cold]
unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
if !(*vtab).zErrMsg.is_null() {
ffi::sqlite3_free((*vtab).zErrMsg as *mut c_void);
@ -1004,6 +1033,7 @@ unsafe fn set_err_msg(vtab: *mut ffi::sqlite3_vtab, err_msg: &str) {
/// To raise an error, the `column` method should use this method to set the
/// error message and return the error code.
#[cold]
unsafe fn result_error<T>(ctx: *mut ffi::sqlite3_context, result: Result<T>) -> c_int {
match result {
Ok(_) => ffi::SQLITE_OK,