sqlx_build_trust_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::connection::collation::Collation;
21use sqlx_core::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/// This type also implements [`FromStr`][std::str::FromStr] so you can parse it from a string
29/// containing a connection URL and then further adjust options if necessary (see example below).
30///
31/// | URL | Description |
32/// | -- | -- |
33/// `sqlite::memory:` | Open an in-memory database. |
34/// `sqlite:data.db` | Open the file `data.db` in the current directory. |
35/// `sqlite://data.db` | Open the file `data.db` in the current directory. |
36/// `sqlite:///data.db` | Open the file `data.db` from the root (`/`) directory. |
37/// `sqlite://data.db?mode=ro` | Open the file `data.db` for read-only access. |
38///
39/// # Example
40///
41/// ```rust,no_run
42/// # async fn example() -> sqlx::Result<()> {
43/// use sqlx::ConnectOptions;
44/// use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode};
45/// use std::str::FromStr;
46///
47/// let conn = SqliteConnectOptions::from_str("sqlite://data.db")?
48///     .journal_mode(SqliteJournalMode::Wal)
49///     .read_only(true)
50///     .connect().await?;
51/// #
52/// # Ok(())
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) vfs: Option<Cow<'static, str>>,
67
68    pub(crate) pragmas: IndexMap<Cow<'static, str>, Option<Cow<'static, str>>>,
69    /// Extensions are specified as a pair of <Extension Name : Optional Entry Point>, the majority
70    /// of SQLite extensions will use the default entry points specified in the docs, these should
71    /// be added to the map with a `None` value.
72    /// <https://www.sqlite.org/loadext.html#loading_an_extension>
73    pub(crate) extensions: IndexMap<Cow<'static, str>, Option<Cow<'static, str>>>,
74
75    pub(crate) command_channel_size: usize,
76    pub(crate) row_channel_size: usize,
77
78    pub(crate) collations: Vec<Collation>,
79
80    pub(crate) serialized: bool,
81    pub(crate) thread_name: Arc<DebugFn<dyn Fn(u64) -> String + Send + Sync + 'static>>,
82
83    pub(crate) optimize_on_close: OptimizeOnClose,
84
85    #[cfg(feature = "regexp")]
86    pub(crate) register_regexp_function: bool,
87}
88
89#[derive(Clone, Debug)]
90pub enum OptimizeOnClose {
91    Enabled { analysis_limit: Option<u32> },
92    Disabled,
93}
94
95impl Default for SqliteConnectOptions {
96    fn default() -> Self {
97        Self::new()
98    }
99}
100
101impl SqliteConnectOptions {
102    /// Construct `Self` with default options.
103    ///
104    /// See the source of this method for the current defaults.
105    pub fn new() -> Self {
106        let mut pragmas: IndexMap<Cow<'static, str>, Option<Cow<'static, str>>> = IndexMap::new();
107
108        // Standard pragmas
109        //
110        // Most of these don't actually need to be sent because they would be set to their
111        // default values anyway. See the SQLite documentation for default values of these PRAGMAs:
112        // https://www.sqlite.org/pragma.html
113        //
114        // However, by inserting into the map here, we can ensure that they're set in the proper
115        // order, even if they're overwritten later by their respective setters or
116        // directly by `pragma()`
117
118        // SQLCipher special case: if the `key` pragma is set, it must be executed first.
119        pragmas.insert("key".into(), None);
120
121        // Other SQLCipher pragmas that has to be after the key, but before any other operation on the database.
122        // https://www.zetetic.net/sqlcipher/sqlcipher-api/
123
124        // Bytes of the database file that is not encrypted
125        // Default for SQLCipher v4 is 0
126        // If greater than zero 'cipher_salt' pragma must be also defined
127        pragmas.insert("cipher_plaintext_header_size".into(), None);
128
129        // Allows to provide salt manually
130        // By default SQLCipher sets salt automatically, use only in conjunction with
131        // 'cipher_plaintext_header_size' pragma
132        pragmas.insert("cipher_salt".into(), None);
133
134        // Number of iterations used in PBKDF2 key derivation.
135        // Default for SQLCipher v4 is 256000
136        pragmas.insert("kdf_iter".into(), None);
137
138        // Define KDF algorithm to be used.
139        // Default for SQLCipher v4 is PBKDF2_HMAC_SHA512.
140        pragmas.insert("cipher_kdf_algorithm".into(), None);
141
142        // Enable or disable HMAC functionality.
143        // Default for SQLCipher v4 is 1.
144        pragmas.insert("cipher_use_hmac".into(), None);
145
146        // Set default encryption settings depending on the version 1,2,3, or 4.
147        pragmas.insert("cipher_compatibility".into(), None);
148
149        // Page size of encrypted database.
150        // Default for SQLCipher v4 is 4096.
151        pragmas.insert("cipher_page_size".into(), None);
152
153        // Choose algorithm used for HMAC.
154        // Default for SQLCipher v4 is HMAC_SHA512.
155        pragmas.insert("cipher_hmac_algorithm".into(), None);
156
157        // Normally, page_size must be set before any other action on the database.
158        // Defaults to 4096 for new databases.
159        pragmas.insert("page_size".into(), None);
160
161        // locking_mode should be set before journal_mode:
162        // https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory
163        pragmas.insert("locking_mode".into(), None);
164
165        // Don't set `journal_mode` unless the user requested it.
166        // WAL mode is a permanent setting for created databases and changing into or out of it
167        // requires an exclusive lock that can't be waited on with `sqlite3_busy_timeout()`.
168        // https://github.com/launchbadge/sqlx/pull/1930#issuecomment-1168165414
169        pragmas.insert("journal_mode".into(), None);
170
171        // We choose to enable foreign key enforcement by default, though SQLite normally
172        // leaves it off for backward compatibility: https://www.sqlite.org/foreignkeys.html#fk_enable
173        pragmas.insert("foreign_keys".into(), Some("ON".into()));
174
175        // The `synchronous` pragma defaults to FULL
176        // https://www.sqlite.org/compile.html#default_synchronous.
177        pragmas.insert("synchronous".into(), None);
178
179        pragmas.insert("auto_vacuum".into(), None);
180
181        // Soft limit on the number of rows that `ANALYZE` touches per index.
182        pragmas.insert("analysis_limit".into(), None);
183
184        Self {
185            filename: Cow::Borrowed(Path::new(":memory:")),
186            in_memory: false,
187            read_only: false,
188            create_if_missing: false,
189            shared_cache: false,
190            statement_cache_capacity: 100,
191            busy_timeout: Duration::from_secs(5),
192            log_settings: Default::default(),
193            immutable: false,
194            vfs: None,
195            pragmas,
196            extensions: Default::default(),
197            collations: Default::default(),
198            serialized: false,
199            thread_name: Arc::new(DebugFn(|id| format!("sqlx-sqlite-worker-{id}"))),
200            command_channel_size: 50,
201            row_channel_size: 50,
202            optimize_on_close: OptimizeOnClose::Disabled,
203            #[cfg(feature = "regexp")]
204            register_regexp_function: false,
205        }
206    }
207
208    /// Sets the name of the database file.
209    pub fn filename(mut self, filename: impl AsRef<Path>) -> Self {
210        self.filename = Cow::Owned(filename.as_ref().to_owned());
211        self
212    }
213
214    /// Gets the current name of the database file.
215    pub fn get_filename(self) -> Cow<'static, Path> {
216        self.filename
217    }
218
219    /// Set the enforcement of [foreign key constraints](https://www.sqlite.org/pragma.html#pragma_foreign_keys).
220    ///
221    /// SQLx chooses to enable this by default so that foreign keys function as expected,
222    /// compared to other database flavors.
223    pub fn foreign_keys(self, on: bool) -> Self {
224        self.pragma("foreign_keys", if on { "ON" } else { "OFF" })
225    }
226
227    /// Set the [`SQLITE_OPEN_SHAREDCACHE` flag](https://sqlite.org/sharedcache.html).
228    ///
229    /// By default, this is disabled.
230    pub fn shared_cache(mut self, on: bool) -> Self {
231        self.shared_cache = on;
232        self
233    }
234
235    /// Sets the [journal mode](https://www.sqlite.org/pragma.html#pragma_journal_mode) for the database connection.
236    ///
237    /// Journal modes are ephemeral per connection, with the exception of the
238    /// [Write-Ahead Log (WAL) mode](https://www.sqlite.org/wal.html).
239    ///
240    /// A database created in WAL mode retains the setting and will apply it to all connections
241    /// opened against it that don't set a `journal_mode`.
242    ///
243    /// Opening a connection to a database created in WAL mode with a different `journal_mode` will
244    /// erase the setting on the database, requiring an exclusive lock to do so.
245    /// You may get a `database is locked` (corresponding to `SQLITE_BUSY`) error if another
246    /// connection is accessing the database file at the same time.
247    ///
248    /// SQLx does not set a journal mode by default, to avoid unintentionally changing a database
249    /// into or out of WAL mode.
250    ///
251    /// The default journal mode for non-WAL databases is `DELETE`, or `MEMORY` for in-memory
252    /// databases.
253    ///
254    /// For consistency, any commands in `sqlx-cli` which create a SQLite database will create it
255    /// in WAL mode.
256    pub fn journal_mode(self, mode: SqliteJournalMode) -> Self {
257        self.pragma("journal_mode", mode.as_str())
258    }
259
260    /// Sets the [locking mode](https://www.sqlite.org/pragma.html#pragma_locking_mode) for the database connection.
261    ///
262    /// The default locking mode is NORMAL.
263    pub fn locking_mode(self, mode: SqliteLockingMode) -> Self {
264        self.pragma("locking_mode", mode.as_str())
265    }
266
267    /// Sets the [access mode](https://www.sqlite.org/c3ref/open.html) to open the database
268    /// for read-only access.
269    pub fn read_only(mut self, read_only: bool) -> Self {
270        self.read_only = read_only;
271        self
272    }
273
274    /// Sets the [access mode](https://www.sqlite.org/c3ref/open.html) to create the database file
275    /// if the file does not exist.
276    ///
277    /// By default, a new file **will not be created** if one is not found.
278    pub fn create_if_missing(mut self, create: bool) -> Self {
279        self.create_if_missing = create;
280        self
281    }
282
283    /// Sets the capacity of the connection's statement cache in a number of stored
284    /// distinct statements. Caching is handled using LRU, meaning when the
285    /// amount of queries hits the defined limit, the oldest statement will get
286    /// dropped.
287    ///
288    /// The default cache capacity is 100 statements.
289    pub fn statement_cache_capacity(mut self, capacity: usize) -> Self {
290        self.statement_cache_capacity = capacity;
291        self
292    }
293
294    /// Sets a timeout value to wait when the database is locked, before
295    /// returning a busy timeout error.
296    ///
297    /// The default busy timeout is 5 seconds.
298    pub fn busy_timeout(mut self, timeout: Duration) -> Self {
299        self.busy_timeout = timeout;
300        self
301    }
302
303    /// Sets the [synchronous](https://www.sqlite.org/pragma.html#pragma_synchronous) setting for the database connection.
304    ///
305    /// The default synchronous settings is FULL. However, if durability is not a concern,
306    /// then NORMAL is normally all one needs in WAL mode.
307    pub fn synchronous(self, synchronous: SqliteSynchronous) -> Self {
308        self.pragma("synchronous", synchronous.as_str())
309    }
310
311    /// Sets the [auto_vacuum](https://www.sqlite.org/pragma.html#pragma_auto_vacuum) setting for the database connection.
312    ///
313    /// The default auto_vacuum setting is NONE.
314    ///
315    /// For existing databases, a change to this value does not take effect unless a
316    /// [`VACUUM` command](https://www.sqlite.org/lang_vacuum.html) is executed.
317    pub fn auto_vacuum(self, auto_vacuum: SqliteAutoVacuum) -> Self {
318        self.pragma("auto_vacuum", auto_vacuum.as_str())
319    }
320
321    /// Sets the [page_size](https://www.sqlite.org/pragma.html#pragma_page_size) setting for the database connection.
322    ///
323    /// The default page_size setting is 4096.
324    ///
325    /// For existing databases, a change to this value does not take effect unless a
326    /// [`VACUUM` command](https://www.sqlite.org/lang_vacuum.html) is executed.
327    /// However, it cannot be changed in WAL mode.
328    pub fn page_size(self, page_size: u32) -> Self {
329        self.pragma("page_size", page_size.to_string())
330    }
331
332    /// Sets custom initial pragma for the database connection.
333    pub fn pragma<K, V>(mut self, key: K, value: V) -> Self
334    where
335        K: Into<Cow<'static, str>>,
336        V: Into<Cow<'static, str>>,
337    {
338        self.pragmas.insert(key.into(), Some(value.into()));
339        self
340    }
341
342    /// Add a custom collation for comparing strings in SQL.
343    ///
344    /// If a collation with the same name already exists, it will be replaced.
345    ///
346    /// See [`sqlite3_create_collation()`](https://www.sqlite.org/c3ref/create_collation.html) for details.
347    ///
348    /// Note this excerpt:
349    /// > The collating function must obey the following properties for all strings A, B, and C:
350    /// >
351    /// > If A==B then B==A.
352    /// > If A==B and B==C then A==C.
353    /// > If A\<B then B>A.
354    /// > If A<B and B<C then A<C.
355    /// >
356    /// > If a collating function fails any of the above constraints and that collating function is
357    /// > registered and used, then the behavior of SQLite is undefined.
358    pub fn collation<N, F>(mut self, name: N, collate: F) -> Self
359    where
360        N: Into<Arc<str>>,
361        F: Fn(&str, &str) -> Ordering + Send + Sync + 'static,
362    {
363        self.collations.push(Collation::new(name, collate));
364        self
365    }
366
367    /// Set to `true` to signal to SQLite that the database file is on read-only media.
368    ///
369    /// If enabled, SQLite assumes the database file _cannot_ be modified, even by higher
370    /// privileged processes, and so disables locking and change detection. This is intended
371    /// to improve performance but can produce incorrect query results or errors if the file
372    /// _does_ change.
373    ///
374    /// Note that this is different from the `SQLITE_OPEN_READONLY` flag set by
375    /// [`.read_only()`][Self::read_only], though the documentation suggests that this
376    /// does _imply_ `SQLITE_OPEN_READONLY`.
377    ///
378    /// See [`sqlite3_open`](https://www.sqlite.org/capi3ref.html#sqlite3_open) (subheading
379    /// "URI Filenames") for details.
380    pub fn immutable(mut self, immutable: bool) -> Self {
381        self.immutable = immutable;
382        self
383    }
384
385    /// Sets the [threading mode](https://www.sqlite.org/threadsafe.html) for the database connection.
386    ///
387    /// The default setting is `false` corresponding to using `OPEN_NOMUTEX`.
388    /// If set to `true` then `OPEN_FULLMUTEX`.
389    ///
390    /// See [open](https://www.sqlite.org/c3ref/open.html) for more details.
391    ///
392    /// ### Note
393    /// Setting this to `true` may help if you are getting access violation errors or segmentation
394    /// faults, but will also incur a significant performance penalty. You should leave this
395    /// set to `false` if at all possible.
396    ///
397    /// If you do end up needing to set this to `true` for some reason, please
398    /// [open an issue](https://github.com/launchbadge/sqlx/issues/new/choose) as this may indicate
399    /// a concurrency bug in SQLx. Please provide clear instructions for reproducing the issue,
400    /// including a sample database schema if applicable.
401    pub fn serialized(mut self, serialized: bool) -> Self {
402        self.serialized = serialized;
403        self
404    }
405
406    /// Provide a callback to generate the name of the background worker thread.
407    ///
408    /// The value passed to the callback is an auto-incremented integer for use as the thread ID.
409    pub fn thread_name(
410        mut self,
411        generator: impl Fn(u64) -> String + Send + Sync + 'static,
412    ) -> Self {
413        self.thread_name = Arc::new(DebugFn(generator));
414        self
415    }
416
417    /// Set the maximum number of commands to buffer for the worker thread before backpressure is
418    /// applied.
419    ///
420    /// Given that most commands sent to the worker thread involve waiting for a result,
421    /// the command channel is unlikely to fill up unless a lot queries are executed in a short
422    /// period but cancelled before their full resultsets are returned.
423    pub fn command_buffer_size(mut self, size: usize) -> Self {
424        self.command_channel_size = size;
425        self
426    }
427
428    /// Set the maximum number of rows to buffer back to the calling task when a query is executed.
429    ///
430    /// If the calling task cannot keep up, backpressure will be applied to the worker thread
431    /// in order to limit CPU and memory usage.
432    pub fn row_buffer_size(mut self, size: usize) -> Self {
433        self.row_channel_size = size;
434        self
435    }
436
437    /// Sets the [`vfs`](https://www.sqlite.org/vfs.html) parameter of the database connection.
438    ///
439    /// The default value is empty, and sqlite will use the default VFS object depending on the
440    /// operating system.
441    pub fn vfs(mut self, vfs_name: impl Into<Cow<'static, str>>) -> Self {
442        self.vfs = Some(vfs_name.into());
443        self
444    }
445
446    /// Load an [extension](https://www.sqlite.org/loadext.html) at run-time when the database connection
447    /// is established, using the default entry point.
448    ///
449    /// Most common SQLite extensions can be loaded using this method, for extensions where you need
450    /// to specify the entry point, use [`extension_with_entrypoint`][`Self::extension_with_entrypoint`] instead.
451    ///
452    /// Multiple extensions can be loaded by calling the method repeatedly on the options struct, they
453    /// will be loaded in the order they are added.
454    /// ```rust,no_run
455    /// # use sqlx_core::error::Error;
456    /// # use std::str::FromStr;
457    /// # use sqlx_sqlite::SqliteConnectOptions;
458    /// # fn options() -> Result<SqliteConnectOptions, Error> {
459    /// let options = SqliteConnectOptions::from_str("sqlite://data.db")?
460    ///     .extension("vsv")
461    ///     .extension("mod_spatialite");
462    /// # Ok(options)
463    /// # }
464    /// ```
465    pub fn extension(mut self, extension_name: impl Into<Cow<'static, str>>) -> Self {
466        self.extensions.insert(extension_name.into(), None);
467        self
468    }
469
470    /// Load an extension with a specified entry point.
471    ///
472    /// Useful when using non-standard extensions, or when developing your own, the second argument
473    /// specifies where SQLite should expect to find the extension init routine.
474    pub fn extension_with_entrypoint(
475        mut self,
476        extension_name: impl Into<Cow<'static, str>>,
477        entry_point: impl Into<Cow<'static, str>>,
478    ) -> Self {
479        self.extensions
480            .insert(extension_name.into(), Some(entry_point.into()));
481        self
482    }
483
484    /// Execute `PRAGMA optimize;` on the SQLite connection before closing.
485    ///
486    /// The SQLite manual recommends using this for long-lived databases.
487    ///
488    /// This will collect and store statistics about the layout of data in your tables to help the query planner make better decisions.
489    /// Over the connection's lifetime, the query planner will make notes about which tables could use up-to-date statistics so this
490    /// command doesn't have to scan the whole database every time. Thus, the best time to execute this is on connection close.
491    ///
492    /// `analysis_limit` sets a soft limit on the maximum number of rows to scan per index.
493    /// It is equivalent to setting [`Self::analysis_limit`] but only takes effect for the `PRAGMA optimize;` call
494    /// and does not affect the behavior of any `ANALYZE` statements made during the connection's lifetime.
495    ///
496    /// If not `None`, the `analysis_limit` here overrides the global `analysis_limit` setting,
497    /// but only for the `PRAGMA optimize;` call.
498    ///
499    /// Not enabled by default.
500    ///
501    /// See [the SQLite manual](https://www.sqlite.org/lang_analyze.html#automatically_running_analyze) for details.
502    pub fn optimize_on_close(
503        mut self,
504        enabled: bool,
505        analysis_limit: impl Into<Option<u32>>,
506    ) -> Self {
507        self.optimize_on_close = if enabled {
508            OptimizeOnClose::Enabled {
509                analysis_limit: (analysis_limit.into()),
510            }
511        } else {
512            OptimizeOnClose::Disabled
513        };
514        self
515    }
516
517    /// Set a soft limit on the number of rows that `ANALYZE` touches per index.
518    ///
519    /// This also affects `PRAGMA optimize` which is set by [Self::optimize_on_close].
520    ///
521    /// The value recommended by SQLite is `400`. There is no default.
522    ///
523    /// See [the SQLite manual](https://www.sqlite.org/lang_analyze.html#approx) for details.
524    pub fn analysis_limit(mut self, limit: impl Into<Option<u32>>) -> Self {
525        if let Some(limit) = limit.into() {
526            return self.pragma("analysis_limit", limit.to_string());
527        }
528        self.pragmas.insert("analysis_limit".into(), None);
529        self
530    }
531
532    /// Register a regexp function that allows using regular expressions in queries.
533    ///
534    /// ```
535    /// # use std::str::FromStr;
536    /// # use sqlx::{ConnectOptions, Connection, Row};
537    /// # use sqlx_sqlite::SqliteConnectOptions;
538    /// # async fn run() -> sqlx::Result<()> {
539    /// let mut sqlite = SqliteConnectOptions::from_str("sqlite://:memory:")?
540    ///     .with_regexp()
541    ///     .connect()
542    ///     .await?;
543    /// let tables = sqlx::query("SELECT name FROM sqlite_schema WHERE name REGEXP 'foo(\\d+)bar'")
544    ///     .fetch_all(&mut sqlite)
545    ///     .await?;
546    /// # Ok(())
547    /// # }
548    /// ```
549    ///
550    /// This uses the [`regex`] crate, and is only enabled when you enable the `regex` feature is enabled on sqlx
551    #[cfg(feature = "regexp")]
552    pub fn with_regexp(mut self) -> Self {
553        self.register_regexp_function = true;
554        self
555    }
556}