uqa_storage_sqlite/
connection_lease.rs1use std::ops::{Deref, DerefMut};
10
11use rusqlite::Connection;
12
13use crate::connection::PooledConnection;
14
15pub struct SQLiteConnectionLease(pub(crate) PooledConnection);
20
21impl Deref for SQLiteConnectionLease {
22 type Target = Connection;
23
24 fn deref(&self) -> &Self::Target {
25 self.0
26 .connection()
27 .expect("a live connection lease owns its checked-out connection")
28 }
29}
30
31impl DerefMut for SQLiteConnectionLease {
32 fn deref_mut(&mut self) -> &mut Self::Target {
33 self.0
34 .connection_mut()
35 .expect("a live connection lease owns its checked-out connection")
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use crate::{ManagedConnection, SQLiteError};
42
43 #[test]
44 fn auxiliary_pool_preserves_rollback_mode_and_rejects_wal_without_conversion() {
45 let directory = tempfile::tempdir().unwrap();
46 let path = directory.path().join("auxiliary.db");
47 let auxiliary = ManagedConnection::open_auxiliary(&path, None).unwrap();
48 assert!(!auxiliary.supports_concurrent_pinned_read_and_write());
49 assert!(auxiliary.data_version_monitor_is_nonblocking().unwrap());
50 auxiliary.begin_deferred_transaction().unwrap();
51 assert!(!auxiliary.data_version_monitor_is_nonblocking().unwrap());
52 auxiliary.rollback_transaction().unwrap();
53 drop(auxiliary);
54 let wal = ManagedConnection::open(&path).unwrap();
55 wal.with(|connection| {
56 connection.execute_batch(
57 "CREATE TABLE retained(value TEXT); INSERT INTO retained VALUES ('unchanged')",
58 )?;
59 Ok(())
60 })
61 .unwrap();
62 drop(wal);
63 let before = std::fs::read(&path).unwrap();
64 let error = ManagedConnection::open_auxiliary(&path, None)
65 .err()
66 .expect("reject WAL");
67 assert!(matches!(error, SQLiteError::AuxiliaryJournalMode(mode) if mode == "wal"));
68 assert_eq!(std::fs::read(&path).unwrap(), before);
69 }
70
71 #[test]
72 fn encrypted_lease_reuses_its_connection_and_rolls_back_independently() {
73 let directory = tempfile::tempdir().unwrap();
74 let managed = ManagedConnection::open_encrypted(
75 &directory.path().join("leases.db"),
76 "lease-encryption-test-key",
77 )
78 .unwrap();
79 {
80 let leased = managed.lease_connection().unwrap();
81 leased
82 .execute_batch(
83 "CREATE TABLE retained(value TEXT); \
84 CREATE TEMP TABLE connection_identity(value INTEGER); \
85 INSERT INTO connection_identity VALUES (73); \
86 BEGIN IMMEDIATE; INSERT INTO retained VALUES ('must roll back')",
87 )
88 .unwrap();
89 }
90 let leased = managed.lease_connection().unwrap();
91 assert!(leased.is_autocommit());
92 let identity: i64 = leased
93 .query_row("SELECT value FROM connection_identity", [], |row| {
94 row.get(0)
95 })
96 .unwrap();
97 assert_eq!(
98 identity, 73,
99 "the physical connection and key derivation are reused"
100 );
101 let retained: i64 = leased
102 .query_row("SELECT count(*) FROM retained", [], |row| row.get(0))
103 .unwrap();
104 assert_eq!(retained, 0);
105
106 managed.begin_deferred_transaction().unwrap();
109 leased
110 .execute_batch("BEGIN IMMEDIATE; INSERT INTO retained VALUES ('separate')")
111 .unwrap();
112 drop(leased);
113 managed
114 .with(|connection| {
115 assert!(!connection.is_autocommit());
116 let retained: i64 =
117 connection.query_row("SELECT count(*) FROM retained", [], |row| row.get(0))?;
118 assert_eq!(retained, 0);
119 Ok(())
120 })
121 .unwrap();
122 managed.rollback_transaction().unwrap();
123 }
124}