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 --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
|
||||||
|
15
README.md
15
README.md
@ -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
|
||||||
|
|
||||||
|
@ -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,26 +429,23 @@ 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
// 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;
|
|
||||||
// see https://github.com/rusqlite/rusqlite/issues/207.
|
|
||||||
println!("cargo:rustc-link-lib={}={}", find_link_mode(), link_lib);
|
|
||||||
HeaderLocation::Wrapper
|
HeaderLocation::Wrapper
|
||||||
}
|
}
|
||||||
|
} 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;
|
||||||
|
// see https://github.com/rusqlite/rusqlite/issues/207.
|
||||||
|
println!("cargo:rustc-link-lib={}={}", find_link_mode(), link_lib);
|
||||||
|
HeaderLocation::Wrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
@ -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,
|
||||||
|
@ -84,18 +84,15 @@ 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);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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(|| {
|
||||||
|
41
src/hooks.rs
41
src/hooks.rs
@ -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,23 +577,20 @@ 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(
|
self.db(),
|
||||||
self.db(),
|
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);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unsafe { ffi::sqlite3_progress_handler(self.db(), num_ops, None, ptr::null_mut()) }
|
|
||||||
self.progress_handler = None;
|
|
||||||
}
|
}
|
||||||
|
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>();
|
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 => {
|
||||||
|
@ -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> {
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
src/row.rs
14
src/row.rs
@ -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,11 +226,10 @@ impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
|
|||||||
self.row = None;
|
self.row = None;
|
||||||
Err(e)
|
Err(e)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
None => {
|
|
||||||
self.row = None;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.row = None;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
src/trace.rs
19
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 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();
|
||||||
|
@ -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.
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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) {
|
||||||
|
@ -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()
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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)) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user