1#![allow(clippy::manual_async_fn)]
8#![allow(clippy::result_large_err)]
10
11use std::collections::HashMap;
12use std::future::Future;
13use std::io::{self, Read as StdRead, Write as StdWrite};
14use std::net::TcpStream as StdTcpStream;
15use std::sync::Arc;
16
17use asupersync::io::{AsyncRead, AsyncWrite, ReadBuf};
18use asupersync::net::TcpStream;
19use asupersync::sync::{Mutex, OwnedMutexGuard};
20use asupersync::{Cx, Outcome};
21
22use sqlmodel_core::connection::{Connection, IsolationLevel, PreparedStatement, TransactionOps};
23use sqlmodel_core::error::{
24 ConnectionError, ConnectionErrorKind, ProtocolError, QueryError, QueryErrorKind,
25};
26use sqlmodel_core::{Error, Row, Value};
27
28#[cfg(feature = "console")]
29use sqlmodel_console::{ConsoleAware, SqlModelConsole};
30
31use crate::auth;
32use crate::config::MySqlConfig;
33use crate::connection::{ConnectionState, ServerCapabilities};
34use crate::protocol::{
35 Command, ErrPacket, MAX_PACKET_SIZE, PacketHeader, PacketReader, PacketType, PacketWriter,
36 capabilities, charset, prepared,
37};
38use crate::types::{
39 ColumnDef, FieldType, decode_binary_value_with_len, decode_text_value, interpolate_params,
40};
41
42pub struct MySqlAsyncConnection {
47 stream: Option<ConnectionStream>,
49 state: ConnectionState,
51 server_caps: Option<ServerCapabilities>,
53 connection_id: u32,
55 status_flags: u16,
57 affected_rows: u64,
59 last_insert_id: u64,
61 warnings: u16,
63 config: MySqlConfig,
65 sequence_id: u8,
67 prepared_stmts: HashMap<u32, PreparedStmtMeta>,
69 #[cfg(feature = "console")]
71 console: Option<Arc<SqlModelConsole>>,
72}
73
74#[derive(Debug, Clone)]
79struct PreparedStmtMeta {
80 #[allow(dead_code)]
82 statement_id: u32,
83 params: Vec<ColumnDef>,
85 columns: Vec<ColumnDef>,
87}
88
89#[allow(dead_code, clippy::large_enum_variant)]
93enum ConnectionStream {
94 Sync(StdTcpStream),
96 Async(TcpStream),
98 #[cfg(feature = "tls")]
100 Tls(AsyncTlsStream),
101}
102
103#[cfg(feature = "tls")]
108struct AsyncTlsStream {
109 tcp: TcpStream,
110 tls: rustls::ClientConnection,
111}
112
113#[cfg(feature = "tls")]
114impl std::fmt::Debug for AsyncTlsStream {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 f.debug_struct("AsyncTlsStream")
117 .field("protocol_version", &self.tls.protocol_version())
118 .field("is_handshaking", &self.tls.is_handshaking())
119 .finish_non_exhaustive()
120 }
121}
122
123#[cfg(feature = "tls")]
124impl AsyncTlsStream {
125 async fn handshake(
126 mut tcp: TcpStream,
127 tls_config: &crate::config::TlsConfig,
128 host: &str,
129 ssl_mode: crate::config::SslMode,
130 ) -> Result<Self, Error> {
131 let config = crate::tls::build_client_config(tls_config, ssl_mode)?;
132
133 let sni = tls_config.server_name.as_deref().unwrap_or(host);
134 let server_name = sni
135 .to_string()
136 .try_into()
137 .map_err(|e| connection_error(format!("Invalid server name '{sni}': {e}")))?;
138
139 let mut tls = rustls::ClientConnection::new(std::sync::Arc::new(config), server_name)
140 .map_err(|e| connection_error(format!("Failed to create TLS connection: {e}")))?;
141
142 while tls.is_handshaking() {
144 while tls.wants_write() {
145 let mut out = Vec::new();
146 tls.write_tls(&mut out)
147 .map_err(|e| connection_error(format!("TLS handshake write_tls error: {e}")))?;
148 if !out.is_empty() {
149 write_all_async(&mut tcp, &out).await.map_err(|e| {
150 Error::Connection(ConnectionError {
151 kind: ConnectionErrorKind::Disconnected,
152 message: format!("TLS handshake write error: {e}"),
153 source: Some(Box::new(e)),
154 })
155 })?;
156 }
157 }
158
159 if tls.wants_read() {
160 let mut buf = [0u8; 8192];
161 let n = read_some_async(&mut tcp, &mut buf).await.map_err(|e| {
162 Error::Connection(ConnectionError {
163 kind: ConnectionErrorKind::Disconnected,
164 message: format!("TLS handshake read error: {e}"),
165 source: Some(Box::new(e)),
166 })
167 })?;
168 if n == 0 {
169 return Err(connection_error("Connection closed during TLS handshake"));
170 }
171
172 let mut cursor = std::io::Cursor::new(&buf[..n]);
173 tls.read_tls(&mut cursor)
174 .map_err(|e| connection_error(format!("TLS handshake read_tls error: {e}")))?;
175 tls.process_new_packets()
176 .map_err(|e| connection_error(format!("TLS handshake error: {e}")))?;
177 }
178 }
179
180 Ok(Self { tcp, tls })
181 }
182
183 async fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
184 let mut read = 0;
185 while read < buf.len() {
186 let n = self.read_plain(&mut buf[read..]).await?;
187 if n == 0 {
188 return Err(io::Error::new(
189 io::ErrorKind::UnexpectedEof,
190 "connection closed",
191 ));
192 }
193 read += n;
194 }
195 Ok(())
196 }
197
198 async fn read_plain(&mut self, out: &mut [u8]) -> io::Result<usize> {
199 loop {
200 match self.tls.reader().read(out) {
201 Ok(n) if n > 0 => return Ok(n),
202 Ok(_) => {}
203 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {}
204 Err(e) => return Err(e),
205 }
206
207 if !self.tls.wants_read() {
208 return Ok(0);
209 }
210
211 let mut enc = [0u8; 8192];
212 let n = read_some_async(&mut self.tcp, &mut enc).await?;
213 if n == 0 {
214 return Ok(0);
215 }
216
217 let mut cursor = std::io::Cursor::new(&enc[..n]);
218 self.tls.read_tls(&mut cursor)?;
219 self.tls
220 .process_new_packets()
221 .map_err(|e| io::Error::other(format!("TLS error: {e}")))?;
222 }
223 }
224
225 async fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
226 let mut written = 0;
227 while written < buf.len() {
228 let n = self.tls.writer().write(&buf[written..])?;
229 if n == 0 {
230 return Err(io::Error::new(io::ErrorKind::WriteZero, "TLS write zero"));
231 }
232 written += n;
233 self.flush().await?;
234 }
235 Ok(())
236 }
237
238 async fn flush(&mut self) -> io::Result<()> {
239 self.tls.writer().flush()?;
240 while self.tls.wants_write() {
241 let mut out = Vec::new();
242 self.tls.write_tls(&mut out)?;
243 if !out.is_empty() {
244 write_all_async(&mut self.tcp, &out).await?;
245 }
246 }
247 flush_async(&mut self.tcp).await
248 }
249}
250
251#[cfg(feature = "tls")]
252async fn read_some_async(stream: &mut TcpStream, buf: &mut [u8]) -> io::Result<usize> {
253 let mut read_buf = ReadBuf::new(buf);
254 std::future::poll_fn(|cx| std::pin::Pin::new(&mut *stream).poll_read(cx, &mut read_buf))
255 .await?;
256 Ok(read_buf.filled().len())
257}
258
259#[cfg(feature = "tls")]
260async fn write_all_async(stream: &mut TcpStream, buf: &[u8]) -> io::Result<()> {
261 let mut written = 0;
262 while written < buf.len() {
263 let n = std::future::poll_fn(|cx| {
264 std::pin::Pin::new(&mut *stream).poll_write(cx, &buf[written..])
265 })
266 .await?;
267 if n == 0 {
268 return Err(io::Error::new(
269 io::ErrorKind::WriteZero,
270 "connection closed",
271 ));
272 }
273 written += n;
274 }
275 Ok(())
276}
277
278#[cfg(feature = "tls")]
279async fn flush_async(stream: &mut TcpStream) -> io::Result<()> {
280 std::future::poll_fn(|cx| std::pin::Pin::new(&mut *stream).poll_flush(cx)).await
281}
282
283impl std::fmt::Debug for MySqlAsyncConnection {
284 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285 f.debug_struct("MySqlAsyncConnection")
286 .field("state", &self.state)
287 .field("connection_id", &self.connection_id)
288 .field("host", &self.config.host)
289 .field("port", &self.config.port)
290 .field("database", &self.config.database)
291 .finish_non_exhaustive()
292 }
293}
294
295impl MySqlAsyncConnection {
296 pub async fn connect(_cx: &Cx, config: MySqlConfig) -> Outcome<Self, Error> {
304 let addr = config.socket_addr();
306 let socket_addr: std::net::SocketAddr = match addr.parse() {
307 Ok(a) => a,
308 Err(e) => {
309 return Outcome::Err(Error::Connection(ConnectionError {
310 kind: ConnectionErrorKind::Connect,
311 message: format!("Invalid socket address: {}", e),
312 source: None,
313 }));
314 }
315 };
316 let stream = match TcpStream::connect_timeout(socket_addr, config.connect_timeout).await {
317 Ok(s) => s,
318 Err(e) => {
319 let kind = if e.kind() == io::ErrorKind::ConnectionRefused {
320 ConnectionErrorKind::Refused
321 } else {
322 ConnectionErrorKind::Connect
323 };
324 return Outcome::Err(Error::Connection(ConnectionError {
325 kind,
326 message: format!("Failed to connect to {}: {}", addr, e),
327 source: Some(Box::new(e)),
328 }));
329 }
330 };
331
332 stream.set_nodelay(true).ok();
334
335 let mut conn = Self {
336 stream: Some(ConnectionStream::Async(stream)),
337 state: ConnectionState::Connecting,
338 server_caps: None,
339 connection_id: 0,
340 status_flags: 0,
341 affected_rows: 0,
342 last_insert_id: 0,
343 warnings: 0,
344 config,
345 sequence_id: 0,
346 prepared_stmts: HashMap::new(),
347 #[cfg(feature = "console")]
348 console: None,
349 };
350
351 match conn.read_handshake_async().await {
353 Outcome::Ok(server_caps) => {
354 conn.connection_id = server_caps.connection_id;
355 conn.server_caps = Some(server_caps);
356 conn.state = ConnectionState::Authenticating;
357 }
358 Outcome::Err(e) => return Outcome::Err(e),
359 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
360 Outcome::Panicked(p) => return Outcome::Panicked(p),
361 }
362
363 if let Outcome::Err(e) = conn.send_handshake_response_async().await {
365 return Outcome::Err(e);
366 }
367
368 if let Outcome::Err(e) = conn.handle_auth_result_async().await {
370 return Outcome::Err(e);
371 }
372
373 conn.state = ConnectionState::Ready;
374 Outcome::Ok(conn)
375 }
376
377 pub fn state(&self) -> ConnectionState {
379 self.state
380 }
381
382 pub fn is_ready(&self) -> bool {
384 matches!(self.state, ConnectionState::Ready)
385 }
386
387 fn is_secure_transport(&self) -> bool {
388 #[cfg(feature = "tls")]
389 {
390 matches!(self.stream, Some(ConnectionStream::Tls(_)))
391 }
392 #[cfg(not(feature = "tls"))]
393 {
394 false
395 }
396 }
397
398 pub fn connection_id(&self) -> u32 {
400 self.connection_id
401 }
402
403 pub fn server_version(&self) -> Option<&str> {
405 self.server_caps
406 .as_ref()
407 .map(|caps| caps.server_version.as_str())
408 }
409
410 pub fn affected_rows(&self) -> u64 {
412 self.affected_rows
413 }
414
415 pub fn last_insert_id(&self) -> u64 {
417 self.last_insert_id
418 }
419
420 async fn read_packet_async(&mut self) -> Outcome<(Vec<u8>, u8), Error> {
424 let mut header_buf = [0u8; 4];
426
427 let Some(stream) = self.stream.as_mut() else {
428 return Outcome::Err(connection_error("Connection stream missing"));
429 };
430
431 match stream {
432 ConnectionStream::Async(stream) => {
433 let mut header_read = 0;
434 while header_read < 4 {
435 let mut read_buf = ReadBuf::new(&mut header_buf[header_read..]);
436 match std::future::poll_fn(|cx| {
437 std::pin::Pin::new(&mut *stream).poll_read(cx, &mut read_buf)
438 })
439 .await
440 {
441 Ok(()) => {
442 let n = read_buf.filled().len();
443 if n == 0 {
444 return Outcome::Err(Error::Connection(ConnectionError {
445 kind: ConnectionErrorKind::Disconnected,
446 message: "Connection closed while reading header".to_string(),
447 source: None,
448 }));
449 }
450 header_read += n;
451 }
452 Err(e) => {
453 return Outcome::Err(Error::Connection(ConnectionError {
454 kind: ConnectionErrorKind::Disconnected,
455 message: format!("Failed to read packet header: {}", e),
456 source: Some(Box::new(e)),
457 }));
458 }
459 }
460 }
461 }
462 ConnectionStream::Sync(stream) => {
463 if let Err(e) = stream.read_exact(&mut header_buf) {
464 return Outcome::Err(Error::Connection(ConnectionError {
465 kind: ConnectionErrorKind::Disconnected,
466 message: format!("Failed to read packet header: {}", e),
467 source: Some(Box::new(e)),
468 }));
469 }
470 }
471 #[cfg(feature = "tls")]
472 ConnectionStream::Tls(stream) => {
473 if let Err(e) = stream.read_exact(&mut header_buf).await {
474 return Outcome::Err(Error::Connection(ConnectionError {
475 kind: ConnectionErrorKind::Disconnected,
476 message: format!("Failed to read packet header: {e}"),
477 source: Some(Box::new(e)),
478 }));
479 }
480 }
481 }
482
483 let header = PacketHeader::from_bytes(&header_buf);
484 let payload_len = header.payload_length as usize;
485 self.sequence_id = header.sequence_id.wrapping_add(1);
486
487 let mut payload = vec![0u8; payload_len];
489 if payload_len > 0 {
490 let Some(stream) = self.stream.as_mut() else {
491 return Outcome::Err(connection_error("Connection stream missing"));
492 };
493 match stream {
494 ConnectionStream::Async(stream) => {
495 let mut total_read = 0;
496 while total_read < payload_len {
497 let mut read_buf = ReadBuf::new(&mut payload[total_read..]);
498 match std::future::poll_fn(|cx| {
499 std::pin::Pin::new(&mut *stream).poll_read(cx, &mut read_buf)
500 })
501 .await
502 {
503 Ok(()) => {
504 let n = read_buf.filled().len();
505 if n == 0 {
506 return Outcome::Err(Error::Connection(ConnectionError {
507 kind: ConnectionErrorKind::Disconnected,
508 message: "Connection closed while reading payload"
509 .to_string(),
510 source: None,
511 }));
512 }
513 total_read += n;
514 }
515 Err(e) => {
516 return Outcome::Err(Error::Connection(ConnectionError {
517 kind: ConnectionErrorKind::Disconnected,
518 message: format!("Failed to read packet payload: {}", e),
519 source: Some(Box::new(e)),
520 }));
521 }
522 }
523 }
524 }
525 ConnectionStream::Sync(stream) => {
526 if let Err(e) = stream.read_exact(&mut payload) {
527 return Outcome::Err(Error::Connection(ConnectionError {
528 kind: ConnectionErrorKind::Disconnected,
529 message: format!("Failed to read packet payload: {}", e),
530 source: Some(Box::new(e)),
531 }));
532 }
533 }
534 #[cfg(feature = "tls")]
535 ConnectionStream::Tls(stream) => {
536 if let Err(e) = stream.read_exact(&mut payload).await {
537 return Outcome::Err(Error::Connection(ConnectionError {
538 kind: ConnectionErrorKind::Disconnected,
539 message: format!("Failed to read packet payload: {e}"),
540 source: Some(Box::new(e)),
541 }));
542 }
543 }
544 }
545 }
546
547 if payload_len == MAX_PACKET_SIZE {
549 loop {
550 let mut header_buf = [0u8; 4];
552 let Some(stream) = self.stream.as_mut() else {
553 return Outcome::Err(connection_error("Connection stream missing"));
554 };
555 match stream {
556 ConnectionStream::Async(stream) => {
557 let mut header_read = 0;
558 while header_read < 4 {
559 let mut read_buf = ReadBuf::new(&mut header_buf[header_read..]);
560 match std::future::poll_fn(|cx| {
561 std::pin::Pin::new(&mut *stream).poll_read(cx, &mut read_buf)
562 })
563 .await
564 {
565 Ok(()) => {
566 let n = read_buf.filled().len();
567 if n == 0 {
568 return Outcome::Err(Error::Connection(ConnectionError {
569 kind: ConnectionErrorKind::Disconnected,
570 message: "Connection closed while reading continuation header".to_string(),
571 source: None,
572 }));
573 }
574 header_read += n;
575 }
576 Err(e) => {
577 return Outcome::Err(Error::Connection(ConnectionError {
578 kind: ConnectionErrorKind::Disconnected,
579 message: format!(
580 "Failed to read continuation header: {}",
581 e
582 ),
583 source: Some(Box::new(e)),
584 }));
585 }
586 }
587 }
588 }
589 ConnectionStream::Sync(stream) => {
590 if let Err(e) = stream.read_exact(&mut header_buf) {
591 return Outcome::Err(Error::Connection(ConnectionError {
592 kind: ConnectionErrorKind::Disconnected,
593 message: format!("Failed to read continuation header: {}", e),
594 source: Some(Box::new(e)),
595 }));
596 }
597 }
598 #[cfg(feature = "tls")]
599 ConnectionStream::Tls(stream) => {
600 if let Err(e) = stream.read_exact(&mut header_buf).await {
601 return Outcome::Err(Error::Connection(ConnectionError {
602 kind: ConnectionErrorKind::Disconnected,
603 message: format!("Failed to read continuation header: {e}"),
604 source: Some(Box::new(e)),
605 }));
606 }
607 }
608 }
609
610 let cont_header = PacketHeader::from_bytes(&header_buf);
611 let cont_len = cont_header.payload_length as usize;
612 self.sequence_id = cont_header.sequence_id.wrapping_add(1);
613
614 if cont_len > 0 {
615 let mut cont_payload = vec![0u8; cont_len];
616 let Some(stream) = self.stream.as_mut() else {
617 return Outcome::Err(connection_error("Connection stream missing"));
618 };
619 match stream {
620 ConnectionStream::Async(stream) => {
621 let mut total_read = 0;
622 while total_read < cont_len {
623 let mut read_buf = ReadBuf::new(&mut cont_payload[total_read..]);
624 match std::future::poll_fn(|cx| {
625 std::pin::Pin::new(&mut *stream).poll_read(cx, &mut read_buf)
626 })
627 .await
628 {
629 Ok(()) => {
630 let n = read_buf.filled().len();
631 if n == 0 {
632 return Outcome::Err(Error::Connection(ConnectionError {
633 kind: ConnectionErrorKind::Disconnected,
634 message: "Connection closed while reading continuation payload".to_string(),
635 source: None,
636 }));
637 }
638 total_read += n;
639 }
640 Err(e) => {
641 return Outcome::Err(Error::Connection(ConnectionError {
642 kind: ConnectionErrorKind::Disconnected,
643 message: format!(
644 "Failed to read continuation payload: {}",
645 e
646 ),
647 source: Some(Box::new(e)),
648 }));
649 }
650 }
651 }
652 }
653 ConnectionStream::Sync(stream) => {
654 if let Err(e) = stream.read_exact(&mut cont_payload) {
655 return Outcome::Err(Error::Connection(ConnectionError {
656 kind: ConnectionErrorKind::Disconnected,
657 message: format!("Failed to read continuation payload: {}", e),
658 source: Some(Box::new(e)),
659 }));
660 }
661 }
662 #[cfg(feature = "tls")]
663 ConnectionStream::Tls(stream) => {
664 if let Err(e) = stream.read_exact(&mut cont_payload).await {
665 return Outcome::Err(Error::Connection(ConnectionError {
666 kind: ConnectionErrorKind::Disconnected,
667 message: format!("Failed to read continuation payload: {e}"),
668 source: Some(Box::new(e)),
669 }));
670 }
671 }
672 }
673 payload.extend_from_slice(&cont_payload);
674 }
675
676 if cont_len < MAX_PACKET_SIZE {
677 break;
678 }
679 }
680 }
681
682 Outcome::Ok((payload, header.sequence_id))
683 }
684
685 async fn write_packet_async(&mut self, payload: &[u8]) -> Outcome<(), Error> {
687 let writer = PacketWriter::new();
688 let packet = writer.build_packet_from_payload(payload, self.sequence_id);
689 self.sequence_id = self.sequence_id.wrapping_add(1);
690
691 let Some(stream) = self.stream.as_mut() else {
692 return Outcome::Err(connection_error("Connection stream missing"));
693 };
694
695 match stream {
696 ConnectionStream::Async(stream) => {
697 let mut written = 0;
699 while written < packet.len() {
700 match std::future::poll_fn(|cx| {
701 std::pin::Pin::new(&mut *stream).poll_write(cx, &packet[written..])
702 })
703 .await
704 {
705 Ok(n) => {
706 if n == 0 {
707 return Outcome::Err(Error::Connection(ConnectionError {
708 kind: ConnectionErrorKind::Disconnected,
709 message: "Connection closed while writing packet".to_string(),
710 source: None,
711 }));
712 }
713 written += n;
714 }
715 Err(e) => {
716 return Outcome::Err(Error::Connection(ConnectionError {
717 kind: ConnectionErrorKind::Disconnected,
718 message: format!("Failed to write packet: {}", e),
719 source: Some(Box::new(e)),
720 }));
721 }
722 }
723 }
724
725 match std::future::poll_fn(|cx| std::pin::Pin::new(&mut *stream).poll_flush(cx))
726 .await
727 {
728 Ok(()) => {}
729 Err(e) => {
730 return Outcome::Err(Error::Connection(ConnectionError {
731 kind: ConnectionErrorKind::Disconnected,
732 message: format!("Failed to flush stream: {}", e),
733 source: Some(Box::new(e)),
734 }));
735 }
736 }
737 }
738 ConnectionStream::Sync(stream) => {
739 if let Err(e) = stream.write_all(&packet) {
740 return Outcome::Err(Error::Connection(ConnectionError {
741 kind: ConnectionErrorKind::Disconnected,
742 message: format!("Failed to write packet: {}", e),
743 source: Some(Box::new(e)),
744 }));
745 }
746 if let Err(e) = stream.flush() {
747 return Outcome::Err(Error::Connection(ConnectionError {
748 kind: ConnectionErrorKind::Disconnected,
749 message: format!("Failed to flush stream: {}", e),
750 source: Some(Box::new(e)),
751 }));
752 }
753 }
754 #[cfg(feature = "tls")]
755 ConnectionStream::Tls(stream) => {
756 if let Err(e) = stream.write_all(&packet).await {
757 return Outcome::Err(Error::Connection(ConnectionError {
758 kind: ConnectionErrorKind::Disconnected,
759 message: format!("Failed to write packet: {e}"),
760 source: Some(Box::new(e)),
761 }));
762 }
763 if let Err(e) = stream.flush().await {
764 return Outcome::Err(Error::Connection(ConnectionError {
765 kind: ConnectionErrorKind::Disconnected,
766 message: format!("Failed to flush stream: {e}"),
767 source: Some(Box::new(e)),
768 }));
769 }
770 }
771 }
772
773 Outcome::Ok(())
774 }
775
776 async fn read_handshake_async(&mut self) -> Outcome<ServerCapabilities, Error> {
780 let (payload, _) = match self.read_packet_async().await {
781 Outcome::Ok(p) => p,
782 Outcome::Err(e) => return Outcome::Err(e),
783 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
784 Outcome::Panicked(p) => return Outcome::Panicked(p),
785 };
786
787 let mut reader = PacketReader::new(&payload);
788
789 let Some(protocol_version) = reader.read_u8() else {
791 return Outcome::Err(protocol_error("Missing protocol version"));
792 };
793
794 if protocol_version != 10 {
795 return Outcome::Err(protocol_error(format!(
796 "Unsupported protocol version: {}",
797 protocol_version
798 )));
799 }
800
801 let Some(server_version) = reader.read_null_string() else {
803 return Outcome::Err(protocol_error("Missing server version"));
804 };
805
806 let Some(connection_id) = reader.read_u32_le() else {
808 return Outcome::Err(protocol_error("Missing connection ID"));
809 };
810
811 let Some(auth_data_1) = reader.read_bytes(8) else {
813 return Outcome::Err(protocol_error("Missing auth data"));
814 };
815
816 reader.skip(1);
818
819 let Some(caps_lower) = reader.read_u16_le() else {
821 return Outcome::Err(protocol_error("Missing capability flags"));
822 };
823
824 let charset_val = reader.read_u8().unwrap_or(charset::UTF8MB4_0900_AI_CI);
826
827 let status_flags = reader.read_u16_le().unwrap_or(0);
829
830 let caps_upper = reader.read_u16_le().unwrap_or(0);
832 let capabilities_val = u32::from(caps_lower) | (u32::from(caps_upper) << 16);
833
834 let auth_data_len = if capabilities_val & capabilities::CLIENT_PLUGIN_AUTH != 0 {
836 reader.read_u8().unwrap_or(0) as usize
837 } else {
838 0
839 };
840
841 reader.skip(10);
843
844 let mut auth_data = auth_data_1.to_vec();
846 if capabilities_val & capabilities::CLIENT_SECURE_CONNECTION != 0 {
847 let len2 = if auth_data_len > 8 {
848 auth_data_len - 8
849 } else {
850 13 };
852 if let Some(data2) = reader.read_bytes(len2) {
853 let data2_clean = if data2.last() == Some(&0) {
855 &data2[..data2.len() - 1]
856 } else {
857 data2
858 };
859 auth_data.extend_from_slice(data2_clean);
860 }
861 }
862
863 let auth_plugin = if capabilities_val & capabilities::CLIENT_PLUGIN_AUTH != 0 {
865 reader.read_null_string().unwrap_or_default()
866 } else {
867 auth::plugins::MYSQL_NATIVE_PASSWORD.to_string()
868 };
869
870 Outcome::Ok(ServerCapabilities {
871 capabilities: capabilities_val,
872 protocol_version,
873 server_version,
874 connection_id,
875 auth_plugin,
876 auth_data,
877 charset: charset_val,
878 status_flags,
879 })
880 }
881
882 async fn send_handshake_response_async(&mut self) -> Outcome<(), Error> {
884 let Some(server_caps) = self.server_caps.as_ref() else {
885 return Outcome::Err(protocol_error("No server handshake received"));
886 };
887
888 let server_caps_bits = server_caps.capabilities;
890 let auth_plugin = server_caps.auth_plugin.clone();
891 let auth_data = server_caps.auth_data.clone();
892
893 let mut client_caps = self.config.capability_flags() & server_caps_bits;
895 #[cfg(feature = "tls")]
896 if let Outcome::Err(e) = self
897 .maybe_upgrade_tls_async(server_caps_bits, &mut client_caps)
898 .await
899 {
900 return Outcome::Err(e);
901 }
902
903 #[cfg(not(feature = "tls"))]
904 if let Outcome::Err(e) = self.maybe_upgrade_tls(server_caps_bits, &mut client_caps) {
905 return Outcome::Err(e);
906 }
907
908 let auth_response = self.compute_auth_response(&auth_plugin, &auth_data);
910
911 let mut writer = PacketWriter::new();
912
913 writer.write_u32_le(client_caps);
915
916 writer.write_u32_le(self.config.max_packet_size);
918
919 writer.write_u8(self.config.charset);
921
922 writer.write_zeros(23);
924
925 writer.write_null_string(&self.config.user);
927
928 if client_caps & capabilities::CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA != 0 {
930 writer.write_lenenc_bytes(&auth_response);
931 } else if client_caps & capabilities::CLIENT_SECURE_CONNECTION != 0 {
932 #[allow(clippy::cast_possible_truncation)]
933 writer.write_u8(auth_response.len() as u8);
934 writer.write_bytes(&auth_response);
935 } else {
936 writer.write_bytes(&auth_response);
937 writer.write_u8(0); }
939
940 if client_caps & capabilities::CLIENT_CONNECT_WITH_DB != 0 {
942 if let Some(ref db) = self.config.database {
943 writer.write_null_string(db);
944 } else {
945 writer.write_u8(0); }
947 }
948
949 if client_caps & capabilities::CLIENT_PLUGIN_AUTH != 0 {
951 writer.write_null_string(&auth_plugin);
952 }
953
954 if client_caps & capabilities::CLIENT_CONNECT_ATTRS != 0
956 && !self.config.attributes.is_empty()
957 {
958 let mut attrs_writer = PacketWriter::new();
959 for (key, value) in &self.config.attributes {
960 attrs_writer.write_lenenc_string(key);
961 attrs_writer.write_lenenc_string(value);
962 }
963 let attrs_data = attrs_writer.into_bytes();
964 writer.write_lenenc_bytes(&attrs_data);
965 }
966
967 self.write_packet_async(writer.as_bytes()).await
968 }
969
970 #[cfg(feature = "tls")]
971 async fn maybe_upgrade_tls_async(
972 &mut self,
973 server_caps: u32,
974 client_caps: &mut u32,
975 ) -> Outcome<(), Error> {
976 let ssl_mode = self.config.ssl_mode;
977
978 if !ssl_mode.should_try_ssl() {
979 *client_caps &= !capabilities::CLIENT_SSL;
980 return Outcome::Ok(());
981 }
982
983 let use_tls = match crate::tls::validate_ssl_mode(ssl_mode, server_caps) {
984 Ok(v) => v,
985 Err(e) => return Outcome::Err(e),
986 };
987
988 if !use_tls {
989 *client_caps &= !capabilities::CLIENT_SSL;
991 return Outcome::Ok(());
992 }
993
994 if let Err(e) = crate::tls::validate_tls_config(ssl_mode, &self.config.tls_config) {
995 return Outcome::Err(e);
996 }
997
998 let packet = crate::tls::build_ssl_request_packet(
1001 *client_caps,
1002 self.config.max_packet_size,
1003 self.config.charset,
1004 self.sequence_id,
1005 );
1006 if let Outcome::Err(e) = self.write_packet_raw_async(&packet).await {
1007 return Outcome::Err(e);
1008 }
1009 self.sequence_id = self.sequence_id.wrapping_add(1);
1010
1011 let Some(stream) = self.stream.take() else {
1012 return Outcome::Err(connection_error("Connection stream missing"));
1013 };
1014 let ConnectionStream::Async(tcp) = stream else {
1015 return Outcome::Err(connection_error("TLS upgrade requires async TCP stream"));
1016 };
1017
1018 let tls = match AsyncTlsStream::handshake(
1019 tcp,
1020 &self.config.tls_config,
1021 &self.config.host,
1022 ssl_mode,
1023 )
1024 .await
1025 {
1026 Ok(s) => s,
1027 Err(e) => return Outcome::Err(e),
1028 };
1029
1030 self.stream = Some(ConnectionStream::Tls(tls));
1031 Outcome::Ok(())
1032 }
1033
1034 #[cfg(not(feature = "tls"))]
1035 fn maybe_upgrade_tls(&mut self, server_caps: u32, client_caps: &mut u32) -> Outcome<(), Error> {
1036 let ssl_mode = self.config.ssl_mode;
1037
1038 if !ssl_mode.should_try_ssl() {
1039 *client_caps &= !capabilities::CLIENT_SSL;
1040 return Outcome::Ok(());
1041 }
1042
1043 let use_tls = match crate::tls::validate_ssl_mode(ssl_mode, server_caps) {
1044 Ok(v) => v,
1045 Err(e) => return Outcome::Err(e),
1046 };
1047
1048 if !use_tls {
1049 *client_caps &= !capabilities::CLIENT_SSL;
1051 return Outcome::Ok(());
1052 }
1053
1054 if ssl_mode == crate::config::SslMode::Preferred {
1056 *client_caps &= !capabilities::CLIENT_SSL;
1057 Outcome::Ok(())
1058 } else {
1059 Outcome::Err(connection_error(
1060 "TLS requested but 'sqlmodel-mysql' was built without feature 'tls'",
1061 ))
1062 }
1063 }
1064
1065 fn compute_auth_response(&self, plugin: &str, auth_data: &[u8]) -> Vec<u8> {
1067 let pw = self.config.password_str();
1068
1069 match plugin {
1070 auth::plugins::MYSQL_NATIVE_PASSWORD => {
1072 auth::mysql_native_password(pw, auth_data)
1073 }
1074 auth::plugins::CACHING_SHA2_PASSWORD => {
1075 auth::caching_sha2_password(pw, auth_data)
1076 }
1077 auth::plugins::MYSQL_CLEAR_PASSWORD => {
1078 let mut result = pw.as_bytes().to_vec();
1079 result.push(0);
1080 result
1081 }
1082 _ => auth::mysql_native_password(pw, auth_data),
1083 }
1084 }
1085
1086 async fn handle_auth_result_async(&mut self) -> Outcome<(), Error> {
1089 loop {
1091 let (payload, _) = match self.read_packet_async().await {
1092 Outcome::Ok(p) => p,
1093 Outcome::Err(e) => return Outcome::Err(e),
1094 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1095 Outcome::Panicked(p) => return Outcome::Panicked(p),
1096 };
1097
1098 if payload.is_empty() {
1099 return Outcome::Err(protocol_error("Empty authentication response"));
1100 }
1101
1102 #[allow(clippy::cast_possible_truncation)] match PacketType::from_first_byte(payload[0], payload.len() as u32) {
1104 PacketType::Ok => {
1105 let mut reader = PacketReader::new(&payload);
1106 if let Some(ok) = reader.parse_ok_packet() {
1107 self.status_flags = ok.status_flags;
1108 self.affected_rows = ok.affected_rows;
1109 }
1110 return Outcome::Ok(());
1111 }
1112 PacketType::Error => {
1113 let mut reader = PacketReader::new(&payload);
1114 let Some(err) = reader.parse_err_packet() else {
1115 return Outcome::Err(protocol_error("Invalid error packet"));
1116 };
1117 return Outcome::Err(auth_error(format!(
1118 "Authentication failed: {} ({})",
1119 err.error_message, err.error_code
1120 )));
1121 }
1122 PacketType::Eof => {
1123 let data = &payload[1..];
1125 let mut reader = PacketReader::new(data);
1126
1127 let Some(plugin) = reader.read_null_string() else {
1128 return Outcome::Err(protocol_error("Missing plugin name in auth switch"));
1129 };
1130
1131 let auth_data = reader.read_rest();
1132 let response = self.compute_auth_response(&plugin, auth_data);
1133
1134 if let Outcome::Err(e) = self.write_packet_async(&response).await {
1135 return Outcome::Err(e);
1136 }
1137 }
1139 _ => {
1140 match self.handle_additional_auth_async(&payload).await {
1142 Outcome::Ok(()) => continue,
1143 Outcome::Err(e) => return Outcome::Err(e),
1144 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1145 Outcome::Panicked(p) => return Outcome::Panicked(p),
1146 }
1147 }
1148 }
1149 }
1150 }
1151
1152 async fn handle_additional_auth_async(&mut self, data: &[u8]) -> Outcome<(), Error> {
1154 if data.is_empty() {
1155 return Outcome::Err(protocol_error("Empty additional auth data"));
1156 }
1157
1158 match data[0] {
1159 auth::caching_sha2::FAST_AUTH_SUCCESS => {
1160 Outcome::Ok(())
1162 }
1163 auth::caching_sha2::PERFORM_FULL_AUTH => {
1164 let Some(server_caps) = self.server_caps.as_ref() else {
1165 return Outcome::Err(protocol_error("Missing server capabilities during auth"));
1166 };
1167
1168 let pw = self.config.password_owned();
1169 let seed = server_caps.auth_data.clone();
1170 let server_version = server_caps.server_version.clone();
1171
1172 if self.is_secure_transport() {
1173 let mut clear = pw.as_bytes().to_vec();
1176 clear.push(0);
1177 if let Outcome::Err(e) = self.write_packet_async(&clear).await {
1178 return Outcome::Err(e);
1179 }
1180 Outcome::Ok(())
1181 } else {
1182 if let Outcome::Err(e) = self
1184 .write_packet_async(&[auth::caching_sha2::REQUEST_PUBLIC_KEY])
1185 .await
1186 {
1187 return Outcome::Err(e);
1188 }
1189
1190 let (payload, _) = match self.read_packet_async().await {
1191 Outcome::Ok(p) => p,
1192 Outcome::Err(e) => return Outcome::Err(e),
1193 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1194 Outcome::Panicked(p) => return Outcome::Panicked(p),
1195 };
1196 if payload.is_empty() {
1197 return Outcome::Err(protocol_error("Empty public key response"));
1198 }
1199
1200 let public_key = if payload[0] == 0x01 {
1202 &payload[1..]
1203 } else {
1204 &payload[..]
1205 };
1206
1207 let use_oaep = mysql_server_uses_oaep(&server_version);
1208 let encrypted =
1209 match auth::sha256_password_rsa(&pw, &seed, public_key, use_oaep) {
1210 Ok(v) => v,
1211 Err(e) => return Outcome::Err(auth_error(e)),
1212 };
1213
1214 if let Outcome::Err(e) = self.write_packet_async(&encrypted).await {
1215 return Outcome::Err(e);
1216 }
1217 Outcome::Ok(())
1218 }
1219 }
1220 _ => Outcome::Err(protocol_error(format!(
1221 "Unknown additional auth response: {:02X}",
1222 data[0]
1223 ))),
1224 }
1225 }
1226
1227 pub async fn query_async(
1229 &mut self,
1230 _cx: &Cx,
1231 sql: &str,
1232 params: &[Value],
1233 ) -> Outcome<Vec<Row>, Error> {
1234 let sql = interpolate_params(sql, params);
1235 if !self.is_ready() && self.state != ConnectionState::InTransaction {
1236 return Outcome::Err(connection_error("Connection not ready for queries"));
1237 }
1238
1239 self.state = ConnectionState::InQuery;
1240 self.sequence_id = 0;
1241
1242 let mut writer = PacketWriter::new();
1244 writer.write_u8(Command::Query as u8);
1245 writer.write_bytes(sql.as_bytes());
1246
1247 if let Outcome::Err(e) = self.write_packet_async(writer.as_bytes()).await {
1248 return Outcome::Err(e);
1249 }
1250
1251 let (payload, _) = match self.read_packet_async().await {
1253 Outcome::Ok(p) => p,
1254 Outcome::Err(e) => return Outcome::Err(e),
1255 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1256 Outcome::Panicked(p) => return Outcome::Panicked(p),
1257 };
1258
1259 if payload.is_empty() {
1260 self.state = ConnectionState::Ready;
1261 return Outcome::Err(protocol_error("Empty query response"));
1262 }
1263
1264 #[allow(clippy::cast_possible_truncation)] match PacketType::from_first_byte(payload[0], payload.len() as u32) {
1266 PacketType::Ok => {
1267 let mut reader = PacketReader::new(&payload);
1268 if let Some(ok) = reader.parse_ok_packet() {
1269 self.affected_rows = ok.affected_rows;
1270 self.last_insert_id = ok.last_insert_id;
1271 self.status_flags = ok.status_flags;
1272 self.warnings = ok.warnings;
1273 }
1274 self.state = if self.status_flags
1275 & crate::protocol::server_status::SERVER_STATUS_IN_TRANS
1276 != 0
1277 {
1278 ConnectionState::InTransaction
1279 } else {
1280 ConnectionState::Ready
1281 };
1282 Outcome::Ok(vec![])
1283 }
1284 PacketType::Error => {
1285 self.state = ConnectionState::Ready;
1286 let mut reader = PacketReader::new(&payload);
1287 let Some(err) = reader.parse_err_packet() else {
1288 return Outcome::Err(protocol_error("Invalid error packet"));
1289 };
1290 Outcome::Err(query_error(&err))
1291 }
1292 PacketType::LocalInfile => {
1293 self.state = ConnectionState::Ready;
1294 Outcome::Err(query_error_msg("LOCAL INFILE not supported"))
1295 }
1296 _ => self.read_result_set_async(&payload).await,
1297 }
1298 }
1299
1300 async fn read_result_set_async(&mut self, first_packet: &[u8]) -> Outcome<Vec<Row>, Error> {
1302 let mut reader = PacketReader::new(first_packet);
1303 #[allow(clippy::cast_possible_truncation)] let Some(column_count) = reader.read_lenenc_int().map(|c| c as usize) else {
1305 return Outcome::Err(protocol_error("Invalid column count"));
1306 };
1307
1308 let mut columns = Vec::with_capacity(column_count);
1310 for _ in 0..column_count {
1311 let (payload, _) = match self.read_packet_async().await {
1312 Outcome::Ok(p) => p,
1313 Outcome::Err(e) => return Outcome::Err(e),
1314 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1315 Outcome::Panicked(p) => return Outcome::Panicked(p),
1316 };
1317 match self.parse_column_def(&payload) {
1318 Ok(col) => columns.push(col),
1319 Err(e) => return Outcome::Err(e),
1320 }
1321 }
1322
1323 let server_caps = self.server_caps.as_ref().map_or(0, |c| c.capabilities);
1325 if server_caps & capabilities::CLIENT_DEPRECATE_EOF == 0 {
1326 let (payload, _) = match self.read_packet_async().await {
1327 Outcome::Ok(p) => p,
1328 Outcome::Err(e) => return Outcome::Err(e),
1329 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1330 Outcome::Panicked(p) => return Outcome::Panicked(p),
1331 };
1332 if payload.first() == Some(&0xFE) {
1333 }
1335 }
1336
1337 let mut rows = Vec::new();
1339 loop {
1340 let (payload, _) = match self.read_packet_async().await {
1341 Outcome::Ok(p) => p,
1342 Outcome::Err(e) => return Outcome::Err(e),
1343 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1344 Outcome::Panicked(p) => return Outcome::Panicked(p),
1345 };
1346
1347 if payload.is_empty() {
1348 break;
1349 }
1350
1351 #[allow(clippy::cast_possible_truncation)] match PacketType::from_first_byte(payload[0], payload.len() as u32) {
1353 PacketType::Eof | PacketType::Ok => {
1354 let mut reader = PacketReader::new(&payload);
1355 if payload[0] == 0x00 {
1356 if let Some(ok) = reader.parse_ok_packet() {
1357 self.status_flags = ok.status_flags;
1358 self.warnings = ok.warnings;
1359 }
1360 } else if payload[0] == 0xFE
1361 && let Some(eof) = reader.parse_eof_packet()
1362 {
1363 self.status_flags = eof.status_flags;
1364 self.warnings = eof.warnings;
1365 }
1366 break;
1367 }
1368 PacketType::Error => {
1369 let mut reader = PacketReader::new(&payload);
1370 let Some(err) = reader.parse_err_packet() else {
1371 return Outcome::Err(protocol_error("Invalid error packet"));
1372 };
1373 self.state = ConnectionState::Ready;
1374 return Outcome::Err(query_error(&err));
1375 }
1376 _ => {
1377 let row = self.parse_text_row(&payload, &columns);
1378 rows.push(row);
1379 }
1380 }
1381 }
1382
1383 self.state =
1384 if self.status_flags & crate::protocol::server_status::SERVER_STATUS_IN_TRANS != 0 {
1385 ConnectionState::InTransaction
1386 } else {
1387 ConnectionState::Ready
1388 };
1389
1390 Outcome::Ok(rows)
1391 }
1392
1393 fn parse_column_def(&self, data: &[u8]) -> Result<ColumnDef, Error> {
1395 let mut reader = PacketReader::new(data);
1396
1397 let catalog = reader
1398 .read_lenenc_string()
1399 .ok_or_else(|| protocol_error("Missing catalog"))?;
1400 let schema = reader
1401 .read_lenenc_string()
1402 .ok_or_else(|| protocol_error("Missing schema"))?;
1403 let table = reader
1404 .read_lenenc_string()
1405 .ok_or_else(|| protocol_error("Missing table"))?;
1406 let org_table = reader
1407 .read_lenenc_string()
1408 .ok_or_else(|| protocol_error("Missing org_table"))?;
1409 let name = reader
1410 .read_lenenc_string()
1411 .ok_or_else(|| protocol_error("Missing name"))?;
1412 let org_name = reader
1413 .read_lenenc_string()
1414 .ok_or_else(|| protocol_error("Missing org_name"))?;
1415
1416 let _fixed_len = reader.read_lenenc_int();
1417
1418 let charset_val = reader
1419 .read_u16_le()
1420 .ok_or_else(|| protocol_error("Missing charset"))?;
1421 let column_length = reader
1422 .read_u32_le()
1423 .ok_or_else(|| protocol_error("Missing column_length"))?;
1424 let column_type = FieldType::from_u8(
1425 reader
1426 .read_u8()
1427 .ok_or_else(|| protocol_error("Missing column_type"))?,
1428 );
1429 let flags = reader
1430 .read_u16_le()
1431 .ok_or_else(|| protocol_error("Missing flags"))?;
1432 let decimals = reader
1433 .read_u8()
1434 .ok_or_else(|| protocol_error("Missing decimals"))?;
1435
1436 Ok(ColumnDef {
1437 catalog,
1438 schema,
1439 table,
1440 org_table,
1441 name,
1442 org_name,
1443 charset: charset_val,
1444 column_length,
1445 column_type,
1446 flags,
1447 decimals,
1448 })
1449 }
1450
1451 fn parse_text_row(&self, data: &[u8], columns: &[ColumnDef]) -> Row {
1453 let mut reader = PacketReader::new(data);
1454 let mut values = Vec::with_capacity(columns.len());
1455
1456 for col in columns {
1457 if reader.peek() == Some(0xFB) {
1458 reader.skip(1);
1459 values.push(Value::Null);
1460 } else if let Some(data) = reader.read_lenenc_bytes() {
1461 let is_unsigned = col.is_unsigned();
1462 let value = decode_text_value(col.column_type, &data, is_unsigned);
1463 values.push(value);
1464 } else {
1465 values.push(Value::Null);
1466 }
1467 }
1468
1469 let column_names: Vec<String> = columns.iter().map(|c| c.name.clone()).collect();
1470 Row::new(column_names, values)
1471 }
1472
1473 pub async fn execute_async(
1478 &mut self,
1479 cx: &Cx,
1480 sql: &str,
1481 params: &[Value],
1482 ) -> Outcome<u64, Error> {
1483 match self.query_async(cx, sql, params).await {
1485 Outcome::Ok(_) => Outcome::Ok(self.affected_rows),
1486 Outcome::Err(e) => Outcome::Err(e),
1487 Outcome::Cancelled(c) => Outcome::Cancelled(c),
1488 Outcome::Panicked(p) => Outcome::Panicked(p),
1489 }
1490 }
1491
1492 pub async fn prepare_async(
1497 &mut self,
1498 _cx: &Cx,
1499 sql: &str,
1500 ) -> Outcome<PreparedStatement, Error> {
1501 if !self.is_ready() && self.state != ConnectionState::InTransaction {
1502 return Outcome::Err(connection_error("Connection not ready for prepare"));
1503 }
1504
1505 self.sequence_id = 0;
1506
1507 let packet = prepared::build_stmt_prepare_packet(sql, self.sequence_id);
1509 if let Outcome::Err(e) = self.write_packet_raw_async(&packet).await {
1510 return Outcome::Err(e);
1511 }
1512
1513 let (payload, _) = match self.read_packet_async().await {
1515 Outcome::Ok(p) => p,
1516 Outcome::Err(e) => return Outcome::Err(e),
1517 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1518 Outcome::Panicked(p) => return Outcome::Panicked(p),
1519 };
1520
1521 if payload.first() == Some(&0xFF) {
1523 let mut reader = PacketReader::new(&payload);
1524 let Some(err) = reader.parse_err_packet() else {
1525 return Outcome::Err(protocol_error("Invalid error packet"));
1526 };
1527 return Outcome::Err(query_error(&err));
1528 }
1529
1530 let Some(prep_ok) = prepared::parse_stmt_prepare_ok(&payload) else {
1532 return Outcome::Err(protocol_error("Invalid prepare OK response"));
1533 };
1534
1535 let mut param_defs = Vec::with_capacity(prep_ok.num_params as usize);
1537 for _ in 0..prep_ok.num_params {
1538 let (payload, _) = match self.read_packet_async().await {
1539 Outcome::Ok(p) => p,
1540 Outcome::Err(e) => return Outcome::Err(e),
1541 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1542 Outcome::Panicked(p) => return Outcome::Panicked(p),
1543 };
1544 match self.parse_column_def(&payload) {
1545 Ok(col) => param_defs.push(col),
1546 Err(e) => return Outcome::Err(e),
1547 }
1548 }
1549
1550 let server_caps = self.server_caps.as_ref().map_or(0, |c| c.capabilities);
1552 if prep_ok.num_params > 0 && server_caps & capabilities::CLIENT_DEPRECATE_EOF == 0 {
1553 let (payload, _) = match self.read_packet_async().await {
1554 Outcome::Ok(p) => p,
1555 Outcome::Err(e) => return Outcome::Err(e),
1556 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1557 Outcome::Panicked(p) => return Outcome::Panicked(p),
1558 };
1559 if payload.first() != Some(&0xFE) {
1560 return Outcome::Err(protocol_error("Expected EOF after param definitions"));
1561 }
1562 }
1563
1564 let mut column_defs = Vec::with_capacity(prep_ok.num_columns as usize);
1566 for _ in 0..prep_ok.num_columns {
1567 let (payload, _) = match self.read_packet_async().await {
1568 Outcome::Ok(p) => p,
1569 Outcome::Err(e) => return Outcome::Err(e),
1570 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1571 Outcome::Panicked(p) => return Outcome::Panicked(p),
1572 };
1573 match self.parse_column_def(&payload) {
1574 Ok(col) => column_defs.push(col),
1575 Err(e) => return Outcome::Err(e),
1576 }
1577 }
1578
1579 if prep_ok.num_columns > 0 && server_caps & capabilities::CLIENT_DEPRECATE_EOF == 0 {
1581 let (payload, _) = match self.read_packet_async().await {
1582 Outcome::Ok(p) => p,
1583 Outcome::Err(e) => return Outcome::Err(e),
1584 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1585 Outcome::Panicked(p) => return Outcome::Panicked(p),
1586 };
1587 if payload.first() != Some(&0xFE) {
1588 return Outcome::Err(protocol_error("Expected EOF after column definitions"));
1589 }
1590 }
1591
1592 let meta = PreparedStmtMeta {
1594 statement_id: prep_ok.statement_id,
1595 params: param_defs,
1596 columns: column_defs.clone(),
1597 };
1598 self.prepared_stmts.insert(prep_ok.statement_id, meta);
1599
1600 let column_names: Vec<String> = column_defs.iter().map(|c| c.name.clone()).collect();
1602 Outcome::Ok(PreparedStatement::with_columns(
1603 u64::from(prep_ok.statement_id),
1604 sql.to_string(),
1605 prep_ok.num_params as usize,
1606 column_names,
1607 ))
1608 }
1609
1610 pub async fn query_prepared_async(
1612 &mut self,
1613 _cx: &Cx,
1614 stmt: &PreparedStatement,
1615 params: &[Value],
1616 ) -> Outcome<Vec<Row>, Error> {
1617 #[allow(clippy::cast_possible_truncation)] let stmt_id = stmt.id() as u32;
1619
1620 let Some(meta) = self.prepared_stmts.get(&stmt_id).cloned() else {
1622 return Outcome::Err(connection_error("Unknown prepared statement"));
1623 };
1624
1625 if params.len() != meta.params.len() {
1627 return Outcome::Err(connection_error(format!(
1628 "Expected {} parameters, got {}",
1629 meta.params.len(),
1630 params.len()
1631 )));
1632 }
1633
1634 if !self.is_ready() && self.state != ConnectionState::InTransaction {
1635 return Outcome::Err(connection_error("Connection not ready for query"));
1636 }
1637
1638 self.state = ConnectionState::InQuery;
1639 self.sequence_id = 0;
1640
1641 let param_types: Vec<FieldType> = meta.params.iter().map(|c| c.column_type).collect();
1643 let packet = prepared::build_stmt_execute_packet(
1644 stmt_id,
1645 params,
1646 Some(¶m_types),
1647 self.sequence_id,
1648 );
1649 if let Outcome::Err(e) = self.write_packet_raw_async(&packet).await {
1650 return Outcome::Err(e);
1651 }
1652
1653 let (payload, _) = match self.read_packet_async().await {
1655 Outcome::Ok(p) => p,
1656 Outcome::Err(e) => return Outcome::Err(e),
1657 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1658 Outcome::Panicked(p) => return Outcome::Panicked(p),
1659 };
1660
1661 if payload.is_empty() {
1662 self.state = ConnectionState::Ready;
1663 return Outcome::Err(protocol_error("Empty execute response"));
1664 }
1665
1666 #[allow(clippy::cast_possible_truncation)] match PacketType::from_first_byte(payload[0], payload.len() as u32) {
1668 PacketType::Ok => {
1669 let mut reader = PacketReader::new(&payload);
1671 if let Some(ok) = reader.parse_ok_packet() {
1672 self.affected_rows = ok.affected_rows;
1673 self.last_insert_id = ok.last_insert_id;
1674 self.status_flags = ok.status_flags;
1675 self.warnings = ok.warnings;
1676 }
1677 self.state = ConnectionState::Ready;
1678 Outcome::Ok(vec![])
1679 }
1680 PacketType::Error => {
1681 self.state = ConnectionState::Ready;
1682 let mut reader = PacketReader::new(&payload);
1683 let Some(err) = reader.parse_err_packet() else {
1684 return Outcome::Err(protocol_error("Invalid error packet"));
1685 };
1686 Outcome::Err(query_error(&err))
1687 }
1688 _ => {
1689 self.read_binary_result_set_async(&payload, &meta.columns)
1691 .await
1692 }
1693 }
1694 }
1695
1696 pub async fn execute_prepared_async(
1698 &mut self,
1699 cx: &Cx,
1700 stmt: &PreparedStatement,
1701 params: &[Value],
1702 ) -> Outcome<u64, Error> {
1703 match self.query_prepared_async(cx, stmt, params).await {
1704 Outcome::Ok(_) => Outcome::Ok(self.affected_rows),
1705 Outcome::Err(e) => Outcome::Err(e),
1706 Outcome::Cancelled(c) => Outcome::Cancelled(c),
1707 Outcome::Panicked(p) => Outcome::Panicked(p),
1708 }
1709 }
1710
1711 pub async fn close_prepared_async(&mut self, stmt: &PreparedStatement) {
1713 #[allow(clippy::cast_possible_truncation)] let stmt_id = stmt.id() as u32;
1715 self.prepared_stmts.remove(&stmt_id);
1716
1717 self.sequence_id = 0;
1718 let packet = prepared::build_stmt_close_packet(stmt_id, self.sequence_id);
1719 let _ = self.write_packet_raw_async(&packet).await;
1721 }
1722
1723 async fn read_binary_result_set_async(
1725 &mut self,
1726 first_packet: &[u8],
1727 columns: &[ColumnDef],
1728 ) -> Outcome<Vec<Row>, Error> {
1729 let mut reader = PacketReader::new(first_packet);
1731 #[allow(clippy::cast_possible_truncation)] let Some(column_count) = reader.read_lenenc_int().map(|c| c as usize) else {
1733 return Outcome::Err(protocol_error("Invalid column count"));
1734 };
1735
1736 let mut result_columns = Vec::with_capacity(column_count);
1739 for _ in 0..column_count {
1740 let (payload, _) = match self.read_packet_async().await {
1741 Outcome::Ok(p) => p,
1742 Outcome::Err(e) => return Outcome::Err(e),
1743 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1744 Outcome::Panicked(p) => return Outcome::Panicked(p),
1745 };
1746 match self.parse_column_def(&payload) {
1747 Ok(col) => result_columns.push(col),
1748 Err(e) => return Outcome::Err(e),
1749 }
1750 }
1751
1752 let cols = if result_columns.len() == columns.len() {
1754 &result_columns
1755 } else {
1756 columns
1757 };
1758
1759 let server_caps = self.server_caps.as_ref().map_or(0, |c| c.capabilities);
1761 if server_caps & capabilities::CLIENT_DEPRECATE_EOF == 0 {
1762 let (payload, _) = match self.read_packet_async().await {
1763 Outcome::Ok(p) => p,
1764 Outcome::Err(e) => return Outcome::Err(e),
1765 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1766 Outcome::Panicked(p) => return Outcome::Panicked(p),
1767 };
1768 if payload.first() == Some(&0xFE) {
1769 }
1771 }
1772
1773 let mut rows = Vec::new();
1775 loop {
1776 let (payload, _) = match self.read_packet_async().await {
1777 Outcome::Ok(p) => p,
1778 Outcome::Err(e) => return Outcome::Err(e),
1779 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1780 Outcome::Panicked(p) => return Outcome::Panicked(p),
1781 };
1782
1783 if payload.is_empty() {
1784 break;
1785 }
1786
1787 #[allow(clippy::cast_possible_truncation)] match PacketType::from_first_byte(payload[0], payload.len() as u32) {
1789 PacketType::Eof | PacketType::Ok => {
1790 let mut reader = PacketReader::new(&payload);
1791 if payload[0] == 0x00 {
1792 if let Some(ok) = reader.parse_ok_packet() {
1793 self.status_flags = ok.status_flags;
1794 self.warnings = ok.warnings;
1795 }
1796 } else if payload[0] == 0xFE
1797 && let Some(eof) = reader.parse_eof_packet()
1798 {
1799 self.status_flags = eof.status_flags;
1800 self.warnings = eof.warnings;
1801 }
1802 break;
1803 }
1804 PacketType::Error => {
1805 let mut reader = PacketReader::new(&payload);
1806 let Some(err) = reader.parse_err_packet() else {
1807 return Outcome::Err(protocol_error("Invalid error packet"));
1808 };
1809 self.state = ConnectionState::Ready;
1810 return Outcome::Err(query_error(&err));
1811 }
1812 _ => {
1813 let row = self.parse_binary_row(&payload, cols);
1814 rows.push(row);
1815 }
1816 }
1817 }
1818
1819 self.state =
1820 if self.status_flags & crate::protocol::server_status::SERVER_STATUS_IN_TRANS != 0 {
1821 ConnectionState::InTransaction
1822 } else {
1823 ConnectionState::Ready
1824 };
1825
1826 Outcome::Ok(rows)
1827 }
1828
1829 fn parse_binary_row(&self, data: &[u8], columns: &[ColumnDef]) -> Row {
1831 let mut values = Vec::with_capacity(columns.len());
1837 let mut column_names = Vec::with_capacity(columns.len());
1838
1839 if data.is_empty() {
1840 return Row::new(column_names, values);
1841 }
1842
1843 let mut pos = 1;
1845
1846 let null_bitmap_len = (columns.len() + 7 + 2) / 8;
1849 if pos + null_bitmap_len > data.len() {
1850 return Row::new(column_names, values);
1851 }
1852 let null_bitmap = &data[pos..pos + null_bitmap_len];
1853 pos += null_bitmap_len;
1854
1855 for (i, col) in columns.iter().enumerate() {
1857 column_names.push(col.name.clone());
1858
1859 let bit_pos = i + 2;
1861 let is_null = (null_bitmap[bit_pos / 8] & (1 << (bit_pos % 8))) != 0;
1862
1863 if is_null {
1864 values.push(Value::Null);
1865 } else {
1866 let is_unsigned = col.flags & 0x20 != 0; let (value, consumed) =
1868 decode_binary_value_with_len(&data[pos..], col.column_type, is_unsigned);
1869 values.push(value);
1870 pos += consumed;
1871 }
1872 }
1873
1874 Row::new(column_names, values)
1875 }
1876
1877 async fn write_packet_raw_async(&mut self, packet: &[u8]) -> Outcome<(), Error> {
1879 let Some(stream) = self.stream.as_mut() else {
1880 return Outcome::Err(connection_error("Connection stream missing"));
1881 };
1882 match stream {
1883 ConnectionStream::Async(stream) => {
1884 let mut written = 0;
1885 while written < packet.len() {
1886 match std::future::poll_fn(|cx| {
1887 std::pin::Pin::new(&mut *stream).poll_write(cx, &packet[written..])
1888 })
1889 .await
1890 {
1891 Ok(n) => written += n,
1892 Err(e) => {
1893 return Outcome::Err(Error::Connection(ConnectionError {
1894 kind: ConnectionErrorKind::Disconnected,
1895 message: format!("Failed to write packet: {}", e),
1896 source: Some(Box::new(e)),
1897 }));
1898 }
1899 }
1900 }
1901 if let Err(e) =
1903 std::future::poll_fn(|cx| std::pin::Pin::new(&mut *stream).poll_flush(cx)).await
1904 {
1905 return Outcome::Err(Error::Connection(ConnectionError {
1906 kind: ConnectionErrorKind::Disconnected,
1907 message: format!("Failed to flush: {}", e),
1908 source: Some(Box::new(e)),
1909 }));
1910 }
1911 Outcome::Ok(())
1912 }
1913 ConnectionStream::Sync(stream) => {
1914 if let Err(e) = stream.write_all(packet) {
1915 return Outcome::Err(Error::Connection(ConnectionError {
1916 kind: ConnectionErrorKind::Disconnected,
1917 message: format!("Failed to write packet: {}", e),
1918 source: Some(Box::new(e)),
1919 }));
1920 }
1921 if let Err(e) = stream.flush() {
1922 return Outcome::Err(Error::Connection(ConnectionError {
1923 kind: ConnectionErrorKind::Disconnected,
1924 message: format!("Failed to flush: {}", e),
1925 source: Some(Box::new(e)),
1926 }));
1927 }
1928 Outcome::Ok(())
1929 }
1930 #[cfg(feature = "tls")]
1931 ConnectionStream::Tls(_) => Outcome::Err(connection_error(
1932 "write_packet_raw_async called after TLS upgrade (bug)",
1933 )),
1934 }
1935 }
1936
1937 pub async fn ping_async(&mut self, _cx: &Cx) -> Outcome<(), Error> {
1939 self.sequence_id = 0;
1940
1941 let mut writer = PacketWriter::new();
1942 writer.write_u8(Command::Ping as u8);
1943
1944 if let Outcome::Err(e) = self.write_packet_async(writer.as_bytes()).await {
1945 return Outcome::Err(e);
1946 }
1947
1948 let (payload, _) = match self.read_packet_async().await {
1949 Outcome::Ok(p) => p,
1950 Outcome::Err(e) => return Outcome::Err(e),
1951 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1952 Outcome::Panicked(p) => return Outcome::Panicked(p),
1953 };
1954
1955 if payload.first() == Some(&0x00) {
1956 Outcome::Ok(())
1957 } else {
1958 Outcome::Err(connection_error("Ping failed"))
1959 }
1960 }
1961
1962 pub async fn close_async(mut self, _cx: &Cx) -> Result<(), Error> {
1964 if self.state == ConnectionState::Closed {
1965 return Ok(());
1966 }
1967
1968 self.sequence_id = 0;
1969
1970 let mut writer = PacketWriter::new();
1971 writer.write_u8(Command::Quit as u8);
1972
1973 let _ = self.write_packet_async(writer.as_bytes()).await;
1975
1976 self.state = ConnectionState::Closed;
1977 Ok(())
1978 }
1979}
1980
1981#[cfg(feature = "console")]
1984impl ConsoleAware for MySqlAsyncConnection {
1985 fn set_console(&mut self, console: Option<Arc<SqlModelConsole>>) {
1986 self.console = console;
1987 }
1988
1989 fn console(&self) -> Option<&Arc<SqlModelConsole>> {
1990 self.console.as_ref()
1991 }
1992}
1993
1994fn protocol_error(msg: impl Into<String>) -> Error {
1997 Error::Protocol(ProtocolError {
1998 message: msg.into(),
1999 raw_data: None,
2000 source: None,
2001 })
2002}
2003
2004fn auth_error(msg: impl Into<String>) -> Error {
2005 Error::Connection(ConnectionError {
2006 kind: ConnectionErrorKind::Authentication,
2007 message: msg.into(),
2008 source: None,
2009 })
2010}
2011
2012fn connection_error(msg: impl Into<String>) -> Error {
2013 Error::Connection(ConnectionError {
2014 kind: ConnectionErrorKind::Connect,
2015 message: msg.into(),
2016 source: None,
2017 })
2018}
2019
2020fn mysql_server_uses_oaep(server_version: &str) -> bool {
2021 let prefix: String = server_version
2024 .chars()
2025 .take_while(|c| c.is_ascii_digit() || *c == '.')
2026 .collect();
2027 let mut it = prefix.split('.').filter(|s| !s.is_empty());
2028 let major: u64 = match it.next().and_then(|s| s.parse().ok()) {
2029 Some(v) => v,
2030 None => return true,
2031 };
2032 let minor: u64 = it.next().and_then(|s| s.parse().ok()).unwrap_or(0);
2033 let patch: u64 = it.next().and_then(|s| s.parse().ok()).unwrap_or(0);
2034
2035 (major, minor, patch) >= (8, 0, 5)
2036}
2037
2038fn query_error(err: &ErrPacket) -> Error {
2039 let kind = if err.is_duplicate_key() || err.is_foreign_key_violation() {
2040 QueryErrorKind::Constraint
2041 } else {
2042 QueryErrorKind::Syntax
2043 };
2044
2045 Error::Query(QueryError {
2046 kind,
2047 message: err.error_message.clone(),
2048 sqlstate: Some(err.sql_state.clone()),
2049 sql: None,
2050 detail: None,
2051 hint: None,
2052 position: None,
2053 source: None,
2054 })
2055}
2056
2057fn query_error_msg(msg: impl Into<String>) -> Error {
2058 Error::Query(QueryError {
2059 kind: QueryErrorKind::Syntax,
2060 message: msg.into(),
2061 sqlstate: None,
2062 sql: None,
2063 detail: None,
2064 hint: None,
2065 position: None,
2066 source: None,
2067 })
2068}
2069
2070fn validate_savepoint_name(name: &str) -> Result<(), Error> {
2078 if name.is_empty() {
2079 return Err(query_error_msg("Savepoint name cannot be empty"));
2080 }
2081 if name.len() > 64 {
2082 return Err(query_error_msg(
2083 "Savepoint name exceeds maximum length of 64 characters",
2084 ));
2085 }
2086 let mut chars = name.chars();
2087 let Some(first) = chars.next() else {
2088 return Err(query_error_msg("Savepoint name cannot be empty"));
2090 };
2091 if !first.is_ascii_alphabetic() && first != '_' {
2092 return Err(query_error_msg(
2093 "Savepoint name must start with a letter or underscore",
2094 ));
2095 }
2096 for c in chars {
2097 if !c.is_ascii_alphanumeric() && c != '_' && c != '$' {
2098 return Err(query_error_msg(format!(
2099 "Savepoint name contains invalid character: '{}'",
2100 c
2101 )));
2102 }
2103 }
2104 Ok(())
2105}
2106
2107pub struct SharedMySqlConnection {
2124 inner: Arc<Mutex<MySqlAsyncConnection>>,
2125}
2126
2127impl SharedMySqlConnection {
2128 pub fn new(conn: MySqlAsyncConnection) -> Self {
2130 Self {
2131 inner: Arc::new(Mutex::new(conn)),
2132 }
2133 }
2134
2135 pub async fn connect(cx: &Cx, config: MySqlConfig) -> Outcome<Self, Error> {
2137 match MySqlAsyncConnection::connect(cx, config).await {
2138 Outcome::Ok(conn) => Outcome::Ok(Self::new(conn)),
2139 Outcome::Err(e) => Outcome::Err(e),
2140 Outcome::Cancelled(c) => Outcome::Cancelled(c),
2141 Outcome::Panicked(p) => Outcome::Panicked(p),
2142 }
2143 }
2144
2145 pub fn inner(&self) -> &Arc<Mutex<MySqlAsyncConnection>> {
2147 &self.inner
2148 }
2149}
2150
2151impl Clone for SharedMySqlConnection {
2152 fn clone(&self) -> Self {
2153 Self {
2154 inner: Arc::clone(&self.inner),
2155 }
2156 }
2157}
2158
2159impl std::fmt::Debug for SharedMySqlConnection {
2160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2161 f.debug_struct("SharedMySqlConnection")
2162 .field("inner", &"Arc<Mutex<MySqlAsyncConnection>>")
2163 .finish()
2164 }
2165}
2166
2167pub struct SharedMySqlTransaction<'conn> {
2186 inner: Arc<Mutex<MySqlAsyncConnection>>,
2187 committed: bool,
2188 _marker: std::marker::PhantomData<&'conn ()>,
2189}
2190
2191impl SharedMySqlConnection {
2192 async fn begin_transaction_impl(
2194 &self,
2195 cx: &Cx,
2196 isolation: Option<IsolationLevel>,
2197 ) -> Outcome<SharedMySqlTransaction<'_>, Error> {
2198 let inner = Arc::clone(&self.inner);
2199
2200 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2202 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2203 };
2204
2205 if let Some(level) = isolation {
2207 let isolation_sql = format!("SET TRANSACTION ISOLATION LEVEL {}", level.as_sql());
2208 match guard.execute_async(cx, &isolation_sql, &[]).await {
2209 Outcome::Ok(_) => {}
2210 Outcome::Err(e) => return Outcome::Err(e),
2211 Outcome::Cancelled(c) => return Outcome::Cancelled(c),
2212 Outcome::Panicked(p) => return Outcome::Panicked(p),
2213 }
2214 }
2215
2216 match guard.execute_async(cx, "BEGIN", &[]).await {
2218 Outcome::Ok(_) => {}
2219 Outcome::Err(e) => return Outcome::Err(e),
2220 Outcome::Cancelled(c) => return Outcome::Cancelled(c),
2221 Outcome::Panicked(p) => return Outcome::Panicked(p),
2222 }
2223
2224 drop(guard);
2225
2226 Outcome::Ok(SharedMySqlTransaction {
2227 inner,
2228 committed: false,
2229 _marker: std::marker::PhantomData,
2230 })
2231 }
2232}
2233
2234impl Connection for SharedMySqlConnection {
2235 type Tx<'conn>
2236 = SharedMySqlTransaction<'conn>
2237 where
2238 Self: 'conn;
2239
2240 fn dialect(&self) -> sqlmodel_core::Dialect {
2241 sqlmodel_core::Dialect::Mysql
2242 }
2243
2244 fn query(
2245 &self,
2246 cx: &Cx,
2247 sql: &str,
2248 params: &[Value],
2249 ) -> impl Future<Output = Outcome<Vec<Row>, Error>> + Send {
2250 let inner = Arc::clone(&self.inner);
2251 let sql = sql.to_string();
2252 let params = params.to_vec();
2253 async move {
2254 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2255 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2256 };
2257 guard.query_async(cx, &sql, ¶ms).await
2258 }
2259 }
2260
2261 fn query_one(
2262 &self,
2263 cx: &Cx,
2264 sql: &str,
2265 params: &[Value],
2266 ) -> impl Future<Output = Outcome<Option<Row>, Error>> + Send {
2267 let inner = Arc::clone(&self.inner);
2268 let sql = sql.to_string();
2269 let params = params.to_vec();
2270 async move {
2271 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2272 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2273 };
2274 let rows = match guard.query_async(cx, &sql, ¶ms).await {
2275 Outcome::Ok(r) => r,
2276 Outcome::Err(e) => return Outcome::Err(e),
2277 Outcome::Cancelled(c) => return Outcome::Cancelled(c),
2278 Outcome::Panicked(p) => return Outcome::Panicked(p),
2279 };
2280 Outcome::Ok(rows.into_iter().next())
2281 }
2282 }
2283
2284 fn execute(
2285 &self,
2286 cx: &Cx,
2287 sql: &str,
2288 params: &[Value],
2289 ) -> impl Future<Output = Outcome<u64, Error>> + Send {
2290 let inner = Arc::clone(&self.inner);
2291 let sql = sql.to_string();
2292 let params = params.to_vec();
2293 async move {
2294 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2295 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2296 };
2297 guard.execute_async(cx, &sql, ¶ms).await
2298 }
2299 }
2300
2301 fn insert(
2302 &self,
2303 cx: &Cx,
2304 sql: &str,
2305 params: &[Value],
2306 ) -> impl Future<Output = Outcome<i64, Error>> + Send {
2307 let inner = Arc::clone(&self.inner);
2308 let sql = sql.to_string();
2309 let params = params.to_vec();
2310 async move {
2311 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2312 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2313 };
2314 match guard.execute_async(cx, &sql, ¶ms).await {
2315 Outcome::Ok(_) => Outcome::Ok(guard.last_insert_id() as i64),
2316 Outcome::Err(e) => Outcome::Err(e),
2317 Outcome::Cancelled(c) => Outcome::Cancelled(c),
2318 Outcome::Panicked(p) => Outcome::Panicked(p),
2319 }
2320 }
2321 }
2322
2323 fn batch(
2324 &self,
2325 cx: &Cx,
2326 statements: &[(String, Vec<Value>)],
2327 ) -> impl Future<Output = Outcome<Vec<u64>, Error>> + Send {
2328 let inner = Arc::clone(&self.inner);
2329 let statements = statements.to_vec();
2330 async move {
2331 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2332 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2333 };
2334 let mut results = Vec::with_capacity(statements.len());
2335 for (sql, params) in &statements {
2336 match guard.execute_async(cx, sql, params).await {
2337 Outcome::Ok(n) => results.push(n),
2338 Outcome::Err(e) => return Outcome::Err(e),
2339 Outcome::Cancelled(c) => return Outcome::Cancelled(c),
2340 Outcome::Panicked(p) => return Outcome::Panicked(p),
2341 }
2342 }
2343 Outcome::Ok(results)
2344 }
2345 }
2346
2347 fn begin(&self, cx: &Cx) -> impl Future<Output = Outcome<Self::Tx<'_>, Error>> + Send {
2348 self.begin_transaction_impl(cx, None)
2349 }
2350
2351 fn begin_with(
2352 &self,
2353 cx: &Cx,
2354 isolation: IsolationLevel,
2355 ) -> impl Future<Output = Outcome<Self::Tx<'_>, Error>> + Send {
2356 self.begin_transaction_impl(cx, Some(isolation))
2357 }
2358
2359 fn prepare(
2360 &self,
2361 cx: &Cx,
2362 sql: &str,
2363 ) -> impl Future<Output = Outcome<PreparedStatement, Error>> + Send {
2364 let inner = Arc::clone(&self.inner);
2365 let sql = sql.to_string();
2366 async move {
2367 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2368 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2369 };
2370 guard.prepare_async(cx, &sql).await
2371 }
2372 }
2373
2374 fn query_prepared(
2375 &self,
2376 cx: &Cx,
2377 stmt: &PreparedStatement,
2378 params: &[Value],
2379 ) -> impl Future<Output = Outcome<Vec<Row>, Error>> + Send {
2380 let inner = Arc::clone(&self.inner);
2381 let stmt = stmt.clone();
2382 let params = params.to_vec();
2383 async move {
2384 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2385 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2386 };
2387 guard.query_prepared_async(cx, &stmt, ¶ms).await
2388 }
2389 }
2390
2391 fn execute_prepared(
2392 &self,
2393 cx: &Cx,
2394 stmt: &PreparedStatement,
2395 params: &[Value],
2396 ) -> impl Future<Output = Outcome<u64, Error>> + Send {
2397 let inner = Arc::clone(&self.inner);
2398 let stmt = stmt.clone();
2399 let params = params.to_vec();
2400 async move {
2401 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2402 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2403 };
2404 guard.execute_prepared_async(cx, &stmt, ¶ms).await
2405 }
2406 }
2407
2408 fn ping(&self, cx: &Cx) -> impl Future<Output = Outcome<(), Error>> + Send {
2409 let inner = Arc::clone(&self.inner);
2410 async move {
2411 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2412 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2413 };
2414 guard.ping_async(cx).await
2415 }
2416 }
2417
2418 fn close(self, cx: &Cx) -> impl Future<Output = Result<(), Error>> + Send {
2419 async move {
2420 match Arc::try_unwrap(self.inner) {
2422 Ok(mutex) => {
2423 let conn = mutex.into_inner().map_err(|_| {
2424 connection_error("Cannot close: connection mutex is unavailable")
2425 })?;
2426 conn.close_async(cx).await
2427 }
2428 Err(_) => {
2429 Err(connection_error(
2431 "Cannot close: other references to connection exist",
2432 ))
2433 }
2434 }
2435 }
2436 }
2437}
2438
2439impl<'conn> TransactionOps for SharedMySqlTransaction<'conn> {
2440 fn query(
2441 &self,
2442 cx: &Cx,
2443 sql: &str,
2444 params: &[Value],
2445 ) -> impl Future<Output = Outcome<Vec<Row>, Error>> + Send {
2446 let inner = Arc::clone(&self.inner);
2447 let sql = sql.to_string();
2448 let params = params.to_vec();
2449 async move {
2450 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2451 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2452 };
2453 guard.query_async(cx, &sql, ¶ms).await
2454 }
2455 }
2456
2457 fn query_one(
2458 &self,
2459 cx: &Cx,
2460 sql: &str,
2461 params: &[Value],
2462 ) -> impl Future<Output = Outcome<Option<Row>, Error>> + Send {
2463 let inner = Arc::clone(&self.inner);
2464 let sql = sql.to_string();
2465 let params = params.to_vec();
2466 async move {
2467 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2468 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2469 };
2470 let rows = match guard.query_async(cx, &sql, ¶ms).await {
2471 Outcome::Ok(r) => r,
2472 Outcome::Err(e) => return Outcome::Err(e),
2473 Outcome::Cancelled(c) => return Outcome::Cancelled(c),
2474 Outcome::Panicked(p) => return Outcome::Panicked(p),
2475 };
2476 Outcome::Ok(rows.into_iter().next())
2477 }
2478 }
2479
2480 fn execute(
2481 &self,
2482 cx: &Cx,
2483 sql: &str,
2484 params: &[Value],
2485 ) -> impl Future<Output = Outcome<u64, Error>> + Send {
2486 let inner = Arc::clone(&self.inner);
2487 let sql = sql.to_string();
2488 let params = params.to_vec();
2489 async move {
2490 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2491 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2492 };
2493 guard.execute_async(cx, &sql, ¶ms).await
2494 }
2495 }
2496
2497 fn savepoint(&self, cx: &Cx, name: &str) -> impl Future<Output = Outcome<(), Error>> + Send {
2498 let inner = Arc::clone(&self.inner);
2499 let validation_result = validate_savepoint_name(name);
2501 let sql = format!("SAVEPOINT {}", name);
2502 async move {
2503 if let Err(e) = validation_result {
2505 return Outcome::Err(e);
2506 }
2507 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2508 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2509 };
2510 match guard.execute_async(cx, &sql, &[]).await {
2511 Outcome::Ok(_) => Outcome::Ok(()),
2512 Outcome::Err(e) => Outcome::Err(e),
2513 Outcome::Cancelled(c) => Outcome::Cancelled(c),
2514 Outcome::Panicked(p) => Outcome::Panicked(p),
2515 }
2516 }
2517 }
2518
2519 fn rollback_to(&self, cx: &Cx, name: &str) -> impl Future<Output = Outcome<(), Error>> + Send {
2520 let inner = Arc::clone(&self.inner);
2521 let validation_result = validate_savepoint_name(name);
2523 let sql = format!("ROLLBACK TO SAVEPOINT {}", name);
2524 async move {
2525 if let Err(e) = validation_result {
2527 return Outcome::Err(e);
2528 }
2529 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2530 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2531 };
2532 match guard.execute_async(cx, &sql, &[]).await {
2533 Outcome::Ok(_) => Outcome::Ok(()),
2534 Outcome::Err(e) => Outcome::Err(e),
2535 Outcome::Cancelled(c) => Outcome::Cancelled(c),
2536 Outcome::Panicked(p) => Outcome::Panicked(p),
2537 }
2538 }
2539 }
2540
2541 fn release(&self, cx: &Cx, name: &str) -> impl Future<Output = Outcome<(), Error>> + Send {
2542 let inner = Arc::clone(&self.inner);
2543 let validation_result = validate_savepoint_name(name);
2545 let sql = format!("RELEASE SAVEPOINT {}", name);
2546 async move {
2547 if let Err(e) = validation_result {
2549 return Outcome::Err(e);
2550 }
2551 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
2552 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2553 };
2554 match guard.execute_async(cx, &sql, &[]).await {
2555 Outcome::Ok(_) => Outcome::Ok(()),
2556 Outcome::Err(e) => Outcome::Err(e),
2557 Outcome::Cancelled(c) => Outcome::Cancelled(c),
2558 Outcome::Panicked(p) => Outcome::Panicked(p),
2559 }
2560 }
2561 }
2562
2563 #[allow(unused_assignments)]
2566 fn commit(mut self, cx: &Cx) -> impl Future<Output = Outcome<(), Error>> + Send {
2567 async move {
2568 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&self.inner), cx).await else {
2569 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2570 };
2571 match guard.execute_async(cx, "COMMIT", &[]).await {
2572 Outcome::Ok(_) => {
2573 self.committed = true;
2574 Outcome::Ok(())
2575 }
2576 Outcome::Err(e) => Outcome::Err(e),
2577 Outcome::Cancelled(c) => Outcome::Cancelled(c),
2578 Outcome::Panicked(p) => Outcome::Panicked(p),
2579 }
2580 }
2581 }
2582
2583 fn rollback(self, cx: &Cx) -> impl Future<Output = Outcome<(), Error>> + Send {
2584 async move {
2585 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&self.inner), cx).await else {
2586 return Outcome::Err(connection_error("Failed to acquire connection lock"));
2587 };
2588 match guard.execute_async(cx, "ROLLBACK", &[]).await {
2589 Outcome::Ok(_) => Outcome::Ok(()),
2590 Outcome::Err(e) => Outcome::Err(e),
2591 Outcome::Cancelled(c) => Outcome::Cancelled(c),
2592 Outcome::Panicked(p) => Outcome::Panicked(p),
2593 }
2594 }
2595 }
2596}
2597
2598impl<'conn> Drop for SharedMySqlTransaction<'conn> {
2599 fn drop(&mut self) {
2600 if !self.committed {
2601 #[cfg(debug_assertions)]
2609 eprintln!(
2610 "WARNING: SharedMySqlTransaction dropped without commit/rollback. \
2611 The MySQL transaction may still be open."
2612 );
2613 }
2614 }
2615}
2616
2617#[cfg(test)]
2618mod tests {
2619 use super::*;
2620
2621 #[test]
2622 fn test_connection_state() {
2623 assert_eq!(ConnectionState::Disconnected, ConnectionState::Disconnected);
2624 }
2625
2626 #[test]
2627 fn test_error_helpers() {
2628 let err = protocol_error("test");
2629 assert!(matches!(err, Error::Protocol(_)));
2630
2631 let err = auth_error("auth failed");
2632 assert!(matches!(err, Error::Connection(_)));
2633
2634 let err = connection_error("conn failed");
2635 assert!(matches!(err, Error::Connection(_)));
2636 }
2637
2638 #[test]
2639 fn test_validate_savepoint_name_valid() {
2640 assert!(validate_savepoint_name("sp1").is_ok());
2642 assert!(validate_savepoint_name("_savepoint").is_ok());
2643 assert!(validate_savepoint_name("SavePoint_123").is_ok());
2644 assert!(validate_savepoint_name("sp$test").is_ok());
2645 assert!(validate_savepoint_name("a").is_ok());
2646 assert!(validate_savepoint_name("_").is_ok());
2647 }
2648
2649 #[test]
2650 fn test_validate_savepoint_name_invalid() {
2651 assert!(validate_savepoint_name("").is_err());
2653
2654 assert!(validate_savepoint_name("1savepoint").is_err());
2656
2657 assert!(validate_savepoint_name("save-point").is_err());
2659 assert!(validate_savepoint_name("save point").is_err());
2660 assert!(validate_savepoint_name("save;drop table").is_err());
2661 assert!(validate_savepoint_name("sp'--").is_err());
2662
2663 let long_name = "a".repeat(65);
2665 assert!(validate_savepoint_name(&long_name).is_err());
2666 }
2667}