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