Struct deltachat::sql::Sql

source ·
pub struct Sql {
    pub(crate) dbfile: PathBuf,
    write_mtx: Mutex<()>,
    pool: RwLock<Option<Pool>>,
    is_encrypted: RwLock<Option<bool>>,
    pub(crate) config_cache: RwLock<HashMap<String, Option<String>>>,
}
Expand description

A wrapper around the underlying Sqlite3 object.

Fields§

§dbfile: PathBuf

Database file path

§write_mtx: Mutex<()>

Write transactions mutex.

See Self::write_lock.

§pool: RwLock<Option<Pool>>

SQL connection pool.

§is_encrypted: RwLock<Option<bool>>

None if the database is not open, true if it is open with passphrase and false if it is open without a passphrase.

§config_cache: RwLock<HashMap<String, Option<String>>>

Cache of config table.

Implementations§

source§

impl Sql

source

async fn set_db_version(&self, version: i32) -> Result<()>

source

fn set_db_version_trans( transaction: &mut Transaction<'_>, version: i32 ) -> Result<()>

source

async fn set_db_version_in_cache(&self, version: i32) -> Result<()>

source

async fn execute_migration(&self, query: &str, version: i32) -> Result<()>

source§

impl Sql

source

pub fn new(dbfile: PathBuf) -> Sql

Creates new SQL database.

source

pub async fn check_passphrase(&self, passphrase: String) -> Result<bool>

Tests SQLCipher passphrase.

Returns true if passphrase is correct, i.e. the database is new or can be unlocked with this passphrase, and false if the database is already encrypted with another passphrase or corrupted.

Fails if database is already open.

source

pub async fn is_open(&self) -> bool

Checks if there is currently a connection to the underlying Sqlite database.

source

pub(crate) async fn is_encrypted(&self) -> Option<bool>

Returns true if the database is encrypted.

If database is not open, returns None.

source

async fn close(&self)

Closes all underlying Sqlite connections.

source

pub(crate) async fn import(&self, path: &Path, passphrase: String) -> Result<()>

Imports the database from a separate file with the given passphrase.

source

fn new_pool(dbfile: &Path, passphrase: String) -> Result<Pool>

Creates a new connection pool.

source

async fn try_open( &self, context: &Context, dbfile: &Path, passphrase: String ) -> Result<()>

source

pub async fn run_migrations(&self, context: &Context) -> Result<()>

Updates SQL schema to the latest version.

source

pub async fn open(&self, context: &Context, passphrase: String) -> Result<()>

Opens the provided database and runs any necessary migrations. If a database is already open, this will return an error.

source

pub async fn change_passphrase(&self, passphrase: String) -> Result<()>

Changes the passphrase of encrypted database.

The database must already be encrypted and the passphrase cannot be empty. It is impossible to turn encrypted database into unencrypted and vice versa this way, use import/export for this.

source

pub async fn write_lock(&self) -> MutexGuard<'_, ()>

Locks the write transactions mutex in order to make sure that there never are multiple write transactions at once.

Doing the locking ourselves instead of relying on SQLite has these reasons:

  • SQLite’s locking mechanism is non-async, blocking a thread
  • SQLite’s locking mechanism just sleeps in a loop, which is really inefficient

More considerations on alternatives to the current approach:

We use DEFERRED transactions.

In order to never get concurrency issues, we could make all transactions IMMEDIATE, but this would mean that there can never be two simultaneous transactions.

Read transactions can simply be made DEFERRED to run in parallel w/o any drawbacks.

DEFERRED write transactions without doing the locking ourselves would have these drawbacks:

  1. As mentioned above, SQLite’s locking mechanism is non-async and sleeps in a loop.
  2. If there are other write transactions, we block the db connection until upgraded. If some reader comes then, it has to get the next, less used connection with a worse per-connection page cache (SQLite allows one write and any number of reads in parallel).
  3. If a transaction is blocked for more than busy_timeout, it fails with SQLITE_BUSY.
  4. If upon a successful upgrade to a write transaction the db has been modified, the transaction has to be rolled back and retried, which means extra work in terms of CPU/battery.

The only pro of making write transactions DEFERRED w/o the external locking would be some parallelism between them.

Another option would be to make write transactions IMMEDIATE, also w/o the external locking. But then cons 1. - 3. above would still be valid.

source

async fn call<'a, F, R>(&'a self, function: F) -> Result<R>
where F: 'a + FnOnce(&mut Connection) -> Result<R> + Send, R: Send + 'static,

