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}