From 222cd688a41a30c6e12b41d46ce88051111a4969 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Thu, 2 Jul 2020 23:18:14 -0700 Subject: [PATCH] feat(sqlite): enable configuration of journal_mode and foreign_keys and default to WAL and ON --- sqlx-core/src/mysql/options.rs | 16 ++--- sqlx-core/src/postgres/options.rs | 6 +- sqlx-core/src/sqlite/connection/mod.rs | 12 +++- sqlx-core/src/sqlite/options.rs | 79 +++++++++++++++++++++++-- tests/sqlite/sqlite.db | Bin 36864 -> 36864 bytes 5 files changed, 96 insertions(+), 17 deletions(-) diff --git a/sqlx-core/src/mysql/options.rs b/sqlx-core/src/mysql/options.rs index ee25e690..1051cffc 100644 --- a/sqlx-core/src/mysql/options.rs +++ b/sqlx-core/src/mysql/options.rs @@ -43,15 +43,17 @@ impl FromStr for MySqlSslMode { type Err = Error; fn from_str(s: &str) -> Result { - Ok(match s { - "DISABLED" => MySqlSslMode::Disabled, - "PREFERRED" => MySqlSslMode::Preferred, - "REQUIRED" => MySqlSslMode::Required, - "VERIFY_CA" => MySqlSslMode::VerifyCa, - "VERIFY_IDENTITY" => MySqlSslMode::VerifyIdentity, + Ok(match &*s.to_ascii_lowercase() { + "disabled" => MySqlSslMode::Disabled, + "preferred" => MySqlSslMode::Preferred, + "required" => MySqlSslMode::Required, + "verify_ca" => MySqlSslMode::VerifyCa, + "verify_identity" => MySqlSslMode::VerifyIdentity, _ => { - return Err(err_protocol!("unknown SSL mode value: {:?}", s)); + return Err(Error::ParseConnectOptions( + format!("unknown value {:?} for `ssl_mode`", s).into(), + )); } }) } diff --git a/sqlx-core/src/postgres/options.rs b/sqlx-core/src/postgres/options.rs index 1dcfa09b..48f6040d 100644 --- a/sqlx-core/src/postgres/options.rs +++ b/sqlx-core/src/postgres/options.rs @@ -43,7 +43,7 @@ impl FromStr for PgSslMode { type Err = Error; fn from_str(s: &str) -> Result { - Ok(match s { + Ok(match &*s.to_ascii_lowercase() { "disable" => PgSslMode::Disable, "allow" => PgSslMode::Allow, "prefer" => PgSslMode::Prefer, @@ -52,7 +52,9 @@ impl FromStr for PgSslMode { "verify-full" => PgSslMode::VerifyFull, _ => { - return Err(err_protocol!("unknown SSL mode value: {:?}", s)); + return Err(Error::ParseConnectOptions( + format!("unknown value {:?} for `ssl_mode`", s).into(), + )); } }) } diff --git a/sqlx-core/src/sqlite/connection/mod.rs b/sqlx-core/src/sqlite/connection/mod.rs index d768f143..1b5e0d90 100644 --- a/sqlx-core/src/sqlite/connection/mod.rs +++ b/sqlx-core/src/sqlite/connection/mod.rs @@ -10,6 +10,7 @@ use crate::common::StatementCache; use crate::connection::{Connect, Connection}; use crate::error::Error; use crate::ext::ustr::UStr; +use crate::executor::Executor; use crate::sqlite::connection::establish::establish; use crate::sqlite::statement::{SqliteStatement, StatementWorker}; use crate::sqlite::{Sqlite, SqliteConnectOptions}; @@ -100,9 +101,16 @@ impl Connect for SqliteConnection { #[inline] fn connect_with(options: &Self::Options) -> BoxFuture<'_, Result> { Box::pin(async move { - let conn = establish(options).await?; + let mut conn = establish(options).await?; - // TODO: Apply any connection options once we have them defined + // send an initial sql statement comprised of options + let init = format!( + "PRAGMA journal_mode = {}; PRAGMA foreign_keys = {};", + options.journal_mode.as_str(), + if options.foreign_keys { "ON" } else { "OFF" } + ); + + conn.execute(&*init).await?; Ok(conn) }) diff --git a/sqlx-core/src/sqlite/options.rs b/sqlx-core/src/sqlite/options.rs index 42c9db97..9387fd37 100644 --- a/sqlx-core/src/sqlite/options.rs +++ b/sqlx-core/src/sqlite/options.rs @@ -1,15 +1,67 @@ use std::path::PathBuf; use std::str::FromStr; -use crate::error::BoxDynError; +use crate::error::{BoxDynError, Error}; // TODO: Look at go-sqlite for option ideas // TODO: journal_mode +#[derive(Debug)] +pub enum SqliteJournalMode { + Delete, + Truncate, + Persist, + Memory, + Wal, + Off, +} + +impl SqliteJournalMode { + pub(crate) fn as_str(&self) -> &'static str { + match self { + SqliteJournalMode::Delete => "DELETE", + SqliteJournalMode::Truncate => "TRUNCATE", + SqliteJournalMode::Persist => "PERSIST", + SqliteJournalMode::Memory => "MEMORY", + SqliteJournalMode::Wal => "WAL", + SqliteJournalMode::Off => "OFF", + } + } +} + +impl Default for SqliteJournalMode { + fn default() -> Self { + SqliteJournalMode::Wal + } +} + +impl FromStr for SqliteJournalMode { + type Err = Error; + + fn from_str(s: &str) -> Result { + Ok(match &*s.to_ascii_lowercase() { + "delete" => SqliteJournalMode::Delete, + "truncate" => SqliteJournalMode::Truncate, + "persist" => SqliteJournalMode::Persist, + "memory" => SqliteJournalMode::Memory, + "wal" => SqliteJournalMode::Wal, + "off" => SqliteJournalMode::Off, + + _ => { + return Err(Error::ParseConnectOptions( + format!("unknown value {:?} for `journal_mode`", s).into(), + )); + } + }) + } +} + /// Options and flags which can be used to configure a SQLite connection. pub struct SqliteConnectOptions { pub(crate) filename: PathBuf, pub(crate) in_memory: bool, + pub(crate) journal_mode: SqliteJournalMode, + pub(crate) foreign_keys: bool, pub(crate) statement_cache_capacity: usize, } @@ -24,10 +76,29 @@ impl SqliteConnectOptions { Self { filename: PathBuf::from(":memory:"), in_memory: false, + foreign_keys: true, statement_cache_capacity: 100, + journal_mode: SqliteJournalMode::Wal, } } + /// Set the enforcement of [foreign key constriants](https://www.sqlite.org/pragma.html#pragma_foreign_keys). + /// + /// By default, this is enabled. + pub fn foreign_keys(mut self, on: bool) -> Self { + self.foreign_keys = on; + self + } + + /// Sets the [journal mode](https://www.sqlite.org/pragma.html#pragma_journal_mode) for the database connection. + /// + /// 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 + } + /// Sets the capacity of the connection's statement cache in a number of stored /// distinct statements. Caching is handled using LRU, meaning when the /// amount of queries hits the defined limit, the oldest statement will get @@ -44,11 +115,7 @@ impl FromStr for SqliteConnectOptions { type Err = BoxDynError; fn from_str(mut s: &str) -> Result { - let mut options = Self { - filename: PathBuf::new(), - in_memory: false, - statement_cache_capacity: 100, - }; + let mut options = Self::new(); // remove scheme s = s diff --git a/tests/sqlite/sqlite.db b/tests/sqlite/sqlite.db index 77339064b5f5200eef7b521a4f91270446c8138c..eadde2721c0ffc60b3fd91041ef503b1b6ce0ac7 100644 GIT binary patch delta 139 zcmZozz|^pSNhUbZC$l6~AuYcsH?c&)m_dMniHX5ML4kpR!FZyKGo$gwgeCgS5_}eu z*$s4A_`LZn77GgSsR>FjGia7%WELv`QKCXgYH^96IEK*XIJ;$x%o6;ali3|~S@`?- YJ2wjo1oCsSFf%YpfC%x;ll^lY0C005%m4rY delta 80 zcmZozz|^pSNhUbZC$l6~AuYcsH?c&)m_dMnk&(ecL4kpR!Dyn4Go#VQgeCgSVtjFv i*$s3z3kqoQZH}{B#>gzjKY22{14tyEfAeJjTn7MCK@}bV