Merge remote-tracking branch 'origin/master' into ptr_as_ptr

This commit is contained in:
gwenn 2022-01-06 18:20:01 +01:00
commit cc4f059d9b
30 changed files with 173 additions and 151 deletions

View File

@ -50,12 +50,12 @@ jobs:
- run: cargo test --features bundled --workspace --all-targets --verbose - run: cargo test --features bundled --workspace --all-targets --verbose
- run: cargo test --features bundled --workspace --doc --verbose - run: cargo test --features bundled --workspace --doc --verbose
- name: Test Features - name: Add llvm path on Windows
# TODO: clang is installed on these -- but `bindgen` can't find it... if: matrix.os == 'windows-latest'
if: matrix.os != 'windows-latest' run: echo "C:\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
run: |
cargo test --features 'bundled-full session buildtime_bindgen' --all-targets --workspace --verbose - run: cargo test --features 'bundled-full session buildtime_bindgen' --all-targets --workspace --verbose
cargo test --features 'bundled-full session buildtime_bindgen' --doc --workspace --verbose - run: cargo test --features 'bundled-full session buildtime_bindgen' --doc --workspace --verbose
# TODO: move into own action for better caching # TODO: move into own action for better caching
- name: Static build - name: Static build
@ -97,11 +97,12 @@ jobs:
- run: cargo test --features 'modern-full bundled-sqlcipher-vendored-openssl' --all-targets --workspace --verbose - run: cargo test --features 'modern-full bundled-sqlcipher-vendored-openssl' --all-targets --workspace --verbose
- run: cargo test --features 'modern-full bundled-sqlcipher-vendored-openssl' --doc --workspace --verbose - run: cargo test --features 'modern-full bundled-sqlcipher-vendored-openssl' --doc --workspace --verbose
- name: Test Features - name: Add llvm path on Windows
if: matrix.os != 'windows-latest' if: matrix.os == 'windows-latest'
run: | run: echo "C:\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
cargo test --features 'bundled-full session buildtime_bindgen' --all-targets --workspace --verbose
cargo test --features 'bundled-full session buildtime_bindgen' --doc --workspace --verbose - run: cargo test --features 'bundled-full session buildtime_bindgen' --all-targets --workspace --verbose
- run: cargo test --features 'bundled-full session buildtime_bindgen' --doc --workspace --verbose
winsqlite3: winsqlite3:
name: Test with winsqlite3 name: Test with winsqlite3

View File

