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             let r = ffi::sqlite3_busy_timeout(db, 5000);
110             if r != ffi::SQLITE_OK {
111                 let e = error_from_handle(db, r);
112                 ffi::sqlite3_close(db);
113                 return Err(e);
114             }
115 
116             // attempt to turn on extended results code; don't fail if we can't.
117             ffi::sqlite3_extended_result_codes(db, 1);
118 
119             Ok(InnerConnection::new(db, true))
120         }
121     }
122 
db(&self) -> *mut ffi::sqlite3123     pub fn db(&self) -> *mut ffi::sqlite3 {
124         self.db
125     }
126 
decode_result(&mut self, code: c_int) -> Result<()>127     pub fn decode_result(&mut self, code: c_int) -> Result<()> {
128         unsafe { InnerConnection::decode_result_raw(self.db(), code) }
129     }
130 
decode_result_raw(db: *mut ffi::sqlite3, code: c_int) -> Result<()>131     unsafe fn decode_result_raw(db: *mut ffi::sqlite3, code: c_int) -> Result<()> {
132         if code == ffi::SQLITE_OK {
133             Ok(())
134         } else {
135             Err(error_from_handle(db, code))
136         }
137     }
138 
139     #[allow(clippy::mutex_atomic)]
close(&mut self) -> Result<()>140     pub fn close(&mut self) -> Result<()> {
141         if self.db.is_null() {
142             return Ok(());
143         }
144         self.remove_hooks();
145         let mut shared_handle = self.interrupt_lock.lock().unwrap();
146         assert!(
147             !shared_handle.is_null(),
148             "Bug: Somehow interrupt_lock was cleared before the DB was closed"
149         );
150         if !self.owned {
151             self.db = ptr::null_mut();
152             return Ok(());
153         }
154         unsafe {
155             let r = ffi::sqlite3_close(self.db);
156             // Need to use _raw because _guard has a reference out, and
157             // decode_result takes &mut self.
158             let r = InnerConnection::decode_result_raw(self.db, r);
159             if r.is_ok() {
160                 *shared_handle = ptr::null_mut();
161                 self.db = ptr::null_mut();
162             }
163             r
164         }
165     }
166 
get_interrupt_handle(&self) -> InterruptHandle167     pub fn get_interrupt_handle(&self) -> InterruptHandle {
168         InterruptHandle {
169             db_lock: Arc::clone(&self.interrupt_lock),
170         }
171     }
172 
execute_batch(&mut self, sql: &str) -> Result<()>173     pub fn execute_batch(&mut self, sql: &str) -> Result<()> {
174         // use CString instead of SmallCString because it's probably big.
175         let c_sql = std::ffi::CString::new(sql)?;
176         unsafe {
177             let r = ffi::sqlite3_exec(
178                 self.db(),
179                 c_sql.as_ptr(),
180                 None,
181                 ptr::null_mut(),
182                 ptr::null_mut(),
183             );
184             self.decode_result(r)
185         }
186     }
187 
188     #[cfg(feature = "load_extension")]
enable_load_extension(&mut self, onoff: c_int) -> Result<()>189     pub fn enable_load_extension(&mut self, onoff: c_int) -> Result<()> {
190         let r = unsafe { ffi::sqlite3_enable_load_extension(self.db, onoff) };
191         self.decode_result(r)
192     }
193 
194     #[cfg(feature = "load_extension")]
load_extension(&self, dylib_path: &Path, entry_point: Option<&str>) -> Result<()>195     pub fn load_extension(&self, dylib_path: &Path, entry_point: Option<&str>) -> Result<()> {
196         let dylib_str = super::path_to_cstring(dylib_path)?;
197         unsafe {
198             let mut errmsg: *mut c_char = ptr::null_mut();
199             let r = if let Some(entry_point) = entry_point {
200                 let c_entry = crate::str_to_cstring(entry_point)?;
201                 ffi::sqlite3_load_extension(
202                     self.db,
203                     dylib_str.as_ptr(),
204                     c_entry.as_ptr(),
205                     &mut errmsg,
206                 )
207             } else {
208                 ffi::sqlite3_load_extension(self.db, dylib_str.as_ptr(), ptr::null(), &mut errmsg)
209             };
210             if r == ffi::SQLITE_OK {
211                 Ok(())
212             } else {
213                 let message = super::errmsg_to_string(errmsg);
214                 ffi::sqlite3_free(errmsg as *mut ::std::os::raw::c_void);
215                 Err(error_from_sqlite_code(r, Some(message)))
216             }
217         }
218     }
219 
last_insert_rowid(&self) -> i64220     pub fn last_insert_rowid(&self) -> i64 {
221         unsafe { ffi::sqlite3_last_insert_rowid(self.db()) }
222     }
223 
prepare<'a>(&mut self, conn: &'a Connection, sql: &str) -> Result<Statement<'a>>224     pub fn prepare<'a>(&mut self, conn: &'a Connection, sql: &str) -> Result<Statement<'a>> {
225         let mut c_stmt = ptr::null_mut();
226         let (c_sql, len, _) = str_for_sqlite(sql.as_bytes())?;
227         let mut c_tail = ptr::null();
228         let r = unsafe {
229             if cfg!(feature = "unlock_notify") {
230                 let mut rc;
231                 loop {
232                     rc = ffi::sqlite3_prepare_v2(
233                         self.db(),
234                         c_sql,
235                         len,
236                         &mut c_stmt as *mut *mut ffi::sqlite3_stmt,
237                         &mut c_tail as *mut *const c_char,
238                     );
239                     if !unlock_notify::is_locked(self.db, rc) {
240                         break;
241                     }
242                     rc = unlock_notify::wait_for_unlock_notify(self.db);
243                     if rc != ffi::SQLITE_OK {
244                         break;
245                     }
246                 }
247                 rc
248             } else {
249                 ffi::sqlite3_prepare_v2(
250                     self.db(),
251                     c_sql,
252                     len,
253                     &mut c_stmt as *mut *mut ffi::sqlite3_stmt,
254                     &mut c_tail as *mut *const c_char,
255                 )
256             }
257         };
258         // If there is an error, *ppStmt is set to NULL.
259         self.decode_result(r)?;
260         // If the input text contains no SQL (if the input is an empty string or a
261         // comment) then *ppStmt is set to NULL.
262         let c_stmt: *mut ffi::sqlite3_stmt = c_stmt;
263         let c_tail: *const c_char = c_tail;
264         // TODO ignore spaces, comments, ... at the end
265         let tail = !c_tail.is_null() && unsafe { c_tail != c_sql.offset(len as isize) };
266         Ok(Statement::new(conn, unsafe {
267             RawStatement::new(c_stmt, tail)
268         }))
269     }
270 
changes(&mut self) -> usize271     pub fn changes(&mut self) -> usize {
272         unsafe { ffi::sqlite3_changes(self.db()) as usize }
273     }
274 
is_autocommit(&self) -> bool275     pub fn is_autocommit(&self) -> bool {
276         unsafe { ffi::sqlite3_get_autocommit(self.db()) != 0 }
277     }
278 
279     #[cfg(feature = "modern_sqlite")] // 3.8.6
is_busy(&self) -> bool280     pub fn is_busy(&self) -> bool {
281         let db = self.db();
282         unsafe {
283             let mut stmt = ffi::sqlite3_next_stmt(db, ptr::null_mut());
284             while !stmt.is_null() {
285                 if ffi::sqlite3_stmt_busy(stmt) != 0 {
286                     return true;
287                 }
288                 stmt = ffi::sqlite3_next_stmt(db, stmt);
289             }
290         }
291         false
292     }
293 
294     #[cfg(not(feature = "hooks"))]
remove_hooks(&mut self)295     fn remove_hooks(&mut self) {}
296 }
297 
298 impl Drop for InnerConnection {
299     #[allow(unused_must_use)]
drop(&mut self)300     fn drop(&mut self) {
301         use std::thread::panicking;
302 
303         if let Err(e) = self.close() {
304             if panicking() {
305                 eprintln!("Error while closing SQLite connection: {:?}", e);
306             } else {
307                 panic!("Error while closing SQLite connection: {:?}", e);
308             }
309         }
310     }
311 }
312 
313 #[cfg(not(feature = "bundled"))]
314 static SQLITE_VERSION_CHECK: std::sync::Once = std::sync::Once::new();
315 #[cfg(not(feature = "bundled"))]
316 pub static BYPASS_VERSION_CHECK: AtomicBool = AtomicBool::new(false);
317 
318 #[cfg(not(feature = "bundled"))]
ensure_valid_sqlite_version()319 fn ensure_valid_sqlite_version() {
320     use crate::version::version;
321 
322     SQLITE_VERSION_CHECK.call_once(|| {
323         let version_number = version_number();
324 
325         // Check our hard floor.
326         if version_number < 3_006_008 {
327             panic!("rusqlite requires SQLite 3.6.8 or newer");
328         }
329 
330         // Check that the major version number for runtime and buildtime match.
331         let buildtime_major = ffi::SQLITE_VERSION_NUMBER / 1_000_000;
332         let runtime_major = version_number / 1_000_000;
333         if buildtime_major != runtime_major {
334             panic!(
335                 "rusqlite was built against SQLite {} but is running with SQLite {}",
336                 str::from_utf8(ffi::SQLITE_VERSION).unwrap(),
337                 version()
338             );
339         }
340 
341         if BYPASS_VERSION_CHECK.load(Ordering::Relaxed) {
342             return;
343         }
344 
345         // Check that the runtime version number is compatible with the version number
346         // we found at build-time.
347         if version_number < ffi::SQLITE_VERSION_NUMBER {
348             panic!(
349                 "\
350 rusqlite was built against SQLite {} but the runtime SQLite version is {}. To fix this, either:
351 * Recompile rusqlite and link against the SQLite version you are using at runtime, or
352 * Call rusqlite::bypass_sqlite_version_check() prior to your first connection attempt. Doing this
353   means you're sure everything will work correctly even though the runtime version is older than
354   the version we found at build time.",
355                 str::from_utf8(ffi::SQLITE_VERSION).unwrap(),
356                 version()
357             );
358         }
359     });
360 }
361 
362 #[cfg(not(any(target_arch = "wasm32")))]
363 static SQLITE_INIT: std::sync::Once = std::sync::Once::new();
364 
365 pub static BYPASS_SQLITE_INIT: AtomicBool = AtomicBool::new(false);
366 
367 // threading mode checks are not necessary (and do not work) on target
368 // platforms that do not have threading (such as webassembly)
369 #[cfg(any(target_arch = "wasm32"))]
ensure_safe_sqlite_threading_mode() -> Result<()>370 fn ensure_safe_sqlite_threading_mode() -> Result<()> {
371     Ok(())
372 }
373 
374 #[cfg(not(any(target_arch = "wasm32")))]
ensure_safe_sqlite_threading_mode() -> Result<()>375 fn ensure_safe_sqlite_threading_mode() -> Result<()> {
376     // Ensure SQLite was compiled in thredsafe mode.
377     if unsafe { ffi::sqlite3_threadsafe() == 0 } {
378         return Err(Error::SqliteSingleThreadedMode);
379     }
380 
381     // Now we know SQLite is _capable_ of being in Multi-thread of Serialized mode,
382     // but it's possible someone configured it to be in Single-thread mode
383     // before calling into us. That would mean we're exposing an unsafe API via
384     // a safe one (in Rust terminology), which is no good. We have two options
385     // to protect against this, depending on the version of SQLite we're linked
386     // with:
387     //
388     // 1. If we're on 3.7.0 or later, we can ask SQLite for a mutex and check for
389     //    the magic value 8. This isn't documented, but it's what SQLite
390     //    returns for its mutex allocation function in Single-thread mode.
391     // 2. If we're prior to SQLite 3.7.0, AFAIK there's no way to check the
392     //    threading mode. The check we perform for >= 3.7.0 will segfault.
393     //    Instead, we insist on being able to call sqlite3_config and
394     //    sqlite3_initialize ourself, ensuring we know the threading
395     //    mode. This will fail if someone else has already initialized SQLite
396     //    even if they initialized it safely. That's not ideal either, which is
397     //    why we expose bypass_sqlite_initialization    above.
398     if version_number() >= 3_007_000 {
399         const SQLITE_SINGLETHREADED_MUTEX_MAGIC: usize = 8;
400         let is_singlethreaded = unsafe {
401             let mutex_ptr = ffi::sqlite3_mutex_alloc(0);
402             let is_singlethreaded = mutex_ptr as usize == SQLITE_SINGLETHREADED_MUTEX_MAGIC;
403             ffi::sqlite3_mutex_free(mutex_ptr);
404             is_singlethreaded
405         };
406         if is_singlethreaded {
407             Err(Error::SqliteSingleThreadedMode)
408         } else {
409             Ok(())
410         }
411     } else {
412         SQLITE_INIT.call_once(|| {
413             if BYPASS_SQLITE_INIT.load(Ordering::Relaxed) {
414                 return;
415             }
416 
417             unsafe {
418                 let msg = "\
419 Could not ensure safe initialization of SQLite.
420 To fix this, either:
421 * Upgrade SQLite to at least version 3.7.0
422 * Ensure that SQLite has been initialized in Multi-thread or Serialized mode and call
423   rusqlite::bypass_sqlite_initialization() prior to your first connection attempt.";
424 
425                 if ffi::sqlite3_config(ffi::SQLITE_CONFIG_MULTITHREAD) != ffi::SQLITE_OK {
426                     panic!(msg);
427                 }
428                 if ffi::sqlite3_initialize() != ffi::SQLITE_OK {
429                     panic!(msg);
430                 }
431             }
432         });
433         Ok(())
434     }
435 }
436