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}