sqlite_ll/connection.rs
1use core::ffi::CStr;
2use core::ffi::{c_int, c_uint, c_void};
3use core::mem::MaybeUninit;
4use core::ops::BitOr;
5use core::ptr;
6use core::ptr::NonNull;
7
8#[cfg(feature = "std")]
9use std::path::Path;
10
11use crate::State;
12use crate::error::{Error, Result};
13use crate::owned::Owned;
14use crate::statement::Statement;
15use crate::utils::sqlite3_try;
16
17use sqlite3_sys as ffi;
18
19/// A collection of flags use to prepare a statement.
20pub struct Prepare(c_uint);
21
22impl Prepare {
23 /// No flags.
24 ///
25 /// This provides the default behavior when preparing a statement.
26 pub const EMPTY: Self = Self(0);
27
28 /// The PERSISTENT flag is a hint to the query planner that the prepared
29 /// statement will be retained for a long time and probably reused many
30 /// times. Without this flag, sqlite3_prepare_v3() and
31 /// sqlite3_prepare16_v3() assume that the prepared statement will be used
32 /// just once or at most a few times and then destroyed using
33 /// sqlite3_finalize() relatively soon. The current implementation acts on
34 /// this hint by avoiding the use of lookaside memory so as not to deplete
35 /// the limited store of lookaside memory. Future versions of SQLite may act
36 /// on this hint differently.
37 pub const PERSISTENT: Self = Self(ffi::SQLITE_PREPARE_PERSISTENT as c_uint);
38
39 /// The NORMALIZE flag is a no-op. This flag used to be required for any
40 /// prepared statement that wanted to use the sqlite3_normalized_sql()
41 /// interface. However, the sqlite3_normalized_sql() interface is now
42 /// available to all prepared statements, regardless of whether or not they
43 /// use this flag.
44 pub const NORMALIZE: Self = Self(ffi::SQLITE_PREPARE_NORMALIZE as c_uint);
45
46 /// The NO_VTAB flag causes the SQL compiler to return an error if the
47 /// statement uses any virtual tables.
48 pub const NO_VTAB: Self = Self(ffi::SQLITE_PREPARE_NO_VTAB as c_uint);
49}
50
51impl BitOr for Prepare {
52 type Output = Self;
53
54 fn bitor(self, rhs: Self) -> Self::Output {
55 Self(self.0 | rhs.0)
56 }
57}
58
59/// A sqlite database connection.
60///
61/// Connections are not thread-safe objects.
62///
63/// # Examples
64///
65/// Opening a connection to a filesystem path:
66///
67/// ```no_run
68/// use sqlite_ll::Connection;
69///
70/// let c = Connection::open("database.db")?;
71/// c.execute("CREATE TABLE test (id INTEGER);")?;
72/// # Ok::<_, sqlite_ll::Error>(())
73/// ```
74///
75/// Opening an in-memory database:
76///
77/// ```
78/// use sqlite_ll::Connection;
79///
80/// let c = Connection::open_memory()?;
81/// c.execute("CREATE TABLE test (id INTEGER);")?;
82/// # Ok::<_, sqlite_ll::Error>(())
83/// ```
84pub struct Connection {
85 raw: NonNull<ffi::sqlite3>,
86 busy_callback: Option<Owned>,
87}
88
89/// Connection is `Send`.
90unsafe impl Send for Connection {}
91
92impl Connection {
93 /// Open a database to the given path.
94 ///
95 /// Note that it is possible to open an in-memory database by passing
96 /// `":memory:"` here, this call might require allocating depending on the
97 /// platform, so it should be avoided in favor of using [`memory`]. To avoid
98 /// allocating for regular paths, you can use [`open_c_str`], however you
99 /// are responsible for ensuring the c-string is a valid path.
100 ///
101 /// This is the same as calling
102 /// `OpenOptions::new().read_write().create().open(path)`.
103 ///
104 /// [`memory`]: Self::memory
105 /// [`open_c_str`]: Self::open_c_str
106 #[cfg(feature = "std")]
107 #[cfg_attr(docsrs, cfg(feature = "std"))]
108 #[inline]
109 pub fn open(path: impl AsRef<Path>) -> Result<Connection> {
110 OpenOptions::new().read_write().create().open(path)
111 }
112
113 /// Open a database connection with a raw c-string.
114 ///
115 /// This can be used to open in-memory databases by passing `c":memory:"` or
116 /// a regular open call with a filesystem path like
117 /// `c"/path/to/database.sql"`.
118 ///
119 /// This is the same as calling
120 /// `OpenOptions::new().read_write().create().open_c_str(name)`.
121 #[inline]
122 pub fn open_c_str(name: &CStr) -> Result<Connection> {
123 OpenOptions::new().read_write().create().open_c_str(name)
124 }
125
126 /// Open an in-memory database.
127 ///
128 /// This is the same as calling
129 /// `OpenOptions::new().read_write().create().open_memory()`.
130 #[inline]
131 pub fn open_memory() -> Result<Connection> {
132 OpenOptions::new().read_write().create().open_memory()
133 }
134
135 /// Execute a statement without processing the resulting rows if any.
136 #[inline]
137 pub fn execute(&self, stmt: impl AsRef<str>) -> Result<()> {
138 self._execute(stmt.as_ref())
139 }
140
141 fn _execute(&self, stmt: &str) -> Result<()> {
142 unsafe {
143 let mut ptr = stmt.as_ptr().cast();
144 let mut len = stmt.len();
145
146 while len > 0 {
147 let mut raw = MaybeUninit::uninit();
148 let mut rest = MaybeUninit::uninit();
149
150 let l = i32::try_from(len).unwrap_or(i32::MAX);
151
152 let res = ffi::sqlite3_prepare_v3(
153 self.raw.as_ptr(),
154 ptr,
155 l,
156 0,
157 raw.as_mut_ptr(),
158 rest.as_mut_ptr(),
159 );
160
161 if res != ffi::SQLITE_OK {
162 return Err(Error::new(ffi::sqlite3_errcode(self.raw.as_ptr())));
163 }
164
165 let rest = rest.assume_init();
166
167 // If statement is null then it's simply empty, so we can safely
168 // skip it, otherwise iterate over all rows.
169 if let Some(raw) = NonNull::new(raw.assume_init()) {
170 let mut statement = Statement::from_raw(raw);
171 while let State::Row = statement.step()? {}
172 }
173
174 // Skip over empty statements.
175 let o = rest.offset_from_unsigned(ptr);
176 len -= o;
177 ptr = rest;
178 }
179
180 Ok(())
181 }
182 }
183
184 /// Build a prepared statement.
185 ///
186 /// This is the same as calling `prepare_with` with `Prepare::EMPTY`.
187 ///
188 /// The database connection will be kept open for the lifetime of this
189 /// statement.
190 ///
191 /// # Errors
192 ///
193 /// If the prepare call contains multiple statements, it will error. To
194 /// execute multiple statements, use [`execute`] instead.
195 ///
196 /// ```
197 /// use sqlite_ll::{Connection, Code};
198 ///
199 /// let c = Connection::open_memory()?;
200 ///
201 /// let e = c.prepare(
202 /// "
203 /// CREATE TABLE test (id INTEGER) /* test */;
204 /// INSERT INTO test (id) VALUES (1);
205 /// "
206 /// ).unwrap_err();
207 ///
208 /// assert_eq!(e.code(), Code::ERROR);
209 /// # Ok::<_, sqlite_ll::Error>(())
210 /// ```
211 ///
212 /// [`execute`]: Self::execute
213 ///
214 /// # Examples
215 ///
216 /// ```
217 /// use sqlite_ll::{Connection, State, Prepare};
218 ///
219 /// let c = Connection::open_memory()?;
220 /// c.execute("CREATE TABLE test (id INTEGER);")?;
221 ///
222 /// let mut insert_stmt = c.prepare("INSERT INTO test (id) VALUES (?);")?;
223 /// let mut query_stmt = c.prepare("SELECT id FROM test;")?;
224 ///
225 /// drop(c);
226 ///
227 /// insert_stmt.reset()?;
228 /// insert_stmt.bind(1, 42)?;
229 /// assert_eq!(insert_stmt.step()?, State::Done);
230 ///
231 /// query_stmt.reset()?;
232 ///
233 /// while let State::Row = query_stmt.step()? {
234 /// let id: i64 = query_stmt.read(0)?;
235 /// assert_eq!(id, 42);
236 /// }
237 /// # Ok::<_, sqlite_ll::Error>(())
238 /// ```
239 #[inline]
240 pub fn prepare(&self, stmt: impl AsRef<str>) -> Result<Statement> {
241 self.prepare_with(stmt, Prepare::EMPTY)
242 }
243
244 /// Build a prepared statement with custom flags.
245 ///
246 /// For long-running statements it is recommended that they have the
247 /// [`Prepare::PERSISTENT`] flag set.
248 ///
249 /// The database connection will be kept open for the lifetime of this
250 /// statement.
251 ///
252 /// # Errors
253 ///
254 /// If the prepare call contains multiple statements, it will error. To
255 /// execute multiple statements, use [`execute`] instead.
256 ///
257 /// ```
258 /// use sqlite_ll::{Connection, Code, Prepare};
259 ///
260 /// let c = Connection::open_memory()?;
261 ///
262 /// let e = c.prepare_with(
263 /// "
264 /// CREATE TABLE test (id INTEGER) /* test */;
265 /// INSERT INTO test (id) VALUES (1);
266 /// ",
267 /// Prepare::PERSISTENT
268 /// ).unwrap_err();
269 /// assert_eq!(e.code(), Code::ERROR);
270 /// # Ok::<_, sqlite_ll::Error>(())
271 /// ```
272 ///
273 /// [`execute`]: Self::execute
274 ///
275 /// # Examples
276 ///
277 /// ```
278 /// use sqlite_ll::{Connection, State, Prepare};
279 ///
280 /// let c = Connection::open_memory()?;
281 /// c.execute("CREATE TABLE test (id INTEGER);")?;
282 ///
283 /// let mut insert_stmt = c.prepare_with("INSERT INTO test (id) VALUES (?);", Prepare::PERSISTENT)?;
284 /// let mut query_stmt = c.prepare_with("SELECT id FROM test;", Prepare::PERSISTENT)?;
285 ///
286 /// drop(c);
287 ///
288 /// /* .. */
289 ///
290 /// insert_stmt.reset()?;
291 /// insert_stmt.bind(1, 42)?;
292 /// assert_eq!(insert_stmt.step()?, State::Done);
293 ///
294 /// query_stmt.reset()?;
295 ///
296 /// while let State::Row = query_stmt.step()? {
297 /// let id: i64 = query_stmt.read(0)?;
298 /// assert_eq!(id, 42);
299 /// }
300 /// # Ok::<_, sqlite_ll::Error>(())
301 /// ```
302 pub fn prepare_with(&self, stmt: impl AsRef<str>, flags: Prepare) -> Result<Statement> {
303 let stmt = stmt.as_ref();
304
305 unsafe {
306 let mut raw = MaybeUninit::uninit();
307 let mut rest = MaybeUninit::uninit();
308
309 let ptr = stmt.as_ptr().cast();
310 let len = i32::try_from(stmt.len()).unwrap_or(i32::MAX);
311
312 sqlite3_try! {
313 ffi::sqlite3_prepare_v3(
314 self.raw.as_ptr(),
315 ptr,
316 len,
317 flags.0,
318 raw.as_mut_ptr(),
319 rest.as_mut_ptr(),
320 )
321 };
322
323 let rest = rest.assume_init();
324
325 let o = rest.offset_from_unsigned(ptr);
326
327 if o != stmt.len() {
328 return Err(Error::new(ffi::SQLITE_ERROR));
329 }
330
331 let raw = ptr::NonNull::new_unchecked(raw.assume_init());
332 Ok(Statement::from_raw(raw))
333 }
334 }
335
336 /// Return the number of rows inserted, updated, or deleted by the most
337 /// recent INSERT, UPDATE, or DELETE statement.
338 #[inline]
339 pub fn change_count(&self) -> usize {
340 unsafe { ffi::sqlite3_changes(self.raw.as_ptr()) as usize }
341 }
342
343 /// Return the total number of rows inserted, updated, and deleted by all
344 /// INSERT, UPDATE, and DELETE statements since the connection was opened.
345 #[inline]
346 pub fn total_change_count(&self) -> usize {
347 unsafe { ffi::sqlite3_total_changes(self.raw.as_ptr()) as usize }
348 }
349
350 /// Set a callback for handling busy events.
351 ///
352 /// The callback is triggered when the database cannot perform an operation
353 /// due to processing of some other request. If the callback returns `true`,
354 /// the operation will be repeated.
355 pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()>
356 where
357 F: FnMut(usize) -> bool + Send + 'static,
358 {
359 self.remove_busy_handler()?;
360
361 unsafe {
362 let callback = Owned::new(callback)?;
363
364 let result = ffi::sqlite3_busy_handler(
365 self.raw.as_ptr(),
366 Some(busy_callback::<F>),
367 callback.as_ptr().cast(),
368 );
369
370 self.busy_callback = Some(callback);
371 sqlite3_try!(result);
372 }
373
374 Ok(())
375 }
376
377 /// Set an implicit callback for handling busy events that tries to repeat
378 /// rejected operations until a timeout expires.
379 #[inline]
380 pub fn set_busy_timeout(&mut self, ms: c_int) -> Result<()> {
381 unsafe {
382 sqlite3_try! {
383 ffi::sqlite3_busy_timeout(
384 self.raw.as_ptr(),
385 ms
386 )
387 };
388 }
389
390 Ok(())
391 }
392
393 /// Remove the callback handling busy events.
394 #[inline]
395 pub fn remove_busy_handler(&mut self) -> Result<()> {
396 unsafe {
397 sqlite3_try! {
398 ffi::sqlite3_busy_handler(
399 self.raw.as_ptr(),
400 None,
401 ptr::null_mut()
402 )
403 };
404 }
405
406 self.busy_callback = None;
407 Ok(())
408 }
409}
410
411impl Drop for Connection {
412 #[inline]
413 #[allow(unused_must_use)]
414 fn drop(&mut self) {
415 self.remove_busy_handler();
416
417 // Will close the connection unconditionally. The database will stay
418 // alive until all associated prepared statements have been closed since
419 // we're using v2.
420 let code = unsafe { ffi::sqlite3_close_v2(self.raw.as_ptr()) };
421 debug_assert_eq!(code, sqlite3_sys::SQLITE_OK);
422 }
423}
424
425/// Options that can be used to customize the opening of a SQLite database.
426///
427/// By default the database is opened in multi-threaded mode with the
428/// [`SQLITE_OPEN_NOMUTEX`] set to ensure that [`Statement`] objects can be used
429/// separately from the connection that constructed them.
430///
431/// To avoid this overhead in case you know how the statements will be used, you
432/// can unset this by calling [`unset_no_mutex`].
433///
434/// [`unset_no_mutex`]: Self::unset_no_mutex
435/// [`SQLITE_OPEN_NOMUTEX`]: https://sqlite.org/c3ref/open.html
436#[derive(Clone, Copy, Debug)]
437pub struct OpenOptions {
438 raw: c_int,
439}
440
441impl OpenOptions {
442 /// Create flags for opening a database connection.
443 #[inline]
444 pub fn new() -> Self {
445 Self {
446 raw: ffi::SQLITE_OPEN_NOMUTEX,
447 }
448 }
449
450 /// The database is opened in read-only mode. If the database does not
451 /// already exist, an error is returned.
452 #[inline]
453 pub fn read_only(mut self) -> Self {
454 self.raw |= ffi::SQLITE_OPEN_READONLY;
455 self
456 }
457
458 /// The database is opened for reading and writing if possible, or reading
459 /// only if the file is write protected by the operating system. In either
460 /// case the database must already exist, otherwise an error is returned.
461 /// For historical reasons, if opening in read-write mode fails due to
462 /// OS-level permissions, an attempt is made to open it in read-only mode.
463 /// sqlite3_db_readonly() can be used to determine whether the database is
464 /// actually read-write.
465 #[inline]
466 pub fn read_write(mut self) -> Self {
467 self.raw |= ffi::SQLITE_OPEN_READWRITE;
468 self
469 }
470
471 /// The database is opened for reading and writing, and is created if it
472 /// does not already exist.
473 ///
474 /// Note that a mode option like [`read_write`] must be set, otherwise this
475 /// will cause an error when opening.
476 ///
477 /// [`read_write`]: Self::read_write
478 #[inline]
479 pub fn create(mut self) -> Self {
480 self.raw |= ffi::SQLITE_OPEN_CREATE;
481 self
482 }
483
484 /// The filename can be interpreted as a URI if this flag is set.
485 #[inline]
486 pub fn uri(mut self) -> Self {
487 self.raw |= ffi::SQLITE_OPEN_URI;
488 self
489 }
490
491 /// The database will be opened as an in-memory database. The database is
492 /// named by the "filename" argument for the purposes of cache-sharing, if
493 /// shared cache mode is enabled, but the "filename" is otherwise ignored.
494 #[inline]
495 pub fn memory(mut self) -> Self {
496 self.raw |= ffi::SQLITE_OPEN_MEMORY;
497 self
498 }
499
500 /// The new database connection will use the "multi-thread" [threading mode].
501 /// This means that separate threads are allowed to use SQLite at the same
502 /// time, as long as each thread is using a different database connection.
503 ///
504 /// [threading mode]: https://www.sqlite.org/threadsafe.html
505 #[inline]
506 pub fn no_mutex(mut self) -> Self {
507 self.raw |= ffi::SQLITE_OPEN_NOMUTEX;
508 self
509 }
510
511 /// The new database connection will use the "serialized" [threading mode].
512 /// This means the multiple threads can safely attempt to use the same
513 /// database connection at the same time. Mutexes will block any actual
514 /// concurrency, but in this mode there is no harm in trying.
515 ///
516 /// [threading mode]: https://sqlite.org/threadsafe.html
517 #[inline]
518 pub fn full_mutex(mut self) -> Self {
519 self.raw |= ffi::SQLITE_OPEN_FULLMUTEX;
520 self
521 }
522
523 /// Set the database to be opened without the "multi-thread" [threading
524 /// mode]. The effect of calling this is that [`open_full_mutex`] and
525 /// [`open_no_mutex`] are unset.
526 ///
527 /// [threading mode]: https://www.sqlite.org/threadsafe.html
528 ///
529 /// # Safety
530 ///
531 /// Prepared statements being separated from the connection object rely on
532 /// sqlite being in a multi-threaded mode to work safely. Unsetting this
533 /// option means you take responsibility for ensuring that no two threads
534 /// access the same connection even indirectly through [`Statement`]
535 /// simultaneously.
536 #[inline]
537 pub unsafe fn unsynchronized(mut self) -> Self {
538 self.raw &= !(ffi::SQLITE_OPEN_NOMUTEX | ffi::SQLITE_OPEN_FULLMUTEX);
539 self
540 }
541
542 /// The database is opened with shared cache enabled, overriding the default
543 /// shared cache setting provided. The use of shared cache mode is
544 /// discouraged and hence shared cache capabilities may be omitted from many
545 /// builds of SQLite. In such cases, this option is a no-op.
546 #[inline]
547 pub fn shared_cache(mut self) -> Self {
548 self.raw |= ffi::SQLITE_OPEN_SHAREDCACHE;
549 self
550 }
551
552 /// The database is opened with shared cache disabled, overriding the
553 /// default shared cache setting provided.
554 #[inline]
555 pub fn private_cache(mut self) -> Self {
556 self.raw |= ffi::SQLITE_OPEN_PRIVATECACHE;
557 self
558 }
559
560 /// The database connection comes up in "extended result code mode". In
561 /// other words, the database behaves as if
562 /// [`Connection::extended_result_codes`] were called on the database
563 /// connection as soon as the connection is created. In addition to setting
564 /// the extended result code mode, this flag also causes the [`open`] call
565 /// to return an extended result code.
566 ///
567 /// [`open`]: Self::open
568 #[inline]
569 pub fn extended_result_code(mut self) -> Self {
570 self.raw |= ffi::SQLITE_OPEN_EXRESCODE;
571 self
572 }
573
574 /// The database filename is not allowed to contain a symbolic link.
575 #[inline]
576 pub fn no_follow(mut self) -> Self {
577 self.raw |= ffi::SQLITE_OPEN_NOFOLLOW;
578 self
579 }
580
581 /// Open a database to the given path.
582 ///
583 /// Note that it is possible to open an in-memory database by passing
584 /// `":memory:"` here, this call might require allocating depending on the
585 /// platform, so it should be avoided in favor of using [`memory`]. To avoid
586 /// allocating for regular paths, you can use [`open_c_str`], however you
587 /// are responsible for ensuring the c-string is a valid path.
588 ///
589 /// [`memory`]: Self::memory
590 /// [`open_c_str`]: Self::open_c_str
591 #[cfg(feature = "std")]
592 #[cfg_attr(docsrs, cfg(feature = "std"))]
593 pub fn open(&self, path: impl AsRef<Path>) -> Result<Connection> {
594 let path = crate::utils::path_to_cstring(path.as_ref())?;
595 self._open(&path)
596 }
597
598 /// Open a database connection with a raw c-string.
599 ///
600 /// This can be used to open in-memory databases by passing `c":memory:"` or
601 /// a regular open call with a filesystem path like
602 /// `c"/path/to/database.sql"`.
603 pub fn open_c_str(&self, name: &CStr) -> Result<Connection> {
604 self._open(name)
605 }
606
607 /// Open an in-memory database.
608 pub fn open_memory(&self) -> Result<Connection> {
609 self._open(c":memory:")
610 }
611
612 fn _open(&self, name: &CStr) -> Result<Connection> {
613 unsafe {
614 let mut raw = MaybeUninit::uninit();
615
616 let code = ffi::sqlite3_open_v2(name.as_ptr(), raw.as_mut_ptr(), self.raw, ptr::null());
617
618 let raw = raw.assume_init();
619
620 if code != ffi::SQLITE_OK {
621 ffi::sqlite3_close(raw);
622 return Err(Error::new(code));
623 }
624
625 Ok(Connection {
626 raw: NonNull::new_unchecked(raw),
627 busy_callback: None,
628 })
629 }
630 }
631}
632
633extern "C" fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
634where
635 F: FnMut(usize) -> bool,
636{
637 unsafe {
638 if (*(callback as *mut F))(attempts as usize) {
639 1
640 } else {
641 0
642 }
643 }
644}