Allocates a connection and calls function with the connection. If function does write queries,

  • either first take a lock using write_lock()
  • or use call_write() instead.

Returns the result of the function.

source

pub async fn call_write<'a, F, R>(&'a self, function: F) -> Result<R>
where F: 'a + FnOnce(&mut Connection) -> Result<R> + Send, R: Send + 'static,

Allocates a connection and calls given function, assuming it does write queries, with the connection.

Returns the result of the function.

source

pub async fn execute( &self, query: &str, params: impl Params + Send ) -> Result<usize>

Execute query assuming it is a write query, returning the number of affected rows.

source

pub async fn insert( &self, query: &str, params: impl Params + Send ) -> Result<i64>

Executes the given query, returning the last inserted row ID.

source

pub async fn query_map<T, F, G, H>( &self, sql: &str, params: impl Params + Send, f: F, g: G ) -> Result<H>
where F: Send + FnMut(&Row<'_>) -> Result<T>, G: Send + FnMut(MappedRows<'_, F>) -> Result<H>, H: Send + 'static,

Prepares and executes the statement and maps a function over the resulting rows. Then executes the second function over the returned iterator and returns the result of that function.

source

pub async fn count( &self, query: &str, params: impl Params + Send ) -> Result<usize>

Used for executing SELECT COUNT statements only. Returns the resulting count.

source

pub async fn exists( &self, sql: &str, params: impl Params + Send ) -> Result<bool>

Used for executing SELECT COUNT statements only. Returns true, if the count is at least one, false otherwise.

source

pub async fn query_row<T, F>( &self, query: &str, params: impl Params + Send, f: F ) -> Result<T>
where F: FnOnce(&Row<'_>) -> Result<T> + Send, T: Send + 'static,

Execute a query which is expected to return one row.

source

pub async fn transaction<G, H>(&self, callback: G) -> Result<H>
where H: Send + 'static, G: Send + FnOnce(&mut Transaction<'_>) -> Result<H>,

Execute the function inside a transaction assuming that it does write queries.

If the function returns an error, the transaction will be rolled back. If it does not return an error, the transaction will be committed.

source

pub async fn table_exists(&self, name: &str) -> Result<bool>

Query the database if the requested table already exists.

source

pub async fn col_exists(&self, table_name: &str, col_name: &str) -> Result<bool>

Check if a column exists in a given table.

source

pub async fn query_row_optional<T, F>( &self, sql: &str, params: impl Params + Send, f: F ) -> Result<Option<T>>
where F: Send + FnOnce(&Row<'_>) -> Result<T>, T: Send + 'static,

Execute a query which is expected to return zero or one row.

source

pub async fn query_get_value<T>( &self, query: &str, params: impl Params + Send ) -> Result<Option<T>>
where T: FromSql + Send + 'static,

Executes a query which is expected to return one row and one column. If the query does not return a value or returns SQL NULL, returns Ok(None).

source

pub async fn set_raw_config(&self, key: &str, value: Option<&str>) -> Result<()>

Set private configuration options.

Setting None deletes the value. On failure an error message will already have been logged.

source

pub async fn get_raw_config(&self, key: &str) -> Result<Option<String>>

Get configuration options from the database.

source

pub async fn set_raw_config_int(&self, key: &str, value: i32) -> Result<()>

Sets configuration for the given key to 32-bit signed integer value.

source

pub async fn get_raw_config_int(&self, key: &str) -> Result<Option<i32>>

Returns 32-bit signed integer configuration value for the given key.

source

pub async fn get_raw_config_u32(&self, key: &str) -> Result<Option<u32>>

Returns 32-bit unsigned integer configuration value for the given key.

source

pub async fn get_raw_config_bool(&self, key: &str) -> Result<bool>

Returns boolean configuration value for the given key.

source

pub async fn set_raw_config_bool(&self, key: &str, value: bool) -> Result<()>

Sets configuration for the given key to boolean value.

source

pub async fn set_raw_config_int64(&self, key: &str, value: i64) -> Result<()>

Sets configuration for the given key to 64-bit signed integer value.

source

pub async fn get_raw_config_int64(&self, key: &str) -> Result<Option<i64>>

Returns 64-bit signed integer configuration value for the given key.

Trait Implementations§

source§

impl Debug for Sql

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Sql

§

impl Send for Sql

§

impl Sync for Sql

§

impl Unpin for Sql

§

impl !UnwindSafe for Sql

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

§

fn implicit( self, class: Class, constructed: bool, tag: u32 ) -> TaggedParser<'a, Implicit, Self, E>

source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more