@ -1,13 +1,12 @@
# Rusqlite # Rusqlite
[![Travis Build Status](https://api.travis-ci.org/rusqlite/rusqlite.svg?branch=master)](https://travis-ci.org/rusqlite/rusqlite)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/rusqlite/rusqlite?branch=master&svg=true)](https://ci.appveyor.com/project/rusqlite/rusqlite)
[![Build Status](https://github.com/rusqlite/rusqlite/workflows/CI/badge.svg)](https://github.com/rusqlite/rusqlite/actions)
[![dependency status](https://deps.rs/repo/github/rusqlite/rusqlite/status.svg)](https://deps.rs/repo/github/rusqlite/rusqlite)
[![Latest Version](https://img.shields.io/crates/v/rusqlite.svg)](https://crates.io/crates/rusqlite) [![Latest Version](https://img.shields.io/crates/v/rusqlite.svg)](https://crates.io/crates/rusqlite)
[![Gitter](https://badges.gitter.im/rusqlite.svg)](https://gitter.im/rusqlite/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Documentation](https://docs.rs/rusqlite/badge.svg)](https://docs.rs/rusqlite)
[![Docs](https://docs.rs/rusqlite/badge.svg)](https://docs.rs/rusqlite) [![Build Status (GitHub)](https://github.com/rusqlite/rusqlite/workflows/CI/badge.svg)](https://github.com/rusqlite/rusqlite/actions)
[![codecov](https://codecov.io/gh/rusqlite/rusqlite/branch/master/graph/badge.svg)](https://codecov.io/gh/rusqlite/rusqlite) [![Build Status (AppVeyor)](https://ci.appveyor.com/api/projects/status/github/rusqlite/rusqlite?branch=master&svg=true)](https://ci.appveyor.com/project/rusqlite/rusqlite)
[![Code Coverage](https://codecov.io/gh/rusqlite/rusqlite/branch/master/graph/badge.svg)](https://codecov.io/gh/rusqlite/rusqlite)
[![Dependency Status](https://deps.rs/repo/github/rusqlite/rusqlite/status.svg)](https://deps.rs/repo/github/rusqlite/rusqlite)
[![Discord Chat](https://img.shields.io/discord/927966344266256434.svg?logo=discord)](https://discord.gg/G6Se6Yzw)
Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose
an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres). an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres).
@ -212,7 +211,7 @@ here: https://github.com/rusqlite/rusqlite/graphs/contributors
## Community ## Community
Currently there's a gitter channel set up for rusqlite [here](https://gitter.im/rusqlite/community). Feel free to join the [Rusqlite Discord Server](https://discord.gg/G6Se6Yzw) to discuss or get help with `rusqlite` or `libsqlite3-sys`.
## License ## License

View File

@ -46,9 +46,9 @@ fn main() {
features 'bundled' and 'bundled-windows'. If you want a bundled build of features 'bundled' and 'bundled-windows'. If you want a bundled build of
SQLCipher (available for the moment only on Unix), use feature 'bundled-sqlcipher' SQLCipher (available for the moment only on Unix), use feature 'bundled-sqlcipher'
or 'bundled-sqlcipher-vendored-openssl' to also bundle OpenSSL crypto." or 'bundled-sqlcipher-vendored-openssl' to also bundle OpenSSL crypto."
) );
} }
build_linked::main(&out_dir, &out_path) build_linked::main(&out_dir, &out_path);
} else if cfg!(feature = "bundled") } else if cfg!(feature = "bundled")
|| (win_target() && cfg!(feature = "bundled-windows")) || (win_target() && cfg!(feature = "bundled-windows"))
|| cfg!(feature = "bundled-sqlcipher") || cfg!(feature = "bundled-sqlcipher")
@ -66,7 +66,7 @@ fn main() {
)))] )))]
panic!("The runtime test should not run this branch, which has not compiled any logic.") panic!("The runtime test should not run this branch, which has not compiled any logic.")
} else { } else {
build_linked::main(&out_dir, &out_path) build_linked::main(&out_dir, &out_path);
} }
} }
@ -168,7 +168,7 @@ mod build_bundled {
panic!( panic!(
"OpenSSL include directory does not exist: {}", "OpenSSL include directory does not exist: {}",
inc_dir.to_string_lossy() inc_dir.to_string_lossy()
) );
} }
use_openssl = true; use_openssl = true;
@ -429,19 +429,17 @@ mod build_linked {
} }
// See if pkg-config can do everything for us. // See if pkg-config can do everything for us.
match pkg_config::Config::new() if let Ok(mut lib) = pkg_config::Config::new()
.print_system_libs(false) .print_system_libs(false)
.probe(link_lib) .probe(link_lib)
{ {
Ok(mut lib) => {
if let Some(mut header) = lib.include_paths.pop() { if let Some(mut header) = lib.include_paths.pop() {
header.push("sqlite3.h"); header.push("sqlite3.h");
HeaderLocation::FromPath(header.to_string_lossy().into()) HeaderLocation::FromPath(header.to_string_lossy().into())
} else { } else {
HeaderLocation::Wrapper HeaderLocation::Wrapper
} }
} } else {
Err(_) => {
// No env var set and pkg-config couldn't help; just output the link-lib // No env var set and pkg-config couldn't help; just output the link-lib
// request and hope that the library exists on the system paths. We used to // request and hope that the library exists on the system paths. We used to
// output /usr/lib explicitly, but that can introduce other linking problems; // output /usr/lib explicitly, but that can introduce other linking problems;
@ -450,7 +448,6 @@ mod build_linked {
HeaderLocation::Wrapper HeaderLocation::Wrapper
} }
} }
}
fn try_vcpkg() -> Option<HeaderLocation> { fn try_vcpkg() -> Option<HeaderLocation> {
if cfg!(feature = "vcpkg") && is_compiler("msvc") { if cfg!(feature = "vcpkg") && is_compiler("msvc") {

View File

@ -63,6 +63,7 @@ pub struct Error {
} }
impl Error { impl Error {
#[must_use]
pub fn new(result_code: c_int) -> Error { pub fn new(result_code: c_int) -> Error {
let code = match result_code & 0xff { let code = match result_code & 0xff {
super::SQLITE_INTERNAL => ErrorCode::InternalMalfunction, super::SQLITE_INTERNAL => ErrorCode::InternalMalfunction,
@ -192,6 +193,7 @@ const SQLITE_WARNING_AUTOINDEX: c_int = SQLITE_WARNING | (1 << 8);
const SQLITE_AUTH_USER: c_int = super::SQLITE_AUTH | (1 << 8); const SQLITE_AUTH_USER: c_int = super::SQLITE_AUTH | (1 << 8);
#[must_use]
pub fn code_to_str(code: c_int) -> &'static str { pub fn code_to_str(code: c_int) -> &'static str {
match code { match code {
super::SQLITE_OK => "Successful result", super::SQLITE_OK => "Successful result",

View File

@ -12,12 +12,14 @@ use std::mem;
mod error; mod error;
#[must_use]
pub fn SQLITE_STATIC() -> sqlite3_destructor_type { pub fn SQLITE_STATIC() -> sqlite3_destructor_type {
None None
} }
#[must_use]
pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type { pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type {
Some(unsafe { mem::transmute(-1isize) }) Some(unsafe { mem::transmute(-1_isize) })
} }
/// Run-Time Limit Categories /// Run-Time Limit Categories

View File

@ -107,7 +107,7 @@ impl Connection {
let restore = Backup::new_with_names(&src, DatabaseName::Main, self, name)?; let restore = Backup::new_with_names(&src, DatabaseName::Main, self, name)?;
let mut r = More; let mut r = More;
let mut busy_count = 0i32; let mut busy_count = 0_i32;
'restore_loop: while r == More || r == Busy { 'restore_loop: while r == More || r == Busy {
r = restore.step(100)?; r = restore.step(100)?;
if let Some(ref f) = progress { if let Some(ref f) = progress {
@ -231,6 +231,7 @@ impl Backup<'_, '_> {
/// Gets the progress of the backup as of the last call to /// Gets the progress of the backup as of the last call to
/// [`step`](Backup::step). /// [`step`](Backup::step).
#[inline] #[inline]
#[must_use]
pub fn progress(&self) -> Progress { pub fn progress(&self) -> Progress {
unsafe { unsafe {
Progress { Progress {
@ -296,7 +297,7 @@ impl Backup<'_, '_> {
loop { loop {
let r = self.step(pages_per_step)?; let r = self.step(pages_per_step)?;
if let Some(progress) = progress { if let Some(progress) = progress {
progress(self.progress()) progress(self.progress());
} }
match r { match r {
More | Busy | Locked => thread::sleep(pause_between_pages), More | Busy | Locked => thread::sleep(pause_between_pages),

View File

@ -265,12 +265,14 @@ impl Blob<'_> {
/// Return the size in bytes of the BLOB. /// Return the size in bytes of the BLOB.
#[inline] #[inline]
#[must_use]
pub fn size(&self) -> i32 { pub fn size(&self) -> i32 {
unsafe { ffi::sqlite3_blob_bytes(self.blob) } unsafe { ffi::sqlite3_blob_bytes(self.blob) }
} }
/// Return the current size in bytes of the BLOB. /// Return the current size in bytes of the BLOB.
#[inline] #[inline]
#[must_use]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
use std::convert::TryInto; use std::convert::TryInto;
self.size().try_into().unwrap() self.size().try_into().unwrap()
@ -278,6 +280,7 @@ impl Blob<'_> {
/// Return true if the BLOB is empty. /// Return true if the BLOB is empty.
#[inline] #[inline]
#[must_use]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.size() == 0 self.size() == 0
} }

View File

@ -46,13 +46,13 @@ impl Connection {
/// can set the capacity manually using this method. /// can set the capacity manually using this method.
#[inline] #[inline]
pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) { pub fn set_prepared_statement_cache_capacity(&self, capacity: usize) {
self.cache.set_capacity(capacity) self.cache.set_capacity(capacity);
} }
/// Remove/finalize all prepared statements currently in the cache. /// Remove/finalize all prepared statements currently in the cache.
#[inline] #[inline]
pub fn flush_prepared_statement_cache(&self) { pub fn flush_prepared_statement_cache(&self) {
self.cache.flush() self.cache.flush();
} }
} }
@ -122,7 +122,7 @@ impl StatementCache {
#[inline] #[inline]
fn set_capacity(&self, capacity: usize) { fn set_capacity(&self, capacity: usize) {
self.0.borrow_mut().set_capacity(capacity) self.0.borrow_mut().set_capacity(capacity);
} }
// Search the cache for a prepared-statement object that implements `sql`. // Search the cache for a prepared-statement object that implements `sql`.
@ -169,7 +169,7 @@ impl StatementCache {
#[inline] #[inline]
fn flush(&self) { fn flush(&self) {
let mut cache = self.0.borrow_mut(); let mut cache = self.0.borrow_mut();
cache.clear() cache.clear();
} }
} }

View File

@ -12,12 +12,14 @@ pub struct Column<'stmt> {
impl Column<'_> { impl Column<'_> {
/// Returns the name of the column. /// Returns the name of the column.
#[inline] #[inline]
#[must_use]
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
self.name self.name
} }
/// Returns the type of the column (`None` for expression). /// Returns the type of the column (`None` for expression).
#[inline] #[inline]
#[must_use]
pub fn decl_type(&self) -> Option<&str> { pub fn decl_type(&self) -> Option<&str> {
self.decl_type self.decl_type
} }

View File

@ -64,17 +64,17 @@ pub enum DbConfig {
impl Connection { impl Connection {
/// Returns the current value of a `config`. /// Returns the current value of a `config`.
/// ///
/// - SQLITE_DBCONFIG_ENABLE_FKEY: return `false` or `true` to indicate /// - `SQLITE_DBCONFIG_ENABLE_FKEY`: return `false` or `true` to indicate
/// whether FK enforcement is off or on /// whether FK enforcement is off or on
/// - SQLITE_DBCONFIG_ENABLE_TRIGGER: return `false` or `true` to indicate /// - `SQLITE_DBCONFIG_ENABLE_TRIGGER`: return `false` or `true` to indicate
/// whether triggers are disabled or enabled /// whether triggers are disabled or enabled
/// - SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: return `false` or `true` to /// - `SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER`: return `false` or `true` to
/// indicate whether fts3_tokenizer are disabled or enabled /// indicate whether `fts3_tokenizer` are disabled or enabled
/// - SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: return `false` to indicate /// - `SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE`: return `false` to indicate
/// checkpoints-on-close are not disabled or `true` if they are /// checkpoints-on-close are not disabled or `true` if they are
/// - SQLITE_DBCONFIG_ENABLE_QPSG: return `false` or `true` to indicate /// - `SQLITE_DBCONFIG_ENABLE_QPSG`: return `false` or `true` to indicate
/// whether the QPSG is disabled or enabled /// whether the QPSG is disabled or enabled
/// - SQLITE_DBCONFIG_TRIGGER_EQP: return `false` to indicate /// - `SQLITE_DBCONFIG_TRIGGER_EQP`: return `false` to indicate
/// output-for-trigger are not disabled or `true` if it is /// output-for-trigger are not disabled or `true` if it is
#[inline] #[inline]
pub fn db_config(&self, config: DbConfig) -> Result<bool> { pub fn db_config(&self, config: DbConfig) -> Result<bool> {
@ -93,17 +93,17 @@ impl Connection {
/// Make configuration changes to a database connection /// Make configuration changes to a database connection
/// ///
/// - SQLITE_DBCONFIG_ENABLE_FKEY: `false` to disable FK enforcement, `true` /// - `SQLITE_DBCONFIG_ENABLE_FKEY`: `false` to disable FK enforcement, `true`
/// to enable FK enforcement /// to enable FK enforcement
/// - SQLITE_DBCONFIG_ENABLE_TRIGGER: `false` to disable triggers, `true` to /// - `SQLITE_DBCONFIG_ENABLE_TRIGGER`: `false` to disable triggers, `true` to
/// enable triggers /// enable triggers
/// - SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: `false` to disable /// - `SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER`: `false` to disable
/// fts3_tokenizer(), `true` to enable fts3_tokenizer() /// `fts3_tokenizer()`, `true` to enable `fts3_tokenizer()`
/// - SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: `false` (the default) to enable /// - `SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE`: `false` (the default) to enable
/// checkpoints-on-close, `true` to disable them /// checkpoints-on-close, `true` to disable them
/// - SQLITE_DBCONFIG_ENABLE_QPSG: `false` to disable the QPSG, `true` to /// - `SQLITE_DBCONFIG_ENABLE_QPSG`: `false` to disable the QPSG, `true` to
/// enable QPSG /// enable QPSG
/// - SQLITE_DBCONFIG_TRIGGER_EQP: `false` to disable output for trigger /// - `SQLITE_DBCONFIG_TRIGGER_EQP`: `false` to disable output for trigger
/// programs, `true` to enable it /// programs, `true` to enable it
#[inline] #[inline]
pub fn set_db_config(&self, config: DbConfig, new_val: bool) -> Result<bool> { pub fn set_db_config(&self, config: DbConfig, new_val: bool) -> Result<bool> {

View File

@ -58,7 +58,7 @@ pub(super) unsafe fn set_result(ctx: *mut sqlite3_context, result: &ToSqlOutput<
if length > c_int::max_value() as usize { if length > c_int::max_value() as usize {
ffi::sqlite3_result_error_toobig(ctx); ffi::sqlite3_result_error_toobig(ctx);
} else if length == 0 { } else if length == 0 {
ffi::sqlite3_result_zeroblob(ctx, 0) ffi::sqlite3_result_zeroblob(ctx, 0);
} else { } else {
ffi::sqlite3_result_blob( ffi::sqlite3_result_blob(
ctx, ctx,

View File

@ -84,21 +84,18 @@ unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) {
ffi::SQLITE_CONSTRAINT ffi::SQLITE_CONSTRAINT
} }
match *err { if let Error::SqliteFailure(ref err, ref s) = *err {
Error::SqliteFailure(ref err, ref s) => {
ffi::sqlite3_result_error_code(ctx, err.extended_code); ffi::sqlite3_result_error_code(ctx, err.extended_code);
if let Some(Ok(cstr)) = s.as_ref().map(|s| str_to_cstring(s)) { if let Some(Ok(cstr)) = s.as_ref().map(|s| str_to_cstring(s)) {
ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1); ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
} }
} } else {
_ => {
ffi::sqlite3_result_error_code(ctx, constraint_error_code()); ffi::sqlite3_result_error_code(ctx, constraint_error_code());
if let Ok(cstr) = str_to_cstring(&err.to_string()) { if let Ok(cstr) = str_to_cstring(&err.to_string()) {
ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1); ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
} }
} }
} }
}
unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) { unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
drop(Box::from_raw(p.cast::<T>())); drop(Box::from_raw(p.cast::<T>()));
@ -114,12 +111,14 @@ pub struct Context<'a> {
impl Context<'_> { impl Context<'_> {
/// Returns the number of arguments to the function. /// Returns the number of arguments to the function.
#[inline] #[inline]
#[must_use]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.args.len() self.args.len()
} }
/// Returns `true` when there is no argument. /// Returns `true` when there is no argument.
#[inline] #[inline]
#[must_use]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.args.is_empty() self.args.is_empty()
} }
@ -157,6 +156,7 @@ impl Context<'_> {
/// Will panic if `idx` is greater than or equal to /// Will panic if `idx` is greater than or equal to
/// [`self.len()`](Context::len). /// [`self.len()`](Context::len).
#[inline] #[inline]
#[must_use]
pub fn get_raw(&self, idx: usize) -> ValueRef<'_> { pub fn get_raw(&self, idx: usize) -> ValueRef<'_> {
let arg = self.args[idx]; let arg = self.args[idx];
unsafe { ValueRef::from_value(arg) } unsafe { ValueRef::from_value(arg) }
@ -200,7 +200,7 @@ impl Context<'_> {
arg, arg,
raw.cast(), raw.cast(),
Some(free_boxed_value::<AuxInner>), Some(free_boxed_value::<AuxInner>),
) );
}; };
Ok(orig) Ok(orig)
} }
@ -287,7 +287,7 @@ where
fn finalize(&self, _: &mut Context<'_>, _: Option<A>) -> Result<T>; fn finalize(&self, _: &mut Context<'_>, _: Option<A>) -> Result<T>;
} }
/// WindowAggregate is the callback interface for /// `WindowAggregate` is the callback interface for
/// user-defined aggregate window function. /// user-defined aggregate window function.
#[cfg(feature = "window")] #[cfg(feature = "window")]
#[cfg_attr(docsrs, doc(cfg(feature = "window")))] #[cfg_attr(docsrs, doc(cfg(feature = "window")))]
@ -617,12 +617,11 @@ unsafe extern "C" fn call_boxed_step<A, D, T>(
D: Aggregate<A, T>, D: Aggregate<A, T>,
T: ToSql, T: ToSql,
{ {
let pac = match aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) { let pac = if let Some(pac) = aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) {
Some(pac) => pac, pac
None => { } else {
ffi::sqlite3_result_error_nomem(ctx); ffi::sqlite3_result_error_nomem(ctx);
return; return;
}
}; };
let r = catch_unwind(|| { let r = catch_unwind(|| {
@ -665,12 +664,11 @@ unsafe extern "C" fn call_boxed_inverse<A, W, T>(
W: WindowAggregate<A, T>, W: WindowAggregate<A, T>,
T: ToSql, T: ToSql,
{ {
let pac = match aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) { let pac = if let Some(pac) = aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) {
Some(pac) => pac, pac
None => { } else {
ffi::sqlite3_result_error_nomem(ctx); ffi::sqlite3_result_error_nomem(ctx);
return; return;
}
}; };
let r = catch_unwind(|| { let r = catch_unwind(|| {

View File

@ -367,8 +367,8 @@ impl Connection {
/// ///
/// The callback parameters are: /// The callback parameters are:
/// ///
/// - the type of database update (SQLITE_INSERT, SQLITE_UPDATE or /// - the type of database update (`SQLITE_INSERT`, `SQLITE_UPDATE` or
/// SQLITE_DELETE), /// `SQLITE_DELETE`),
/// - the name of the database ("main", "temp", ...), /// - the name of the database ("main", "temp", ...),
/// - the name of the table that is updated, /// - the name of the table that is updated,
/// - the ROWID of the row that is updated. /// - the ROWID of the row that is updated.
@ -402,7 +402,7 @@ impl Connection {
where where
F: for<'r> FnMut(AuthContext<'r>) -> Authorization + Send + RefUnwindSafe + 'static, F: for<'r> FnMut(AuthContext<'r>) -> Authorization + Send + RefUnwindSafe + 'static,
{ {
self.db.borrow_mut().authorizer(hook) self.db.borrow_mut().authorizer(hook);
} }
} }
@ -577,8 +577,7 @@ impl InnerConnection {
} }
} }
match handler { if let Some(handler) = handler {
Some(handler) => {
let boxed_handler = Box::new(handler); let boxed_handler = Box::new(handler);
unsafe { unsafe {
ffi::sqlite3_progress_handler( ffi::sqlite3_progress_handler(
@ -586,14 +585,12 @@ impl InnerConnection {
num_ops, num_ops,
Some(call_boxed_closure::<F>), Some(call_boxed_closure::<F>),
&*boxed_handler as *const F as *mut _, &*boxed_handler as *const F as *mut _,
) );
} }
self.progress_handler = Some(boxed_handler); self.progress_handler = Some(boxed_handler);
} } else {
_ => {
unsafe { ffi::sqlite3_progress_handler(self.db(), num_ops, None, ptr::null_mut()) } unsafe { ffi::sqlite3_progress_handler(self.db(), num_ops, None, ptr::null_mut()) }
self.progress_handler = None; self.progress_handler = None;
}
}; };
} }
@ -629,8 +626,7 @@ impl InnerConnection {
let boxed_hook: *mut F = p_arg.cast::<F>(); let boxed_hook: *mut F = p_arg.cast::<F>();
(*boxed_hook)(auth_ctx) (*boxed_hook)(auth_ctx)
}) })
.map(Authorization::into_raw) .map_or_else(|_| ffi::SQLITE_ERROR, Authorization::into_raw)
.unwrap_or_else(|_| ffi::SQLITE_ERROR)
} }
let callback_fn = authorizer let callback_fn = authorizer
@ -644,8 +640,7 @@ impl InnerConnection {
callback_fn, callback_fn,
boxed_authorizer boxed_authorizer
.as_ref() .as_ref()
.map(|f| &**f as *const F as *mut _) .map_or_else(ptr::null_mut, |f| &**f as *const F as *mut _),
.unwrap_or_else(ptr::null_mut),
) )
} { } {
ffi::SQLITE_OK => { ffi::SQLITE_OK => {

View File

@ -450,7 +450,7 @@ impl Connection {
/// ///
/// # Failure /// # Failure
/// ///
/// Will return `Err` if vfs` cannot be converted to a C-compatible /// Will return `Err` if `vfs` cannot be converted to a C-compatible
/// string or if the underlying SQLite open call fails. /// string or if the underlying SQLite open call fails.
#[inline] #[inline]
pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Connection> { pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Connection> {

View File

@ -99,7 +99,7 @@ use sealed::Sealed;
/// ///
/// - As a slice of `&[(&str, &dyn ToSql)]`. This is what essentially all of /// - As a slice of `&[(&str, &dyn ToSql)]`. This is what essentially all of
/// these boil down to in the end, conceptually at least. In theory you can /// these boil down to in the end, conceptually at least. In theory you can
/// pass this as `stmt. /// pass this as `stmt`.
/// ///
/// - As array references, similar to the positional params. This looks like /// - As array references, similar to the positional params. This looks like
/// `thing.query(&[(":foo", &1i32), (":bar", &2i32)])` or /// `thing.query(&[(":foo", &1i32), (":bar", &2i32)])` or

View File

@ -143,7 +143,7 @@ impl Sql {
if ch == quote { if ch == quote {
self.buf.push(ch); self.buf.push(ch);
} }
self.buf.push(ch) self.buf.push(ch);
} }
self.buf.push(quote); self.buf.push(quote);
} }

View File

@ -1,5 +1,6 @@
use super::ffi; use super::ffi;
use super::StatementStatus; use super::StatementStatus;
use crate::util::ParamIndexCache;
#[cfg(feature = "modern_sqlite")] #[cfg(feature = "modern_sqlite")]
use crate::util::SqliteMallocString; use crate::util::SqliteMallocString;
use std::ffi::CStr; use std::ffi::CStr;
@ -13,7 +14,7 @@ pub struct RawStatement {
ptr: *mut ffi::sqlite3_stmt, ptr: *mut ffi::sqlite3_stmt,
tail: usize, tail: usize,
// Cached indices of named parameters, computed on the fly. // Cached indices of named parameters, computed on the fly.
cache: crate::util::ParamIndexCache, cache: ParamIndexCache,
// Cached SQL (trimmed) that we use as the key when we're in the statement // Cached SQL (trimmed) that we use as the key when we're in the statement
// cache. This is None for statements which didn't come from the statement // cache. This is None for statements which didn't come from the statement
// cache. // cache.
@ -33,7 +34,7 @@ impl RawStatement {
RawStatement { RawStatement {
ptr: stmt, ptr: stmt,
tail, tail,
cache: Default::default(), cache: ParamIndexCache::default(),
statement_cache_key: None, statement_cache_key: None,
} }
} }

View File

@ -80,6 +80,7 @@ impl<'stmt> Rows<'stmt> {
} }
/// Give access to the underlying statement /// Give access to the underlying statement
#[must_use]
pub fn as_ref(&self) -> Option<&Statement<'stmt>> { pub fn as_ref(&self) -> Option<&Statement<'stmt>> {
self.stmt self.stmt
} }
@ -187,7 +188,7 @@ where
/// `FallibleStreamingIterator` differs from the standard library's `Iterator` /// `FallibleStreamingIterator` differs from the standard library's `Iterator`
/// in two ways: /// in two ways:
/// * each call to `next` (sqlite3_step) can fail. /// * each call to `next` (`sqlite3_step`) can fail.
/// * returned `Row` is valid until `next` is called again or `Statement` is /// * returned `Row` is valid until `next` is called again or `Statement` is
/// reset or finalized. /// reset or finalized.
/// ///
@ -209,8 +210,8 @@ impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
#[inline] #[inline]
fn advance(&mut self) -> Result<()> { fn advance(&mut self) -> Result<()> {
match self.stmt { if let Some(stmt) = self.stmt {
Some(stmt) => match stmt.step() { match stmt.step() {
Ok(true) => { Ok(true) => {
self.row = Some(Row { stmt }); self.row = Some(Row { stmt });
Ok(()) Ok(())
@ -225,13 +226,12 @@ impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
self.row = None; self.row = None;
Err(e) Err(e)
} }
}, }
None => { } else {
self.row = None; self.row = None;
Ok(()) Ok(())
} }
} }
}
#[inline] #[inline]
fn get(&self) -> Option<&Row<'stmt>> { fn get(&self) -> Option<&Row<'stmt>> {

View File

@ -31,19 +31,18 @@ pub unsafe fn config_log(callback: Option<fn(c_int, &str)>) -> Result<()> {
let callback: fn(c_int, &str) = unsafe { mem::transmute(p_arg) }; let callback: fn(c_int, &str) = unsafe { mem::transmute(p_arg) };
let s = String::from_utf8_lossy(c_slice); let s = String::from_utf8_lossy(c_slice);
let _ = catch_unwind(|| callback(err, &s)); drop(catch_unwind(|| callback(err, &s)));
} }
let rc = match callback { let rc = if let Some(f) = callback {
Some(f) => ffi::sqlite3_config( ffi::sqlite3_config(
ffi::SQLITE_CONFIG_LOG, ffi::SQLITE_CONFIG_LOG,
log_callback as extern "C" fn(_, _, _), log_callback as extern "C" fn(_, _, _),
f as *mut c_void, f as *mut c_void,
), )
None => { } else {
let nullptr: *mut c_void = ptr::null_mut(); let nullptr: *mut c_void = ptr::null_mut();
ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, nullptr, nullptr) ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, nullptr, nullptr)
}
}; };
if rc == ffi::SQLITE_OK { if rc == ffi::SQLITE_OK {
@ -75,7 +74,7 @@ impl Connection {
let trace_fn: fn(&str) = mem::transmute(p_arg); let trace_fn: fn(&str) = mem::transmute(p_arg);
let c_slice = CStr::from_ptr(z_sql).to_bytes(); let c_slice = CStr::from_ptr(z_sql).to_bytes();
let s = String::from_utf8_lossy(c_slice); let s = String::from_utf8_lossy(c_slice);
let _ = catch_unwind(|| trace_fn(&s)); drop(catch_unwind(|| trace_fn(&s)));
} }
let c = self.db.borrow_mut(); let c = self.db.borrow_mut();
@ -109,7 +108,7 @@ impl Connection {
nanoseconds / NANOS_PER_SEC, nanoseconds / NANOS_PER_SEC,
(nanoseconds % NANOS_PER_SEC) as u32, (nanoseconds % NANOS_PER_SEC) as u32,
); );
let _ = catch_unwind(|| profile_fn(&s, duration)); drop(catch_unwind(|| profile_fn(&s, duration)));
} }
let c = self.db.borrow_mut(); let c = self.db.borrow_mut();

View File

@ -169,6 +169,7 @@ impl Transaction<'_> {
/// Get the current setting for what happens to the transaction when it is /// Get the current setting for what happens to the transaction when it is
/// dropped. /// dropped.
#[inline] #[inline]
#[must_use]
pub fn drop_behavior(&self) -> DropBehavior { pub fn drop_behavior(&self) -> DropBehavior {
self.drop_behavior self.drop_behavior
} }
@ -177,7 +178,7 @@ impl Transaction<'_> {
/// dropped. /// dropped.
#[inline] #[inline]
pub fn set_drop_behavior(&mut self, drop_behavior: DropBehavior) { pub fn set_drop_behavior(&mut self, drop_behavior: DropBehavior) {
self.drop_behavior = drop_behavior self.drop_behavior = drop_behavior;
} }
/// A convenience method which consumes and commits a transaction. /// A convenience method which consumes and commits a transaction.
@ -296,6 +297,7 @@ impl Savepoint<'_> {
/// Get the current setting for what happens to the savepoint when it is /// Get the current setting for what happens to the savepoint when it is
/// dropped. /// dropped.
#[inline] #[inline]
#[must_use]
pub fn drop_behavior(&self) -> DropBehavior { pub fn drop_behavior(&self) -> DropBehavior {
self.drop_behavior self.drop_behavior
} }
@ -304,7 +306,7 @@ impl Savepoint<'_> {
/// dropped. /// dropped.
#[inline] #[inline]
pub fn set_drop_behavior(&mut self, drop_behavior: DropBehavior) { pub fn set_drop_behavior(&mut self, drop_behavior: DropBehavior) {
self.drop_behavior = drop_behavior self.drop_behavior = drop_behavior;
} }
/// A convenience method which consumes and commits a savepoint. /// A convenience method which consumes and commits a savepoint.

View File

@ -177,7 +177,7 @@ impl FromSql for std::sync::Arc<str> {
impl FromSql for Vec<u8> { impl FromSql for Vec<u8> {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_blob().map(|b| b.to_vec()) value.as_blob().map(<[u8]>::to_vec)
} }
} }
@ -198,7 +198,7 @@ impl FromSql for i128 {
#[inline] #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> { fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
let bytes = <[u8; 16]>::column_result(value)?; let bytes = <[u8; 16]>::column_result(value)?;
Ok(i128::from_be_bytes(bytes) ^ (1i128 << 127)) Ok(i128::from_be_bytes(bytes) ^ (1_i128 << 127))
} }
} }

View File

@ -47,7 +47,7 @@ impl FromSql for OffsetDateTime {
len if len <= 19 => { len if len <= 19 => {
// TODO YYYY-MM-DDTHH:MM:SS // TODO YYYY-MM-DDTHH:MM:SS
PrimitiveDateTime::parse(s, &PRIMITIVE_SHORT_DATE_TIME_FORMAT) PrimitiveDateTime::parse(s, &PRIMITIVE_SHORT_DATE_TIME_FORMAT)
.map(|d| d.assume_utc()) .map(PrimitiveDateTime::assume_utc)
} }
_ if s.as_bytes()[19] == b':' => { _ if s.as_bytes()[19] == b':' => {
// legacy // legacy
@ -56,7 +56,7 @@ impl FromSql for OffsetDateTime {
_ if s.as_bytes()[19] == b'.' => OffsetDateTime::parse(s, &OFFSET_DATE_TIME_FORMAT) _ if s.as_bytes()[19] == b'.' => OffsetDateTime::parse(s, &OFFSET_DATE_TIME_FORMAT)
.or_else(|err| { .or_else(|err| {
PrimitiveDateTime::parse(s, &PRIMITIVE_DATE_TIME_FORMAT) PrimitiveDateTime::parse(s, &PRIMITIVE_DATE_TIME_FORMAT)
.map(|d| d.assume_utc()) .map(PrimitiveDateTime::assume_utc)
.map_err(|_| err) .map_err(|_| err)
}), }),
_ => OffsetDateTime::parse(s, &OFFSET_SHORT_DATE_TIME_FORMAT), _ => OffsetDateTime::parse(s, &OFFSET_SHORT_DATE_TIME_FORMAT),

View File

@ -47,7 +47,7 @@ impl From<i128> for Value {
fn from(i: i128) -> Value { fn from(i: i128) -> Value {
// We store these biased (e.g. with the most significant bit flipped) // We store these biased (e.g. with the most significant bit flipped)
// so that comparisons with negative numbers work properly. // so that comparisons with negative numbers work properly.
Value::Blob(i128::to_be_bytes(i ^ (1i128 << 127)).to_vec()) Value::Blob(i128::to_be_bytes(i ^ (1_i128 << 127)).to_vec())
} }
} }
@ -129,6 +129,7 @@ where
impl Value { impl Value {
/// Returns SQLite fundamental datatype. /// Returns SQLite fundamental datatype.
#[inline] #[inline]
#[must_use]
pub fn data_type(&self) -> Type { pub fn data_type(&self) -> Type {
match *self { match *self {
Value::Null => Type::Null, Value::Null => Type::Null,

View File

@ -22,6 +22,7 @@ pub enum ValueRef<'a> {
impl ValueRef<'_> { impl ValueRef<'_> {
/// Returns SQLite fundamental datatype. /// Returns SQLite fundamental datatype.
#[inline] #[inline]
#[must_use]
pub fn data_type(&self) -> Type { pub fn data_type(&self) -> Type {
match *self { match *self {
ValueRef::Null => Type::Null, ValueRef::Null => Type::Null,

View File

@ -45,7 +45,7 @@ unsafe extern "C" fn unlock_notify_cb(ap_arg: *mut *mut c_void, n_arg: c_int) {
use std::slice::from_raw_parts; use std::slice::from_raw_parts;
let args = from_raw_parts(ap_arg as *const &UnlockNotification, n_arg as usize); let args = from_raw_parts(ap_arg as *const &UnlockNotification, n_arg as usize);
for un in args { for un in args {
let _ = catch_unwind(std::panic::AssertUnwindSafe(|| un.fired())); drop(catch_unwind(std::panic::AssertUnwindSafe(|| un.fired())));
} }
} }

View File

@ -1,7 +1,7 @@
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use std::ffi::{CStr, CString, NulError}; use std::ffi::{CStr, CString, NulError};
/// Similar to std::ffi::CString, but avoids heap allocating if the string is /// Similar to `std::ffi::CString`, but avoids heap allocating if the string is
/// small enough. Also guarantees it's input is UTF-8 -- used for cases where we /// small enough. Also guarantees it's input is UTF-8 -- used for cases where we
/// need to pass a NUL-terminated string to SQLite, and we have a `&str`. /// need to pass a NUL-terminated string to SQLite, and we have a `&str`.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
@ -10,7 +10,7 @@ pub(crate) struct SmallCString(smallvec::SmallVec<[u8; 16]>);
impl SmallCString { impl SmallCString {
#[inline] #[inline]
pub fn new(s: &str) -> Result<Self, NulError> { pub fn new(s: &str) -> Result<Self, NulError> {
if s.as_bytes().contains(&0u8) { if s.as_bytes().contains(&0_u8) {
return Err(Self::fabricate_nul_error(s)); return Err(Self::fabricate_nul_error(s));
} }
let mut buf = SmallVec::with_capacity(s.len() + 1); let mut buf = SmallVec::with_capacity(s.len() + 1);
@ -31,7 +31,7 @@ impl SmallCString {
/// Get the bytes not including the NUL terminator. E.g. the bytes which /// Get the bytes not including the NUL terminator. E.g. the bytes which
/// make up our `str`: /// make up our `str`:
/// - `SmallCString::new("foo").as_bytes_without_nul() == b"foo"` /// - `SmallCString::new("foo").as_bytes_without_nul() == b"foo"`
/// - `SmallCString::new("foo").as_bytes_with_nul() == b"foo\0" /// - `SmallCString::new("foo").as_bytes_with_nul() == b"foo\0"`
#[inline] #[inline]
pub fn as_bytes_without_nul(&self) -> &[u8] { pub fn as_bytes_without_nul(&self) -> &[u8] {
self.debug_checks(); self.debug_checks();

View File

@ -38,7 +38,7 @@ pub(crate) struct SqliteMallocString {
impl SqliteMallocString { impl SqliteMallocString {
/// SAFETY: Caller must be certain that `m` a nul-terminated c string /// SAFETY: Caller must be certain that `m` a nul-terminated c string
/// allocated by sqlite3_malloc, and that SQLite expects us to free it! /// allocated by `sqlite3_malloc`, and that SQLite expects us to free it!
#[inline] #[inline]
pub(crate) unsafe fn from_raw_nonnull(ptr: NonNull<c_char>) -> Self { pub(crate) unsafe fn from_raw_nonnull(ptr: NonNull<c_char>) -> Self {
Self { Self {
@ -48,7 +48,7 @@ impl SqliteMallocString {
} }
/// SAFETY: Caller must be certain that `m` a nul-terminated c string /// SAFETY: Caller must be certain that `m` a nul-terminated c string
/// allocated by sqlite3_malloc, and that SQLite expects us to free it! /// allocated by `sqlite3_malloc`, and that SQLite expects us to free it!
#[inline] #[inline]
pub(crate) unsafe fn from_raw(ptr: *mut c_char) -> Option<Self> { pub(crate) unsafe fn from_raw(ptr: *mut c_char) -> Option<Self> {
NonNull::new(ptr).map(|p| Self::from_raw_nonnull(p)) NonNull::new(ptr).map(|p| Self::from_raw_nonnull(p))
@ -95,13 +95,13 @@ impl SqliteMallocString {
/// If `s` contains internal NULs, we'll replace them with /// If `s` contains internal NULs, we'll replace them with
/// `NUL_REPLACE_CHAR`. /// `NUL_REPLACE_CHAR`.
/// ///
/// Except for debug_asserts which may trigger during testing, this function /// Except for `debug_assert`s which may trigger during testing, this function
/// never panics. If we hit integer overflow or the allocation fails, we /// never panics. If we hit integer overflow or the allocation fails, we
/// call `handle_alloc_error` which aborts the program after calling a /// call `handle_alloc_error` which aborts the program after calling a
/// global hook. /// global hook.
/// ///
/// This means it's safe to use in extern "C" functions even outside of /// This means it's safe to use in extern "C" functions even outside of
/// catch_unwind. /// `catch_unwind`.
pub(crate) fn from_str(s: &str) -> Self { pub(crate) fn from_str(s: &str) -> Self {
use std::convert::TryFrom; use std::convert::TryFrom;
let s = if s.as_bytes().contains(&0) { let s = if s.as_bytes().contains(&0) {

View File

@ -6,6 +6,7 @@ use std::ffi::CStr;
/// ///
/// See [`sqlite3_libversion_number()`](https://www.sqlite.org/c3ref/libversion.html). /// See [`sqlite3_libversion_number()`](https://www.sqlite.org/c3ref/libversion.html).
#[inline] #[inline]
#[must_use]
pub fn version_number() -> i32 { pub fn version_number() -> i32 {
unsafe { ffi::sqlite3_libversion_number() } unsafe { ffi::sqlite3_libversion_number() }
} }
@ -14,6 +15,7 @@ pub fn version_number() -> i32 {
/// ///
/// See [`sqlite3_libversion()`](https://www.sqlite.org/c3ref/libversion.html). /// See [`sqlite3_libversion()`](https://www.sqlite.org/c3ref/libversion.html).
#[inline] #[inline]
#[must_use]
pub fn version() -> &'static str { pub fn version() -> &'static str {
let cstr = unsafe { CStr::from_ptr(ffi::sqlite3_libversion()) }; let cstr = unsafe { CStr::from_ptr(ffi::sqlite3_libversion()) };
cstr.to_str() cstr.to_str()

View File

@ -44,7 +44,7 @@ use crate::{Connection, Result};
pub(crate) const ARRAY_TYPE: *const c_char = (b"rarray\0" as *const u8).cast::<c_char>(); pub(crate) const ARRAY_TYPE: *const c_char = (b"rarray\0" as *const u8).cast::<c_char>();
pub(crate) unsafe extern "C" fn free_array(p: *mut c_void) { pub(crate) unsafe extern "C" fn free_array(p: *mut c_void) {
let _: Array = Rc::from_raw(p as *const Vec<Value>); drop(Rc::from_raw(p as *const Vec<Value>));
} }
/// Array parameter / pointer /// Array parameter / pointer
@ -106,11 +106,11 @@ unsafe impl<'vtab> VTab<'vtab> for ArrayTab {
} }
} }
if ptr_idx { if ptr_idx {
info.set_estimated_cost(1f64); info.set_estimated_cost(1_f64);
info.set_estimated_rows(100); info.set_estimated_rows(100);
info.set_idx_num(1); info.set_idx_num(1);
} else { } else {
info.set_estimated_cost(2_147_483_647f64); info.set_estimated_cost(2_147_483_647_f64);
info.set_estimated_rows(2_147_483_647); info.set_estimated_rows(2_147_483_647);
info.set_idx_num(0); info.set_idx_num(0);
} }

View File

@ -79,7 +79,7 @@ union ModuleZeroHack {
// structs are allowed to be zeroed. // structs are allowed to be zeroed.
const ZERO_MODULE: ffi::sqlite3_module = unsafe { const ZERO_MODULE: ffi::sqlite3_module = unsafe {
ModuleZeroHack { ModuleZeroHack {
bytes: [0u8; std::mem::size_of::<ffi::sqlite3_module>()], bytes: [0_u8; std::mem::size_of::<ffi::sqlite3_module>()],
} }
.module .module
}; };
@ -87,6 +87,7 @@ const ZERO_MODULE: ffi::sqlite3_module = unsafe {
/// Create a read-only virtual table implementation. /// Create a read-only virtual table implementation.
/// ///
/// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
#[must_use]
pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T> { pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab, T> {
// The xConnect and xCreate methods do the same thing, but they must be // The xConnect and xCreate methods do the same thing, but they must be
// different so that the virtual table is not an eponymous virtual table. // different so that the virtual table is not an eponymous virtual table.
@ -126,6 +127,7 @@ pub fn read_only_module<'vtab, T: CreateVTab<'vtab>>() -> &'static Module<'vtab,
/// Create an eponymous only virtual table implementation. /// Create an eponymous only virtual table implementation.
/// ///
/// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations). /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
#[must_use]
pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T> { pub fn eponymous_only_module<'vtab, T: VTab<'vtab>>() -> &'static Module<'vtab, T> {
// A virtual table is eponymous if its xCreate method is the exact same function // A virtual table is eponymous if its xCreate method is the exact same function
// as the xConnect method For eponymous-only virtual tables, the xCreate // as the xConnect method For eponymous-only virtual tables, the xCreate
@ -193,7 +195,7 @@ impl VTabConnection {
/// ///
/// # Safety /// # Safety
/// ///
/// The first item in a struct implementing VTab must be /// The first item in a struct implementing `VTab` must be
/// `rusqlite::sqlite3_vtab`, and the struct must be `#[repr(C)]`. /// `rusqlite::sqlite3_vtab`, and the struct must be `#[repr(C)]`.
/// ///
/// ```rust,ignore /// ```rust,ignore
@ -326,6 +328,7 @@ impl IndexInfo {
/// Record WHERE clause constraints. /// Record WHERE clause constraints.
#[inline] #[inline]
#[must_use]
pub fn constraints(&self) -> IndexConstraintIter<'_> { pub fn constraints(&self) -> IndexConstraintIter<'_> {
let constraints = let constraints =
unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) }; unsafe { slice::from_raw_parts((*self.0).aConstraint, (*self.0).nConstraint as usize) };
@ -336,6 +339,7 @@ impl IndexInfo {
/// Information about the ORDER BY clause. /// Information about the ORDER BY clause.
#[inline] #[inline]
#[must_use]
pub fn order_bys(&self) -> OrderByIter<'_> { pub fn order_bys(&self) -> OrderByIter<'_> {
let order_bys = let order_bys =
unsafe { slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize) }; unsafe { slice::from_raw_parts((*self.0).aOrderBy, (*self.0).nOrderBy as usize) };
@ -346,6 +350,7 @@ impl IndexInfo {
/// Number of terms in the ORDER BY clause /// Number of terms in the ORDER BY clause
#[inline] #[inline]
#[must_use]
pub fn num_of_order_by(&self) -> usize { pub fn num_of_order_by(&self) -> usize {
unsafe { (*self.0).nOrderBy as usize } unsafe { (*self.0).nOrderBy as usize }
} }
@ -448,18 +453,21 @@ pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
impl IndexConstraint<'_> { impl IndexConstraint<'_> {
/// Column constrained. -1 for ROWID /// Column constrained. -1 for ROWID
#[inline] #[inline]
#[must_use]
pub fn column(&self) -> c_int { pub fn column(&self) -> c_int {
self.0.iColumn self.0.iColumn
} }
/// Constraint operator /// Constraint operator
#[inline] #[inline]
#[must_use]
pub fn operator(&self) -> IndexConstraintOp { pub fn operator(&self) -> IndexConstraintOp {
IndexConstraintOp::from(self.0.op) IndexConstraintOp::from(self.0.op)
} }
/// True if this constraint is usable /// True if this constraint is usable
#[inline] #[inline]
#[must_use]
pub fn is_usable(&self) -> bool { pub fn is_usable(&self) -> bool {
self.0.usable != 0 self.0.usable != 0
} }
@ -509,12 +517,14 @@ pub struct OrderBy<'a>(&'a ffi::sqlite3_index_info_sqlite3_index_orderby);
impl OrderBy<'_> { impl OrderBy<'_> {
/// Column number /// Column number
#[inline] #[inline]
#[must_use]
pub fn column(&self) -> c_int { pub fn column(&self) -> c_int {
self.0.iColumn self.0.iColumn
} }
/// True for DESC. False for ASC. /// True for DESC. False for ASC.
#[inline] #[inline]
#[must_use]
pub fn is_order_by_desc(&self) -> bool { pub fn is_order_by_desc(&self) -> bool {
self.0.desc != 0 self.0.desc != 0
} }
@ -581,12 +591,14 @@ pub struct Values<'a> {
impl Values<'_> { impl Values<'_> {
/// Returns the number of values. /// Returns the number of values.
#[inline] #[inline]
#[must_use]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.args.len() self.args.len()
} }
/// Returns `true` if there is no value. /// Returns `true` if there is no value.
#[inline] #[inline]
#[must_use]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.args.is_empty() self.args.is_empty()
} }
@ -629,6 +641,7 @@ impl Values<'_> {
/// Turns `Values` into an iterator. /// Turns `Values` into an iterator.
#[inline] #[inline]
#[must_use]
pub fn iter(&self) -> ValueIter<'_> { pub fn iter(&self) -> ValueIter<'_> {
ValueIter { ValueIter {
iter: self.args.iter(), iter: self.args.iter(),
@ -720,6 +733,7 @@ impl InnerConnection {
/// Escape double-quote (`"`) character occurrences by /// Escape double-quote (`"`) character occurrences by
/// doubling them (`""`). /// doubling them (`""`).
#[must_use]
pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> { pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
if identifier.contains('"') { if identifier.contains('"') {
// escape quote by doubling them // escape quote by doubling them
@ -729,6 +743,7 @@ pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
} }
} }
/// Dequote string /// Dequote string
#[must_use]
pub fn dequote(s: &str) -> &str { pub fn dequote(s: &str) -> &str {
if s.len() < 2 { if s.len() < 2 {
return s; return s;
@ -746,6 +761,7 @@ pub fn dequote(s: &str) -> &str {
/// 1 yes true on /// 1 yes true on
/// 0 no false off /// 0 no false off
/// ``` /// ```
#[must_use]
pub fn parse_boolean(s: &str) -> Option<bool> { pub fn parse_boolean(s: &str) -> Option<bool> {
if s.eq_ignore_ascii_case("yes") if s.eq_ignore_ascii_case("yes")
|| s.eq_ignore_ascii_case("on") || s.eq_ignore_ascii_case("on")
@ -919,7 +935,7 @@ where
let vt = vtab.cast::<T>(); let vt = vtab.cast::<T>();
match (*vt).destroy() { match (*vt).destroy() {
Ok(_) => { Ok(_) => {
let _: Box<T> = Box::from_raw(vt); drop(Box::from_raw(vt));
ffi::SQLITE_OK ffi::SQLITE_OK
} }
Err(Error::SqliteFailure(err, s)) => { Err(Error::SqliteFailure(err, s)) => {