mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
Add #[inline]
and #[cold]
in far more places
This commit is contained in:
parent
7574124233
commit
65c38bf813
@ -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) };
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
11
src/cache.rs
11
src/cache.rs
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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>);
|
||||
|
@ -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;
|
||||
|
||||
|
32
src/lib.rs
32
src/lib.rs
@ -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()
|
||||
|
@ -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) }
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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<()> {
|
||||
|
@ -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
|
||||
}
|
||||
|
31
src/row.rs
31
src/row.rs
@ -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()
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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))
|
||||
|
@ -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)),
|
||||
|
@ -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) => {
|
||||
|
@ -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,
|
||||
|
@ -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(),
|
||||
|
@ -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()) };
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user