mirror of
https://github.com/isar/rusqlite.git
synced 2025-03-29 00:32:57 +08:00
Remove obsolete codes and comments
Minimal SQLite version supported by rusqlite is 3.14
This commit is contained in:
parent
059b7d06ac
commit
cd5b780505
@ -94,17 +94,14 @@ features](https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-s
|
|||||||
allows loading dynamic library-based SQLite extensions.
|
allows loading dynamic library-based SQLite extensions.
|
||||||
* `loadable_extension` to program [loadable extension](https://sqlite.org/loadext.html) in Rust.
|
* `loadable_extension` to program [loadable extension](https://sqlite.org/loadext.html) in Rust.
|
||||||
* [`backup`](https://docs.rs/rusqlite/~0/rusqlite/backup/index.html)
|
* [`backup`](https://docs.rs/rusqlite/~0/rusqlite/backup/index.html)
|
||||||
allows use of SQLite's online backup API. Note: This feature requires SQLite 3.6.11 or later.
|
allows use of SQLite's online backup API.
|
||||||
* [`functions`](https://docs.rs/rusqlite/~0/rusqlite/functions/index.html)
|
* [`functions`](https://docs.rs/rusqlite/~0/rusqlite/functions/index.html)
|
||||||
allows you to load Rust closures into SQLite connections for use in queries.
|
allows you to load Rust closures into SQLite connections for use in queries.
|
||||||
Note: This feature requires SQLite 3.7.3 or later.
|
|
||||||
* `window` for [window function](https://www.sqlite.org/windowfunctions.html) support (`fun(...) OVER ...`). (Implies `functions`.)
|
* `window` for [window function](https://www.sqlite.org/windowfunctions.html) support (`fun(...) OVER ...`). (Implies `functions`.)
|
||||||
* [`trace`](https://docs.rs/rusqlite/~0/rusqlite/trace/index.html)
|
* [`trace`](https://docs.rs/rusqlite/~0/rusqlite/trace/index.html)
|
||||||
allows hooks into SQLite's tracing and profiling APIs. Note: This feature
|
allows hooks into SQLite's tracing and profiling APIs.
|
||||||
requires SQLite 3.6.23 or later.
|
|
||||||
* [`blob`](https://docs.rs/rusqlite/~0/rusqlite/blob/index.html)
|
* [`blob`](https://docs.rs/rusqlite/~0/rusqlite/blob/index.html)
|
||||||
gives `std::io::{Read, Write, Seek}` access to SQL BLOBs. Note: This feature
|
gives `std::io::{Read, Write, Seek}` access to SQL BLOBs.
|
||||||
requires SQLite 3.7.4 or later.
|
|
||||||
* [`limits`](https://docs.rs/rusqlite/~0/rusqlite/struct.Connection.html#method.limit)
|
* [`limits`](https://docs.rs/rusqlite/~0/rusqlite/struct.Connection.html#method.limit)
|
||||||
allows you to set and retrieve SQLite's per connection limits.
|
allows you to set and retrieve SQLite's per connection limits.
|
||||||
* `chrono` implements [`FromSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.FromSql.html)
|
* `chrono` implements [`FromSql`](https://docs.rs/rusqlite/~0/rusqlite/types/trait.FromSql.html)
|
||||||
|
@ -4,7 +4,6 @@ use std::os::raw::{c_char, c_int};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::sync::atomic::AtomicBool;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use super::ffi;
|
use super::ffi;
|
||||||
@ -13,7 +12,6 @@ use super::{Connection, InterruptHandle, OpenFlags, PrepFlags, Result};
|
|||||||
use crate::error::{error_from_handle, error_from_sqlite_code, error_with_offset, Error};
|
use crate::error::{error_from_handle, error_from_sqlite_code, error_with_offset, Error};
|
||||||
use crate::raw_statement::RawStatement;
|
use crate::raw_statement::RawStatement;
|
||||||
use crate::statement::Statement;
|
use crate::statement::Statement;
|
||||||
use crate::version::version_number;
|
|
||||||
|
|
||||||
pub struct InnerConnection {
|
pub struct InnerConnection {
|
||||||
pub db: *mut ffi::sqlite3,
|
pub db: *mut ffi::sqlite3,
|
||||||
@ -67,21 +65,6 @@ impl InnerConnection {
|
|||||||
) -> Result<InnerConnection> {
|
) -> Result<InnerConnection> {
|
||||||
ensure_safe_sqlite_threading_mode()?;
|
ensure_safe_sqlite_threading_mode()?;
|
||||||
|
|
||||||
// Replicate the check for sane open flags from SQLite, because the check in
|
|
||||||
// SQLite itself wasn't added until version 3.7.3.
|
|
||||||
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_ONLY.bits(), 0x02);
|
|
||||||
debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_WRITE.bits(), 0x04);
|
|
||||||
debug_assert_eq!(
|
|
||||||
1 << (OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE).bits(),
|
|
||||||
0x40
|
|
||||||
);
|
|
||||||
if (1 << (flags.bits() & 0x7)) & 0x46 == 0 {
|
|
||||||
return Err(Error::SqliteFailure(
|
|
||||||
ffi::Error::new(ffi::SQLITE_MISUSE),
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let z_vfs = match vfs {
|
let z_vfs = match vfs {
|
||||||
Some(c_vfs) => c_vfs.as_ptr(),
|
Some(c_vfs) => c_vfs.as_ptr(),
|
||||||
None => ptr::null(),
|
None => ptr::null(),
|
||||||
@ -390,11 +373,6 @@ impl Drop for InnerConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_arch = "wasm32", feature = "loadable_extension")))]
|
|
||||||
static SQLITE_INIT: std::sync::Once = std::sync::Once::new();
|
|
||||||
|
|
||||||
pub static BYPASS_SQLITE_INIT: AtomicBool = AtomicBool::new(false);
|
|
||||||
|
|
||||||
// threading mode checks are not necessary (and do not work) on target
|
// threading mode checks are not necessary (and do not work) on target
|
||||||
// platforms that do not have threading (such as webassembly)
|
// platforms that do not have threading (such as webassembly)
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
@ -412,51 +390,21 @@ fn ensure_safe_sqlite_threading_mode() -> Result<()> {
|
|||||||
// Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode,
|
// Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode,
|
||||||
// but it's possible someone configured it to be in Single-thread mode
|
// but it's possible someone configured it to be in Single-thread mode
|
||||||
// before calling into us. That would mean we're exposing an unsafe API via
|
// before calling into us. That would mean we're exposing an unsafe API via
|
||||||
// a safe one (in Rust terminology), which is no good. We have two options
|
// a safe one (in Rust terminology).
|
||||||
// to protect against this, depending on the version of SQLite we're linked
|
|
||||||
// with:
|
|
||||||
//
|
//
|
||||||
// 1. If we're on 3.7.0 or later, we can ask SQLite for a mutex and check for
|
// We can ask SQLite for a mutex and check for
|
||||||
// the magic value 8. This isn't documented, but it's what SQLite
|
// the magic value 8. This isn't documented, but it's what SQLite
|
||||||
// returns for its mutex allocation function in Single-thread mode.
|
// returns for its mutex allocation function in Single-thread mode.
|
||||||
// 2. If we're prior to SQLite 3.7.0, AFAIK there's no way to check the
|
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
|
||||||
// threading mode. The check we perform for >= 3.7.0 will segfault.
|
let is_singlethreaded = unsafe {
|
||||||
// Instead, we insist on being able to call sqlite3_config and
|
let mutex_ptr = ffi::sqlite3_mutex_alloc(0);
|
||||||
// sqlite3_initialize ourself, ensuring we know the threading
|
let is_singlethreaded = mutex_ptr as usize == SQLITE_SINGLETHREADED_MUTEX_MAGIC;
|
||||||
// mode. This will fail if someone else has already initialized SQLite
|
ffi::sqlite3_mutex_free(mutex_ptr);
|
||||||
// even if they initialized it safely. That's not ideal either, which is
|
is_singlethreaded
|
||||||
// why we expose bypass_sqlite_initialization above.
|
};
|
||||||
if version_number() >= 3_007_000 {
|
if is_singlethreaded {
|
||||||
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
|
Err(Error::SqliteSingleThreadedMode)
|
||||||
let is_singlethreaded = unsafe {
|
|
||||||
let mutex_ptr = ffi::sqlite3_mutex_alloc(0);
|
|
||||||
let is_singlethreaded = mutex_ptr as usize == SQLITE_SINGLETHREADED_MUTEX_MAGIC;
|
|
||||||
ffi::sqlite3_mutex_free(mutex_ptr);
|
|
||||||
is_singlethreaded
|
|
||||||
};
|
|
||||||
if is_singlethreaded {
|
|
||||||
Err(Error::SqliteSingleThreadedMode)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
#[cfg(not(feature = "loadable_extension"))]
|
|
||||||
SQLITE_INIT.call_once(|| {
|
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
if BYPASS_SQLITE_INIT.load(Ordering::Relaxed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
assert!(ffi::sqlite3_config(ffi::SQLITE_CONFIG_MULTITHREAD) == ffi::SQLITE_OK && ffi::sqlite3_initialize() == ffi::SQLITE_OK,
|
|
||||||
"Could not ensure safe initialization of SQLite.\n\
|
|
||||||
To fix this, either:\n\
|
|
||||||
* Upgrade SQLite to at least version 3.7.0\n\
|
|
||||||
* Ensure that SQLite has been initialized in Multi-thread or Serialized mode and call\n\
|
|
||||||
rusqlite::bypass_sqlite_initialization() prior to your first connection attempt."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
src/lib.rs
34
src/lib.rs
@ -65,11 +65,10 @@ use std::os::raw::{c_char, c_int};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::cache::StatementCache;
|
use crate::cache::StatementCache;
|
||||||
use crate::inner_connection::{InnerConnection, BYPASS_SQLITE_INIT};
|
use crate::inner_connection::InnerConnection;
|
||||||
use crate::raw_statement::RawStatement;
|
use crate::raw_statement::RawStatement;
|
||||||
use crate::types::ValueRef;
|
use crate::types::ValueRef;
|
||||||
|
|
||||||
@ -1196,29 +1195,6 @@ bitflags::bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// rusqlite's check for a safe SQLite threading mode requires SQLite 3.7.0 or
|
|
||||||
/// later. If you are running against a SQLite older than that, rusqlite
|
|
||||||
/// attempts to ensure safety by performing configuration and initialization of
|
|
||||||
/// SQLite itself the first time you
|
|
||||||
/// attempt to open a connection. By default, rusqlite panics if that
|
|
||||||
/// initialization fails, since that could mean SQLite has been initialized in
|
|
||||||
/// single-thread mode.
|
|
||||||
///
|
|
||||||
/// If you are encountering that panic _and_ can ensure that SQLite has been
|
|
||||||
/// initialized in either multi-thread or serialized mode, call this function
|
|
||||||
/// prior to attempting to open a connection and rusqlite's initialization
|
|
||||||
/// process will by skipped.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// This function is unsafe because if you call it and SQLite has actually been
|
|
||||||
/// configured to run in single-thread mode,
|
|
||||||
/// you may encounter memory errors or data corruption or any number of terrible
|
|
||||||
/// things that should not be possible when you're using Rust.
|
|
||||||
pub unsafe fn bypass_sqlite_initialization() {
|
|
||||||
BYPASS_SQLITE_INIT.store(true, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allows interrupting a long-running computation.
|
/// Allows interrupting a long-running computation.
|
||||||
pub struct InterruptHandle {
|
pub struct InterruptHandle {
|
||||||
db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
|
db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
|
||||||
@ -1756,12 +1732,6 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_notnull_constraint_error() -> Result<()> {
|
fn test_notnull_constraint_error() -> Result<()> {
|
||||||
// extended error codes for constraints were added in SQLite 3.7.16; if we're
|
|
||||||
// running on our bundled version, we know the extended error code exists.
|
|
||||||
fn check_extended_code(extended_code: c_int) {
|
|
||||||
assert_eq!(extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
let db = Connection::open_in_memory()?;
|
let db = Connection::open_in_memory()?;
|
||||||
db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
|
db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
|
||||||
|
|
||||||
@ -1770,7 +1740,7 @@ mod test {
|
|||||||
match result.unwrap_err() {
|
match result.unwrap_err() {
|
||||||
Error::SqliteFailure(err, _) => {
|
Error::SqliteFailure(err, _) => {
|
||||||
assert_eq!(err.code, ErrorCode::ConstraintViolation);
|
assert_eq!(err.code, ErrorCode::ConstraintViolation);
|
||||||
check_extended_code(err.extended_code);
|
assert_eq!(err.extended_code, ffi::SQLITE_CONSTRAINT_NOTNULL);
|
||||||
}
|
}
|
||||||
err => panic!("Unexpected error {err}"),
|
err => panic!("Unexpected error {err}"),
|
||||||
}
|
}
|
||||||
|
@ -148,17 +148,11 @@ mod test {
|
|||||||
db.set_limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER, 99);
|
db.set_limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER, 99);
|
||||||
assert_eq!(99, db.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER));
|
assert_eq!(99, db.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER));
|
||||||
|
|
||||||
// SQLITE_LIMIT_TRIGGER_DEPTH was added in SQLite 3.6.18.
|
db.set_limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH, 32);
|
||||||
if crate::version_number() >= 3_006_018 {
|
assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH));
|
||||||
db.set_limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH, 32);
|
|
||||||
assert_eq!(32, db.limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH));
|
|
||||||
}
|
|
||||||
|
|
||||||
// SQLITE_LIMIT_WORKER_THREADS was added in SQLite 3.8.7.
|
db.set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, 2);
|
||||||
if crate::version_number() >= 3_008_007 {
|
assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_WORKER_THREADS));
|
||||||
db.set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, 2);
|
|
||||||
assert_eq!(2, db.limit(Limit::SQLITE_LIMIT_WORKER_THREADS));
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user