diesel/mysql_like/connection/
mod.rs1mod bind;
2mod raw;
3mod stmt;
4mod url;
5
6use core::num::NonZeroU64;
7
8use self::raw::RawConnection;
9use self::stmt::Statement;
10use self::stmt::iterator::StatementIterator;
11use self::url::ConnectionOptions;
12use crate::RunQueryDsl;
13use crate::connection::instrumentation::{DebugQuery, DynInstrumentation, StrQueryHelper};
14use crate::connection::statement_cache::{MaybeCached, StatementCache};
15use crate::connection::*;
16use crate::expression::QueryMetadata;
17use crate::mysql_like::MysqlLikeBackend;
18use crate::query_builder::bind_collector::RawBytesBindCollector;
19use crate::query_builder::*;
20use crate::result::*;
21
22#[allow(missing_debug_implementations, missing_copy_implementations)]
23pub struct MysqlLikeConnection<DB: MysqlLikeBackend> {
112 raw_connection: RawConnection,
113 transaction_state: AnsiTransactionManager,
114 statement_cache: StatementCache<DB, Statement<DB>>,
115 instrumentation: DynInstrumentation,
116}
117
118#[allow(unsafe_code)]
120unsafe impl<DB: MysqlLikeBackend> Send for MysqlLikeConnection<DB> {}
121
122impl<DB: MysqlLikeBackend> SimpleConnection for MysqlLikeConnection<DB> {
123 fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
124 self.instrumentation
125 .on_connection_event(InstrumentationEvent::StartQuery {
126 query: &StrQueryHelper::new(query),
127 });
128 let r = self
129 .raw_connection
130 .enable_multi_statements(|| self.raw_connection.execute(query));
131 self.instrumentation
132 .on_connection_event(InstrumentationEvent::FinishQuery {
133 query: &StrQueryHelper::new(query),
134 error: r.as_ref().err(),
135 });
136 r
137 }
138}
139
140impl<DB: MysqlLikeBackend> ConnectionSealed for MysqlLikeConnection<DB> {}
141
142impl<DB: MysqlLikeBackend> Connection for MysqlLikeConnection<DB> {
143 type Backend = DB;
144 type TransactionManager = AnsiTransactionManager;
145
146 fn establish(database_url: &str) -> ConnectionResult<Self> {
161 let mut instrumentation = DynInstrumentation::default_instrumentation();
162 instrumentation.on_connection_event(InstrumentationEvent::StartEstablishConnection {
163 url: database_url,
164 });
165
166 let establish_result = Self::establish_inner(database_url);
167 instrumentation.on_connection_event(InstrumentationEvent::FinishEstablishConnection {
168 url: database_url,
169 error: establish_result.as_ref().err(),
170 });
171 let mut conn = establish_result?;
172 conn.instrumentation = instrumentation;
173 Ok(conn)
174 }
175
176 fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
177 where
178 T: QueryFragment<Self::Backend> + QueryId,
179 {
180 #[allow(unsafe_code)] update_transaction_manager_status(
182 prepared_query(
183 &source,
184 &mut self.statement_cache,
185 &mut self.raw_connection,
186 &mut *self.instrumentation,
187 )
188 .and_then(|stmt| {
189 let stmt_use = unsafe { stmt.execute() }?;
192 stmt_use.affected_rows()
193 }),
194 &mut self.transaction_state,
195 &mut self.instrumentation,
196 &crate::debug_query(source),
197 )
198 }
199
200 fn transaction_state(&mut self) -> &mut AnsiTransactionManager {
201 &mut self.transaction_state
202 }
203
204 fn instrumentation(&mut self) -> &mut dyn Instrumentation {
205 &mut *self.instrumentation
206 }
207
208 fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) {
209 self.instrumentation = instrumentation.into();
210 }
211
212 fn set_prepared_statement_cache_size(&mut self, size: CacheSize) {
213 self.statement_cache.set_cache_size(size);
214 }
215}
216
217#[inline(always)]
218fn update_transaction_manager_status<T>(
219 query_result: QueryResult<T>,
220 transaction_manager: &mut AnsiTransactionManager,
221 instrumentation: &mut DynInstrumentation,
222 query: &dyn DebugQuery,
223) -> QueryResult<T> {
224 fn non_generic_inner(
225 query_result: Result<(), &Error>,
226 transaction_manager: &mut AnsiTransactionManager,
227 instrumentation: &mut DynInstrumentation,
228 query: &dyn DebugQuery,
229 ) {
230 if let Err(Error::DatabaseError(DatabaseErrorKind::SerializationFailure, _)) = query_result
231 {
232 transaction_manager
233 .status
234 .set_requires_rollback_maybe_up_to_top_level(true)
235 }
236 instrumentation.on_connection_event(InstrumentationEvent::FinishQuery {
237 query,
238 error: query_result.err(),
239 });
240 }
241
242 non_generic_inner(
243 query_result.as_ref().map(|_| ()),
244 transaction_manager,
245 instrumentation,
246 query,
247 );
248 query_result
249}
250
251impl<DB: MysqlLikeBackend> LoadConnection<DefaultLoadingMode> for MysqlLikeConnection<DB> {
252 type Cursor<'conn, 'query> = self::stmt::iterator::StatementIterator<'conn, DB>;
253 type Row<'conn, 'query> = self::stmt::iterator::MysqlRow<DB>;
254
255 fn load<'conn, 'query, T>(
256 &'conn mut self,
257 source: T,
258 ) -> QueryResult<Self::Cursor<'conn, 'query>>
259 where
260 T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
261 Self::Backend: QueryMetadata<T::SqlType>,
262 {
263 update_transaction_manager_status(
264 prepared_query(
265 &source,
266 &mut self.statement_cache,
267 &mut self.raw_connection,
268 &mut *self.instrumentation,
269 )
270 .and_then(|stmt| {
271 let mut metadata = Vec::new();
272 DB::row_metadata(&mut (), &mut metadata);
273 StatementIterator::from_stmt(stmt, &metadata)
274 }),
275 &mut self.transaction_state,
276 &mut self.instrumentation,
277 &crate::debug_query(&source),
278 )
279 }
280}
281
282#[cfg(feature = "r2d2")]
283impl<DB: MysqlLikeBackend> crate::r2d2::R2D2Connection for MysqlLikeConnection<DB> {
284 fn ping(&mut self) -> QueryResult<()> {
285 crate::r2d2::CheckConnectionQuery.execute(self).map(|_| ())
286 }
287
288 fn is_broken(&mut self) -> bool {
289 AnsiTransactionManager::is_broken_transaction_manager(self)
290 }
291}
292
293impl<DB: MysqlLikeBackend> MultiConnectionHelper for MysqlLikeConnection<DB> {
294 fn to_any<'a>(
295 lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
296 ) -> &mut (dyn core::any::Any + 'a) {
297 lookup
298 }
299
300 fn from_any(
301 lookup: &mut dyn core::any::Any,
302 ) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup> {
303 lookup.downcast_mut()
304 }
305}
306
307fn prepared_query<'a, DB: MysqlLikeBackend + Default, T: QueryFragment<DB> + QueryId>(
308 source: &'_ T,
309 statement_cache: &'a mut StatementCache<DB, Statement<DB>>,
310 raw_connection: &'a mut RawConnection,
311 instrumentation: &mut dyn Instrumentation,
312) -> QueryResult<MaybeCached<'a, Statement<DB>>> {
313 instrumentation.on_connection_event(InstrumentationEvent::StartQuery {
314 query: &crate::debug_query(source),
315 });
316 let mut stmt = statement_cache.cached_statement(
317 source,
318 &DB::default(),
319 &[],
320 &*raw_connection,
321 RawConnection::prepare,
322 instrumentation,
323 )?;
324
325 let mut bind_collector = RawBytesBindCollector::new();
326 source.collect_binds(&mut bind_collector, &mut (), &DB::default())?;
327 let binds = bind_collector
328 .metadata
329 .into_iter()
330 .zip(bind_collector.binds);
331 stmt.bind(binds)?;
332 Ok(stmt)
333}
334
335impl<DB: MysqlLikeBackend> MysqlLikeConnection<DB> {
336 pub(crate) fn execute_returning_id<T>(&mut self, source: &T) -> QueryResult<Option<NonZeroU64>>
339 where
340 T: QueryFragment<DB> + QueryId,
341 {
342 #[allow(unsafe_code)] update_transaction_manager_status(
344 prepared_query(
345 &source,
346 &mut self.statement_cache,
347 &mut self.raw_connection,
348 &mut *self.instrumentation,
349 )
350 .and_then(|stmt| {
351 let stmt_use = unsafe { stmt.execute() }?;
355 Ok(NonZeroU64::new(stmt_use.insert_id()))
356 }),
357 &mut self.transaction_state,
358 &mut self.instrumentation,
359 &crate::debug_query(source),
360 )
361 }
362
363 fn set_config_options(&mut self) -> QueryResult<()> {
364 crate::sql_query("SET time_zone = '+00:00';").execute(self)?;
365 crate::sql_query("SET character_set_client = 'utf8mb4'").execute(self)?;
366 crate::sql_query("SET character_set_connection = 'utf8mb4'").execute(self)?;
367 crate::sql_query("SET character_set_results = 'utf8mb4'").execute(self)?;
368 Ok(())
369 }
370
371 fn establish_inner(database_url: &str) -> Result<MysqlLikeConnection<DB>, ConnectionError> {
372 use crate::ConnectionError::CouldntSetupConfiguration;
373
374 let raw_connection = RawConnection::new();
375 let connection_options = ConnectionOptions::parse::<DB>(database_url)?;
376 raw_connection.connect(&connection_options)?;
377 let mut conn = MysqlLikeConnection {
378 raw_connection,
379 transaction_state: AnsiTransactionManager::default(),
380 statement_cache: StatementCache::new(),
381 instrumentation: DynInstrumentation::none(),
382 };
383 conn.set_config_options()
384 .map_err(CouldntSetupConfiguration)?;
385 Ok(conn)
386 }
387}