diesel/sqlite/connection/
borrowed_connection.rs1use super::{RawConnection, SqliteConnection};
2use crate::connection::instrumentation::DynInstrumentation;
3use crate::connection::statement_cache::StatementCache;
4use crate::connection::*;
5use crate::expression::QueryMetadata;
6use crate::prelude::{ConnectionResult, QueryResult};
7use crate::query_builder::{Query, QueryFragment, QueryId};
8use crate::sqlite::Sqlite;
9use core::mem::ManuallyDrop;
10
11#[allow(missing_debug_implementations)]
21pub struct BorrowedSqliteConnection {
22 inner: ManuallyDrop<SqliteConnection>,
28}
29
30impl Drop for BorrowedSqliteConnection {
31 #[allow(unsafe_code)] fn drop(&mut self) {
33 let conn = unsafe { core::mem::ManuallyDrop::take(&mut self.inner) };
35 let SqliteConnection {
36 statement_cache,
37 raw_connection,
38 transaction_state: _,
39 metadata_lookup: (),
40 instrumentation,
41 } = conn;
42 let mut raw_connection = core::mem::ManuallyDrop::new(raw_connection);
45 raw_connection.reset_registered_hooks();
47 drop(statement_cache);
50 drop(instrumentation);
51 }
52}
53
54impl SimpleConnection for BorrowedSqliteConnection {
55 fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
56 SqliteConnection::batch_execute(&mut self.inner, query)
57 }
58}
59
60impl Connection for BorrowedSqliteConnection {
61 type Backend = Sqlite;
62
63 type TransactionManager = AnsiTransactionManager;
64
65 fn establish(_database_url: &str) -> ConnectionResult<Self> {
66 Err(crate::ConnectionError::BadConnection(
67 "Cannot create a pinned sqlite connection".into(),
68 ))
69 }
70
71 fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
72 where
73 T: QueryFragment<Self::Backend> + QueryId,
74 {
75 SqliteConnection::execute_returning_count(&mut self.inner, source)
76 }
77
78 fn transaction_state(
79 &mut self,
80 ) -> &mut <Self::TransactionManager as TransactionManager<Self>>::TransactionStateData {
81 SqliteConnection::transaction_state(&mut self.inner)
82 }
83
84 fn instrumentation(&mut self) -> &mut dyn Instrumentation {
85 SqliteConnection::instrumentation(&mut self.inner)
86 }
87
88 fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) {
89 SqliteConnection::set_instrumentation(&mut self.inner, instrumentation);
90 }
91
92 fn set_prepared_statement_cache_size(&mut self, size: CacheSize) {
93 SqliteConnection::set_prepared_statement_cache_size(&mut self.inner, size)
94 }
95}
96
97impl LoadConnection for BorrowedSqliteConnection {
98 type Cursor<'conn, 'query>
99 = <SqliteConnection as LoadConnection>::Cursor<'conn, 'query>
100 where
101 Self: 'conn;
102
103 type Row<'conn, 'query>
104 = <SqliteConnection as LoadConnection>::Row<'conn, 'query>
105 where
106 Self: 'conn;
107
108 fn load<'conn, 'query, T>(
109 &'conn mut self,
110 source: T,
111 ) -> QueryResult<Self::Cursor<'conn, 'query>>
112 where
113 T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
114 Self::Backend: QueryMetadata<T::SqlType>,
115 {
116 SqliteConnection::load(&mut self.inner, source)
117 }
118}
119
120impl ConnectionSealed for BorrowedSqliteConnection {}
121
122impl BorrowedSqliteConnection {
123 pub(super) fn new(conn: RawConnection) -> Self {
124 BorrowedSqliteConnection {
125 inner: core::mem::ManuallyDrop::new(SqliteConnection {
126 statement_cache: StatementCache::new(),
127 raw_connection: conn,
128 transaction_state: AnsiTransactionManager::default(),
129 metadata_lookup: (),
130 instrumentation: DynInstrumentation::default_instrumentation(),
131 }),
132 }
133 }
134
135 #[allow(unsafe_code)] pub unsafe fn inner_mut(&mut self) -> &mut SqliteConnection {
143 &mut self.inner
144 }
145}
146
147#[cfg(all(
153 test,
154 not(any(miri, all(target_family = "wasm", target_os = "unknown")))
155))]
156mod tests {
157 use super::*;
158 use crate::connection::SimpleConnection;
159 use std::sync::Arc;
160 use std::sync::atomic::{AtomicU32, Ordering};
161
162 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
165 #[diesel_test_helper::test]
166 fn wal_hook_survives_its_own_call() {
167 let dir = tempfile::tempdir().unwrap();
168 let path = dir.path().join("test.db");
169 let conn = &mut SqliteConnection::establish(path.to_str().unwrap()).unwrap();
170 conn.batch_execute("PRAGMA journal_mode = WAL; CREATE TABLE borrowed_wal (x)")
171 .unwrap();
172
173 let calls = Arc::new(AtomicU32::new(0));
174 let c2 = calls.clone();
175 conn.on_wal(move |_conn, _db_name, _n_pages| {
176 c2.fetch_add(1, Ordering::Relaxed);
177 });
178
179 conn.batch_execute("INSERT INTO borrowed_wal VALUES (1)")
180 .unwrap();
181 conn.batch_execute("INSERT INTO borrowed_wal VALUES (2)")
182 .unwrap();
183 assert_eq!(calls.load(Ordering::Relaxed), 2);
184 }
185
186 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
189 #[diesel_test_helper::test]
190 #[allow(unsafe_code)]
191 fn hooks_registered_in_wal_callback_are_freed() {
192 use crate::sqlite::CommitDecision;
193 struct Token(Arc<AtomicU32>);
194 impl Drop for Token {
195 fn drop(&mut self) {
196 self.0.fetch_add(1, Ordering::SeqCst);
197 }
198 }
199 let dir = tempfile::tempdir().unwrap();
200 let path = dir.path().join("test.db");
201 let conn = &mut SqliteConnection::establish(path.to_str().unwrap()).unwrap();
202 conn.batch_execute("PRAGMA journal_mode = WAL; CREATE TABLE borrowed_wal_hooks (x)")
203 .unwrap();
204
205 let dropped = Arc::new(AtomicU32::new(0));
206 let inner_wal_calls = Arc::new(AtomicU32::new(0));
207 let (d, w) = (dropped.clone(), inner_wal_calls.clone());
208 conn.on_wal(move |conn, _db_name, _n_pages| {
209 let conn = unsafe { conn.inner_mut() };
210 let t = Token(d.clone());
211 conn.on_commit(move || {
212 let _ = &t;
213 CommitDecision::Proceed
214 });
215 let (t, w) = (Token(d.clone()), w.clone());
216 conn.on_wal(move |_conn, _, _| {
218 let _ = &t;
219 w.fetch_add(1, Ordering::SeqCst);
220 });
221 conn.batch_execute("INSERT INTO borrowed_wal_hooks VALUES (0)")
222 .unwrap();
223 });
224
225 conn.batch_execute("INSERT INTO borrowed_wal_hooks VALUES (1)")
226 .unwrap();
227 assert_eq!(inner_wal_calls.load(Ordering::SeqCst), 1);
228 assert_eq!(dropped.load(Ordering::SeqCst), 2);
229 }
230}