1 use std::ffi::CStr;
2 use std::os::raw::{c_char, c_int};
3 #[cfg(feature = "load_extension")]
4 use std::path::Path;
5 use std::ptr;
6 use std::str;
7 use std::sync::atomic::{AtomicBool, Ordering};
8 use std::sync::{Arc, Mutex};
9
10 use super::ffi;
11 use super::str_for_sqlite;
12 use super::{Connection, InterruptHandle, OpenFlags, Result};
13 use crate::error::{error_from_handle, error_from_sqlite_code, Error};
14 use crate::raw_statement::RawStatement;
15 use crate::statement::Statement;
16 use crate::unlock_notify;
17 use crate::version::version_number;
18
19 pub struct InnerConnection {
20 pub db: *mut ffi::sqlite3,
21 // It's unsafe to call `sqlite3_close` while another thread is performing
22 // a `sqlite3_interrupt`, and vice versa, so we take this mutex during
23 // those functions. This protects a copy of the `db` pointer (which is
24 // cleared on closing), however the main copy, `db`, is unprotected.
25 // Otherwise, a long running query would prevent calling interrupt, as
26 // interrupt would only acquire the lock after the query's completion.
27 interrupt_lock: Arc<Mutex<*mut ffi::sqlite3>>,
28 #[cfg(feature = "hooks")]
29 pub free_commit_hook: Option<unsafe fn(*mut ::std::os::raw::c_void)>,
30 #[cfg(feature = "hooks")]
31 pub free_rollback_hook: Option<unsafe fn(*mut ::std::os::raw::c_void)>,
32 #[cfg(feature = "hooks")]
33 pub free_update_hook: Option<unsafe fn(*mut ::std::os::raw::c_void)>,
34 owned: bool,
35 }
36
37 impl InnerConnection {
38 #[allow(clippy::mutex_atomic)]
new(db: *mut ffi::sqlite3, owned: bool) -> InnerConnection39 pub unsafe fn new(db: *mut ffi::sqlite3, owned: bool) -> InnerConnection {
40 InnerConnection {
41 db,
42 interrupt_lock: Arc::new(Mutex::new(db)),
43 #[cfg(feature = "hooks")]
44 free_commit_hook: None,
45 #[cfg(feature = "hooks")]
46 free_rollback_hook: None,
47 #[cfg(feature = "hooks")]
48 free_update_hook: None,
49 owned,
50 }
51 }
52
open_with_flags( c_path: &CStr, flags: OpenFlags, vfs: Option<&CStr>, ) -> Result<InnerConnection>53 pub fn open_with_flags(
54 c_path: &CStr,
55 flags: OpenFlags,
56 vfs: Option<&CStr>,
57 ) -> Result<InnerConnection> {
58 #[cfg(not(feature = "bundled"))]
59 ensure_valid_sqlite_version();
60 ensure_safe_sqlite_threading_mode()?;
61
62 // Replicate the check for sane open flags from SQLite, because the check in
63 // SQLite itself wasn't added until version 3.7.3.
64 debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_ONLY.bits, 0x02);
65 debug_assert_eq!(1 << OpenFlags::SQLITE_OPEN_READ_WRITE.bits, 0x04);
66 debug_assert_eq!(
67 1 << (OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE).bits,
68 0x40
69 );
70 if (1 << (flags.bits & 0x7)) & 0x46 == 0 {
71 return Err(Error::SqliteFailure(
72 ffi::Error::new(ffi::SQLITE_MISUSE),
73 None,
74 ));
75 }
76
77 let z_vfs = match vfs {
78 Some(c_vfs) => c_vfs.as_ptr(),
79 None => ptr::null(),
80 };
81
82 unsafe {
83 let mut db: *mut ffi::sqlite3 = ptr::null_mut();
84 let r = ffi::sqlite3_open_v2(c_path.as_ptr(), &mut db, flags.bits(), z_vfs);
85 if r != ffi::SQLITE_OK {
86 let e = if db.is_null() {
87 error_from_sqlite_code(r, Some(c_path.to_string_lossy().to_string()))
88 } else {
89 let mut e = error_from_handle(db, r);
90 if let Error::SqliteFailure(
91 ffi::Error {
92 code: ffi::ErrorCode::CannotOpen,
93 ..
94 },
95 Some(msg),
96 ) = e
97 {
98 e = Error::SqliteFailure(
99 ffi::Error::new(r),
100 Some(format!("{}: {}", msg, c_path.to_string_lossy())),
101 );
102 }
103 ffi::sqlite3_close(db);
104 e
105 };
106
107 return Err(e);
108 }
109
110 // attempt to turn on extended results code; don't fail if we can't.
111 ffi::sqlite3_extended_result_codes(db, 1);
112
113 let r = ffi::sqlite3_busy_timeout(db, 5000);
114 if r != ffi::SQLITE_OK {
115 let e = error_from_handle(db, r);
116 ffi::sqlite3_close(db);
117 return Err(e);
118 }
119
120 Ok(InnerConnection::new(db, true))
121 }
122 }
123
db(&self) -> *mut ffi::sqlite3124 pub fn db(&self) -> *mut ffi::sqlite3 {
125 self.db
126 }
127
decode_result(&mut self, code: c_int) -> Result<()>128 pub fn decode_result(&mut self, code: c_int) -> Result<()> {
129 unsafe { InnerConnection::decode_result_raw(self.db(), code) }
130 }
131
decode_result_raw(db: *mut ffi::sqlite3, code: c_int) -> Result<()>132 unsafe fn decode_result_raw(db: *mut ffi::sqlite3, code: c_int) -> Result<()> {
133 if code == ffi::SQLITE_OK {
134 Ok(())
135 } else {
136 Err(error_from_handle(db, code))
137 }
138 }
139
140 #[allow(clippy::mutex_atomic)]
close(&mut self) -> Result<()>141 pub fn close(&mut self) -> Result<()> {
142 if self.db.is_null() {
143 return Ok(());
144 }
145 self.remove_hooks();
146 let mut shared_handle = self.interrupt_lock.lock().unwrap();
147 assert!(
148 !shared_handle.is_null(),
149 "Bug: Somehow interrupt_lock was cleared before the DB was closed"
150 );
151 if !self.owned {
152 self.db = ptr::null_mut();
153 return Ok(());
154 }
155 unsafe {
156 let r = ffi::sqlite3_close(self.db);
157 // Need to use _raw because _guard has a reference out, and
158 // decode_result takes &mut self.
159 let r = InnerConnection::decode_result_raw(self.db, r);
160 if r.is_ok() {
161 *shared_handle = ptr::null_mut();
162 self.db = ptr::null_mut();
163 }
164 r
165 }
166 }
167
get_interrupt_handle(&self) -> InterruptHandle168 pub fn get_interrupt_handle(&self) -> InterruptHandle {
169 InterruptHandle {
170 db_lock: Arc::clone(&self.interrupt_lock),
171 }
172 }
173
174 #[cfg(feature = "load_extension")]
enable_load_extension(&mut self, onoff: c_int) -> Result<()>175 pub fn enable_load_extension(&mut self, onoff: c_int) -> Result<()> {
176 let r = unsafe { ffi::sqlite3_enable_load_extension(self.db, onoff) };
177 self.decode_result(r)
178 }
179
180 #[cfg(feature = "load_extension")]
load_extension(&self, dylib_path: &Path, entry_point: Option<&str>) -> Result<()>181 pub fn load_extension(&self, dylib_path: &Path, entry_point: Option<&str>) -> Result<()> {
182 let dylib_str = super::path_to_cstring(dylib_path)?;
183 unsafe {
184 let mut errmsg: *mut c_char = ptr::null_mut();
185 let r = if let Some(entry_point) = entry_point {
186 let c_entry = crate::str_to_cstring(entry_point)?;
187 ffi::sqlite3_load_extension(
188 self.db,
189 dylib_str.as_ptr(),
190 c_entry.as_ptr(),
191 &mut errmsg,
192 )
193 } else {
194 ffi::sqlite3_load_extension(self.db, dylib_str.as_ptr(), ptr::null(), &mut errmsg)
195 };
196 if r == ffi::SQLITE_OK {
197 Ok(())
198 } else {
199 let message = super::errmsg_to_string(errmsg);
200 ffi::sqlite3_free(errmsg as *mut ::std::os::raw::c_void);
201 Err(error_from_sqlite_code(r, Some(message)))
202 }
203 }
204 }
205
last_insert_rowid(&self) -> i64206 pub fn last_insert_rowid(&self) -> i64 {
207 unsafe { ffi::sqlite3_last_insert_rowid(self.db()) }
208 }
209
prepare<'a>(&mut self, conn: &'a Connection, sql: &str) -> Result<Statement<'a>>210 pub fn prepare<'a>(&mut self, conn: &'a Connection, sql: &str) -> Result<Statement<'a>> {
211 let mut c_stmt = ptr::null_mut();
212 let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?;
213 let mut c_tail = ptr::null();
214 let r = unsafe {
215 if cfg!(feature = "unlock_notify") {
216 let mut rc;
217 loop {
218 rc = ffi::sqlite3_prepare_v2(
219 self.db(),
220 c_sql,
221 len,
222 &mut c_stmt as *mut *mut ffi::sqlite3_stmt,
223 &mut c_tail as *mut *const c_char,
224 );
225 if !unlock_notify::is_locked(self.db, rc) {
226 break;
227 }
228 rc = unlock_notify::wait_for_unlock_notify(self.db);
229 if rc != ffi::SQLITE_OK {
230 break;
231 }
232 }
233 rc
234 } else {
235 ffi::sqlite3_prepare_v2(
236 self.db(),
237 c_sql,
238 len,
239 &mut c_stmt as *mut *mut ffi::sqlite3_stmt,
240 &mut c_tail as *mut *const c_char,
241 )
242 }
243 };
244 // If there is an error, *ppStmt is set to NULL.
245 self.decode_result(r)?;
246 // If the input text contains no SQL (if the input is an empty string or a
247 // comment) then *ppStmt is set to NULL.
248 let c_stmt: *mut ffi::sqlite3_stmt = c_stmt;
249 let c_tail: *const c_char = c_tail;
250 let tail = if c_tail.is_null() {
251 0
252 } else {
253 // TODO nightly feature ptr_offset_from #41079
254 let n = (c_tail as isize) - (c_sql as isize);
255 if n <= 0 || n >= len as isize {
256 0
257 } else {
258 n as usize
259 }
260 };
261 Ok(Statement::new(conn, unsafe {
262 RawStatement::new(c_stmt, tail)
263 }))
264 }
265
changes(&mut self) -> usize266 pub fn changes(&mut self) -> usize {
267 unsafe { ffi::sqlite3_changes(self.db()) as usize }
268 }
269
is_autocommit(&self) -> bool270 pub fn is_autocommit(&self) -> bool {
271 unsafe { ffi::sqlite3_get_autocommit(self.db()) != 0 }
272 }
273
274 #[cfg(feature = "modern_sqlite")] // 3.8.6
is_busy(&self) -> bool275 pub fn is_busy(&self) -> bool {
276 let db = self.db();
277 unsafe {
278 let mut stmt = ffi::sqlite3_next_stmt(db, ptr::null_mut());
279 while !stmt.is_null() {
280 if ffi::sqlite3_stmt_busy(stmt) != 0 {
281 return true;
282 }
283 stmt = ffi::sqlite3_next_stmt(db, stmt);
284 }
285 }
286 false
287 }
288
289 #[cfg(not(feature = "hooks"))]
remove_hooks(&mut self)290 fn remove_hooks(&mut self) {}
291 }
292
293 impl Drop for InnerConnection {
294 #[allow(unused_must_use)]
drop(&mut self)295 fn drop(&mut self) {
296 use std::thread::panicking;
297
298 if let Err(e) = self.close() {
299 if panicking() {
300 eprintln!("Error while closing SQLite connection: {:?}", e);
301 } else {
302 panic!("Error while closing SQLite connection: {:?}", e);
303 }
304 }
305 }
306 }
307
308 #[cfg(not(feature = "bundled"))]
309 static SQLITE_VERSION_CHECK: std::sync::Once = std::sync::Once::new();
310 #[cfg(not(feature = "bundled"))]
311 pub static BYPASS_VERSION_CHECK: AtomicBool = AtomicBool::new(false);
312
313 #[cfg(not(feature = "bundled"))]
ensure_valid_sqlite_version()314 fn ensure_valid_sqlite_version() {
315 use crate::version::version;
316
317 SQLITE_VERSION_CHECK.call_once(|| {
318 let version_number = version_number();
319
320 // Check our hard floor.
321 if version_number < 3_006_008 {
322 panic!("rusqlite requires SQLite 3.6.8 or newer");
323 }
324
325 // Check that the major version number for runtime and buildtime match.
326 let buildtime_major = ffi::SQLITE_VERSION_NUMBER / 1_000_000;
327 let runtime_major = version_number / 1_000_000;
328 if buildtime_major != runtime_major {
329 panic!(
330 "rusqlite was built against SQLite {} but is running with SQLite {}",
331 str::from_utf8(ffi::SQLITE_VERSION).unwrap(),
332 version()
333 );
334 }
335
336 if BYPASS_VERSION_CHECK.load(Ordering::Relaxed) {
337 return;
338 }
339
340 // Check that the runtime version number is compatible with the version number
341 // we found at build-time.
342 if version_number < ffi::SQLITE_VERSION_NUMBER {
343 panic!(
344 "\
345 rusqlite was built against SQLite {} but the runtime SQLite version is {}. To fix this, either:
346 * Recompile rusqlite and link against the SQLite version you are using at runtime, or
347 * Call rusqlite::bypass_sqlite_version_check() prior to your first connection attempt. Doing this
348 means you're sure everything will work correctly even though the runtime version is older than
349 the version we found at build time.",
350 str::from_utf8(ffi::SQLITE_VERSION).unwrap(),
351 version()
352 );
353 }
354 });
355 }
356
357 #[cfg(not(any(target_arch = "wasm32")))]
358 static SQLITE_INIT: std::sync::Once = std::sync::Once::new();
359
360 pub static BYPASS_SQLITE_INIT: AtomicBool = AtomicBool::new(false);
361
362 // threading mode checks are not necessary (and do not work) on target
363 // platforms that do not have threading (such as webassembly)
364 #[cfg(any(target_arch = "wasm32"))]
ensure_safe_sqlite_threading_mode() -> Result<()>365 fn ensure_safe_sqlite_threading_mode() -> Result<()> {
366 Ok(())
367 }
368
369 #[cfg(not(any(target_arch = "wasm32")))]
ensure_safe_sqlite_threading_mode() -> Result<()>370 fn ensure_safe_sqlite_threading_mode() -> Result<()> {
371 // Ensure SQLite was compiled in thredsafe mode.
372 if unsafe { ffi::sqlite3_threadsafe() == 0 } {
373 return Err(Error::SqliteSingleThreadedMode);
374 }
375
376 // Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode,
377 // but it's possible someone configured it to be in Single-thread mode
378 // before calling into us. That would mean we're exposing an unsafe API via
379 // a safe one (in Rust terminology), which is no good. We have two options
380 // to protect against this, depending on the version of SQLite we're linked
381 // with:
382 //
383 // 1. If we're on 3.7.0 or later, we can ask SQLite for a mutex and check for
384 // the magic value 8. This isn't documented, but it's what SQLite
385 // returns for its mutex allocation function in Single-thread mode.
386 // 2. If we're prior to SQLite 3.7.0, AFAIK there's no way to check the
387 // threading mode. The check we perform for >= 3.7.0 will segfault.
388 // Instead, we insist on being able to call sqlite3_config and
389 // sqlite3_initialize ourself, ensuring we know the threading
390 // mode. This will fail if someone else has already initialized SQLite
391 // even if they initialized it safely. That's not ideal either, which is
392 // why we expose bypass_sqlite_initialization above.
393 if version_number() >= 3_007_000 {
394 const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
395 let is_singlethreaded = unsafe {
396 let mutex_ptr = ffi::sqlite3_mutex_alloc(0);
397 let is_singlethreaded = mutex_ptr as usize == SQLITE_SINGLETHREADED_MUTEX_MAGIC;
398 ffi::sqlite3_mutex_free(mutex_ptr);
399 is_singlethreaded
400 };
401 if is_singlethreaded {
402 Err(Error::SqliteSingleThreadedMode)
403 } else {
404 Ok(())
405 }
406 } else {
407 SQLITE_INIT.call_once(|| {
408 if BYPASS_SQLITE_INIT.load(Ordering::Relaxed) {
409 return;
410 }
411
412 unsafe {
413 let msg = "\
414 Could not ensure safe initialization of SQLite.
415 To fix this, either:
416 * Upgrade SQLite to at least version 3.7.0
417 * Ensure that SQLite has been initialized in Multi-thread or Serialized mode and call
418 rusqlite::bypass_sqlite_initialization() prior to your first connection attempt.";
419
420 if ffi::sqlite3_config(ffi::SQLITE_CONFIG_MULTITHREAD) != ffi::SQLITE_OK {
421 panic!(msg);
422 }
423 if ffi::sqlite3_initialize() != ffi::SQLITE_OK {
424 panic!(msg);
425 }
426 }
427 });
428 Ok(())
429 }
430 }
431