Skip to content

Commit a5997a2

Browse files
ghassmoabonander
andauthored
Support custom initial options for sqlite (#1295)
* Support custom initial options for sqlite Apply suggestions from code review Co-authored-by: Austin Bonander <[email protected]> Apply suggestions from code review Co-authored-by: Austin Bonander <[email protected]> Use order-preserving map to set pragmas for an initial sqlite statement Use Cow<'static, str> instead of String Co-authored-by: Austin Bonander <[email protected]>
1 parent 2307f43 commit a5997a2

File tree

3 files changed

+62
-32
lines changed

3 files changed

+62
-32
lines changed

sqlx-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,4 @@ stringprep = "0.1.2"
163163
bstr = { version = "0.2.14", default-features = false, features = ["std"], optional = true }
164164
git2 = { version = "0.13.20", default-features = false, optional = true }
165165
hashlink = "0.7.0"
166+
indexmap = "1.7.0"

sqlx-core/src/sqlite/options/connect.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,12 @@ impl ConnectOptions for SqliteConnectOptions {
1818
let mut conn = establish(self).await?;
1919

2020
// send an initial sql statement comprised of options
21-
//
22-
// page_size must be set before any other action on the database.
23-
//
24-
// Note that locking_mode should be set before journal_mode; see
25-
// https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory .
26-
let init = format!(
27-
"PRAGMA page_size = {}; PRAGMA locking_mode = {}; PRAGMA journal_mode = {}; PRAGMA foreign_keys = {}; PRAGMA synchronous = {}; PRAGMA auto_vacuum = {}",
28-
self.page_size,
29-
self.locking_mode.as_str(),
30-
self.journal_mode.as_str(),
31-
if self.foreign_keys { "ON" } else { "OFF" },
32-
self.synchronous.as_str(),
33-
self.auto_vacuum.as_str(),
34-
);
21+
let mut init = String::new();
22+
23+
for (key, value) in self.pragmas.iter() {
24+
use std::fmt::Write;
25+
write!(init, "PRAGMA {} = {}; ", key, value).ok();
26+
}
3527

3628
conn.execute(&*init).await?;
3729

sqlx-core/src/sqlite/options/mod.rs

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ pub use locking_mode::SqliteLockingMode;
1414
use std::{borrow::Cow, time::Duration};
1515
pub use synchronous::SqliteSynchronous;
1616

17+
use indexmap::IndexMap;
18+
1719
/// Options and flags which can be used to configure a SQLite connection.
1820
///
1921
/// A value of `SqliteConnectOptions` can be parsed from a connection URI,
@@ -53,17 +55,12 @@ pub struct SqliteConnectOptions {
5355
pub(crate) in_memory: bool,
5456
pub(crate) read_only: bool,
5557
pub(crate) create_if_missing: bool,
56-
pub(crate) journal_mode: SqliteJournalMode,
57-
pub(crate) locking_mode: SqliteLockingMode,
58-
pub(crate) foreign_keys: bool,
5958
pub(crate) shared_cache: bool,
6059
pub(crate) statement_cache_capacity: usize,
6160
pub(crate) busy_timeout: Duration,
6261
pub(crate) log_settings: LogSettings,
63-
pub(crate) synchronous: SqliteSynchronous,
64-
pub(crate) auto_vacuum: SqliteAutoVacuum,
65-
pub(crate) page_size: u32,
6662
pub(crate) immutable: bool,
63+
pub(crate) pragmas: IndexMap<Cow<'static, str>, Cow<'static, str>>,
6764
}
6865

6966
impl Default for SqliteConnectOptions {
@@ -74,22 +71,44 @@ impl Default for SqliteConnectOptions {
7471

7572
impl SqliteConnectOptions {
7673
pub fn new() -> Self {
74+
// set default pragmas
75+
let mut pragmas: IndexMap<Cow<'static, str>, Cow<'static, str>> = IndexMap::new();
76+
77+
let locking_mode: SqliteLockingMode = Default::default();
78+
let auto_vacuum: SqliteAutoVacuum = Default::default();
79+
80+
// page_size must be set before any other action on the database.
81+
pragmas.insert("page_size".into(), "4096".into());
82+
83+
// Note that locking_mode should be set before journal_mode; see
84+
// https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory .
85+
pragmas.insert("locking_mode".into(), locking_mode.as_str().into());
86+
87+
pragmas.insert(
88+
"journal_mode".into(),
89+
SqliteJournalMode::Wal.as_str().into(),
90+
);
91+
92+
pragmas.insert("foreign_keys".into(), "ON".into());
93+
94+
pragmas.insert(
95+
"synchronous".into(),
96+
SqliteSynchronous::Full.as_str().into(),
97+
);
98+
99+
pragmas.insert("auto_vacuum".into(), auto_vacuum.as_str().into());
100+
77101
Self {
78102
filename: Cow::Borrowed(Path::new(":memory:")),
79103
in_memory: false,
80104
read_only: false,
81105
create_if_missing: false,
82-
foreign_keys: true,
83106
shared_cache: false,
84107
statement_cache_capacity: 100,
85-
journal_mode: SqliteJournalMode::Wal,
86-
locking_mode: Default::default(),
87108
busy_timeout: Duration::from_secs(5),
88109
log_settings: Default::default(),
89-
synchronous: SqliteSynchronous::Full,
90-
auto_vacuum: Default::default(),
91-
page_size: 4096,
92110
immutable: false,
111+
pragmas,
93112
}
94113
}
95114

@@ -103,7 +122,10 @@ impl SqliteConnectOptions {
103122
///
104123
/// By default, this is enabled.
105124
pub fn foreign_keys(mut self, on: bool) -> Self {
106-
self.foreign_keys = on;
125+
self.pragmas.insert(
126+
"foreign_keys".into(),
127+
(if on { "ON" } else { "OFF" }).into(),
128+
);
107129
self
108130
}
109131

@@ -120,15 +142,17 @@ impl SqliteConnectOptions {
120142
/// The default journal mode is WAL. For most use cases this can be significantly faster but
121143
/// there are [disadvantages](https://www.sqlite.org/wal.html).
122144
pub fn journal_mode(mut self, mode: SqliteJournalMode) -> Self {
123-
self.journal_mode = mode;
145+
self.pragmas
146+
.insert("journal_mode".into(), mode.as_str().into());
124147
self
125148
}
126149

127150
/// Sets the [locking mode](https://www.sqlite.org/pragma.html#pragma_locking_mode) for the database connection.
128151
///
129152
/// The default locking mode is NORMAL.
130153
pub fn locking_mode(mut self, mode: SqliteLockingMode) -> Self {
131-
self.locking_mode = mode;
154+
self.pragmas
155+
.insert("locking_mode".into(), mode.as_str().into());
132156
self
133157
}
134158

@@ -173,23 +197,36 @@ impl SqliteConnectOptions {
173197
/// The default synchronous settings is FULL. However, if durability is not a concern,
174198
/// then NORMAL is normally all one needs in WAL mode.
175199
pub fn synchronous(mut self, synchronous: SqliteSynchronous) -> Self {
176-
self.synchronous = synchronous;
200+
self.pragmas
201+
.insert("synchronous".into(), synchronous.as_str().into());
177202
self
178203
}
179204

180205
/// Sets the [auto_vacuum](https://www.sqlite.org/pragma.html#pragma_auto_vacuum) setting for the database connection.
181206
///
182207
/// The default auto_vacuum setting is NONE.
183208
pub fn auto_vacuum(mut self, auto_vacuum: SqliteAutoVacuum) -> Self {
184-
self.auto_vacuum = auto_vacuum;
209+
self.pragmas
210+
.insert("auto_vacuum".into(), auto_vacuum.as_str().into());
185211
self
186212
}
187213

188214
/// Sets the [page_size](https://www.sqlite.org/pragma.html#pragma_page_size) setting for the database connection.
189215
///
190216
/// The default page_size setting is 4096.
191217
pub fn page_size(mut self, page_size: u32) -> Self {
192-
self.page_size = page_size;
218+
self.pragmas
219+
.insert("page_size".into(), page_size.to_string().into());
220+
self
221+
}
222+
223+
/// Sets custom initial pragma for the database connection.
224+
pub fn pragma<K, V>(mut self, key: K, value: V) -> Self
225+
where
226+
K: Into<Cow<'static, str>>,
227+
V: Into<Cow<'static, str>>,
228+
{
229+
self.pragmas.insert(key.into(), value.into());
193230
self
194231
}
195232

0 commit comments

Comments
 (0)