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}