sqll/connection.rs
1use core::ffi::CStr;
2use core::ffi::{c_int, c_longlong, 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 alloc::ffi::CString;
10
11#[cfg(feature = "std")]
12use std::path::Path;
13
14use crate::State;
15use crate::error::{Code, Error, Result};
16use crate::ffi;
17use crate::owned::Owned;
18use crate::statement::Statement;
19use crate::utils::{c_to_str, sqlite3_try};
20
21/// A collection of flags use to prepare a statement.
22pub struct Prepare(c_uint);
23
24impl Prepare {
25 /// No flags.
26 ///
27 /// This provides the default behavior when preparing a statement.
28 pub const EMPTY: Self = Self(0);
29
30 /// The PERSISTENT flag is a hint to the query planner that the prepared
31 /// statement will be retained for a long time and probably reused many
32 /// times. Without this flag, [`Connection::prepare`] assume that the
33 /// prepared statement will be used just once or at most a few times and
34 /// then destroyed relatively soon.
35 ///
36 /// The current implementation acts on this hint by avoiding the use of
37 /// lookaside memory so as not to deplete the limited store of lookaside
38 /// memory. Future versions of SQLite may act on this hint differently.
39 pub const PERSISTENT: Self = Self(ffi::SQLITE_PREPARE_PERSISTENT as c_uint);
40
41 /// The NORMALIZE flag is a no-op. This flag used to be required for any
42 /// prepared statement that wanted to use the normalized sql interface.
43 /// However, the normalized sql interface is now available to all prepared
44 /// statements, regardless of whether or not they use this flag.
45 pub const NORMALIZE: Self = Self(ffi::SQLITE_PREPARE_NORMALIZE as c_uint);
46
47 /// The NO_VTAB flag causes the SQL compiler to return an error if the
48 /// statement uses any virtual tables.
49 pub const NO_VTAB: Self = Self(ffi::SQLITE_PREPARE_NO_VTAB as c_uint);
50}
51
52impl BitOr for Prepare {
53 type Output = Self;
54
55 fn bitor(self, rhs: Self) -> Self::Output {
56 Self(self.0 | rhs.0)
57 }
58}
59
60/// A sqlite database connection.
61///
62/// Connections are not thread-safe objects.
63///
64/// # Examples
65///
66/// Opening a connection to a filesystem path:
67///
68/// ```no_run
69/// use sqll::Connection;
70///
71/// let c = Connection::open("database.db")?;
72/// c.execute("CREATE TABLE test (id INTEGER);")?;
73/// # Ok::<_, sqll::Error>(())
74/// ```
75///
76/// Opening an in-memory database:
77///
78/// ```
79/// use sqll::Connection;
80///
81/// let c = Connection::open_memory()?;
82/// c.execute("CREATE TABLE test (id INTEGER);")?;
83/// # Ok::<_, sqll::Error>(())
84/// ```
85pub struct Connection {
86 raw: NonNull<ffi::sqlite3>,
87 busy_callback: Option<Owned>,
88}
89
90/// Connection is `Send`.
91#[cfg(feature = "threadsafe")]
92unsafe impl Send for Connection {}
93
94impl Connection {
95 /// Open a database to the given path.
96 ///
97 /// Note that it is possible to open an in-memory database by passing
98 /// `":memory:"` here, this call might require allocating depending on the
99 /// platform, so it should be avoided in favor of using [`open_memory`]. To avoid
100 /// allocating for regular paths, you can use [`open_c_str`], however you
101 /// are responsible for ensuring the c-string is a valid path.
102 ///
103 /// This is the same as calling:
104 ///
105 /// ```
106 /// use sqll::OpenOptions;
107 /// # let path = ":memory:";
108 ///
109 /// let c = OpenOptions::new()
110 /// .extended_result_codes()
111 /// .read_write()
112 /// .create()
113 /// .open(path)?;
114 ///
115 /// # Ok::<_, sqll::Error>(())
116 /// ```
117 ///
118 /// [`open_memory`]: Self::open_memory
119 /// [`open_c_str`]: Self::open_c_str
120 #[cfg(feature = "std")]
121 #[cfg_attr(docsrs, cfg(feature = "std"))]
122 #[inline]
123 pub fn open(path: impl AsRef<Path>) -> Result<Connection> {
124 OpenOptions::new()
125 .extended_result_codes()
126 .read_write()
127 .create()
128 .open(path)
129 }
130
131 /// Open a database connection with a raw c-string.
132 ///
133 /// This can be used to open in-memory databases by passing `c":memory:"` or
134 /// a regular open call with a filesystem path like
135 /// `c"/path/to/database.sql"`.
136 ///
137 /// This is the same as calling:
138 ///
139 /// ```
140 /// use sqll::OpenOptions;
141 /// # let name = c":memory:";
142 ///
143 /// let c = OpenOptions::new()
144 /// .extended_result_codes()
145 /// .read_write()
146 /// .create()
147 /// .open_c_str(name)?;
148 ///
149 /// # Ok::<_, sqll::Error>(())
150 /// ```
151 #[inline]
152 pub fn open_c_str(name: &CStr) -> Result<Connection> {
153 OpenOptions::new()
154 .extended_result_codes()
155 .read_write()
156 .create()
157 .open_c_str(name)
158 }
159
160 /// Open an in-memory database.
161 ///
162 /// This is the same as calling
163 ///
164 /// This is the same as calling:
165 ///
166 /// ```
167 /// use sqll::OpenOptions;
168 ///
169 /// let c = OpenOptions::new()
170 /// .extended_result_codes()
171 /// .read_write()
172 /// .create()
173 /// .open_memory()?;
174 ///
175 /// # Ok::<_, sqll::Error>(())
176 /// ```
177 #[inline]
178 pub fn open_memory() -> Result<Connection> {
179 OpenOptions::new()
180 .extended_result_codes()
181 .read_write()
182 .create()
183 .open_memory()
184 }
185
186 /// Execute a statement without processing the resulting rows if any.
187 #[inline]
188 pub fn execute(&self, stmt: impl AsRef<str>) -> Result<()> {
189 self._execute(stmt.as_ref())
190 }
191
192 fn _execute(&self, stmt: &str) -> Result<()> {
193 unsafe {
194 let mut ptr = stmt.as_ptr().cast();
195 let mut len = stmt.len();
196
197 while len > 0 {
198 let mut raw = MaybeUninit::uninit();
199 let mut rest = MaybeUninit::uninit();
200
201 let l = i32::try_from(len).unwrap_or(i32::MAX);
202
203 sqlite3_try!(ffi::sqlite3_prepare_v3(
204 self.raw.as_ptr(),
205 ptr,
206 l,
207 0,
208 raw.as_mut_ptr(),
209 rest.as_mut_ptr(),
210 ));
211
212 let rest = rest.assume_init();
213
214 // If statement is null then it's simply empty, so we can safely
215 // skip it, otherwise iterate over all rows.
216 if let Some(raw) = NonNull::new(raw.assume_init()) {
217 let mut statement = Statement::from_raw(raw);
218 while let State::Row = statement.step()? {}
219 }
220
221 // Skip over empty statements.
222 let o = rest.offset_from_unsigned(ptr);
223 len -= o;
224 ptr = rest;
225 }
226
227 Ok(())
228 }
229 }
230
231 /// Enable or disable extended result codes.
232 ///
233 /// This can also be set during construction with
234 /// [`OpenOptions::extended_result_codes`].
235 ///
236 /// # Examples
237 ///
238 /// ```
239 /// use sqll::{OpenOptions, Code};
240 ///
241 /// let mut c = OpenOptions::new().create().read_write().open_memory()?;
242 ///
243 /// let e = c.execute("
244 /// CREATE TABLE users (name TEXT);
245 /// CREATE UNIQUE INDEX idx_users_name ON users (name);
246 ///
247 /// INSERT INTO users VALUES ('Bob');
248 /// ");
249 ///
250 /// let e = c.execute("INSERT INTO users VALUES ('Bob')").unwrap_err();
251 /// assert_eq!(e.code(), Code::CONSTRAINT);
252 ///
253 /// c.set_extended_result_codes(true)?;
254 ///
255 /// let e = c.execute("INSERT INTO users VALUES ('Bob')").unwrap_err();
256 /// assert_eq!(e.code(), Code::CONSTRAINT_UNIQUE);
257 /// # Ok::<_, sqll::Error>(())
258 /// ```
259 pub fn set_extended_result_codes(&mut self, enabled: bool) -> Result<()> {
260 unsafe {
261 let onoff = i32::from(enabled);
262
263 sqlite3_try!(ffi::sqlite3_extended_result_codes(self.raw.as_ptr(), onoff));
264 }
265
266 Ok(())
267 }
268
269 /// Get the last error message for this connection.
270 ///
271 /// When operating in multi-threaded environment, the error message seen
272 /// here might not correspond to the query that failed unless some kind of
273 /// external synchronization is in use which is the recommended way to use
274 /// sqlite.
275 ///
276 /// This is only meaningful if an error has occured. If no errors have
277 /// occured, this returns a non-erronous message like `"not an error"`
278 /// (default for sqlite3).
279 ///
280 /// # Examples
281 ///
282 /// ```
283 /// use sqll::{Connection, Code};
284 ///
285 /// let mut c = Connection::open_memory()?;
286 ///
287 /// let e = c.execute("
288 /// CREATE TABLE users (name TEXT);
289 /// CREATE UNIQUE INDEX idx_users_name ON users (name);
290 ///
291 /// INSERT INTO users VALUES ('Bob');
292 /// ");
293 ///
294 /// let e = c.execute("INSERT INTO users VALUES ('Bob')").unwrap_err();
295 /// assert_eq!(e.code(), Code::CONSTRAINT_UNIQUE);
296 /// assert_eq!(c.error_message(), "UNIQUE constraint failed: users.name");
297 /// # Ok::<_, sqll::Error>(())
298 /// ```
299 pub fn error_message(&self) -> &str {
300 // NB: This is the same message as set by sqlite.
301 static DEFAULT_MESSAGE: &str = "not an error";
302
303 unsafe { c_to_str(ffi::sqlite3_errmsg(self.raw.as_ptr())).unwrap_or(DEFAULT_MESSAGE) }
304 }
305
306 /// Build a prepared statement.
307 ///
308 /// This is the same as calling `prepare_with` with `Prepare::EMPTY`.
309 ///
310 /// The database connection will be kept open for the lifetime of this
311 /// statement.
312 ///
313 /// # Errors
314 ///
315 /// If the prepare call contains multiple statements, it will error. To
316 /// execute multiple statements, use [`execute`] instead.
317 ///
318 /// ```
319 /// use sqll::{Connection, Code};
320 ///
321 /// let c = Connection::open_memory()?;
322 ///
323 /// let e = c.prepare(
324 /// "
325 /// CREATE TABLE test (id INTEGER) /* test */;
326 /// INSERT INTO test (id) VALUES (1);
327 /// "
328 /// ).unwrap_err();
329 ///
330 /// assert_eq!(e.code(), Code::ERROR);
331 /// # Ok::<_, sqll::Error>(())
332 /// ```
333 ///
334 /// [`execute`]: Self::execute
335 ///
336 /// # Examples
337 ///
338 /// ```
339 /// use sqll::{Connection, State, Prepare};
340 ///
341 /// let c = Connection::open_memory()?;
342 /// c.execute("CREATE TABLE test (id INTEGER);")?;
343 ///
344 /// let mut insert_stmt = c.prepare("INSERT INTO test (id) VALUES (?);")?;
345 /// let mut query_stmt = c.prepare("SELECT id FROM test;")?;
346 ///
347 /// drop(c);
348 ///
349 /// insert_stmt.reset()?;
350 /// insert_stmt.bind(1, 42)?;
351 /// assert_eq!(insert_stmt.step()?, State::Done);
352 ///
353 /// query_stmt.reset()?;
354 ///
355 /// while let Some(row) = query_stmt.next()? {
356 /// let id = row.get::<i64>(0)?;
357 /// assert_eq!(id, 42);
358 /// }
359 /// # Ok::<_, sqll::Error>(())
360 /// ```
361 #[inline]
362 pub fn prepare(&self, stmt: impl AsRef<str>) -> Result<Statement> {
363 self.prepare_with(stmt, Prepare::EMPTY)
364 }
365
366 /// Build a prepared statement with custom flags.
367 ///
368 /// For long-running statements it is recommended that they have the
369 /// [`Prepare::PERSISTENT`] flag set.
370 ///
371 /// The database connection will be kept open for the lifetime of this
372 /// statement.
373 ///
374 /// # Errors
375 ///
376 /// If the prepare call contains multiple statements, it will error. To
377 /// execute multiple statements, use [`execute`] instead.
378 ///
379 /// ```
380 /// use sqll::{Connection, Code, Prepare};
381 ///
382 /// let c = Connection::open_memory()?;
383 ///
384 /// let e = c.prepare_with(
385 /// "
386 /// CREATE TABLE test (id INTEGER) /* test */;
387 /// INSERT INTO test (id) VALUES (1);
388 /// ",
389 /// Prepare::PERSISTENT
390 /// ).unwrap_err();
391 /// assert_eq!(e.code(), Code::ERROR);
392 /// # Ok::<_, sqll::Error>(())
393 /// ```
394 ///
395 /// [`execute`]: Self::execute
396 ///
397 /// # Examples
398 ///
399 /// ```
400 /// use sqll::{Connection, State, Prepare};
401 ///
402 /// let c = Connection::open_memory()?;
403 /// c.execute("CREATE TABLE test (id INTEGER);")?;
404 ///
405 /// let mut insert_stmt = c.prepare_with("INSERT INTO test (id) VALUES (?);", Prepare::PERSISTENT)?;
406 /// let mut query_stmt = c.prepare_with("SELECT id FROM test;", Prepare::PERSISTENT)?;
407 ///
408 /// drop(c);
409 ///
410 /// /* .. */
411 ///
412 /// insert_stmt.reset()?;
413 /// insert_stmt.bind(1, 42)?;
414 /// assert_eq!(insert_stmt.step()?, State::Done);
415 ///
416 /// query_stmt.reset()?;
417 ///
418 /// while let Some(row) = query_stmt.next()? {
419 /// let id = row.get::<i64>(0)?;
420 /// assert_eq!(id, 42);
421 /// }
422 /// # Ok::<_, sqll::Error>(())
423 /// ```
424 pub fn prepare_with(&self, stmt: impl AsRef<str>, flags: Prepare) -> Result<Statement> {
425 let stmt = stmt.as_ref();
426
427 unsafe {
428 let mut raw = MaybeUninit::uninit();
429 let mut rest = MaybeUninit::uninit();
430
431 let ptr = stmt.as_ptr().cast();
432 let len = i32::try_from(stmt.len()).unwrap_or(i32::MAX);
433
434 sqlite3_try! {
435 ffi::sqlite3_prepare_v3(
436 self.raw.as_ptr(),
437 ptr,
438 len,
439 flags.0,
440 raw.as_mut_ptr(),
441 rest.as_mut_ptr(),
442 )
443 };
444
445 let rest = rest.assume_init();
446
447 let o = rest.offset_from_unsigned(ptr);
448
449 if o != stmt.len() {
450 return Err(Error::new(Code::ERROR));
451 }
452
453 let raw = ptr::NonNull::new_unchecked(raw.assume_init());
454 Ok(Statement::from_raw(raw))
455 }
456 }
457
458 /// Return the number of rows inserted, updated, or deleted by the most
459 /// recent INSERT, UPDATE, or DELETE statement.
460 ///
461 /// # Examples
462 ///
463 /// ```
464 /// use sqll::Connection;
465 ///
466 /// let c = Connection::open_memory()?;
467 ///
468 /// c.execute("
469 /// CREATE TABLE users (name TEXT, age INTEGER);
470 /// INSERT INTO users VALUES ('Alice', 42);
471 /// INSERT INTO users VALUES ('Bob', 69);
472 /// ")?;
473 ///
474 /// assert_eq!(c.change_count(), 1);
475 /// # Ok::<_, sqll::Error>(())
476 /// ```
477 #[inline]
478 pub fn change_count(&self) -> usize {
479 unsafe { ffi::sqlite3_changes(self.raw.as_ptr()) as usize }
480 }
481
482 /// Return the total number of rows inserted, updated, and deleted by all
483 /// INSERT, UPDATE, and DELETE statements since the connection was opened.
484 ///
485 /// # Examples
486 ///
487 /// ```
488 /// use sqll::Connection;
489 ///
490 /// let c = Connection::open_memory()?;
491 ///
492 /// c.execute("
493 /// CREATE TABLE users (name TEXT, age INTEGER);
494 /// INSERT INTO users VALUES ('Alice', 42);
495 /// INSERT INTO users VALUES ('Bob', 69);
496 /// ")?;
497 ///
498 /// assert_eq!(c.total_change_count(), 2);
499 /// # Ok::<_, sqll::Error>(())
500 /// ```
501 #[inline]
502 pub fn total_change_count(&self) -> usize {
503 unsafe { ffi::sqlite3_total_changes(self.raw.as_ptr()) as usize }
504 }
505
506 /// Return the rowid of the most recent successful INSERT into a rowid table
507 /// or virtual table.
508 ///
509 /// # Examples
510 ///
511 /// If there is no primary key, the last inserted row id is an internal
512 /// identifier for the row:
513 ///
514 /// ```
515 /// use sqll::Connection;
516 ///
517 /// let c = Connection::open_memory()?;
518 ///
519 /// c.execute("
520 /// CREATE TABLE users (name TEXT);
521 /// INSERT INTO users VALUES ('Alice');
522 /// INSERT INTO users VALUES ('Bob');
523 /// ")?;
524 /// assert_eq!(c.last_insert_rowid(), 2);
525 ///
526 /// c.execute("INSERT INTO users VALUES ('Charlie')")?;
527 /// assert_eq!(c.last_insert_rowid(), 3);
528 ///
529 /// let mut stmt = c.prepare("INSERT INTO users VALUES (?)")?;
530 /// stmt.bind(1, "Dave")?;
531 /// stmt.execute()?;
532 ///
533 /// assert_eq!(c.last_insert_rowid(), 4);
534 /// # Ok::<_, sqll::Error>(())
535 /// ```
536 ///
537 /// If there is a primary key, the last inserted row id corresponds to it:
538 ///
539 /// ```
540 /// use sqll::Connection;
541 ///
542 /// let c = Connection::open_memory()?;
543 ///
544 /// c.execute("
545 /// CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);
546 /// INSERT INTO users (name) VALUES ('Alice');
547 /// INSERT INTO users (name) VALUES ('Bob');
548 /// ")?;
549 /// assert_eq!(c.last_insert_rowid(), 2);
550 ///
551 /// c.execute("INSERT INTO users (name) VALUES ('Charlie')")?;
552 /// assert_eq!(c.last_insert_rowid(), 3);
553 ///
554 /// c.execute("INSERT INTO users (name) VALUES ('Dave')")?;
555 /// assert_eq!(c.last_insert_rowid(), 4);
556 ///
557 /// let mut select = c.prepare("SELECT id FROM users WHERE name = ?")?;
558 /// select.bind(1, "Dave")?;
559 ///
560 /// while let Some(row) = select.next()? {
561 /// let id = row.get::<i64>(0)?;
562 /// assert_eq!(id, 4);
563 /// }
564 ///
565 /// c.execute("DELETE FROM users WHERE id = 3")?;
566 /// assert_eq!(c.last_insert_rowid(), 4);
567 ///
568 /// c.execute("INSERT INTO users (name) VALUES ('Charlie')")?;
569 /// assert_eq!(c.last_insert_rowid(), 5);
570 ///
571 /// select.reset()?;
572 /// select.bind(1, "Charlie")?;
573 ///
574 /// while let Some(row) = select.next()? {
575 /// let id = row.get::<i64>(0)?;
576 /// assert_eq!(id, 5);
577 /// }
578 /// # Ok::<_, sqll::Error>(())
579 /// ```
580 #[inline]
581 pub fn last_insert_rowid(&self) -> c_longlong {
582 unsafe { ffi::sqlite3_last_insert_rowid(self.raw.as_ptr()) }
583 }
584
585 /// Set a callback for handling busy events.
586 ///
587 /// The callback is triggered when the database cannot perform an operation
588 /// due to processing of some other request. If the callback returns `true`,
589 /// the operation will be repeated.
590 pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()>
591 where
592 F: FnMut(usize) -> bool + Send + 'static,
593 {
594 self.remove_busy_handler()?;
595
596 unsafe {
597 let callback = Owned::new(callback)?;
598
599 let result = ffi::sqlite3_busy_handler(
600 self.raw.as_ptr(),
601 Some(busy_callback::<F>),
602 callback.as_ptr().cast(),
603 );
604
605 self.busy_callback = Some(callback);
606 sqlite3_try!(result);
607 }
608
609 Ok(())
610 }
611
612 /// Set an implicit callback for handling busy events that tries to repeat
613 /// rejected operations until a timeout expires.
614 #[inline]
615 pub fn set_busy_timeout(&mut self, ms: c_int) -> Result<()> {
616 unsafe {
617 sqlite3_try! {
618 ffi::sqlite3_busy_timeout(
619 self.raw.as_ptr(),
620 ms
621 )
622 };
623 }
624
625 Ok(())
626 }
627
628 /// Remove the callback handling busy events.
629 #[inline]
630 pub fn remove_busy_handler(&mut self) -> Result<()> {
631 unsafe {
632 sqlite3_try! {
633 ffi::sqlite3_busy_handler(
634 self.raw.as_ptr(),
635 None,
636 ptr::null_mut()
637 )
638 };
639 }
640
641 self.busy_callback = None;
642 Ok(())
643 }
644}
645
646impl Drop for Connection {
647 #[inline]
648 #[allow(unused_must_use)]
649 fn drop(&mut self) {
650 self.remove_busy_handler();
651
652 // Will close the connection unconditionally. The database will stay
653 // alive until all associated prepared statements have been closed since
654 // we're using v2.
655 let code = unsafe { ffi::sqlite3_close_v2(self.raw.as_ptr()) };
656 debug_assert_eq!(code, ffi::SQLITE_OK);
657 }
658}
659
660/// Convert a filesystem path to a c-string.
661///
662/// This used to have a platform-specific implementation, particularly unix is
663/// guaranteed to have a byte-sequence representation.
664///
665/// However, we realized that the behavior is identical to simply calling
666/// `to_str`, with the addition that we check that the string is valid UTF-8.
667#[cfg(feature = "std")]
668pub(crate) fn path_to_cstring(p: &Path) -> Result<CString> {
669 let Some(bytes) = p.to_str() else {
670 return Err(Error::new(Code::MISUSE));
671 };
672
673 match CString::new(bytes) {
674 Ok(string) => Ok(string),
675 Err(..) => Err(Error::new(Code::MISUSE)),
676 }
677}
678
679/// Options that can be used to customize the opening of a SQLite database.
680///
681/// By default the database is opened in multi-threaded mode with the
682/// [`SQLITE_OPEN_FULLMUTEX`] option enabled which makes [`Connection`] and
683/// [`Statement`] objects thread-safe by serializing access. This can be
684/// disabled at runtime through [`no_mutex`], but is unsafe since the caller has
685/// to guarantee that access to *all* database objects are synchronized.
686///
687/// [`no_mutex`]: Self::no_mutex
688/// [`SQLITE_OPEN_FULLMUTEX`]: https://sqlite.org/c3ref/open.html
689#[derive(Clone, Copy, Debug)]
690pub struct OpenOptions {
691 raw: c_int,
692}
693
694impl OpenOptions {
695 /// Create flags for opening a database connection.
696 #[inline]
697 pub fn new() -> Self {
698 Self {
699 raw: ffi::SQLITE_OPEN_FULLMUTEX,
700 }
701 }
702
703 /// The database is opened in read-only mode. If the database does not
704 /// already exist, an error is returned.
705 #[inline]
706 pub fn read_only(mut self) -> Self {
707 self.raw |= ffi::SQLITE_OPEN_READONLY;
708 self
709 }
710
711 /// The database is opened for reading and writing if possible, or reading
712 /// only if the file is write protected by the operating system. In either
713 /// case the database must already exist, otherwise an error is returned.
714 /// For historical reasons, if opening in read-write mode fails due to
715 /// OS-level permissions, an attempt is made to open it in read-only mode.
716 /// sqlite3_db_readonly() can be used to determine whether the database is
717 /// actually read-write.
718 #[inline]
719 pub fn read_write(mut self) -> Self {
720 self.raw |= ffi::SQLITE_OPEN_READWRITE;
721 self
722 }
723
724 /// The database is opened for reading and writing, and is created if it
725 /// does not already exist.
726 ///
727 /// Note that a mode option like [`read_write`] must be set, otherwise this
728 /// will cause an error when opening.
729 ///
730 /// [`read_write`]: Self::read_write
731 #[inline]
732 pub fn create(mut self) -> Self {
733 self.raw |= ffi::SQLITE_OPEN_CREATE;
734 self
735 }
736
737 /// The filename can be interpreted as a URI if this flag is set.
738 #[inline]
739 pub fn uri(mut self) -> Self {
740 self.raw |= ffi::SQLITE_OPEN_URI;
741 self
742 }
743
744 /// The database will be opened as an in-memory database. The database is
745 /// named by the "filename" argument for the purposes of cache-sharing, if
746 /// shared cache mode is enabled, but the "filename" is otherwise ignored.
747 #[inline]
748 pub fn memory(mut self) -> Self {
749 self.raw |= ffi::SQLITE_OPEN_MEMORY;
750 self
751 }
752
753 /// The new database connection will use the "multi-thread" [threading
754 /// mode]. This means that separate threads are allowed to use SQLite at the
755 /// same time, as long as each thread is using a different database
756 /// connection.
757 ///
758 /// [threading mode]: https://www.sqlite.org/threadsafe.html
759 ///
760 /// # Safety
761 ///
762 /// This is unsafe, since it requires that the caller ensures that access to
763 /// the any objects associated with the connection such as [`Statement`] is
764 /// synchronized with the connection that constructed them.
765 #[inline]
766 pub unsafe fn no_mutex(mut self) -> Self {
767 self.raw |= ffi::SQLITE_OPEN_NOMUTEX;
768 self
769 }
770
771 /// The new database connection will use the "serialized" [threading mode].
772 /// This means the multiple threads can safely attempt to use the same
773 /// database connection at the same time. Mutexes will block any actual
774 /// concurrency, but in this mode there is no harm in trying.
775 ///
776 /// [threading mode]: https://sqlite.org/threadsafe.html
777 #[inline]
778 pub fn full_mutex(mut self) -> Self {
779 self.raw |= ffi::SQLITE_OPEN_FULLMUTEX;
780 self
781 }
782
783 /// The database is opened with shared cache enabled, overriding the default
784 /// shared cache setting provided. The use of shared cache mode is
785 /// discouraged and hence shared cache capabilities may be omitted from many
786 /// builds of SQLite. In such cases, this option is a no-op.
787 #[inline]
788 pub fn shared_cache(mut self) -> Self {
789 self.raw |= ffi::SQLITE_OPEN_SHAREDCACHE;
790 self
791 }
792
793 /// The database is opened with shared cache disabled, overriding the
794 /// default shared cache setting provided.
795 #[inline]
796 pub fn private_cache(mut self) -> Self {
797 self.raw |= ffi::SQLITE_OPEN_PRIVATECACHE;
798 self
799 }
800
801 /// The database filename is not allowed to contain a symbolic link.
802 #[inline]
803 pub fn no_follow(mut self) -> Self {
804 self.raw |= ffi::SQLITE_OPEN_NOFOLLOW;
805 self
806 }
807
808 /// The database connection comes up in "extended result code mode". In
809 /// other words, the database behaves as if
810 /// [`Connection::set_extended_result_codes`] were called on the database
811 /// connection as soon as the connection is created. In addition to setting
812 /// the extended result code mode.
813 ///
814 /// # Examples
815 ///
816 /// ```
817 /// use sqll::{OpenOptions, Code};
818 ///
819 /// let mut c = OpenOptions::new()
820 /// .extended_result_codes()
821 /// .create()
822 /// .read_write()
823 /// .open_memory()?;
824 ///
825 /// let e = c.execute("
826 /// CREATE TABLE users (name TEXT);
827 /// CREATE UNIQUE INDEX idx_users_name ON users (name);
828 ///
829 /// INSERT INTO users VALUES ('Bob');
830 /// ");
831 ///
832 /// let e = c.execute("INSERT INTO users VALUES ('Bob')").unwrap_err();
833 /// assert_eq!(e.code(), Code::CONSTRAINT_UNIQUE);
834 /// assert_eq!(c.error_message(), "UNIQUE constraint failed: users.name");
835 /// # Ok::<_, sqll::Error>(())
836 /// ```
837 #[inline]
838 pub fn extended_result_codes(mut self) -> Self {
839 self.raw |= ffi::SQLITE_OPEN_EXRESCODE;
840 self
841 }
842
843 /// Open a database to the given path.
844 ///
845 /// Note that it is possible to open an in-memory database by passing
846 /// `":memory:"` here, this call might require allocating depending on the
847 /// platform, so it should be avoided in favor of using [`open_memory`]. To avoid
848 /// allocating for regular paths, you can use [`open_c_str`], however you
849 /// are responsible for ensuring the c-string is a valid path.
850 ///
851 /// [`open_memory`]: Self::open_memory
852 /// [`open_c_str`]: Self::open_c_str
853 #[cfg(feature = "std")]
854 #[cfg_attr(docsrs, cfg(feature = "std"))]
855 pub fn open(&self, path: impl AsRef<Path>) -> Result<Connection> {
856 let path = path_to_cstring(path.as_ref())?;
857 self._open(&path)
858 }
859
860 /// Open a database connection with a raw c-string.
861 ///
862 /// This can be used to open in-memory databases by passing `c":memory:"` or
863 /// a regular open call with a filesystem path like
864 /// `c"/path/to/database.sql"`.
865 pub fn open_c_str(&self, name: &CStr) -> Result<Connection> {
866 self._open(name)
867 }
868
869 /// Open an in-memory database.
870 pub fn open_memory(&self) -> Result<Connection> {
871 self._open(c":memory:")
872 }
873
874 fn _open(&self, name: &CStr) -> Result<Connection> {
875 unsafe {
876 let mut raw = MaybeUninit::uninit();
877
878 let code = ffi::sqlite3_open_v2(name.as_ptr(), raw.as_mut_ptr(), self.raw, ptr::null());
879
880 let raw = raw.assume_init();
881
882 if code != ffi::SQLITE_OK {
883 ffi::sqlite3_close_v2(raw);
884 return Err(Error::from_raw(code));
885 }
886
887 Ok(Connection {
888 raw: NonNull::new_unchecked(raw),
889 busy_callback: None,
890 })
891 }
892 }
893}
894
895extern "C" fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
896where
897 F: FnMut(usize) -> bool,
898{
899 unsafe {
900 if (*(callback as *mut F))(attempts as usize) {
901 1
902 } else {
903 0
904 }
905 }
906}