From 4f2dd78d12020b3aeebc7e11d442ff852429b030 Mon Sep 17 00:00:00 2001 From: ghassmo Date: Thu, 24 Jun 2021 13:50:02 +0300 Subject: [PATCH 1/6] Support custom initial options for sqlite Apply suggestions from code review Co-authored-by: Austin Bonander Apply suggestions from code review Co-authored-by: Austin Bonander Use order-preserving map to set pragmas for an initial sqlite statement Use Cow<'static, str> instead of String --- sqlx-core/Cargo.toml | 1 + sqlx-core/src/sqlite/options/connect.rs | 19 ++----- sqlx-core/src/sqlite/options/mod.rs | 72 ++++++++++++++++++------- 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/sqlx-core/Cargo.toml b/sqlx-core/Cargo.toml index bfa3f5f9ae..aaf1500c02 100644 --- a/sqlx-core/Cargo.toml +++ b/sqlx-core/Cargo.toml @@ -160,3 +160,4 @@ stringprep = "0.1.2" bstr = { version = "0.2.14", default-features = false, features = ["std"], optional = true } git2 = { version = "0.13.12", default-features = false, optional = true } hashlink = "0.7.0" +indexmap = "1.7.0" diff --git a/sqlx-core/src/sqlite/options/connect.rs b/sqlx-core/src/sqlite/options/connect.rs index 6c29120a2f..b85a19d338 100644 --- a/sqlx-core/src/sqlite/options/connect.rs +++ b/sqlx-core/src/sqlite/options/connect.rs @@ -18,20 +18,11 @@ 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() { + init += &format!("PRAGMA {} = {}; ", key, value); + } conn.execute(&*init).await?; diff --git a/sqlx-core/src/sqlite/options/mod.rs b/sqlx-core/src/sqlite/options/mod.rs index ba50bc05d6..ce438dd638 100644 --- a/sqlx-core/src/sqlite/options/mod.rs +++ b/sqlx-core/src/sqlite/options/mod.rs @@ -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, @@ -53,16 +55,11 @@ 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) pragmas: IndexMap, Cow<'static, str>>, } impl Default for SqliteConnectOptions { @@ -73,21 +70,43 @@ impl Default for SqliteConnectOptions { impl SqliteConnectOptions { pub fn new() -> Self { + // set default pragmas + let mut pragmas: IndexMap, 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, + pragmas, } } @@ -101,7 +120,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 } @@ -118,7 +140,8 @@ 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 } @@ -126,7 +149,8 @@ impl SqliteConnectOptions { /// /// 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 } @@ -171,7 +195,8 @@ 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 } @@ -179,7 +204,8 @@ impl SqliteConnectOptions { /// /// 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 } @@ -187,7 +213,17 @@ impl SqliteConnectOptions { /// /// 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(mut self, key: T, value: T) -> Self + where + T: Into>, + { + self.pragmas.insert(key.into(), value.into()); self } } From 63f9b10c20d9212e7e80c0d24f412ce9e709c4bd Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Mon, 13 Sep 2021 13:08:58 -0700 Subject: [PATCH 2/6] Apply suggestions from code review --- sqlx-core/src/sqlite/options/connect.rs | 2 +- sqlx-core/src/sqlite/options/mod.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sqlx-core/src/sqlite/options/connect.rs b/sqlx-core/src/sqlite/options/connect.rs index b85a19d338..b65624c460 100644 --- a/sqlx-core/src/sqlite/options/connect.rs +++ b/sqlx-core/src/sqlite/options/connect.rs @@ -21,7 +21,7 @@ impl ConnectOptions for SqliteConnectOptions { let mut init = String::new(); for (key, value) in self.pragmas.iter() { - init += &format!("PRAGMA {} = {}; ", key, value); + write!(init, "PRAGMA {} = {}; ", key, value).ok(); } conn.execute(&*init).await?; diff --git a/sqlx-core/src/sqlite/options/mod.rs b/sqlx-core/src/sqlite/options/mod.rs index 7ab40ebe30..15ce9f8250 100644 --- a/sqlx-core/src/sqlite/options/mod.rs +++ b/sqlx-core/src/sqlite/options/mod.rs @@ -219,9 +219,10 @@ impl SqliteConnectOptions { } /// Sets custom initial pragma for the database connection. - pub fn pragma(mut self, key: T, value: T) -> Self + pub fn pragma(mut self, key: K, value: V) -> Self where - T: Into>, + K: Into>, + V: Into>, { self.pragmas.insert(key.into(), value.into()); self From b717a5c1b152c72a0034afb4e2a6e36f42944e6a Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Mon, 13 Sep 2021 13:18:10 -0700 Subject: [PATCH 3/6] Apply suggestions from code review --- sqlx-core/src/sqlite/options/connect.rs | 1 + sqlx-core/src/sqlite/options/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/sqlx-core/src/sqlite/options/connect.rs b/sqlx-core/src/sqlite/options/connect.rs index b65624c460..328785c9fa 100644 --- a/sqlx-core/src/sqlite/options/connect.rs +++ b/sqlx-core/src/sqlite/options/connect.rs @@ -21,6 +21,7 @@ impl ConnectOptions for SqliteConnectOptions { let mut init = String::new(); for (key, value) in self.pragmas.iter() { + use std::fmt::Write; write!(init, "PRAGMA {} = {}; ", key, value).ok(); } diff --git a/sqlx-core/src/sqlite/options/mod.rs b/sqlx-core/src/sqlite/options/mod.rs index 15ce9f8250..2cfa5c9714 100644 --- a/sqlx-core/src/sqlite/options/mod.rs +++ b/sqlx-core/src/sqlite/options/mod.rs @@ -59,6 +59,7 @@ pub struct SqliteConnectOptions { pub(crate) statement_cache_capacity: usize, pub(crate) busy_timeout: Duration, pub(crate) log_settings: LogSettings, + pub(crate) immutable: bool, pub(crate) pragmas: IndexMap, Cow<'static, str>>, } From a6847ccd87999b2992721bbe91499d5c71a07a1f Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Mon, 13 Sep 2021 13:26:24 -0700 Subject: [PATCH 4/6] Update sqlx-core/src/sqlite/options/mod.rs --- sqlx-core/src/sqlite/options/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/sqlx-core/src/sqlite/options/mod.rs b/sqlx-core/src/sqlite/options/mod.rs index 2cfa5c9714..73c625a84f 100644 --- a/sqlx-core/src/sqlite/options/mod.rs +++ b/sqlx-core/src/sqlite/options/mod.rs @@ -107,6 +107,7 @@ impl SqliteConnectOptions { statement_cache_capacity: 100, busy_timeout: Duration::from_secs(5), log_settings: Default::default(), + immutable: false, pragmas, } } From 7c32635c16c5440fc39c2189945359467bed5817 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Mon, 13 Sep 2021 13:31:08 -0700 Subject: [PATCH 5/6] Update sqlx-core/src/sqlite/options/connect.rs --- sqlx-core/src/sqlite/options/connect.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqlx-core/src/sqlite/options/connect.rs b/sqlx-core/src/sqlite/options/connect.rs index 328785c9fa..5bf1a1b395 100644 --- a/sqlx-core/src/sqlite/options/connect.rs +++ b/sqlx-core/src/sqlite/options/connect.rs @@ -22,7 +22,8 @@ impl ConnectOptions for SqliteConnectOptions { for (key, value) in self.pragmas.iter() { use std::fmt::Write; - write!(init, "PRAGMA {} = {}; ", key, value).ok(); + use std::fmt::Write; + write!(init, "PRAGMA {} = {}; ", key, value).ok(); } conn.execute(&*init).await?; From f95d7a889a0b3cc0109cbffe6a19e44e1e5f0651 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Mon, 13 Sep 2021 13:32:55 -0700 Subject: [PATCH 6/6] Update sqlx-core/src/sqlite/options/connect.rs --- sqlx-core/src/sqlite/options/connect.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/sqlx-core/src/sqlite/options/connect.rs b/sqlx-core/src/sqlite/options/connect.rs index 5bf1a1b395..cbd465ec31 100644 --- a/sqlx-core/src/sqlite/options/connect.rs +++ b/sqlx-core/src/sqlite/options/connect.rs @@ -21,7 +21,6 @@ impl ConnectOptions for SqliteConnectOptions { let mut init = String::new(); for (key, value) in self.pragmas.iter() { - use std::fmt::Write; use std::fmt::Write; write!(init, "PRAGMA {} = {}; ", key, value).ok(); }