1#![doc = include_str!("../README.md")]
2use diesel::backend::Backend;
17use diesel::connection::{
18 AnsiTransactionManager, LoadConnection, SimpleConnection, TransactionManager,
19 TransactionManagerStatus,
20};
21use diesel::debug_query;
22use diesel::expression::QueryMetadata;
23use diesel::prelude::*;
24use diesel::query_builder::{AsQuery, QueryFragment, QueryId};
25use diesel::r2d2::R2D2Connection;
26use std::ops::{Deref, DerefMut};
27use usdt::UniqueId;
28use uuid::Uuid;
29
30#[usdt::provider(provider = "diesel_db")]
31pub mod probes {
32 pub fn connection__establish__start(_: &UniqueId, conn_id: Uuid, url: &str) {}
34 pub fn connection__establish__done(_: &UniqueId, conn_id: Uuid, success: u8) {}
37 pub fn query__start(_: &UniqueId, conn_id: Uuid, query: &str) {}
39 pub fn query__done(_: &UniqueId, conn_id: Uuid) {}
41 pub fn transaction__start(conn_id: Uuid, depth: i64) {}
51 pub fn transaction__done(conn_id: Uuid, depth: i64, committed: u8) {}
64}
65
66#[derive(Debug)]
70pub struct DTraceConnection<C: Connection> {
71 inner: C,
72 id: Uuid,
73}
74
75impl<C: Connection> DTraceConnection<C> {
76 pub fn id(&self) -> Uuid {
77 self.id
78 }
79}
80
81impl<C: Connection> Deref for DTraceConnection<C> {
82 type Target = C;
83 fn deref(&self) -> &Self::Target {
84 &self.inner
85 }
86}
87
88impl<C: Connection> DerefMut for DTraceConnection<C> {
89 fn deref_mut(&mut self) -> &mut Self::Target {
90 &mut self.inner
91 }
92}
93
94impl<C: Connection> SimpleConnection for DTraceConnection<C> {
95 fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
96 let id = UniqueId::new();
97 probes::query__start!(|| (&id, self.id, query));
98 let result = self.inner.batch_execute(query);
99 probes::query__done!(|| (&id, self.id));
100 result
101 }
102}
103
104impl<C> LoadConnection for DTraceConnection<C>
105where
106 C: Connection<TransactionManager = AnsiTransactionManager> + LoadConnection,
107 C::Backend: Default,
108 <C::Backend as Backend>::QueryBuilder: Default,
109{
110 type Cursor<'conn, 'query>
111 = C::Cursor<'conn, 'query>
112 where
113 Self: 'conn;
114 type Row<'conn, 'query>
115 = C::Row<'conn, 'query>
116 where
117 Self: 'conn;
118
119 fn load<'conn, 'query, T>(
120 &'conn mut self,
121 source: T,
122 ) -> QueryResult<Self::Cursor<'conn, 'query>>
123 where
124 T: diesel::query_builder::Query + QueryFragment<Self::Backend> + QueryId + 'query,
125 Self::Backend: QueryMetadata<T::SqlType>,
126 {
127 let query = source.as_query();
128 let id = UniqueId::new();
129 probes::query__start!(|| (
130 &id,
131 self.id,
132 debug_query::<Self::Backend, _>(&query).to_string()
133 ));
134 let result = self.inner.load(query);
135 probes::query__done!(|| (&id, self.id));
136 result
137 }
138}
139
140impl<C> Connection for DTraceConnection<C>
141where
142 C: Connection<TransactionManager = AnsiTransactionManager>,
143 C::Backend: Default,
144 <C::Backend as Backend>::QueryBuilder: Default,
145{
146 type Backend = C::Backend;
147 type TransactionManager = DTraceTransactionManager<C>;
148
149 fn establish(database_url: &str) -> ConnectionResult<Self> {
150 let id = UniqueId::new();
151 let conn_id = Uuid::new_v4();
152 probes::connection__establish__start!(|| (&id, conn_id, database_url));
153 let conn = C::establish(database_url);
154 probes::connection__establish__done!(|| (&id, conn_id, u8::from(conn.is_ok())));
155 let inner = conn?;
156 Ok(DTraceConnection { inner, id: conn_id })
157 }
158
159 fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
160 where
161 T: QueryFragment<Self::Backend> + QueryId,
162 {
163 let id = UniqueId::new();
164 probes::query__start!(|| (
165 &id,
166 self.id,
167 debug_query::<Self::Backend, _>(&source).to_string()
168 ));
169 let result = self.inner.execute_returning_count(source);
170 probes::query__done!(|| (&id, self.id));
171 result
172 }
173
174 fn transaction_state(
175 &mut self,
176 ) -> &mut <DTraceTransactionManager<C> as TransactionManager<DTraceConnection<C>>>::TransactionStateData{
177 self.inner.transaction_state()
178 }
179
180 fn instrumentation(&mut self) -> &mut dyn diesel::connection::Instrumentation {
181 self.inner.instrumentation()
182 }
183
184 fn set_instrumentation(&mut self, instrumentation: impl diesel::connection::Instrumentation) {
185 self.inner.set_instrumentation(instrumentation)
186 }
187
188 fn set_prepared_statement_cache_size(&mut self, size: diesel::connection::CacheSize) {
189 self.inner.set_prepared_statement_cache_size(size);
190 }
191}
192
193impl<C> diesel::connection::ConnectionSealed for DTraceConnection<C>
194where
195 C: Connection<TransactionManager = AnsiTransactionManager>,
196 C::Backend: Default,
197 <C::Backend as Backend>::QueryBuilder: Default,
198{
199}
200
201impl<C> R2D2Connection for DTraceConnection<C>
202where
203 C: R2D2Connection + Connection<TransactionManager = AnsiTransactionManager>,
204 C::Backend: Default,
205 <C::Backend as Backend>::QueryBuilder: Default,
206{
207 fn ping(&mut self) -> QueryResult<()> {
208 self.inner.ping()
209 }
210}
211
212pub struct DTraceTransactionManager<C> {
218 _data: std::marker::PhantomData<C>,
219}
220
221impl<C> DTraceTransactionManager<C>
222where
223 C: Connection<TransactionManager = AnsiTransactionManager>,
224{
225 fn depth(conn: &mut DTraceConnection<C>) -> i64 {
227 let status = AnsiTransactionManager::transaction_manager_status_mut(&mut conn.inner);
228 match status.transaction_depth() {
229 Ok(Some(depth)) => i64::from(depth.get()),
230 Ok(None) => 0,
231 Err(_) => -1,
232 }
233 }
234}
235
236impl<C> TransactionManager<DTraceConnection<C>> for DTraceTransactionManager<C>
237where
238 C: Connection<TransactionManager = AnsiTransactionManager>,
239 C::Backend: Default,
240 <C::Backend as Backend>::QueryBuilder: Default,
241{
242 type TransactionStateData = AnsiTransactionManager;
243
244 fn begin_transaction(conn: &mut DTraceConnection<C>) -> QueryResult<()> {
245 let depth = Self::depth(conn);
271 probes::transaction__start!(|| (&conn.id, depth));
272 AnsiTransactionManager::begin_transaction(&mut conn.inner)
273 }
274
275 fn rollback_transaction(conn: &mut DTraceConnection<C>) -> QueryResult<()> {
276 let result = AnsiTransactionManager::rollback_transaction(&mut conn.inner);
277 let depth = Self::depth(conn);
278 probes::transaction__done!(|| (&conn.id, depth, 0));
279 result
280 }
281
282 fn commit_transaction(conn: &mut DTraceConnection<C>) -> QueryResult<()> {
283 let result = AnsiTransactionManager::commit_transaction(&mut conn.inner);
284 let depth = Self::depth(conn);
285 probes::transaction__done!(|| (&conn.id, depth, 1));
286 result
287 }
288
289 fn transaction_manager_status_mut(
290 conn: &mut DTraceConnection<C>,
291 ) -> &mut TransactionManagerStatus {
292 AnsiTransactionManager::transaction_manager_status_mut(&mut conn.inner)
293 }
294}