sqlx_core_guts/sqlite/options/
mod.rs

1use std::path::Path;
2
3mod auto_vacuum;
4mod connect;
5mod journal_mode;
6mod locking_mode;
7mod parse;
8mod synchronous;
9
10use crate::connection::LogSettings;
11pub use auto_vacuum::SqliteAutoVacuum;
12pub use journal_mode::SqliteJournalMode;
13pub use locking_mode::SqliteLockingMode;
14use std::cmp::Ordering;
15use std::sync::Arc;
16use std::{borrow::Cow, time::Duration};
17pub use synchronous::SqliteSynchronous;
18
19use crate::common::DebugFn;
20use crate::sqlite::connection::collation::Collation;
21use indexmap::IndexMap;
22
23/// Options and flags which can be used to configure a SQLite connection.
24///
25/// A value of `SqliteConnectOptions` can be parsed from a connection URL,
26/// as described by [SQLite](https://www.sqlite.org/uri.html).
27///
28/// | URL | Description |
29/// | -- | -- |
30/// `sqlite::memory:` | Open an in-memory database. |
31/// `sqlite:data.db` | Open the file `data.db` in the current directory. |
32/// `sqlite://data.db` | Open the file `data.db` in the current directory. |
33/// `sqlite:///data.db` | Open the file `data.db` from the root (`/`) directory. |
34/// `sqlite://data.db?mode=ro` | Open the file `data.db` for read-only access. |
35///
36/// # Example
37///
38/// ```rust,no_run
39/// # use sqlx_core::connection::ConnectOptions;
40/// # use sqlx_core::error::Error;
41/// use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode};
42/// use std::str::FromStr;
43///
44/// # fn main() {
45/// # #[cfg(feature = "_rt-async-std")]
46/// # sqlx_rt::async_std::task::block_on::<_, Result<(), Error>>(async move {
47/// let conn = SqliteConnectOptions::from_str("sqlite://data.db")?
48///     .journal_mode(SqliteJournalMode::Wal)
49///     .read_only(true)
50///     .connect().await?;
51/// # Ok(())
52/// # }).unwrap();
53/// # }
54/// ```
55#[derive(Clone, Debug)]
56pub struct SqliteConnectOptions {
57    pub(crate) filename: Cow<'static, Path>,
58    pub(crate) in_memory: bool,
59    pub(crate) read_only: bool,
60    pub(crate) create_if_missing: bool,
61    pub(crate) shared_cache: bool,
62    pub(crate) statement_cache_capacity: usize,
63    pub(crate) busy_timeout: Duration,
64    pub(crate) log_settings: LogSettings,
65    pub(crate) immutable: bool,
66    pub(crate) pragmas: IndexMap<Cow<'static, str>, Cow<'static, str>>,
67
68    pub(crate) command_channel_size: usize,
69    pub(crate) row_channel_size: usize,
70
71    pub(crate) collations: Vec<Collation>,
72
73    pub(crate) serialized: bool,
74    pub(crate) thread_name: Arc<DebugFn<dyn Fn(u64) -> String + Send + Sync + 'static>>,
75}
76
77impl Default for SqliteConnectOptions {
78    fn default() -> Self {
79        Self::new()
80    }
81}
82
83impl SqliteConnectOptions {
84    /// Construct `Self` with default options.
85    ///
86    /// See the source of this method for the current defaults.
87    pub fn new() -> Self {
88        // set default pragmas
89        let mut pragmas: IndexMap<Cow<'static, str>, Cow<'static, str>> = IndexMap::new();
90
91        let locking_mode: SqliteLockingMode = Default::default();
92        let auto_vacuum: SqliteAutoVacuum = Default::default();
93
94        // page_size must be set before any other action on the database.
95        pragmas.insert("page_size".into(), "4096".into());
96
97        // Note that locking_mode should be set before journal_mode; see
98        // https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory .
99        pragmas.insert("locking_mode".into(), locking_mode.as_str().into());
100
101        pragmas.insert(
102            "journal_mode".into(),
103            SqliteJournalMode::Wal.as_str().into(),
104        );
105
106        pragmas.insert("foreign_keys".into(), "ON".into());
107
108        pragmas.insert(
109            "synchronous".into(),
110            SqliteSynchronous::Full.as_str().into(),
111        );
112
113        pragmas.insert("auto_vacuum".into(), auto_vacuum.as_str().into());
114
115        Self {
116            filename: Cow::Borrowed(Path::new(":memory:")),
117            in_memory: false,
118            read_only: false,
119            create_if_missing: false,
120            shared_cache: false,
121            statement_cache_capacity: 100,
122            busy_timeout: Duration::from_secs(5),
123            log_settings: Default::default(),
124            immutable: false,
125            pragmas,
126            collations: Default::default(),
127            serialized: false,
128            thread_name: Arc::new(DebugFn(|id| format!("sqlx-sqlite-worker-{}", id))),
129            command_channel_size: 50,
130            row_channel_size: 50,
131        }
132    }
133
134    /// Sets the name of the database file.
135    pub fn filename(mut self, filename: impl AsRef<Path>) -> Self {
136        self.filename = Cow::Owned(filename.as_ref().to_owned());
137        self
138    }
139
140    /// Set the enforcement of [foreign key constraints](https://www.sqlite.org/pragma.html#pragma_foreign_keys).
141    ///
142    /// By default, this is enabled.
143    pub fn foreign_keys(mut self, on: bool) -> Self {
144        self.pragmas.insert(
145            "foreign_keys".into(),
146            (if on { "ON" } else { "OFF" }).into(),
147        );
148        self
149    }
150
151    /// Set the [`SQLITE_OPEN_SHAREDCACHE` flag](https://sqlite.org/sharedcache.html).
152    ///
153    /// By default, this is disabled.
154    pub fn shared_cache(mut self, on: bool) -> Self {
155        self.shared_cache = on;
156        self
157    }
158
159    /// Sets the [journal mode](https://www.sqlite.org/pragma.html#pragma_journal_mode) for the database connection.
160    ///
161    /// The default journal mode is WAL. For most use cases this can be significantly faster but
162    /// there are [disadvantages](https://www.sqlite.org/wal.html).
163    pub fn journal_mode(mut self, mode: SqliteJournalMode) -> Self {
164        self.pragmas
165            .insert("journal_mode".into(), mode.as_str().into());
166        self
167    }
168
169    /// Sets the [locking mode](https://www.sqlite.org/pragma.html#pragma_locking_mode) for the database connection.
170    ///
171    /// The default locking mode is NORMAL.
172    pub fn locking_mode(mut self, mode: SqliteLockingMode) -> Self {
173        self.pragmas
174            .insert("locking_mode".into(), mode.as_str().into());
175        self
176    }
177
178    /// Sets the [access mode](https://www.sqlite.org/c3ref/open.html) to open the database
179    /// for read-only access.
180    pub fn read_only(mut self, read_only: bool) -> Self {
181        self.read_only = read_only;
182        self
183    }
184
185    /// Sets the [access mode](https://www.sqlite.org/c3ref/open.html) to create the database file
186    /// if the file does not exist.
187    ///
188    /// By default, a new file **will not be** created if one is not found.
189    pub fn create_if_missing(mut self, create: bool) -> Self {
190        self.create_if_missing = create;
191        self
192    }
193
194    /// Sets the capacity of the connection's statement cache in a number of stored
195    /// distinct statements. Caching is handled using LRU, meaning when the
196    /// amount of queries hits the defined limit, the oldest statement will get
197    /// dropped.
198    ///
199    /// The default cache capacity is 100 statements.
200    pub fn statement_cache_capacity(mut self, capacity: usize) -> Self {
201        self.statement_cache_capacity = capacity;
202        self
203    }
204
205    /// Sets a timeout value to wait when the database is locked, before
206    /// returning a busy timeout error.
207    ///
208    /// The default busy timeout is 5 seconds.
209    pub fn busy_timeout(mut self, timeout: Duration) -> Self {
210        self.busy_timeout = timeout;
211        self
212    }
213
214    /// Sets the [synchronous](https://www.sqlite.org/pragma.html#pragma_synchronous) setting for the database connection.
215    ///
216    /// The default synchronous settings is FULL. However, if durability is not a concern,
217    /// then NORMAL is normally all one needs in WAL mode.
218    pub fn synchronous(mut self, synchronous: SqliteSynchronous) -> Self {
219        self.pragmas
220            .insert("synchronous".into(), synchronous.as_str().into());
221        self
222    }
223
224    /// Sets the [auto_vacuum](https://www.sqlite.org/pragma.html#pragma_auto_vacuum) setting for the database connection.
225    ///
226    /// The default auto_vacuum setting is NONE.
227    pub fn auto_vacuum(mut self, auto_vacuum: SqliteAutoVacuum) -> Self {
228        self.pragmas
229            .insert("auto_vacuum".into(), auto_vacuum.as_str().into());
230        self
231    }
232
233    /// Sets the [page_size](https://www.sqlite.org/pragma.html#pragma_page_size) setting for the database connection.
234    ///
235    /// The default page_size setting is 4096.
236    pub fn page_size(mut self, page_size: u32) -> Self {
237        self.pragmas
238            .insert("page_size".into(), page_size.to_string().into());
239        self
240    }
241
242    /// Sets custom initial pragma for the database connection.
243    pub fn pragma<K, V>(mut self, key: K, value: V) -> Self
244    where
245        K: Into<Cow<'static, str>>,
246        V: Into<Cow<'static, str>>,
247    {
248        self.pragmas.insert(key.into(), value.into());
249        self
250    }
251
252    /// Add a custom collation for comparing strings in SQL.
253    ///
254    /// If a collation with the same name already exists, it will be replaced.
255    ///
256    /// See [`sqlite3_create_collation()`](https://www.sqlite.org/c3ref/create_collation.html) for details.
257    ///
258    /// Note this excerpt:
259    /// > The collating function must obey the following properties for all strings A, B, and C:
260    /// >
261    /// > If A==B then B==A.  
262    /// > If A==B and B==C then A==C.  
263    /// > If A\<B then B>A.  
264    /// > If A<B and B<C then A<C.
265    /// >
266    /// > If a collating function fails any of the above constraints and that collating function is
267    /// > registered and used, then the behavior of SQLite is undefined.
268    pub fn collation<N, F>(mut self, name: N, collate: F) -> Self
269    where
270        N: Into<Arc<str>>,
271        F: Fn(&str, &str) -> Ordering + Send + Sync + 'static,
272    {
273        self.collations.push(Collation::new(name, collate));
274        self
275    }
276
277    /// Set to `true` to signal to SQLite that the database file is on read-only media.
278    ///
279    /// If enabled, SQLite assumes the database file _cannot_ be modified, even by higher
280    /// privileged processes, and so disables locking and change detection. This is intended
281    /// to improve performance but can produce incorrect query results or errors if the file
282    /// _does_ change.
283    ///
284    /// Note that this is different from the `SQLITE_OPEN_READONLY` flag set by
285    /// [`.read_only()`][Self::read_only], though the documentation suggests that this
286    /// does _imply_ `SQLITE_OPEN_READONLY`.
287    ///
288    /// See [`sqlite3_open`](https://www.sqlite.org/capi3ref.html#sqlite3_open) (subheading
289    /// "URI Filenames") for details.
290    pub fn immutable(mut self, immutable: bool) -> Self {
291        self.immutable = immutable;
292        self
293    }
294
295    /// Sets the [threading mode](https://www.sqlite.org/threadsafe.html) for the database connection.
296    ///
297    /// The default setting is `false` corersponding to using `OPEN_NOMUTEX`, if `true` then `OPEN_FULLMUTEX`.
298    ///
299    /// See [open](https://www.sqlite.org/c3ref/open.html) for more details.
300    ///
301    /// ### Note
302    /// Setting this to `true` may help if you are getting access violation errors or segmentation
303    /// faults, but will also incur a significant performance penalty. You should leave this
304    /// set to `false` if at all possible.    
305    ///
306    /// If you do end up needing to set this to `true` for some reason, please
307    /// [open an issue](https://github.com/launchbadge/sqlx/issues/new/choose) as this may indicate
308    /// a concurrency bug in SQLx. Please provide clear instructions for reproducing the issue,
309    /// including a sample database schema if applicable.
310    pub fn serialized(mut self, serialized: bool) -> Self {
311        self.serialized = serialized;
312        self
313    }
314
315    /// Provide a callback to generate the name of the background worker thread.
316    ///
317    /// The value passed to the callback is an auto-incremented integer for use as the thread ID.
318    pub fn thread_name(
319        mut self,
320        generator: impl Fn(u64) -> String + Send + Sync + 'static,
321    ) -> Self {
322        self.thread_name = Arc::new(DebugFn(generator));
323        self
324    }
325
326    /// Set the maximum number of commands to buffer for the worker thread before backpressure is
327    /// applied.
328    ///
329    /// Given that most commands sent to the worker thread involve waiting for a result,
330    /// the command channel is unlikely to fill up unless a lot queries are executed in a short
331    /// period but cancelled before their full resultsets are returned.
332    pub fn command_buffer_size(mut self, size: usize) -> Self {
333        self.command_channel_size = size;
334        self
335    }
336
337    /// Set the maximum number of rows to buffer back to the calling task when a query is executed.
338    ///
339    /// If the calling task cannot keep up, backpressure will be applied to the worker thread
340    /// in order to limit CPU and memory usage.
341    pub fn row_buffer_size(mut self, size: usize) -> Self {
342        self.row_channel_size = size;
343        self
344    }
345}