Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom initial options for sqlite #1295

Merged
merged 7 commits into from
Sep 13, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sqlx-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,4 @@ stringprep = "0.1.2"
bstr = { version = "0.2.14", default-features = false, features = ["std"], optional = true }
git2 = { version = "0.13.20", default-features = false, optional = true }
hashlink = "0.7.0"
indexmap = "1.7.0"
21 changes: 7 additions & 14 deletions sqlx-core/src/sqlite/options/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,13 @@ impl ConnectOptions for SqliteConnectOptions {
let mut conn = establish(self).await?;

// send an initial sql statement comprised of options
//
// page_size must be set before any other action on the database.
//
// Note that locking_mode should be set before journal_mode; see
// https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory .
let init = format!(
"PRAGMA page_size = {}; PRAGMA locking_mode = {}; PRAGMA journal_mode = {}; PRAGMA foreign_keys = {}; PRAGMA synchronous = {}; PRAGMA auto_vacuum = {}",
self.page_size,
self.locking_mode.as_str(),
self.journal_mode.as_str(),
if self.foreign_keys { "ON" } else { "OFF" },
self.synchronous.as_str(),
self.auto_vacuum.as_str(),
);
let mut init = String::new();

for (key, value) in self.pragmas.iter() {
use std::fmt::Write;
abonander marked this conversation as resolved.
Show resolved Hide resolved
use std::fmt::Write;
write!(init, "PRAGMA {} = {}; ", key, value).ok();
}
ghassmo marked this conversation as resolved.
Show resolved Hide resolved

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

Expand Down
73 changes: 55 additions & 18 deletions sqlx-core/src/sqlite/options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub use locking_mode::SqliteLockingMode;
use std::{borrow::Cow, time::Duration};
pub use synchronous::SqliteSynchronous;

use indexmap::IndexMap;

/// Options and flags which can be used to configure a SQLite connection.
///
/// A value of `SqliteConnectOptions` can be parsed from a connection URI,
Expand Down Expand Up @@ -53,17 +55,12 @@ pub struct SqliteConnectOptions {
pub(crate) in_memory: bool,
pub(crate) read_only: bool,
pub(crate) create_if_missing: bool,
pub(crate) journal_mode: SqliteJournalMode,
pub(crate) locking_mode: SqliteLockingMode,
pub(crate) foreign_keys: bool,
pub(crate) shared_cache: bool,
pub(crate) statement_cache_capacity: usize,
pub(crate) busy_timeout: Duration,
pub(crate) log_settings: LogSettings,
pub(crate) synchronous: SqliteSynchronous,
pub(crate) auto_vacuum: SqliteAutoVacuum,
pub(crate) page_size: u32,
pub(crate) immutable: bool,
pub(crate) pragmas: IndexMap<Cow<'static, str>, Cow<'static, str>>,
abonander marked this conversation as resolved.
Show resolved Hide resolved
}

impl Default for SqliteConnectOptions {
Expand All @@ -74,22 +71,44 @@ impl Default for SqliteConnectOptions {

impl SqliteConnectOptions {
pub fn new() -> Self {
// set default pragmas
let mut pragmas: IndexMap<Cow<'static, str>, Cow<'static, str>> = IndexMap::new();

let locking_mode: SqliteLockingMode = Default::default();
let auto_vacuum: SqliteAutoVacuum = Default::default();

// page_size must be set before any other action on the database.
pragmas.insert("page_size".into(), "4096".into());

// Note that locking_mode should be set before journal_mode; see
// https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory .
pragmas.insert("locking_mode".into(), locking_mode.as_str().into());

pragmas.insert(
"journal_mode".into(),
SqliteJournalMode::Wal.as_str().into(),
);

pragmas.insert("foreign_keys".into(), "ON".into());

pragmas.insert(
"synchronous".into(),
SqliteSynchronous::Full.as_str().into(),
);

pragmas.insert("auto_vacuum".into(), auto_vacuum.as_str().into());

Self {
filename: Cow::Borrowed(Path::new(":memory:")),
in_memory: false,
read_only: false,
create_if_missing: false,
foreign_keys: true,
shared_cache: false,
statement_cache_capacity: 100,
journal_mode: SqliteJournalMode::Wal,
locking_mode: Default::default(),
busy_timeout: Duration::from_secs(5),
log_settings: Default::default(),
synchronous: SqliteSynchronous::Full,
auto_vacuum: Default::default(),
page_size: 4096,
immutable: false,
pragmas,
abonander marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -103,7 +122,10 @@ impl SqliteConnectOptions {
///
/// By default, this is enabled.
pub fn foreign_keys(mut self, on: bool) -> Self {
self.foreign_keys = on;
self.pragmas.insert(
"foreign_keys".into(),
(if on { "ON" } else { "OFF" }).into(),
);
self
}

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

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

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

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

/// Sets the [page_size](https://www.sqlite.org/pragma.html#pragma_page_size) setting for the database connection.
///
/// The default page_size setting is 4096.
pub fn page_size(mut self, page_size: u32) -> Self {
self.page_size = page_size;
self.pragmas
.insert("page_size".into(), page_size.to_string().into());
self
}

/// Sets custom initial pragma for the database connection.
pub fn pragma<K, V>(mut self, key: K, value: V) -> Self
where
K: Into<Cow<'static, str>>,
V: Into<Cow<'static, str>>,
{
self.pragmas.insert(key.into(), value.into());
self
}

Expand Down