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