• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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