mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-22 16:29:20 +08:00
Merge remote-tracking branch 'origin/master' into ptr_as_ptr
This commit is contained in:
commit
cc4f059d9b
23
.github/workflows/main.yml
vendored
23
.github/workflows/main.yml
vendored
@ -50,12 +50,12 @@ jobs:
|
||||
- run: cargo test --features bundled --workspace --all-targets --verbose
|
||||
- run: cargo test --features bundled --workspace --doc --verbose
|
||||
|
||||
- name: Test Features
|
||||
# TODO: clang is installed on these -- but `bindgen` can't find it...
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: |
|
||||
cargo test --features 'bundled-full session buildtime_bindgen' --all-targets --workspace --verbose
|
||||
cargo test --features 'bundled-full session buildtime_bindgen' --doc --workspace --verbose
|
||||
- name: Add llvm path on Windows
|
||||
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' --doc --workspace --verbose
|
||||
|
||||
# TODO: move into own action for better caching
|
||||
- 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' --doc --workspace --verbose
|
||||
|
||||
- name: Test Features
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: |
|
||||
cargo test --features 'bundled-full session buildtime_bindgen' --all-targets --workspace --verbose
|
||||
cargo test --features 'bundled-full session buildtime_bindgen' --doc --workspace --verbose
|
||||
- name: Add llvm path on Windows
|
||||
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' --doc --workspace --verbose
|
||||
|
||||
winsqlite3:
|
||||
name: Test with winsqlite3
|
||||
|
15
README.md
15
README.md
@ -1,13 +1,12 @@
|
||||
# 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)
|
||||
[![Gitter](https://badges.gitter.im/rusqlite.svg)](https://gitter.im/rusqlite/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
[![Docs](https://docs.rs/rusqlite/badge.svg)](https://docs.rs/rusqlite)
|
||||
[![codecov](https://codecov.io/gh/rusqlite/rusqlite/branch/master/graph/badge.svg)](https://codecov.io/gh/rusqlite/rusqlite)
|
||||
[![Documentation](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)
|
||||
[![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
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
@ -46,9 +46,9 @@ fn main() {
|
||||
features 'bundled' and 'bundled-windows'. If you want a bundled build of
|
||||
SQLCipher (available for the moment only on Unix), use feature 'bundled-sqlcipher'
|
||||
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")
|
||||
|| (win_target() && cfg!(feature = "bundled-windows"))
|
||||
|| 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.")
|
||||
} else {
|
||||
build_linked::main(&out_dir, &out_path)
|
||||
build_linked::main(&out_dir, &out_path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +168,7 @@ mod build_bundled {
|
||||
panic!(
|
||||
"OpenSSL include directory does not exist: {}",
|
||||
inc_dir.to_string_lossy()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
use_openssl = true;
|
||||
@ -429,19 +429,17 @@ mod build_linked {
|
||||
}
|
||||
|
||||
// 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)
|
||||
.probe(link_lib)
|
||||
{
|
||||
Ok(mut lib) => {
|
||||
if let Some(mut header) = lib.include_paths.pop() {
|
||||
header.push("sqlite3.h");
|
||||
HeaderLocation::FromPath(header.to_string_lossy().into())
|
||||
} else {
|
||||
HeaderLocation::Wrapper
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
} else {
|
||||
// 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
|
||||
// output /usr/lib explicitly, but that can introduce other linking problems;
|
||||
@ -450,7 +448,6 @@ mod build_linked {
|
||||
HeaderLocation::Wrapper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_vcpkg() -> Option<HeaderLocation> {
|
||||
if cfg!(feature = "vcpkg") && is_compiler("msvc") {
|
||||
|
@ -63,6 +63,7 @@ pub struct Error {
|
||||
}
|
||||
|
||||
impl Error {
|
||||
#[must_use]
|
||||
pub fn new(result_code: c_int) -> Error {
|
||||
let code = match result_code & 0xff {
|
||||
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);
|
||||
|
||||
#[must_use]
|
||||
pub fn code_to_str(code: c_int) -> &'static str {
|
||||
match code {
|
||||
super::SQLITE_OK => "Successful result",
|
||||
|
@ -12,12 +12,14 @@ use std::mem;
|
||||
|
||||
mod error;
|
||||
|
||||
#[must_use]
|
||||
pub fn SQLITE_STATIC() -> sqlite3_destructor_type {
|
||||
None
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn SQLITE_TRANSIENT() -> sqlite3_destructor_type {
|
||||
Some(unsafe { mem::transmute(-1isize) })
|
||||
Some(unsafe { mem::transmute(-1_isize) })
|
||||
}
|
||||
|
||||
/// Run-Time Limit Categories
|
||||
|
@ -107,7 +107,7 @@ impl Connection {
|
||||
let restore = Backup::new_with_names(&src, DatabaseName::Main, self, name)?;
|
||||
|
||||
let mut r = More;
|
||||
let mut busy_count = 0i32;
|
||||
let mut busy_count = 0_i32;
|
||||
'restore_loop: while r == More || r == Busy {
|
||||
r = restore.step(100)?;
|
||||
if let Some(ref f) = progress {
|
||||
@ -231,6 +231,7 @@ impl Backup<'_, '_> {
|
||||
/// Gets the progress of the backup as of the last call to
|
||||
/// [`step`](Backup::step).
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn progress(&self) -> Progress {
|
||||
unsafe {
|
||||
Progress {
|
||||
@ -296,7 +297,7 @@ impl Backup<'_, '_> {
|
||||
loop {
|
||||
let r = self.step(pages_per_step)?;
|
||||
if let Some(progress) = progress {
|
||||
progress(self.progress())
|
||||
progress(self.progress());
|
||||
}
|
||||
match r {
|
||||
More | Busy | Locked => thread::sleep(pause_between_pages),
|
||||
|
@ -265,12 +265,14 @@ impl Blob<'_> {
|
||||
|
||||
/// Return the size in bytes of the BLOB.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn size(&self) -> i32 {
|
||||
unsafe { ffi::sqlite3_blob_bytes(self.blob) }
|
||||
}
|
||||
|
||||
/// Return the current size in bytes of the BLOB.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
use std::convert::TryInto;
|
||||
self.size().try_into().unwrap()
|
||||
@ -278,6 +280,7 @@ impl Blob<'_> {
|
||||
|
||||
/// Return true if the BLOB is empty.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.size() == 0
|
||||
}
|
||||
|
@ -46,13 +46,13 @@ impl Connection {
|
||||
/// can set the capacity manually using this method.
|
||||
#[inline]
|
||||
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.
|
||||
#[inline]
|
||||
pub fn flush_prepared_statement_cache(&self) {
|
||||
self.cache.flush()
|
||||
self.cache.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ impl StatementCache {
|
||||
|
||||
#[inline]
|
||||
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`.
|
||||
@ -169,7 +169,7 @@ impl StatementCache {
|
||||
#[inline]
|
||||
fn flush(&self) {
|
||||
let mut cache = self.0.borrow_mut();
|
||||
cache.clear()
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,12 +12,14 @@ pub struct Column<'stmt> {
|
||||
impl Column<'_> {
|
||||
/// Returns the name of the column.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn name(&self) -> &str {
|
||||
self.name
|
||||
}
|
||||
|
||||
/// Returns the type of the column (`None` for expression).
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn decl_type(&self) -> Option<&str> {
|
||||
self.decl_type
|
||||
}
|
||||
|
@ -64,17 +64,17 @@ pub enum DbConfig {
|
||||
impl Connection {
|
||||
/// 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
|
||||
/// - 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
|
||||
/// - SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: return `false` or `true` to
|
||||
/// indicate whether fts3_tokenizer are disabled or enabled
|
||||
/// - SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: return `false` to indicate
|
||||
/// - `SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER`: return `false` or `true` to
|
||||
/// indicate whether `fts3_tokenizer` are disabled or enabled
|
||||
/// - `SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE`: return `false` to indicate
|
||||
/// 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
|
||||
/// - 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
|
||||
#[inline]
|
||||
pub fn db_config(&self, config: DbConfig) -> Result<bool> {
|
||||
@ -93,17 +93,17 @@ impl 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
|
||||
/// - SQLITE_DBCONFIG_ENABLE_TRIGGER: `false` to disable triggers, `true` to
|
||||
/// - `SQLITE_DBCONFIG_ENABLE_TRIGGER`: `false` to disable triggers, `true` to
|
||||
/// enable triggers
|
||||
/// - SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: `false` to disable
|
||||
/// fts3_tokenizer(), `true` to enable fts3_tokenizer()
|
||||
/// - SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: `false` (the default) to enable
|
||||
/// - `SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER`: `false` to disable
|
||||
/// `fts3_tokenizer()`, `true` to enable `fts3_tokenizer()`
|
||||
/// - `SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE`: `false` (the default) to enable
|
||||
/// 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
|
||||
/// - 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
|
||||
#[inline]
|
||||
pub fn set_db_config(&self, config: DbConfig, new_val: bool) -> Result<bool> {
|
||||
|
@ -58,7 +58,7 @@ pub(super) unsafe fn set_result(ctx: *mut sqlite3_context, result: &ToSqlOutput<
|
||||
if length > c_int::max_value() as usize {
|
||||
ffi::sqlite3_result_error_toobig(ctx);
|
||||
} else if length == 0 {
|
||||
ffi::sqlite3_result_zeroblob(ctx, 0)
|
||||
ffi::sqlite3_result_zeroblob(ctx, 0);
|
||||
} else {
|
||||
ffi::sqlite3_result_blob(
|
||||
ctx,
|
||||
|
@ -84,20 +84,17 @@ unsafe fn report_error(ctx: *mut sqlite3_context, err: &Error) {
|
||||
ffi::SQLITE_CONSTRAINT
|
||||
}
|
||||
|
||||
match *err {
|
||||
Error::SqliteFailure(ref err, ref s) => {
|
||||
if let Error::SqliteFailure(ref err, ref s) = *err {
|
||||
ffi::sqlite3_result_error_code(ctx, err.extended_code);
|
||||
if let Some(Ok(cstr)) = s.as_ref().map(|s| str_to_cstring(s)) {
|
||||
ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
} else {
|
||||
ffi::sqlite3_result_error_code(ctx, constraint_error_code());
|
||||
if let Ok(cstr) = str_to_cstring(&err.to_string()) {
|
||||
ffi::sqlite3_result_error(ctx, cstr.as_ptr(), -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn free_boxed_value<T>(p: *mut c_void) {
|
||||
@ -114,12 +111,14 @@ pub struct Context<'a> {
|
||||
impl Context<'_> {
|
||||
/// Returns the number of arguments to the function.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
self.args.len()
|
||||
}
|
||||
|
||||
/// Returns `true` when there is no argument.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.args.is_empty()
|
||||
}
|
||||
@ -157,6 +156,7 @@ impl Context<'_> {
|
||||
/// Will panic if `idx` is greater than or equal to
|
||||
/// [`self.len()`](Context::len).
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn get_raw(&self, idx: usize) -> ValueRef<'_> {
|
||||
let arg = self.args[idx];
|
||||
unsafe { ValueRef::from_value(arg) }
|
||||
@ -200,7 +200,7 @@ impl Context<'_> {
|
||||
arg,
|
||||
raw.cast(),
|
||||
Some(free_boxed_value::<AuxInner>),
|
||||
)
|
||||
);
|
||||
};
|
||||
Ok(orig)
|
||||
}
|
||||
@ -287,7 +287,7 @@ where
|
||||
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.
|
||||
#[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>,
|
||||
T: ToSql,
|
||||
{
|
||||
let pac = match aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) {
|
||||
Some(pac) => pac,
|
||||
None => {
|
||||
let pac = if let Some(pac) = aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) {
|
||||
pac
|
||||
} else {
|
||||
ffi::sqlite3_result_error_nomem(ctx);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let r = catch_unwind(|| {
|
||||
@ -665,12 +664,11 @@ unsafe extern "C" fn call_boxed_inverse<A, W, T>(
|
||||
W: WindowAggregate<A, T>,
|
||||
T: ToSql,
|
||||
{
|
||||
let pac = match aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) {
|
||||
Some(pac) => pac,
|
||||
None => {
|
||||
let pac = if let Some(pac) = aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) {
|
||||
pac
|
||||
} else {
|
||||
ffi::sqlite3_result_error_nomem(ctx);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let r = catch_unwind(|| {
|
||||
|
21
src/hooks.rs
21
src/hooks.rs
@ -367,8 +367,8 @@ impl Connection {
|
||||
///
|
||||
/// The callback parameters are:
|
||||
///
|
||||
/// - the type of database update (SQLITE_INSERT, SQLITE_UPDATE or
|
||||
/// SQLITE_DELETE),
|
||||
/// - the type of database update (`SQLITE_INSERT`, `SQLITE_UPDATE` or
|
||||
/// `SQLITE_DELETE`),
|
||||
/// - the name of the database ("main", "temp", ...),
|
||||
/// - the name of the table that is updated,
|
||||
/// - the ROWID of the row that is updated.
|
||||
@ -402,7 +402,7 @@ impl Connection {
|
||||
where
|
||||
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 {
|
||||
Some(handler) => {
|
||||
if let Some(handler) = handler {
|
||||
let boxed_handler = Box::new(handler);
|
||||
unsafe {
|
||||
ffi::sqlite3_progress_handler(
|
||||
@ -586,14 +585,12 @@ impl InnerConnection {
|
||||
num_ops,
|
||||
Some(call_boxed_closure::<F>),
|
||||
&*boxed_handler as *const F as *mut _,
|
||||
)
|
||||
);
|
||||
}
|
||||
self.progress_handler = Some(boxed_handler);
|
||||
}
|
||||
_ => {
|
||||
} else {
|
||||
unsafe { ffi::sqlite3_progress_handler(self.db(), num_ops, None, ptr::null_mut()) }
|
||||
self.progress_handler = None;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -629,8 +626,7 @@ impl InnerConnection {
|
||||
let boxed_hook: *mut F = p_arg.cast::<F>();
|
||||
(*boxed_hook)(auth_ctx)
|
||||
})
|
||||
.map(Authorization::into_raw)
|
||||
.unwrap_or_else(|_| ffi::SQLITE_ERROR)
|
||||
.map_or_else(|_| ffi::SQLITE_ERROR, Authorization::into_raw)
|
||||
}
|
||||
|
||||
let callback_fn = authorizer
|
||||
@ -644,8 +640,7 @@ impl InnerConnection {
|
||||
callback_fn,
|
||||
boxed_authorizer
|
||||
.as_ref()
|
||||
.map(|f| &**f as *const F as *mut _)
|
||||
.unwrap_or_else(ptr::null_mut),
|
||||
.map_or_else(ptr::null_mut, |f| &**f as *const F as *mut _),
|
||||
)
|
||||
} {
|
||||
ffi::SQLITE_OK => {
|
||||
|
@ -450,7 +450,7 @@ impl Connection {
|
||||
///
|
||||
/// # 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.
|
||||
#[inline]
|
||||
pub fn open_in_memory_with_flags_and_vfs(flags: OpenFlags, vfs: &str) -> Result<Connection> {
|
||||
|
@ -99,7 +99,7 @@ use sealed::Sealed;
|
||||
///
|
||||
/// - 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
|
||||
/// pass this as `stmt.
|
||||
/// pass this as `stmt`.
|
||||
///
|
||||
/// - As array references, similar to the positional params. This looks like
|
||||
/// `thing.query(&[(":foo", &1i32), (":bar", &2i32)])` or
|
||||
|
@ -143,7 +143,7 @@ impl Sql {
|
||||
if ch == quote {
|
||||
self.buf.push(ch);
|
||||
}
|
||||
self.buf.push(ch)
|
||||
self.buf.push(ch);
|
||||
}
|
||||
self.buf.push(quote);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::ffi;
|
||||
use super::StatementStatus;
|
||||
use crate::util::ParamIndexCache;
|
||||
#[cfg(feature = "modern_sqlite")]
|
||||
use crate::util::SqliteMallocString;
|
||||
use std::ffi::CStr;
|
||||
@ -13,7 +14,7 @@ pub struct RawStatement {
|
||||
ptr: *mut ffi::sqlite3_stmt,
|
||||
tail: usize,
|
||||
// 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
|
||||
// cache. This is None for statements which didn't come from the statement
|
||||
// cache.
|
||||
@ -33,7 +34,7 @@ impl RawStatement {
|
||||
RawStatement {
|
||||
ptr: stmt,
|
||||
tail,
|
||||
cache: Default::default(),
|
||||
cache: ParamIndexCache::default(),
|
||||
statement_cache_key: None,
|
||||
}
|
||||
}
|
||||
|
12
src/row.rs
12
src/row.rs
@ -80,6 +80,7 @@ impl<'stmt> Rows<'stmt> {
|
||||
}
|
||||
|
||||
/// Give access to the underlying statement
|
||||
#[must_use]
|
||||
pub fn as_ref(&self) -> Option<&Statement<'stmt>> {
|
||||
self.stmt
|
||||
}
|
||||
@ -187,7 +188,7 @@ where
|
||||
|
||||
/// `FallibleStreamingIterator` differs from the standard library's `Iterator`
|
||||
/// 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
|
||||
/// reset or finalized.
|
||||
///
|
||||
@ -209,8 +210,8 @@ impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
|
||||
|
||||
#[inline]
|
||||
fn advance(&mut self) -> Result<()> {
|
||||
match self.stmt {
|
||||
Some(stmt) => match stmt.step() {
|
||||
if let Some(stmt) = self.stmt {
|
||||
match stmt.step() {
|
||||
Ok(true) => {
|
||||
self.row = Some(Row { stmt });
|
||||
Ok(())
|
||||
@ -225,13 +226,12 @@ impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
|
||||
self.row = None;
|
||||
Err(e)
|
||||
}
|
||||
},
|
||||
None => {
|
||||
}
|
||||
} else {
|
||||
self.row = None;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get(&self) -> Option<&Row<'stmt>> {
|
||||
|
15
src/trace.rs
15
src/trace.rs
@ -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 s = String::from_utf8_lossy(c_slice);
|
||||
let _ = catch_unwind(|| callback(err, &s));
|
||||
drop(catch_unwind(|| callback(err, &s)));
|
||||
}
|
||||
|
||||
let rc = match callback {
|
||||
Some(f) => ffi::sqlite3_config(
|
||||
let rc = if let Some(f) = callback {
|
||||
ffi::sqlite3_config(
|
||||
ffi::SQLITE_CONFIG_LOG,
|
||||
log_callback as extern "C" fn(_, _, _),
|
||||
f as *mut c_void,
|
||||
),
|
||||
None => {
|
||||
)
|
||||
} else {
|
||||
let nullptr: *mut c_void = ptr::null_mut();
|
||||
ffi::sqlite3_config(ffi::SQLITE_CONFIG_LOG, nullptr, nullptr)
|
||||
}
|
||||
};
|
||||
|
||||
if rc == ffi::SQLITE_OK {
|
||||
@ -75,7 +74,7 @@ impl Connection {
|
||||
let trace_fn: fn(&str) = mem::transmute(p_arg);
|
||||
let c_slice = CStr::from_ptr(z_sql).to_bytes();
|
||||
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();
|
||||
@ -109,7 +108,7 @@ impl Connection {
|
||||
nanoseconds / NANOS_PER_SEC,
|
||||
(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();
|
||||
|
@ -169,6 +169,7 @@ impl Transaction<'_> {
|
||||
/// Get the current setting for what happens to the transaction when it is
|
||||
/// dropped.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn drop_behavior(&self) -> DropBehavior {
|
||||
self.drop_behavior
|
||||
}
|
||||
@ -177,7 +178,7 @@ impl Transaction<'_> {
|
||||
/// dropped.
|
||||
#[inline]
|
||||
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.
|
||||
@ -296,6 +297,7 @@ impl Savepoint<'_> {
|
||||
/// Get the current setting for what happens to the savepoint when it is
|
||||
/// dropped.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn drop_behavior(&self) -> DropBehavior {
|
||||
self.drop_behavior
|
||||
}
|
||||
@ -304,7 +306,7 @@ impl Savepoint<'_> {
|
||||
/// dropped.
|
||||
#[inline]
|
||||
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.
|
||||
|
@ -177,7 +177,7 @@ impl FromSql for std::sync::Arc<str> {
|
||||
impl FromSql for Vec<u8> {
|
||||
#[inline]
|
||||
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]
|
||||
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
||||
let bytes = <[u8; 16]>::column_result(value)?;
|
||||
Ok(i128::from_be_bytes(bytes) ^ (1i128 << 127))
|
||||
Ok(i128::from_be_bytes(bytes) ^ (1_i128 << 127))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ impl FromSql for OffsetDateTime {
|
||||
len if len <= 19 => {
|
||||
// TODO YYYY-MM-DDTHH:MM:SS
|
||||
PrimitiveDateTime::parse(s, &PRIMITIVE_SHORT_DATE_TIME_FORMAT)
|
||||
.map(|d| d.assume_utc())
|
||||
.map(PrimitiveDateTime::assume_utc)
|
||||
}
|
||||
_ if s.as_bytes()[19] == b':' => {
|
||||
// legacy
|
||||
@ -56,7 +56,7 @@ impl FromSql for OffsetDateTime {
|
||||
_ if s.as_bytes()[19] == b'.' => OffsetDateTime::parse(s, &OFFSET_DATE_TIME_FORMAT)
|
||||
.or_else(|err| {
|
||||
PrimitiveDateTime::parse(s, &PRIMITIVE_DATE_TIME_FORMAT)
|
||||
.map(|d| d.assume_utc())
|
||||
.map(PrimitiveDateTime::assume_utc)
|
||||
.map_err(|_| err)
|
||||
}),
|
||||
_ => OffsetDateTime::parse(s, &OFFSET_SHORT_DATE_TIME_FORMAT),
|
||||
|
@ -47,7 +47,7 @@ impl From<i128> for Value {
|
||||
fn from(i: i128) -> Value {
|
||||
// We store these biased (e.g. with the most significant bit flipped)
|
||||
// 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 {
|
||||
/// Returns SQLite fundamental datatype.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn data_type(&self) -> Type {
|
||||
match *self {
|
||||
Value::Null => Type::Null,
|
||||
|
@ -22,6 +22,7 @@ pub enum ValueRef<'a> {
|
||||
impl ValueRef<'_> {
|
||||
/// Returns SQLite fundamental datatype.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn data_type(&self) -> Type {
|
||||
match *self {
|
||||
ValueRef::Null => Type::Null,
|
||||
|
@ -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;
|
||||
let args = from_raw_parts(ap_arg as *const &UnlockNotification, n_arg as usize);
|
||||
for un in args {
|
||||
let _ = catch_unwind(std::panic::AssertUnwindSafe(|| un.fired()));
|
||||
drop(catch_unwind(std::panic::AssertUnwindSafe(|| un.fired())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
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
|
||||
/// need to pass a NUL-terminated string to SQLite, and we have a `&str`.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
@ -10,7 +10,7 @@ pub(crate) struct SmallCString(smallvec::SmallVec<[u8; 16]>);
|
||||
impl SmallCString {
|
||||
#[inline]
|
||||
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));
|
||||
}
|
||||
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
|
||||
/// make up our `str`:
|
||||
/// - `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]
|
||||
pub fn as_bytes_without_nul(&self) -> &[u8] {
|
||||
self.debug_checks();
|
||||
|
@ -38,7 +38,7 @@ pub(crate) struct SqliteMallocString {
|
||||
|
||||
impl SqliteMallocString {
|
||||
/// 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]
|
||||
pub(crate) unsafe fn from_raw_nonnull(ptr: NonNull<c_char>) -> Self {
|
||||
Self {
|
||||
@ -48,7 +48,7 @@ impl SqliteMallocString {
|
||||
}
|
||||
|
||||
/// 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]
|
||||
pub(crate) unsafe fn from_raw(ptr: *mut c_char) -> Option<Self> {
|
||||
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
|
||||
/// `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
|
||||
/// call `handle_alloc_error` which aborts the program after calling a
|
||||
/// global hook.
|
||||
///
|
||||
/// 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 {
|
||||
use std::convert::TryFrom;
|
||||
let s = if s.as_bytes().contains(&0) {
|
||||
|
@ -6,6 +6,7 @@ use std::ffi::CStr;
|
||||
///
|
||||
/// See [`sqlite3_libversion_number()`](https://www.sqlite.org/c3ref/libversion.html).
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn version_number() -> i32 {
|
||||
unsafe { ffi::sqlite3_libversion_number() }
|
||||
}
|
||||
@ -14,6 +15,7 @@ pub fn version_number() -> i32 {
|
||||
///
|
||||
/// See [`sqlite3_libversion()`](https://www.sqlite.org/c3ref/libversion.html).
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn version() -> &'static str {
|
||||
let cstr = unsafe { CStr::from_ptr(ffi::sqlite3_libversion()) };
|
||||
cstr.to_str()
|
||||
|
@ -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) 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
|
||||
@ -106,11 +106,11 @@ unsafe impl<'vtab> VTab<'vtab> for ArrayTab {
|
||||
}
|
||||
}
|
||||
if ptr_idx {
|
||||
info.set_estimated_cost(1f64);
|
||||
info.set_estimated_cost(1_f64);
|
||||
info.set_estimated_rows(100);
|
||||
info.set_idx_num(1);
|
||||
} 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_idx_num(0);
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ union ModuleZeroHack {
|
||||
// structs are allowed to be zeroed.
|
||||
const ZERO_MODULE: ffi::sqlite3_module = unsafe {
|
||||
ModuleZeroHack {
|
||||
bytes: [0u8; std::mem::size_of::<ffi::sqlite3_module>()],
|
||||
bytes: [0_u8; std::mem::size_of::<ffi::sqlite3_module>()],
|
||||
}
|
||||
.module
|
||||
};
|
||||
@ -87,6 +87,7 @@ const ZERO_MODULE: ffi::sqlite3_module = unsafe {
|
||||
/// 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).
|
||||
#[must_use]
|
||||
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
|
||||
// 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.
|
||||
///
|
||||
/// 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> {
|
||||
// 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
|
||||
@ -193,7 +195,7 @@ impl VTabConnection {
|
||||
///
|
||||
/// # 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)]`.
|
||||
///
|
||||
/// ```rust,ignore
|
||||
@ -326,6 +328,7 @@ impl IndexInfo {
|
||||
|
||||
/// Record WHERE clause constraints.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn constraints(&self) -> IndexConstraintIter<'_> {
|
||||
let constraints =
|
||||
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.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn order_bys(&self) -> OrderByIter<'_> {
|
||||
let order_bys =
|
||||
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
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn num_of_order_by(&self) -> usize {
|
||||
unsafe { (*self.0).nOrderBy as usize }
|
||||
}
|
||||
@ -448,18 +453,21 @@ pub struct IndexConstraint<'a>(&'a ffi::sqlite3_index_constraint);
|
||||
impl IndexConstraint<'_> {
|
||||
/// Column constrained. -1 for ROWID
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn column(&self) -> c_int {
|
||||
self.0.iColumn
|
||||
}
|
||||
|
||||
/// Constraint operator
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn operator(&self) -> IndexConstraintOp {
|
||||
IndexConstraintOp::from(self.0.op)
|
||||
}
|
||||
|
||||
/// True if this constraint is usable
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_usable(&self) -> bool {
|
||||
self.0.usable != 0
|
||||
}
|
||||
@ -509,12 +517,14 @@ pub struct OrderBy<'a>(&'a ffi::sqlite3_index_info_sqlite3_index_orderby);
|
||||
impl OrderBy<'_> {
|
||||
/// Column number
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn column(&self) -> c_int {
|
||||
self.0.iColumn
|
||||
}
|
||||
|
||||
/// True for DESC. False for ASC.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_order_by_desc(&self) -> bool {
|
||||
self.0.desc != 0
|
||||
}
|
||||
@ -581,12 +591,14 @@ pub struct Values<'a> {
|
||||
impl Values<'_> {
|
||||
/// Returns the number of values.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
self.args.len()
|
||||
}
|
||||
|
||||
/// Returns `true` if there is no value.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.args.is_empty()
|
||||
}
|
||||
@ -629,6 +641,7 @@ impl Values<'_> {
|
||||
|
||||
/// Turns `Values` into an iterator.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn iter(&self) -> ValueIter<'_> {
|
||||
ValueIter {
|
||||
iter: self.args.iter(),
|
||||
@ -720,6 +733,7 @@ impl InnerConnection {
|
||||
|
||||
/// Escape double-quote (`"`) character occurrences by
|
||||
/// doubling them (`""`).
|
||||
#[must_use]
|
||||
pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
|
||||
if identifier.contains('"') {
|
||||
// escape quote by doubling them
|
||||
@ -729,6 +743,7 @@ pub fn escape_double_quote(identifier: &str) -> Cow<'_, str> {
|
||||
}
|
||||
}
|
||||
/// Dequote string
|
||||
#[must_use]
|
||||
pub fn dequote(s: &str) -> &str {
|
||||
if s.len() < 2 {
|
||||
return s;
|
||||
@ -746,6 +761,7 @@ pub fn dequote(s: &str) -> &str {
|
||||
/// 1 yes true on
|
||||
/// 0 no false off
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn parse_boolean(s: &str) -> Option<bool> {
|
||||
if s.eq_ignore_ascii_case("yes")
|
||||
|| s.eq_ignore_ascii_case("on")
|
||||
@ -919,7 +935,7 @@ where
|
||||
let vt = vtab.cast::<T>();
|
||||
match (*vt).destroy() {
|
||||
Ok(_) => {
|
||||
let _: Box<T> = Box::from_raw(vt);
|
||||
drop(Box::from_raw(vt));
|
||||
ffi::SQLITE_OK
|
||||
}
|
||||
Err(Error::SqliteFailure(err, s)) => {
|
||||
|
Loading…
Reference in New Issue
Block a user