1use futures_util::FutureExt;
10use mysql_common::{
11 constants::{MariadbCapabilities, MAX_PAYLOAD_LEN},
12 io::ParseBuf,
13 proto::{Binary, Text},
14 row::RowDeserializer,
15 value::ServerSide,
16};
17
18use std::{fmt, sync::Arc};
19
20use self::{
21 query_result::QueryResult,
22 stmt::Statement,
23 transaction::{Transaction, TxStatus},
24};
25
26use crate::{
27 conn::routines::{PingRoutine, QueryRoutine},
28 consts::CapabilityFlags,
29 error::*,
30 prelude::{FromRow, StatementLike},
31 query::AsQuery,
32 queryable::query_result::ResultSetMeta,
33 tracing_utils::{LevelInfo, LevelTrace, TracingLevel},
34 BoxFuture, Column, Conn, Connection, Params, ResultSetStream, Row,
35};
36
37pub mod query_result;
38pub mod stmt;
39pub mod transaction;
40
41pub trait Protocol: fmt::Debug + Send + Sync + 'static {
42 fn result_set_meta(columns: Arc<[Column]>) -> ResultSetMeta;
44 fn read_result_set_row(packet: &[u8], columns: Arc<[Column]>) -> Result<Row>;
45 fn is_last_result_set_packet(capabilities: CapabilityFlags, packet: &[u8]) -> bool {
46 if capabilities.contains(CapabilityFlags::CLIENT_DEPRECATE_EOF) {
47 packet[0] == 0xFE && packet.len() < MAX_PAYLOAD_LEN
48 } else {
49 packet[0] == 0xFE && packet.len() < 8
50 }
51 }
52 fn metadata_skip_possible(conn: &Conn) -> bool;
53}
54
55#[derive(Debug)]
57pub struct TextProtocol;
58
59#[derive(Debug)]
61pub struct BinaryProtocol;
62
63impl Protocol for TextProtocol {
64 fn result_set_meta(columns: Arc<[Column]>) -> ResultSetMeta {
65 ResultSetMeta::Text(columns)
66 }
67
68 fn read_result_set_row(packet: &[u8], columns: Arc<[Column]>) -> Result<Row> {
69 ParseBuf(packet)
70 .parse::<RowDeserializer<ServerSide, Text>>(columns)
71 .map(Into::into)
72 .map_err(Into::into)
73 }
74
75 fn metadata_skip_possible(_conn: &Conn) -> bool {
76 false
77 }
78}
79
80impl Protocol for BinaryProtocol {
81 fn result_set_meta(columns: Arc<[Column]>) -> ResultSetMeta {
82 ResultSetMeta::Binary(columns)
83 }
84
85 fn read_result_set_row(packet: &[u8], columns: Arc<[Column]>) -> Result<Row> {
86 ParseBuf(packet)
87 .parse::<RowDeserializer<ServerSide, Binary>>(columns)
88 .map(Into::into)
89 .map_err(Into::into)
90 }
91
92 fn metadata_skip_possible(conn: &Conn) -> bool {
93 conn.has_mariadb_capabilities(MariadbCapabilities::MARIADB_CLIENT_CACHE_METADATA)
94 }
95}
96
97impl Conn {
98 pub(crate) async fn clean_dirty(&mut self) -> Result<()> {
106 self.drop_result().await?;
107 if self.get_tx_status() == TxStatus::RequiresRollback {
108 self.rollback_transaction().await?;
109 }
110 Ok(())
111 }
112
113 pub(crate) async fn raw_query<'a, Q, L: TracingLevel>(&'a mut self, query: Q) -> Result<()>
115 where
116 Q: AsQuery + 'a,
117 {
118 self.routine(QueryRoutine::<'_, L>::new(query.as_query().as_ref()))
119 .await
120 }
121
122 pub(crate) fn query_internal<'a, T, Q>(&'a mut self, query: Q) -> BoxFuture<'a, Option<T>>
127 where
128 Q: AsQuery + 'a,
129 T: FromRow + Send + 'static,
130 {
131 async move {
132 self.raw_query::<'_, _, LevelTrace>(query).await?;
133 Ok(QueryResult::<'_, '_, TextProtocol>::new(self)
134 .collect_and_drop::<T>()
135 .await?
136 .pop())
137 }
138 .boxed()
139 }
140}
141
142pub trait Queryable: Send {
146 fn ping(&mut self) -> BoxFuture<'_, ()>;
148
149 fn query_iter<'a, Q>(
151 &'a mut self,
152 query: Q,
153 ) -> BoxFuture<'a, QueryResult<'a, 'static, TextProtocol>>
154 where
155 Q: AsQuery + 'a;
156
157 fn prep<'a, Q>(&'a mut self, query: Q) -> BoxFuture<'a, Statement>
166 where
167 Q: AsQuery + 'a;
168
169 fn close(&mut self, stmt: Statement) -> BoxFuture<'_, ()>;
176
177 fn exec_iter<'a: 's, 's, Q, P>(
181 &'a mut self,
182 stmt: Q,
183 params: P,
184 ) -> BoxFuture<'s, QueryResult<'a, 'static, BinaryProtocol>>
185 where
186 Q: StatementLike + 's,
187 P: Into<Params>;
188
189 fn query<'a, T, Q>(&'a mut self, query: Q) -> BoxFuture<'a, Vec<T>>
197 where
198 Q: AsQuery + 'a,
199 T: FromRow + Send + 'static,
200 {
201 async move { self.query_iter(query).await?.collect_and_drop::<T>().await }.boxed()
202 }
203
204 fn query_first<'a, T, Q>(&'a mut self, query: Q) -> BoxFuture<'a, Option<T>>
212 where
213 Q: AsQuery + 'a,
214 T: FromRow + Send + 'static,
215 {
216 async move {
217 let mut result = self.query_iter(query).await?;
218 let output = if result.is_empty() {
219 None
220 } else {
221 result.next().await?.map(crate::from_row)
222 };
223 result.drop_result().await?;
224 Ok(output)
225 }
226 .boxed()
227 }
228
229 fn query_map<'a, T, F, Q, U>(&'a mut self, query: Q, mut f: F) -> BoxFuture<'a, Vec<U>>
237 where
238 Q: AsQuery + 'a,
239 T: FromRow + Send + 'static,
240 F: FnMut(T) -> U + Send + 'a,
241 U: Send,
242 {
243 async move {
244 self.query_fold(query, Vec::new(), |mut acc, row| {
245 acc.push(f(crate::from_row(row)));
246 acc
247 })
248 .await
249 }
250 .boxed()
251 }
252
253 fn query_fold<'a, T, F, Q, U>(&'a mut self, query: Q, init: U, mut f: F) -> BoxFuture<'a, U>
261 where
262 Q: AsQuery + 'a,
263 T: FromRow + Send + 'static,
264 F: FnMut(U, T) -> U + Send + 'a,
265 U: Send + 'a,
266 {
267 async move {
268 self.query_iter(query)
269 .await?
270 .reduce_and_drop(init, |acc, row| f(acc, crate::from_row(row)))
271 .await
272 }
273 .boxed()
274 }
275
276 fn query_drop<'a, Q>(&'a mut self, query: Q) -> BoxFuture<'a, ()>
278 where
279 Q: AsQuery + 'a,
280 {
281 async move { self.query_iter(query).await?.drop_result().await }.boxed()
282 }
283
284 fn exec_batch<'a: 'b, 'b, S, P, I>(&'a mut self, stmt: S, params_iter: I) -> BoxFuture<'b, ()>
297 where
298 S: StatementLike + 'b,
299 I: IntoIterator<Item = P> + Send + 'b,
300 I::IntoIter: Send,
301 P: Into<Params> + Send;
302
303 fn exec<'a: 'b, 'b, T, S, P>(&'a mut self, stmt: S, params: P) -> BoxFuture<'b, Vec<T>>
313 where
314 S: StatementLike + 'b,
315 P: Into<Params> + Send + 'b,
316 T: FromRow + Send + 'static,
317 {
318 async move {
319 self.exec_iter(stmt, params)
320 .await?
321 .collect_and_drop::<T>()
322 .await
323 }
324 .boxed()
325 }
326
327 fn exec_first<'a: 'b, 'b, T, S, P>(&'a mut self, stmt: S, params: P) -> BoxFuture<'b, Option<T>>
337 where
338 S: StatementLike + 'b,
339 P: Into<Params> + Send + 'b,
340 T: FromRow + Send + 'static,
341 {
342 async move {
343 let mut result = self.exec_iter(stmt, params).await?;
344 let row = if result.is_empty() {
345 None
346 } else {
347 result.next().await?
348 };
349 result.drop_result().await?;
350 Ok(row.map(crate::from_row))
351 }
352 .boxed()
353 }
354
355 fn exec_map<'a: 'b, 'b, T, S, P, U, F>(
365 &'a mut self,
366 stmt: S,
367 params: P,
368 mut f: F,
369 ) -> BoxFuture<'b, Vec<U>>
370 where
371 S: StatementLike + 'b,
372 P: Into<Params> + Send + 'b,
373 T: FromRow + Send + 'static,
374 F: FnMut(T) -> U + Send + 'a,
375 U: Send + 'a,
376 {
377 async move {
378 self.exec_fold(stmt, params, Vec::new(), |mut acc, row| {
379 acc.push(f(crate::from_row(row)));
380 acc
381 })
382 .await
383 }
384 .boxed()
385 }
386
387 fn exec_fold<'a: 'b, 'b, T, S, P, U, F>(
397 &'a mut self,
398 stmt: S,
399 params: P,
400 init: U,
401 mut f: F,
402 ) -> BoxFuture<'b, U>
403 where
404 S: StatementLike + 'b,
405 P: Into<Params> + Send + 'b,
406 T: FromRow + Send + 'static,
407 F: FnMut(U, T) -> U + Send + 'a,
408 U: Send + 'a,
409 {
410 async move {
411 self.exec_iter(stmt, params)
412 .await?
413 .reduce_and_drop(init, |acc, row| f(acc, crate::from_row(row)))
414 .await
415 }
416 .boxed()
417 }
418
419 fn exec_drop<'a: 'b, 'b, S, P>(&'a mut self, stmt: S, params: P) -> BoxFuture<'b, ()>
421 where
422 S: StatementLike + 'b,
423 P: Into<Params> + Send + 'b,
424 {
425 async move { self.exec_iter(stmt, params).await?.drop_result().await }.boxed()
426 }
427
428 fn query_stream<'a, T, Q>(
434 &'a mut self,
435 query: Q,
436 ) -> BoxFuture<'a, ResultSetStream<'a, 'a, 'static, T, TextProtocol>>
437 where
438 T: Unpin + FromRow + Send + 'static,
439 Q: AsQuery + 'a,
440 {
441 async move {
442 self.query_iter(query)
443 .await?
444 .stream_and_drop()
445 .await
446 .transpose()
447 .expect("At least one result set is expected")
448 }
449 .boxed()
450 }
451
452 fn exec_stream<'a: 's, 's, T, Q, P>(
458 &'a mut self,
459 stmt: Q,
460 params: P,
461 ) -> BoxFuture<'s, ResultSetStream<'a, 'a, 'static, T, BinaryProtocol>>
462 where
463 T: Unpin + FromRow + Send + 'static,
464 Q: StatementLike + 's,
465 P: Into<Params> + Send + 's,
466 {
467 async move {
468 self.exec_iter(stmt, params)
469 .await?
470 .stream_and_drop()
471 .await
472 .transpose()
473 .expect("At least one result set is expected")
474 }
475 .boxed()
476 }
477}
478
479impl Queryable for Conn {
480 fn ping(&mut self) -> BoxFuture<'_, ()> {
481 async move {
482 self.routine(PingRoutine).await?;
483 Ok(())
484 }
485 .boxed()
486 }
487
488 fn query_iter<'a, Q>(
489 &'a mut self,
490 query: Q,
491 ) -> BoxFuture<'a, QueryResult<'a, 'static, TextProtocol>>
492 where
493 Q: AsQuery + 'a,
494 {
495 async move {
496 self.raw_query::<'_, _, LevelInfo>(query).await?;
497 Ok(QueryResult::new(self))
498 }
499 .boxed()
500 }
501
502 fn prep<'a, Q>(&'a mut self, query: Q) -> BoxFuture<'a, Statement>
503 where
504 Q: AsQuery + 'a,
505 {
506 async move { self.get_statement(query.as_query()).await }.boxed()
507 }
508
509 fn close(&mut self, stmt: Statement) -> BoxFuture<'_, ()> {
510 async move {
511 self.stmt_cache_mut().remove(stmt.id());
512 self.close_statement(stmt.id()).await
513 }
514 .boxed()
515 }
516
517 fn exec_iter<'a: 's, 's, Q, P>(
518 &'a mut self,
519 stmt: Q,
520 params: P,
521 ) -> BoxFuture<'s, QueryResult<'a, 'static, BinaryProtocol>>
522 where
523 Q: StatementLike + 's,
524 P: Into<Params>,
525 {
526 let params = params.into();
527 async move {
528 let statement = self.get_statement(stmt).await?;
529 self.execute_statement(&statement, params).await?;
530 Ok(QueryResult::new(self))
531 }
532 .boxed()
533 }
534
535 fn exec_batch<'a: 'b, 'b, S, P, I>(&'a mut self, stmt: S, params_iter: I) -> BoxFuture<'b, ()>
536 where
537 S: StatementLike + 'b,
538 I: IntoIterator<Item = P> + Send + 'b,
539 I::IntoIter: Send,
540 P: Into<Params> + Send,
541 {
542 async move {
543 let statement = self.get_statement(stmt).await?;
544 if self
545 .has_mariadb_capabilities(MariadbCapabilities::MARIADB_CLIENT_STMT_BULK_OPERATIONS)
546 && statement.num_params() > 0
547 {
548 self.execute_bulk(&statement, params_iter).await?;
549 } else {
550 for params in params_iter {
551 self.execute_statement(&statement, params).await?;
552 QueryResult::<BinaryProtocol>::new(&mut *self)
553 .drop_result()
554 .await?;
555 }
556 }
557 Ok(())
558 }
559 .boxed()
560 }
561}
562
563impl Queryable for Transaction<'_> {
564 fn ping(&mut self) -> BoxFuture<'_, ()> {
565 self.0.as_mut().ping()
566 }
567
568 fn query_iter<'a, Q>(
569 &'a mut self,
570 query: Q,
571 ) -> BoxFuture<'a, QueryResult<'a, 'static, TextProtocol>>
572 where
573 Q: AsQuery + 'a,
574 {
575 self.0.as_mut().query_iter(query)
576 }
577
578 fn prep<'a, Q>(&'a mut self, query: Q) -> BoxFuture<'a, Statement>
579 where
580 Q: AsQuery + 'a,
581 {
582 self.0.as_mut().prep(query)
583 }
584
585 fn close(&mut self, stmt: Statement) -> BoxFuture<'_, ()> {
586 self.0.as_mut().close(stmt)
587 }
588
589 fn exec_iter<'a: 's, 's, Q, P>(
590 &'a mut self,
591 stmt: Q,
592 params: P,
593 ) -> BoxFuture<'s, QueryResult<'a, 'static, BinaryProtocol>>
594 where
595 Q: StatementLike + 's,
596 P: Into<Params>,
597 {
598 self.0.as_mut().exec_iter(stmt, params)
599 }
600
601 fn exec_batch<'a: 'b, 'b, S, P, I>(&'a mut self, stmt: S, params_iter: I) -> BoxFuture<'b, ()>
602 where
603 S: StatementLike + 'b,
604 I: IntoIterator<Item = P> + Send + 'b,
605 I::IntoIter: Send,
606 P: Into<Params> + Send,
607 {
608 self.0.as_mut().exec_batch(stmt, params_iter)
609 }
610}
611
612impl<'c, 't: 'c> Queryable for Connection<'c, 't> {
613 #[inline]
614 fn ping(&mut self) -> BoxFuture<'_, ()> {
615 self.as_mut().ping()
616 }
617
618 #[inline]
619 fn query_iter<'a, Q>(
620 &'a mut self,
621 query: Q,
622 ) -> BoxFuture<'a, QueryResult<'a, 'static, TextProtocol>>
623 where
624 Q: AsQuery + 'a,
625 {
626 self.as_mut().query_iter(query)
627 }
628
629 fn prep<'a, Q>(&'a mut self, query: Q) -> BoxFuture<'a, Statement>
630 where
631 Q: AsQuery + 'a,
632 {
633 self.as_mut().prep(query)
634 }
635
636 fn close(&mut self, stmt: Statement) -> BoxFuture<'_, ()> {
637 self.as_mut().close(stmt)
638 }
639
640 fn exec_iter<'a: 's, 's, Q, P>(
641 &'a mut self,
642 stmt: Q,
643 params: P,
644 ) -> BoxFuture<'s, QueryResult<'a, 'static, BinaryProtocol>>
645 where
646 Q: StatementLike + 's,
647 P: Into<Params>,
648 {
649 self.as_mut().exec_iter(stmt, params)
650 }
651
652 fn exec_batch<'a: 'b, 'b, S, P, I>(&'a mut self, stmt: S, params_iter: I) -> BoxFuture<'b, ()>
653 where
654 S: StatementLike + 'b,
655 I: IntoIterator<Item = P> + Send + 'b,
656 I::IntoIter: Send,
657 P: Into<Params> + Send,
658 {
659 self.as_mut().exec_batch(stmt, params_iter)
660 }
661}
662
663#[cfg(test)]
664mod tests {
665 use crate::{prelude::*, test_misc::get_opts, Conn};
666
667 #[tokio::test]
668 async fn should_prep() {
669 const NAMED: &str = "SELECT :foo, :bar, :foo";
670 const POSITIONAL: &str = "SELECT ?, ?, ?";
671
672 let mut conn = Conn::new(get_opts()).await.unwrap();
673
674 let stmt_named = conn.prep(NAMED).await.unwrap();
675 let stmt_positional = conn.prep(POSITIONAL).await.unwrap();
676
677 let result_stmt_named: Option<(String, u8, String)> = conn
678 .exec_first(&stmt_named, params! { "foo" => "bar", "bar" => 42 })
679 .await
680 .unwrap();
681 let result_str_named: Option<(String, u8, String)> = conn
682 .exec_first(NAMED, params! { "foo" => "bar", "bar" => 42 })
683 .await
684 .unwrap();
685
686 let result_stmt_positional: Option<(String, u8, String)> = conn
687 .exec_first(&stmt_positional, ("bar", 42, "bar"))
688 .await
689 .unwrap();
690 let result_str_positional: Option<(String, u8, String)> = conn
691 .exec_first(NAMED, params! { "foo" => "bar", "bar" => 42 })
692 .await
693 .unwrap();
694
695 assert_eq!(
696 Some(("bar".to_owned(), 42_u8, "bar".to_owned())),
697 result_stmt_named
698 );
699 assert_eq!(result_stmt_named, result_str_named);
700 assert_eq!(result_str_named, result_stmt_positional);
701 assert_eq!(result_stmt_positional, result_str_positional);
702
703 conn.disconnect().await.unwrap();
704 }
705}