mirror of
https://github.com/isar/rusqlite.git
synced 2025-03-26 07:16:05 +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.
|
||||
* `loadable_extension` to program [loadable extension](https://sqlite.org/loadext.html) in Rust.
|
||||
* [`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)
|
||||
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`.)
|
||||
* [`trace`](https://docs.rs/rusqlite/~0/rusqlite/trace/index.html)
|
||||
allows hooks into SQLite's tracing and profiling APIs. Note: This feature
|
||||
requires SQLite 3.6.23 or later.
|
||||
allows hooks into SQLite's tracing and profiling APIs.
|
||||
* [`blob`](https://docs.rs/rusqlite/~0/rusqlite/blob/index.html)
|
||||
gives `std::io::{Read, Write, Seek}` access to SQL BLOBs. Note: This feature
|
||||
requires SQLite 3.7.4 or later.
|
||||
gives `std::io::{Read, Write, Seek}` access to SQL BLOBs.
|
||||
* [`limits`](https://docs.rs/rusqlite/~0/rusqlite/struct.Connection.html#method.limit)
|
||||
allows you to set and retrieve SQLite's per connection limits.
|
||||
* `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::ptr;
|
||||
use std::str;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
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::raw_statement::RawStatement;
|
||||
use crate::statement::Statement;
|
||||
use crate::version::version_number;
|
||||
|
||||
pub struct InnerConnection {
|
||||
pub db: *mut ffi::sqlite3,
|
||||
@ -67,21 +65,6 @@ impl InnerConnection {
|
||||
) -> Result<InnerConnection> {
|
||||
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 {
|
||||
Some(c_vfs) => c_vfs.as_ptr(),
|
||||
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
|
||||
// platforms that do not have threading (such as webassembly)
|
||||
#[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,
|
||||
// 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
|
||||
// a safe one (in Rust terminology), which is no good. We have two options
|
||||
// to protect against this, depending on the version of SQLite we're linked
|
||||
// with:
|
||||
// a safe one (in Rust terminology).
|
||||
//
|
||||
// 1. If we're on 3.7.0 or later, we can ask SQLite for a mutex and check for
|
||||
// the magic value 8. This isn't documented, but it's what SQLite
|
||||
// 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
|
||||
// threading mode. The check we perform for >= 3.7.0 will segfault.
|
||||
// Instead, we insist on being able to call sqlite3_config and
|
||||
// sqlite3_initialize ourself, ensuring we know the threading
|
||||
// mode. This will fail if someone else has already initialized SQLite
|
||||
// even if they initialized it safely. That's not ideal either, which is
|
||||
// why we expose bypass_sqlite_initialization above.
|
||||
if version_number() >= 3_007_000 {
|
||||
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
|
||||
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(())
|
||||
}
|
||||
// We can ask SQLite for a mutex and check for
|
||||
// the magic value 8. This isn't documented, but it's what SQLite
|
||||
// returns for its mutex allocation function in Single-thread mode.
|
||||
const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
|
||||
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 {
|
||||
#[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(())
|
||||
}
|
||||
}
|
||||
|
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::result;
|
||||
use std::str;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::cache::StatementCache;
|
||||
use crate::inner_connection::{InnerConnection, BYPASS_SQLITE_INIT};
|
||||
use crate::inner_connection::InnerConnection;
|
||||
use crate::raw_statement::RawStatement;
|
||||
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.
|
||||
pub struct InterruptHandle {
|
||||
db_lock: Arc<Mutex<*mut ffi::sqlite3>>,
|
||||
@ -1756,12 +1732,6 @@ mod test {
|
||||
|
||||
#[test]
|
||||
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()?;
|
||||
db.execute_batch("CREATE TABLE foo(x NOT NULL)")?;
|
||||
|
||||
@ -1770,7 +1740,7 @@ mod test {
|
||||
match result.unwrap_err() {
|
||||
Error::SqliteFailure(err, _) => {
|
||||
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}"),
|
||||
}
|
||||
|
@ -148,17 +148,11 @@ mod test {
|
||||
db.set_limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER, 99);
|
||||
assert_eq!(99, db.limit(Limit::SQLITE_LIMIT_VARIABLE_NUMBER));
|
||||
|
||||
// SQLITE_LIMIT_TRIGGER_DEPTH was added in SQLite 3.6.18.
|
||||
if crate::version_number() >= 3_006_018 {
|
||||
db.set_limit(Limit::SQLITE_LIMIT_TRIGGER_DEPTH, 32);
|
||||
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.
|
||||
if crate::version_number() >= 3_008_007 {
|
||||
db.set_limit(Limit::SQLITE_LIMIT_WORKER_THREADS, 2);
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user