1#![allow(clippy::manual_async_fn)]
15#![allow(clippy::result_large_err)]
17
18use std::collections::HashMap;
19use std::future::Future;
20#[cfg(feature = "tls")]
21use std::io::{Read, Write};
22use std::sync::Arc;
23
24use asupersync::io::{AsyncRead, AsyncWrite, ReadBuf};
25use asupersync::net::TcpStream;
26use asupersync::sync::{Mutex, OwnedMutexGuard};
27use asupersync::{Cx, Outcome};
28
29use sqlmodel_core::connection::{Connection, IsolationLevel, PreparedStatement, TransactionOps};
30use sqlmodel_core::error::{
31 ConnectionError, ConnectionErrorKind, ProtocolError, QueryError, QueryErrorKind,
32};
33use sqlmodel_core::row::ColumnInfo;
34use sqlmodel_core::{Error, Row, Value};
35
36use crate::auth::ScramClient;
37use crate::config::{PgConfig, SslMode};
38use crate::connection::{ConnectionState, TransactionStatusState};
39use crate::protocol::{
40 BackendMessage, DescribeKind, ErrorFields, FrontendMessage, MessageReader, MessageWriter,
41 PROTOCOL_VERSION,
42};
43use crate::types::{Format, decode_value, encode_value};
44
45#[cfg(feature = "tls")]
46use crate::tls;
47
48#[allow(clippy::large_enum_variant)]
51enum PgAsyncStream {
52 Plain(TcpStream),
53 #[cfg(feature = "tls")]
54 Tls(AsyncTlsStream),
55 #[cfg(feature = "tls")]
56 Closed,
57}
58
59impl PgAsyncStream {
60 #[cfg(feature = "tls")]
61 async fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
62 match self {
63 PgAsyncStream::Plain(s) => read_exact_plain_async(s, buf).await,
64 #[cfg(feature = "tls")]
65 PgAsyncStream::Tls(s) => s.read_exact(buf).await,
66 #[cfg(feature = "tls")]
67 PgAsyncStream::Closed => Err(std::io::Error::new(
68 std::io::ErrorKind::NotConnected,
69 "connection closed",
70 )),
71 }
72 }
73
74 async fn read_some(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
75 match self {
76 PgAsyncStream::Plain(s) => read_some_plain_async(s, buf).await,
77 #[cfg(feature = "tls")]
78 PgAsyncStream::Tls(s) => s.read_plain(buf).await,
79 #[cfg(feature = "tls")]
80 PgAsyncStream::Closed => Err(std::io::Error::new(
81 std::io::ErrorKind::NotConnected,
82 "connection closed",
83 )),
84 }
85 }
86
87 async fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
88 match self {
89 PgAsyncStream::Plain(s) => write_all_plain_async(s, buf).await,
90 #[cfg(feature = "tls")]
91 PgAsyncStream::Tls(s) => s.write_all(buf).await,
92 #[cfg(feature = "tls")]
93 PgAsyncStream::Closed => Err(std::io::Error::new(
94 std::io::ErrorKind::NotConnected,
95 "connection closed",
96 )),
97 }
98 }
99
100 async fn flush(&mut self) -> std::io::Result<()> {
101 match self {
102 PgAsyncStream::Plain(s) => flush_plain_async(s).await,
103 #[cfg(feature = "tls")]
104 PgAsyncStream::Tls(s) => s.flush().await,
105 #[cfg(feature = "tls")]
106 PgAsyncStream::Closed => Err(std::io::Error::new(
107 std::io::ErrorKind::NotConnected,
108 "connection closed",
109 )),
110 }
111 }
112}
113
114#[cfg(feature = "tls")]
115struct AsyncTlsStream {
116 tcp: TcpStream,
117 tls: rustls::ClientConnection,
118}
119
120#[cfg(feature = "tls")]
121impl AsyncTlsStream {
122 async fn handshake(mut tcp: TcpStream, ssl_mode: SslMode, host: &str) -> Result<Self, Error> {
123 let config = tls::build_client_config(ssl_mode)?;
124 let server_name = tls::server_name(host)?;
125 let mut tls = rustls::ClientConnection::new(std::sync::Arc::new(config), server_name)
126 .map_err(|e| connection_error(format!("Failed to create TLS connection: {e}")))?;
127
128 while tls.is_handshaking() {
129 while tls.wants_write() {
130 let mut out = Vec::new();
131 tls.write_tls(&mut out)
132 .map_err(|e| connection_error(format!("TLS handshake write_tls error: {e}")))?;
133 if !out.is_empty() {
134 write_all_plain_async(&mut tcp, &out).await.map_err(|e| {
135 Error::Connection(ConnectionError {
136 kind: ConnectionErrorKind::Disconnected,
137 message: format!("TLS handshake write error: {e}"),
138 source: Some(Box::new(e)),
139 })
140 })?;
141 }
142 }
143
144 if tls.wants_read() {
145 let mut buf = [0u8; 8192];
146 let n = read_some_plain_async(&mut tcp, &mut buf)
147 .await
148 .map_err(|e| {
149 Error::Connection(ConnectionError {
150 kind: ConnectionErrorKind::Disconnected,
151 message: format!("TLS handshake read error: {e}"),
152 source: Some(Box::new(e)),
153 })
154 })?;
155 if n == 0 {
156 return Err(connection_error("Connection closed during TLS handshake"));
157 }
158
159 let mut cursor = std::io::Cursor::new(&buf[..n]);
160 tls.read_tls(&mut cursor)
161 .map_err(|e| connection_error(format!("TLS handshake read_tls error: {e}")))?;
162 tls.process_new_packets()
163 .map_err(|e| connection_error(format!("TLS handshake error: {e}")))?;
164 }
165 }
166
167 Ok(Self { tcp, tls })
168 }
169
170 async fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
171 let mut read = 0;
172 while read < buf.len() {
173 let n = self.read_plain(&mut buf[read..]).await?;
174 if n == 0 {
175 return Err(std::io::Error::new(
176 std::io::ErrorKind::UnexpectedEof,
177 "connection closed",
178 ));
179 }
180 read += n;
181 }
182 Ok(())
183 }
184
185 async fn read_plain(&mut self, out: &mut [u8]) -> std::io::Result<usize> {
186 loop {
187 match self.tls.reader().read(out) {
188 Ok(n) if n > 0 => return Ok(n),
189 Ok(_) => {}
190 Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {}
191 Err(e) => return Err(e),
192 }
193
194 if !self.tls.wants_read() {
195 return Ok(0);
196 }
197
198 let mut enc = [0u8; 8192];
199 let n = read_some_plain_async(&mut self.tcp, &mut enc).await?;
200 if n == 0 {
201 return Ok(0);
202 }
203
204 let mut cursor = std::io::Cursor::new(&enc[..n]);
205 self.tls.read_tls(&mut cursor)?;
206 self.tls
207 .process_new_packets()
208 .map_err(|e| std::io::Error::other(format!("TLS error: {e}")))?;
209 }
210 }
211
212 async fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
213 let mut written = 0;
214 while written < buf.len() {
215 let n = self.tls.writer().write(&buf[written..])?;
216 if n == 0 {
217 return Err(std::io::Error::new(
218 std::io::ErrorKind::WriteZero,
219 "TLS write zero",
220 ));
221 }
222 written += n;
223 self.flush().await?;
224 }
225 Ok(())
226 }
227
228 async fn flush(&mut self) -> std::io::Result<()> {
229 self.tls.writer().flush()?;
230 while self.tls.wants_write() {
231 let mut out = Vec::new();
232 self.tls.write_tls(&mut out)?;
233 if !out.is_empty() {
234 write_all_plain_async(&mut self.tcp, &out).await?;
235 }
236 }
237 flush_plain_async(&mut self.tcp).await
238 }
239}
240
241#[cfg(feature = "tls")]
242async fn read_exact_plain_async(stream: &mut TcpStream, buf: &mut [u8]) -> std::io::Result<()> {
243 let mut read = 0;
244 while read < buf.len() {
245 let n = read_some_plain_async(stream, &mut buf[read..]).await?;
246 if n == 0 {
247 return Err(std::io::Error::new(
248 std::io::ErrorKind::UnexpectedEof,
249 "connection closed",
250 ));
251 }
252 read += n;
253 }
254 Ok(())
255}
256
257async fn read_some_plain_async(stream: &mut TcpStream, buf: &mut [u8]) -> std::io::Result<usize> {
258 let mut read_buf = ReadBuf::new(buf);
259 std::future::poll_fn(|cx| std::pin::Pin::new(&mut *stream).poll_read(cx, &mut read_buf))
260 .await?;
261 Ok(read_buf.filled().len())
262}
263
264async fn write_all_plain_async(stream: &mut TcpStream, buf: &[u8]) -> std::io::Result<()> {
265 let mut written = 0;
266 while written < buf.len() {
267 let n = std::future::poll_fn(|cx| {
268 std::pin::Pin::new(&mut *stream).poll_write(cx, &buf[written..])
269 })
270 .await?;
271 if n == 0 {
272 return Err(std::io::Error::new(
273 std::io::ErrorKind::WriteZero,
274 "connection closed",
275 ));
276 }
277 written += n;
278 }
279 Ok(())
280}
281
282async fn flush_plain_async(stream: &mut TcpStream) -> std::io::Result<()> {
283 std::future::poll_fn(|cx| std::pin::Pin::new(&mut *stream).poll_flush(cx)).await
284}
285
286pub struct PgAsyncConnection {
291 stream: PgAsyncStream,
292 state: ConnectionState,
293 process_id: i32,
294 secret_key: i32,
295 parameters: HashMap<String, String>,
296 next_prepared_id: u64,
297 prepared: HashMap<u64, PgPreparedMeta>,
298 config: PgConfig,
299 reader: MessageReader,
300 writer: MessageWriter,
301 read_buf: Vec<u8>,
302}
303
304#[derive(Debug, Clone)]
305struct PgPreparedMeta {
306 name: String,
307 param_type_oids: Vec<u32>,
308}
309
310impl std::fmt::Debug for PgAsyncConnection {
311 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312 f.debug_struct("PgAsyncConnection")
313 .field("state", &self.state)
314 .field("process_id", &self.process_id)
315 .field("host", &self.config.host)
316 .field("port", &self.config.port)
317 .field("database", &self.config.database)
318 .finish_non_exhaustive()
319 }
320}
321
322impl PgAsyncConnection {
323 pub async fn connect(_cx: &Cx, config: PgConfig) -> Outcome<Self, Error> {
325 let addr = config.socket_addr();
326 let socket_addr: std::net::SocketAddr = match addr.parse() {
327 Ok(a) => a,
328 Err(e) => {
329 return Outcome::Err(Error::Connection(ConnectionError {
330 kind: ConnectionErrorKind::Connect,
331 message: format!("Invalid socket address: {}", e),
332 source: None,
333 }));
334 }
335 };
336
337 let stream = match TcpStream::connect_timeout(socket_addr, config.connect_timeout).await {
338 Ok(s) => s,
339 Err(e) => {
340 let kind = if e.kind() == std::io::ErrorKind::ConnectionRefused {
341 ConnectionErrorKind::Refused
342 } else {
343 ConnectionErrorKind::Connect
344 };
345 return Outcome::Err(Error::Connection(ConnectionError {
346 kind,
347 message: format!("Failed to connect to {}: {}", addr, e),
348 source: Some(Box::new(e)),
349 }));
350 }
351 };
352
353 stream.set_nodelay(true).ok();
354
355 let mut conn = Self {
356 stream: PgAsyncStream::Plain(stream),
357 state: ConnectionState::Connecting,
358 process_id: 0,
359 secret_key: 0,
360 parameters: HashMap::new(),
361 next_prepared_id: 1,
362 prepared: HashMap::new(),
363 config,
364 reader: MessageReader::new(),
365 writer: MessageWriter::new(),
366 read_buf: vec![0u8; 8192],
367 };
368
369 if conn.config.ssl_mode.should_try_ssl() {
371 #[cfg(feature = "tls")]
372 match conn.negotiate_ssl().await {
373 Outcome::Ok(()) => {}
374 Outcome::Err(e) => return Outcome::Err(e),
375 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
376 Outcome::Panicked(p) => return Outcome::Panicked(p),
377 }
378
379 #[cfg(not(feature = "tls"))]
380 if conn.config.ssl_mode != SslMode::Prefer {
381 return Outcome::Err(connection_error(
382 "TLS requested but 'sqlmodel-postgres' was built without feature 'tls'",
383 ));
384 }
385 }
386
387 if let Outcome::Err(e) = conn.send_startup().await {
389 return Outcome::Err(e);
390 }
391 conn.state = ConnectionState::Authenticating;
392
393 match conn.handle_auth().await {
394 Outcome::Ok(()) => {}
395 Outcome::Err(e) => return Outcome::Err(e),
396 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
397 Outcome::Panicked(p) => return Outcome::Panicked(p),
398 }
399
400 match conn.read_startup_messages().await {
401 Outcome::Ok(()) => Outcome::Ok(conn),
402 Outcome::Err(e) => Outcome::Err(e),
403 Outcome::Cancelled(r) => Outcome::Cancelled(r),
404 Outcome::Panicked(p) => Outcome::Panicked(p),
405 }
406 }
407
408 pub async fn query_async(
410 &mut self,
411 cx: &Cx,
412 sql: &str,
413 params: &[Value],
414 ) -> Outcome<Vec<Row>, Error> {
415 match self.run_extended(cx, sql, params).await {
416 Outcome::Ok(result) => Outcome::Ok(result.rows),
417 Outcome::Err(e) => Outcome::Err(e),
418 Outcome::Cancelled(r) => Outcome::Cancelled(r),
419 Outcome::Panicked(p) => Outcome::Panicked(p),
420 }
421 }
422
423 pub async fn execute_async(
425 &mut self,
426 cx: &Cx,
427 sql: &str,
428 params: &[Value],
429 ) -> Outcome<u64, Error> {
430 match self.run_extended(cx, sql, params).await {
431 Outcome::Ok(result) => {
432 Outcome::Ok(parse_rows_affected(result.command_tag.as_deref()).unwrap_or(0))
433 }
434 Outcome::Err(e) => Outcome::Err(e),
435 Outcome::Cancelled(r) => Outcome::Cancelled(r),
436 Outcome::Panicked(p) => Outcome::Panicked(p),
437 }
438 }
439
440 pub async fn insert_async(
446 &mut self,
447 cx: &Cx,
448 sql: &str,
449 params: &[Value],
450 ) -> Outcome<i64, Error> {
451 let result = match self.run_extended(cx, sql, params).await {
452 Outcome::Ok(r) => r,
453 Outcome::Err(e) => return Outcome::Err(e),
454 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
455 Outcome::Panicked(p) => return Outcome::Panicked(p),
456 };
457
458 let Some(row) = result.rows.first() else {
459 return Outcome::Err(query_error_msg(
460 "INSERT did not return an id; add `RETURNING id`",
461 QueryErrorKind::Database,
462 ));
463 };
464 let Some(id_value) = row.get(0) else {
465 return Outcome::Err(query_error_msg(
466 "INSERT result row missing id column",
467 QueryErrorKind::Database,
468 ));
469 };
470 match id_value.as_i64() {
471 Some(v) => Outcome::Ok(v),
472 None => Outcome::Err(query_error_msg(
473 "INSERT returned non-integer id",
474 QueryErrorKind::Database,
475 )),
476 }
477 }
478
479 pub async fn ping_async(&mut self, cx: &Cx) -> Outcome<(), Error> {
481 self.execute_async(cx, "SELECT 1", &[]).await.map(|_| ())
482 }
483
484 pub async fn close_async(&mut self, cx: &Cx) -> Outcome<(), Error> {
486 let _ = self.send_message(cx, &FrontendMessage::Terminate).await;
491 self.state = ConnectionState::Closed;
492 Outcome::Ok(())
493 }
494
495 pub async fn prepare_async(&mut self, cx: &Cx, sql: &str) -> Outcome<PreparedStatement, Error> {
499 let stmt_id = self.next_prepared_id;
500 self.next_prepared_id = self.next_prepared_id.saturating_add(1);
501 let stmt_name = format!("sqlmodel_stmt_{stmt_id}");
502
503 if let Outcome::Err(e) = self
504 .send_message(
505 cx,
506 &FrontendMessage::Parse {
507 name: stmt_name.clone(),
508 query: sql.to_string(),
509 param_types: Vec::new(),
512 },
513 )
514 .await
515 {
516 return Outcome::Err(e);
517 }
518
519 if let Outcome::Err(e) = self
520 .send_message(
521 cx,
522 &FrontendMessage::Describe {
523 kind: DescribeKind::Statement,
524 name: stmt_name.clone(),
525 },
526 )
527 .await
528 {
529 return Outcome::Err(e);
530 }
531
532 if let Outcome::Err(e) = self.send_message(cx, &FrontendMessage::Sync).await {
533 return Outcome::Err(e);
534 }
535
536 let mut param_type_oids: Option<Vec<u32>> = None;
537 let mut columns: Option<Vec<String>> = None;
538
539 loop {
540 let msg = match self.receive_message(cx).await {
541 Outcome::Ok(m) => m,
542 Outcome::Err(e) => return Outcome::Err(e),
543 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
544 Outcome::Panicked(p) => return Outcome::Panicked(p),
545 };
546
547 match msg {
548 BackendMessage::ParseComplete
549 | BackendMessage::BindComplete
550 | BackendMessage::CloseComplete
551 | BackendMessage::NoData
552 | BackendMessage::EmptyQueryResponse => {}
553 BackendMessage::ParameterDescription(oids) => {
554 param_type_oids = Some(oids);
555 }
556 BackendMessage::RowDescription(desc) => {
557 columns = Some(desc.iter().map(|f| f.name.clone()).collect());
558 }
559 BackendMessage::ReadyForQuery(status) => {
560 self.state = ConnectionState::Ready(TransactionStatusState::from(status));
561 break;
562 }
563 BackendMessage::ErrorResponse(e) => {
564 self.state = ConnectionState::Error;
565 return Outcome::Err(error_from_fields(&e));
566 }
567 BackendMessage::NoticeResponse(_notice) => {}
568 other => {
569 return Outcome::Err(protocol_error(format!(
570 "Unexpected message during prepare: {other:?}"
571 )));
572 }
573 }
574 }
575
576 let param_type_oids = param_type_oids.unwrap_or_default();
577 self.prepared.insert(
578 stmt_id,
579 PgPreparedMeta {
580 name: stmt_name,
581 param_type_oids: param_type_oids.clone(),
582 },
583 );
584
585 match columns {
586 Some(cols) => Outcome::Ok(PreparedStatement::with_columns(
587 stmt_id,
588 sql.to_string(),
589 param_type_oids.len(),
590 cols,
591 )),
592 None => Outcome::Ok(PreparedStatement::new(
593 stmt_id,
594 sql.to_string(),
595 param_type_oids.len(),
596 )),
597 }
598 }
599
600 pub async fn query_prepared_async(
601 &mut self,
602 cx: &Cx,
603 stmt: &PreparedStatement,
604 params: &[Value],
605 ) -> Outcome<Vec<Row>, Error> {
606 let meta = match self.prepared.get(&stmt.id()) {
607 Some(m) => m.clone(),
608 None => {
609 return Outcome::Err(query_error_msg(
610 format!("Unknown prepared statement id {}", stmt.id()),
611 QueryErrorKind::Database,
612 ));
613 }
614 };
615
616 if meta.param_type_oids.len() != params.len() {
617 return Outcome::Err(query_error_msg(
618 format!(
619 "Prepared statement expects {} params, got {}",
620 meta.param_type_oids.len(),
621 params.len()
622 ),
623 QueryErrorKind::Database,
624 ));
625 }
626
627 match self.run_prepared(cx, &meta, params).await {
628 Outcome::Ok(result) => Outcome::Ok(result.rows),
629 Outcome::Err(e) => Outcome::Err(e),
630 Outcome::Cancelled(r) => Outcome::Cancelled(r),
631 Outcome::Panicked(p) => Outcome::Panicked(p),
632 }
633 }
634
635 pub async fn execute_prepared_async(
636 &mut self,
637 cx: &Cx,
638 stmt: &PreparedStatement,
639 params: &[Value],
640 ) -> Outcome<u64, Error> {
641 let meta = match self.prepared.get(&stmt.id()) {
642 Some(m) => m.clone(),
643 None => {
644 return Outcome::Err(query_error_msg(
645 format!("Unknown prepared statement id {}", stmt.id()),
646 QueryErrorKind::Database,
647 ));
648 }
649 };
650
651 if meta.param_type_oids.len() != params.len() {
652 return Outcome::Err(query_error_msg(
653 format!(
654 "Prepared statement expects {} params, got {}",
655 meta.param_type_oids.len(),
656 params.len()
657 ),
658 QueryErrorKind::Database,
659 ));
660 }
661
662 match self.run_prepared(cx, &meta, params).await {
663 Outcome::Ok(result) => {
664 Outcome::Ok(parse_rows_affected(result.command_tag.as_deref()).unwrap_or(0))
665 }
666 Outcome::Err(e) => Outcome::Err(e),
667 Outcome::Cancelled(r) => Outcome::Cancelled(r),
668 Outcome::Panicked(p) => Outcome::Panicked(p),
669 }
670 }
671
672 async fn read_extended_result(&mut self, cx: &Cx) -> Outcome<PgQueryResult, Error> {
675 let mut field_descs: Option<Vec<crate::protocol::FieldDescription>> = None;
677 let mut columns: Option<Arc<ColumnInfo>> = None;
678 let mut rows: Vec<Row> = Vec::new();
679 let mut command_tag: Option<String> = None;
680
681 loop {
682 let msg = match self.receive_message(cx).await {
683 Outcome::Ok(m) => m,
684 Outcome::Err(e) => return Outcome::Err(e),
685 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
686 Outcome::Panicked(p) => return Outcome::Panicked(p),
687 };
688
689 match msg {
690 BackendMessage::ParseComplete
691 | BackendMessage::BindComplete
692 | BackendMessage::CloseComplete
693 | BackendMessage::ParameterDescription(_)
694 | BackendMessage::NoData
695 | BackendMessage::PortalSuspended
696 | BackendMessage::EmptyQueryResponse => {}
697 BackendMessage::RowDescription(desc) => {
698 let names: Vec<String> = desc.iter().map(|f| f.name.clone()).collect();
699 columns = Some(Arc::new(ColumnInfo::new(names)));
700 field_descs = Some(desc);
701 }
702 BackendMessage::DataRow(raw_values) => {
703 let Some(ref desc) = field_descs else {
704 return Outcome::Err(protocol_error(
705 "DataRow received before RowDescription",
706 ));
707 };
708 let Some(ref cols) = columns else {
709 return Outcome::Err(protocol_error("Row column metadata missing"));
710 };
711 if raw_values.len() != desc.len() {
712 return Outcome::Err(protocol_error("DataRow field count mismatch"));
713 }
714
715 let mut values = Vec::with_capacity(raw_values.len());
716 for (i, raw) in raw_values.into_iter().enumerate() {
717 match raw {
718 None => values.push(Value::Null),
719 Some(bytes) => {
720 let field = &desc[i];
721 let format = Format::from_code(field.format);
722 let decoded = match decode_value(
723 field.type_oid,
724 Some(bytes.as_slice()),
725 format,
726 ) {
727 Ok(v) => v,
728 Err(e) => return Outcome::Err(e),
729 };
730 values.push(decoded);
731 }
732 }
733 }
734 rows.push(Row::with_columns(Arc::clone(cols), values));
735 }
736 BackendMessage::CommandComplete(tag) => {
737 command_tag = Some(tag);
738 }
739 BackendMessage::ReadyForQuery(status) => {
740 self.state = ConnectionState::Ready(TransactionStatusState::from(status));
741 break;
742 }
743 BackendMessage::ErrorResponse(e) => {
744 self.state = ConnectionState::Error;
745 return Outcome::Err(error_from_fields(&e));
746 }
747 BackendMessage::NoticeResponse(_notice) => {}
748 _ => {}
749 }
750 }
751
752 Outcome::Ok(PgQueryResult { rows, command_tag })
753 }
754
755 async fn run_extended(
756 &mut self,
757 cx: &Cx,
758 sql: &str,
759 params: &[Value],
760 ) -> Outcome<PgQueryResult, Error> {
761 let mut param_types = Vec::with_capacity(params.len());
763 let mut param_values = Vec::with_capacity(params.len());
764
765 for v in params {
766 if matches!(v, Value::Null) {
767 param_types.push(0);
768 param_values.push(None);
769 continue;
770 }
771 match encode_value(v, Format::Text) {
772 Ok((bytes, oid)) => {
773 param_types.push(oid);
774 param_values.push(Some(bytes));
775 }
776 Err(e) => return Outcome::Err(e),
777 }
778 }
779
780 if let Outcome::Err(e) = self
782 .send_message(
783 cx,
784 &FrontendMessage::Parse {
785 name: String::new(),
786 query: sql.to_string(),
787 param_types,
788 },
789 )
790 .await
791 {
792 return Outcome::Err(e);
793 }
794
795 let param_formats = if params.is_empty() {
796 Vec::new()
797 } else {
798 vec![Format::Text.code()]
799 };
800 if let Outcome::Err(e) = self
801 .send_message(
802 cx,
803 &FrontendMessage::Bind {
804 portal: String::new(),
805 statement: String::new(),
806 param_formats,
807 params: param_values,
808 result_formats: Vec::new(),
810 },
811 )
812 .await
813 {
814 return Outcome::Err(e);
815 }
816
817 if let Outcome::Err(e) = self
818 .send_message(
819 cx,
820 &FrontendMessage::Describe {
821 kind: DescribeKind::Portal,
822 name: String::new(),
823 },
824 )
825 .await
826 {
827 return Outcome::Err(e);
828 }
829
830 if let Outcome::Err(e) = self
831 .send_message(
832 cx,
833 &FrontendMessage::Execute {
834 portal: String::new(),
835 max_rows: 0,
836 },
837 )
838 .await
839 {
840 return Outcome::Err(e);
841 }
842
843 if let Outcome::Err(e) = self.send_message(cx, &FrontendMessage::Sync).await {
844 return Outcome::Err(e);
845 }
846 self.read_extended_result(cx).await
847 }
848
849 async fn run_prepared(
850 &mut self,
851 cx: &Cx,
852 meta: &PgPreparedMeta,
853 params: &[Value],
854 ) -> Outcome<PgQueryResult, Error> {
855 let mut param_values = Vec::with_capacity(params.len());
856
857 for (i, v) in params.iter().enumerate() {
858 if matches!(v, Value::Null) {
859 param_values.push(None);
860 continue;
861 }
862 match encode_value(v, Format::Text) {
863 Ok((bytes, oid)) => {
864 let expected = meta.param_type_oids.get(i).copied().unwrap_or(0);
865 if expected != 0 && expected != oid {
866 return Outcome::Err(query_error_msg(
867 format!(
868 "Prepared statement param {} expects type OID {}, got {}",
869 i + 1,
870 expected,
871 oid
872 ),
873 QueryErrorKind::Database,
874 ));
875 }
876 param_values.push(Some(bytes));
877 }
878 Err(e) => return Outcome::Err(e),
879 }
880 }
881
882 let param_formats = if params.is_empty() {
883 Vec::new()
884 } else {
885 vec![Format::Text.code()]
886 };
887
888 if let Outcome::Err(e) = self
889 .send_message(
890 cx,
891 &FrontendMessage::Bind {
892 portal: String::new(),
893 statement: meta.name.clone(),
894 param_formats,
895 params: param_values,
896 result_formats: Vec::new(),
897 },
898 )
899 .await
900 {
901 return Outcome::Err(e);
902 }
903
904 if let Outcome::Err(e) = self
905 .send_message(
906 cx,
907 &FrontendMessage::Describe {
908 kind: DescribeKind::Portal,
909 name: String::new(),
910 },
911 )
912 .await
913 {
914 return Outcome::Err(e);
915 }
916
917 if let Outcome::Err(e) = self
918 .send_message(
919 cx,
920 &FrontendMessage::Execute {
921 portal: String::new(),
922 max_rows: 0,
923 },
924 )
925 .await
926 {
927 return Outcome::Err(e);
928 }
929
930 if let Outcome::Err(e) = self.send_message(cx, &FrontendMessage::Sync).await {
931 return Outcome::Err(e);
932 }
933
934 self.read_extended_result(cx).await
935 }
936
937 #[cfg(feature = "tls")]
940 async fn negotiate_ssl(&mut self) -> Outcome<(), Error> {
941 if let Outcome::Err(e) = self.send_message_no_cx(&FrontendMessage::SSLRequest).await {
943 return Outcome::Err(e);
944 }
945
946 let mut buf = [0u8; 1];
948 if let Err(e) = self.stream.read_exact(&mut buf).await {
949 return Outcome::Err(Error::Connection(ConnectionError {
950 kind: ConnectionErrorKind::Ssl,
951 message: format!("Failed to read SSL response: {}", e),
952 source: Some(Box::new(e)),
953 }));
954 }
955
956 match buf[0] {
957 b'S' => {
958 #[cfg(feature = "tls")]
959 {
960 let plain = match std::mem::replace(&mut self.stream, PgAsyncStream::Closed) {
961 PgAsyncStream::Plain(s) => s,
962 other => {
963 self.stream = other;
964 return Outcome::Err(connection_error(
965 "TLS upgrade requires a plain TCP stream",
966 ));
967 }
968 };
969
970 let tls_stream = match AsyncTlsStream::handshake(
971 plain,
972 self.config.ssl_mode,
973 &self.config.host,
974 )
975 .await
976 {
977 Ok(s) => s,
978 Err(e) => return Outcome::Err(e),
979 };
980
981 self.stream = PgAsyncStream::Tls(tls_stream);
982 Outcome::Ok(())
983 }
984
985 #[cfg(not(feature = "tls"))]
986 {
987 Outcome::Err(connection_error(
988 "TLS requested but 'sqlmodel-postgres' was built without feature 'tls'",
989 ))
990 }
991 }
992 b'N' => {
993 if self.config.ssl_mode.is_required() {
994 Outcome::Err(Error::Connection(ConnectionError {
995 kind: ConnectionErrorKind::Ssl,
996 message: "Server does not support SSL".to_string(),
997 source: None,
998 }))
999 } else {
1000 Outcome::Ok(())
1001 }
1002 }
1003 other => Outcome::Err(Error::Connection(ConnectionError {
1004 kind: ConnectionErrorKind::Ssl,
1005 message: format!("Unexpected SSL response: 0x{other:02x}"),
1006 source: None,
1007 })),
1008 }
1009 }
1010
1011 async fn send_startup(&mut self) -> Outcome<(), Error> {
1012 let params = self.config.startup_params();
1013 self.send_message_no_cx(&FrontendMessage::Startup {
1014 version: PROTOCOL_VERSION,
1015 params,
1016 })
1017 .await
1018 }
1019
1020 fn require_auth_value(&self, message: &'static str) -> Outcome<&str, Error> {
1021 match self.config.password.as_deref() {
1023 Some(password) => Outcome::Ok(password),
1024 None => Outcome::Err(auth_error(message)),
1025 }
1026 }
1027
1028 async fn handle_auth(&mut self) -> Outcome<(), Error> {
1029 loop {
1030 let msg = match self.receive_message_no_cx().await {
1031 Outcome::Ok(m) => m,
1032 Outcome::Err(e) => return Outcome::Err(e),
1033 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1034 Outcome::Panicked(p) => return Outcome::Panicked(p),
1035 };
1036
1037 match msg {
1038 BackendMessage::AuthenticationOk => return Outcome::Ok(()),
1039 BackendMessage::AuthenticationCleartextPassword => {
1040 let auth_value = match self
1041 .require_auth_value("Authentication value required but not provided")
1042 {
1043 Outcome::Ok(password) => password,
1044 Outcome::Err(e) => return Outcome::Err(e),
1045 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1046 Outcome::Panicked(p) => return Outcome::Panicked(p),
1047 };
1048 if let Outcome::Err(e) = self
1049 .send_message_no_cx(&FrontendMessage::PasswordMessage(
1050 auth_value.to_string(),
1051 ))
1052 .await
1053 {
1054 return Outcome::Err(e);
1055 }
1056 }
1057 BackendMessage::AuthenticationMD5Password(salt) => {
1058 let auth_value = match self
1059 .require_auth_value("Authentication value required but not provided")
1060 {
1061 Outcome::Ok(password) => password,
1062 Outcome::Err(e) => return Outcome::Err(e),
1063 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1064 Outcome::Panicked(p) => return Outcome::Panicked(p),
1065 };
1066 let hash = md5_password(&self.config.user, auth_value, salt);
1067 if let Outcome::Err(e) = self
1068 .send_message_no_cx(&FrontendMessage::PasswordMessage(hash))
1069 .await
1070 {
1071 return Outcome::Err(e);
1072 }
1073 }
1074 BackendMessage::AuthenticationSASL(mechanisms) => {
1075 if mechanisms.contains(&"SCRAM-SHA-256".to_string()) {
1076 match self.scram_auth().await {
1077 Outcome::Ok(()) => {}
1078 Outcome::Err(e) => return Outcome::Err(e),
1079 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1080 Outcome::Panicked(p) => return Outcome::Panicked(p),
1081 }
1082 } else {
1083 return Outcome::Err(auth_error(format!(
1084 "Unsupported SASL mechanisms: {:?}",
1085 mechanisms
1086 )));
1087 }
1088 }
1089 BackendMessage::ErrorResponse(e) => {
1090 self.state = ConnectionState::Error;
1091 return Outcome::Err(error_from_fields(&e));
1092 }
1093 other => {
1094 return Outcome::Err(protocol_error(format!(
1095 "Unexpected message during auth: {other:?}"
1096 )));
1097 }
1098 }
1099 }
1100 }
1101
1102 async fn scram_auth(&mut self) -> Outcome<(), Error> {
1103 let auth_value =
1104 match self.require_auth_value("Authentication value required for SCRAM-SHA-256") {
1105 Outcome::Ok(password) => password,
1106 Outcome::Err(e) => return Outcome::Err(e),
1107 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1108 Outcome::Panicked(p) => return Outcome::Panicked(p),
1109 };
1110
1111 let mut client = ScramClient::new(&self.config.user, auth_value);
1112
1113 let client_first = client.client_first();
1115 if let Outcome::Err(e) = self
1116 .send_message_no_cx(&FrontendMessage::SASLInitialResponse {
1117 mechanism: "SCRAM-SHA-256".to_string(),
1118 data: client_first,
1119 })
1120 .await
1121 {
1122 return Outcome::Err(e);
1123 }
1124
1125 let msg = match self.receive_message_no_cx().await {
1127 Outcome::Ok(m) => m,
1128 Outcome::Err(e) => return Outcome::Err(e),
1129 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1130 Outcome::Panicked(p) => return Outcome::Panicked(p),
1131 };
1132 let server_first_data = match msg {
1133 BackendMessage::AuthenticationSASLContinue(data) => data,
1134 BackendMessage::ErrorResponse(e) => {
1135 self.state = ConnectionState::Error;
1136 return Outcome::Err(error_from_fields(&e));
1137 }
1138 other => {
1139 return Outcome::Err(protocol_error(format!(
1140 "Expected SASL continue, got: {other:?}"
1141 )));
1142 }
1143 };
1144
1145 let client_final = match client.process_server_first(&server_first_data) {
1147 Ok(v) => v,
1148 Err(e) => return Outcome::Err(e),
1149 };
1150 if let Outcome::Err(e) = self
1151 .send_message_no_cx(&FrontendMessage::SASLResponse(client_final))
1152 .await
1153 {
1154 return Outcome::Err(e);
1155 }
1156
1157 let msg = match self.receive_message_no_cx().await {
1159 Outcome::Ok(m) => m,
1160 Outcome::Err(e) => return Outcome::Err(e),
1161 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1162 Outcome::Panicked(p) => return Outcome::Panicked(p),
1163 };
1164 let server_final_data = match msg {
1165 BackendMessage::AuthenticationSASLFinal(data) => data,
1166 BackendMessage::ErrorResponse(e) => {
1167 self.state = ConnectionState::Error;
1168 return Outcome::Err(error_from_fields(&e));
1169 }
1170 other => {
1171 return Outcome::Err(protocol_error(format!(
1172 "Expected SASL final, got: {other:?}"
1173 )));
1174 }
1175 };
1176
1177 if let Err(e) = client.verify_server_final(&server_final_data) {
1178 return Outcome::Err(e);
1179 }
1180
1181 let msg = match self.receive_message_no_cx().await {
1183 Outcome::Ok(m) => m,
1184 Outcome::Err(e) => return Outcome::Err(e),
1185 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1186 Outcome::Panicked(p) => return Outcome::Panicked(p),
1187 };
1188 match msg {
1189 BackendMessage::AuthenticationOk => Outcome::Ok(()),
1190 BackendMessage::ErrorResponse(e) => {
1191 self.state = ConnectionState::Error;
1192 Outcome::Err(error_from_fields(&e))
1193 }
1194 other => Outcome::Err(protocol_error(format!(
1195 "Expected AuthenticationOk, got: {other:?}"
1196 ))),
1197 }
1198 }
1199
1200 async fn read_startup_messages(&mut self) -> Outcome<(), Error> {
1201 loop {
1202 let msg = match self.receive_message_no_cx().await {
1203 Outcome::Ok(m) => m,
1204 Outcome::Err(e) => return Outcome::Err(e),
1205 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1206 Outcome::Panicked(p) => return Outcome::Panicked(p),
1207 };
1208
1209 match msg {
1210 BackendMessage::BackendKeyData {
1211 process_id,
1212 secret_key,
1213 } => {
1214 self.process_id = process_id;
1215 self.secret_key = secret_key;
1216 }
1217 BackendMessage::ParameterStatus { name, value } => {
1218 self.parameters.insert(name, value);
1219 }
1220 BackendMessage::ReadyForQuery(status) => {
1221 self.state = ConnectionState::Ready(TransactionStatusState::from(status));
1222 return Outcome::Ok(());
1223 }
1224 BackendMessage::ErrorResponse(e) => {
1225 self.state = ConnectionState::Error;
1226 return Outcome::Err(error_from_fields(&e));
1227 }
1228 BackendMessage::NoticeResponse(_notice) => {}
1229 other => {
1230 return Outcome::Err(protocol_error(format!(
1231 "Unexpected startup message: {other:?}"
1232 )));
1233 }
1234 }
1235 }
1236 }
1237
1238 async fn send_message(&mut self, cx: &Cx, msg: &FrontendMessage) -> Outcome<(), Error> {
1241 if let Some(reason) = cx.cancel_reason() {
1243 return Outcome::Cancelled(reason);
1244 }
1245 self.send_message_no_cx(msg).await
1246 }
1247
1248 async fn receive_message(&mut self, cx: &Cx) -> Outcome<BackendMessage, Error> {
1249 if let Some(reason) = cx.cancel_reason() {
1250 return Outcome::Cancelled(reason);
1251 }
1252 self.receive_message_no_cx().await
1253 }
1254
1255 async fn send_message_no_cx(&mut self, msg: &FrontendMessage) -> Outcome<(), Error> {
1256 let data = self.writer.write(msg).to_vec();
1257
1258 if let Err(e) = self.stream.write_all(&data).await {
1259 self.state = ConnectionState::Error;
1260 return Outcome::Err(Error::Connection(ConnectionError {
1261 kind: ConnectionErrorKind::Disconnected,
1262 message: format!("Failed to write to server: {}", e),
1263 source: Some(Box::new(e)),
1264 }));
1265 }
1266
1267 if let Err(e) = self.stream.flush().await {
1268 self.state = ConnectionState::Error;
1269 return Outcome::Err(Error::Connection(ConnectionError {
1270 kind: ConnectionErrorKind::Disconnected,
1271 message: format!("Failed to flush stream: {}", e),
1272 source: Some(Box::new(e)),
1273 }));
1274 }
1275
1276 Outcome::Ok(())
1277 }
1278
1279 async fn receive_message_no_cx(&mut self) -> Outcome<BackendMessage, Error> {
1280 loop {
1281 match self.reader.next_message() {
1282 Ok(Some(msg)) => return Outcome::Ok(msg),
1283 Ok(None) => {}
1284 Err(e) => {
1285 self.state = ConnectionState::Error;
1286 return Outcome::Err(protocol_error(format!("Protocol error: {}", e)));
1287 }
1288 }
1289
1290 let n = match self.stream.read_some(&mut self.read_buf).await {
1291 Ok(n) => n,
1292 Err(e) => {
1293 self.state = ConnectionState::Error;
1294 return Outcome::Err(match e.kind() {
1295 std::io::ErrorKind::TimedOut | std::io::ErrorKind::WouldBlock => {
1296 Error::Timeout
1297 }
1298 _ => Error::Connection(ConnectionError {
1299 kind: ConnectionErrorKind::Disconnected,
1300 message: format!("Failed to read from server: {}", e),
1301 source: Some(Box::new(e)),
1302 }),
1303 });
1304 }
1305 };
1306
1307 if n == 0 {
1308 self.state = ConnectionState::Disconnected;
1309 return Outcome::Err(Error::Connection(ConnectionError {
1310 kind: ConnectionErrorKind::Disconnected,
1311 message: "Connection closed by server".to_string(),
1312 source: None,
1313 }));
1314 }
1315
1316 self.reader.push(&self.read_buf[..n]);
1324 }
1325 }
1326}
1327
1328pub struct SharedPgConnection {
1330 inner: Arc<Mutex<PgAsyncConnection>>,
1331}
1332
1333impl SharedPgConnection {
1334 pub fn new(conn: PgAsyncConnection) -> Self {
1335 Self {
1336 inner: Arc::new(Mutex::new(conn)),
1337 }
1338 }
1339
1340 pub async fn connect(cx: &Cx, config: PgConfig) -> Outcome<Self, Error> {
1341 match PgAsyncConnection::connect(cx, config).await {
1342 Outcome::Ok(conn) => Outcome::Ok(Self::new(conn)),
1343 Outcome::Err(e) => Outcome::Err(e),
1344 Outcome::Cancelled(r) => Outcome::Cancelled(r),
1345 Outcome::Panicked(p) => Outcome::Panicked(p),
1346 }
1347 }
1348
1349 pub fn inner(&self) -> &Arc<Mutex<PgAsyncConnection>> {
1350 &self.inner
1351 }
1352
1353 async fn begin_transaction_impl(
1354 &self,
1355 cx: &Cx,
1356 isolation: Option<IsolationLevel>,
1357 ) -> Outcome<SharedPgTransaction<'_>, Error> {
1358 let inner = Arc::clone(&self.inner);
1359 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1360 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1361 };
1362
1363 if let Some(level) = isolation {
1364 let sql = format!("SET TRANSACTION ISOLATION LEVEL {}", level.as_sql());
1365 match guard.execute_async(cx, &sql, &[]).await {
1366 Outcome::Ok(_) => {}
1367 Outcome::Err(e) => return Outcome::Err(e),
1368 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1369 Outcome::Panicked(p) => return Outcome::Panicked(p),
1370 }
1371 }
1372
1373 match guard.execute_async(cx, "BEGIN", &[]).await {
1374 Outcome::Ok(_) => {}
1375 Outcome::Err(e) => return Outcome::Err(e),
1376 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1377 Outcome::Panicked(p) => return Outcome::Panicked(p),
1378 }
1379
1380 drop(guard);
1381 Outcome::Ok(SharedPgTransaction {
1382 inner,
1383 committed: false,
1384 _marker: std::marker::PhantomData,
1385 })
1386 }
1387}
1388
1389impl Clone for SharedPgConnection {
1390 fn clone(&self) -> Self {
1391 Self {
1392 inner: Arc::clone(&self.inner),
1393 }
1394 }
1395}
1396
1397impl std::fmt::Debug for SharedPgConnection {
1398 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1399 f.debug_struct("SharedPgConnection")
1400 .field("inner", &"Arc<Mutex<PgAsyncConnection>>")
1401 .finish()
1402 }
1403}
1404
1405pub struct SharedPgTransaction<'conn> {
1406 inner: Arc<Mutex<PgAsyncConnection>>,
1407 committed: bool,
1408 _marker: std::marker::PhantomData<&'conn ()>,
1409}
1410
1411impl<'conn> Drop for SharedPgTransaction<'conn> {
1412 fn drop(&mut self) {
1413 if !self.committed {
1414 #[cfg(debug_assertions)]
1419 eprintln!(
1420 "WARNING: SharedPgTransaction dropped without commit/rollback. \
1421 The PostgreSQL transaction may still be open."
1422 );
1423 }
1424 }
1425}
1426
1427impl Connection for SharedPgConnection {
1428 type Tx<'conn>
1429 = SharedPgTransaction<'conn>
1430 where
1431 Self: 'conn;
1432
1433 fn dialect(&self) -> sqlmodel_core::Dialect {
1434 sqlmodel_core::Dialect::Postgres
1435 }
1436
1437 fn query(
1438 &self,
1439 cx: &Cx,
1440 sql: &str,
1441 params: &[Value],
1442 ) -> impl Future<Output = Outcome<Vec<Row>, Error>> + Send {
1443 let inner = Arc::clone(&self.inner);
1444 let sql = sql.to_string();
1445 let params = params.to_vec();
1446 async move {
1447 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1448 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1449 };
1450 guard.query_async(cx, &sql, ¶ms).await
1451 }
1452 }
1453
1454 fn query_one(
1455 &self,
1456 cx: &Cx,
1457 sql: &str,
1458 params: &[Value],
1459 ) -> impl Future<Output = Outcome<Option<Row>, Error>> + Send {
1460 let inner = Arc::clone(&self.inner);
1461 let sql = sql.to_string();
1462 let params = params.to_vec();
1463 async move {
1464 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1465 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1466 };
1467 let rows = match guard.query_async(cx, &sql, ¶ms).await {
1468 Outcome::Ok(r) => r,
1469 Outcome::Err(e) => return Outcome::Err(e),
1470 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1471 Outcome::Panicked(p) => return Outcome::Panicked(p),
1472 };
1473 Outcome::Ok(rows.into_iter().next())
1474 }
1475 }
1476
1477 fn execute(
1478 &self,
1479 cx: &Cx,
1480 sql: &str,
1481 params: &[Value],
1482 ) -> impl Future<Output = Outcome<u64, Error>> + Send {
1483 let inner = Arc::clone(&self.inner);
1484 let sql = sql.to_string();
1485 let params = params.to_vec();
1486 async move {
1487 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1488 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1489 };
1490 guard.execute_async(cx, &sql, ¶ms).await
1491 }
1492 }
1493
1494 fn insert(
1495 &self,
1496 cx: &Cx,
1497 sql: &str,
1498 params: &[Value],
1499 ) -> impl Future<Output = Outcome<i64, Error>> + Send {
1500 let inner = Arc::clone(&self.inner);
1501 let sql = sql.to_string();
1502 let params = params.to_vec();
1503 async move {
1504 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1505 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1506 };
1507 guard.insert_async(cx, &sql, ¶ms).await
1508 }
1509 }
1510
1511 fn batch(
1512 &self,
1513 cx: &Cx,
1514 statements: &[(String, Vec<Value>)],
1515 ) -> impl Future<Output = Outcome<Vec<u64>, Error>> + Send {
1516 let inner = Arc::clone(&self.inner);
1517 let statements = statements.to_vec();
1518 async move {
1519 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1520 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1521 };
1522 let mut results = Vec::with_capacity(statements.len());
1523 for (sql, params) in &statements {
1524 match guard.execute_async(cx, sql, params).await {
1525 Outcome::Ok(n) => results.push(n),
1526 Outcome::Err(e) => return Outcome::Err(e),
1527 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1528 Outcome::Panicked(p) => return Outcome::Panicked(p),
1529 }
1530 }
1531 Outcome::Ok(results)
1532 }
1533 }
1534
1535 fn begin(&self, cx: &Cx) -> impl Future<Output = Outcome<Self::Tx<'_>, Error>> + Send {
1536 self.begin_with(cx, IsolationLevel::default())
1537 }
1538
1539 fn begin_with(
1540 &self,
1541 cx: &Cx,
1542 isolation: IsolationLevel,
1543 ) -> impl Future<Output = Outcome<Self::Tx<'_>, Error>> + Send {
1544 self.begin_transaction_impl(cx, Some(isolation))
1545 }
1546
1547 fn prepare(
1548 &self,
1549 cx: &Cx,
1550 sql: &str,
1551 ) -> impl Future<Output = Outcome<PreparedStatement, Error>> + Send {
1552 let inner = Arc::clone(&self.inner);
1553 let sql = sql.to_string();
1554 async move {
1555 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1556 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1557 };
1558 guard.prepare_async(cx, &sql).await
1559 }
1560 }
1561
1562 fn query_prepared(
1563 &self,
1564 cx: &Cx,
1565 stmt: &PreparedStatement,
1566 params: &[Value],
1567 ) -> impl Future<Output = Outcome<Vec<Row>, Error>> + Send {
1568 let inner = Arc::clone(&self.inner);
1569 let stmt = stmt.clone();
1570 let params = params.to_vec();
1571 async move {
1572 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1573 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1574 };
1575 guard.query_prepared_async(cx, &stmt, ¶ms).await
1576 }
1577 }
1578
1579 fn execute_prepared(
1580 &self,
1581 cx: &Cx,
1582 stmt: &PreparedStatement,
1583 params: &[Value],
1584 ) -> impl Future<Output = Outcome<u64, Error>> + Send {
1585 let inner = Arc::clone(&self.inner);
1586 let stmt = stmt.clone();
1587 let params = params.to_vec();
1588 async move {
1589 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1590 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1591 };
1592 guard.execute_prepared_async(cx, &stmt, ¶ms).await
1593 }
1594 }
1595
1596 fn ping(&self, cx: &Cx) -> impl Future<Output = Outcome<(), Error>> + Send {
1597 let inner = Arc::clone(&self.inner);
1598 async move {
1599 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1600 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1601 };
1602 guard.ping_async(cx).await
1603 }
1604 }
1605
1606 async fn close(self, cx: &Cx) -> sqlmodel_core::Result<()> {
1607 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&self.inner), cx).await else {
1608 return Err(connection_error("Failed to acquire connection lock"));
1609 };
1610 match guard.close_async(cx).await {
1611 Outcome::Ok(()) => Ok(()),
1612 Outcome::Err(e) => Err(e),
1613 Outcome::Cancelled(r) => Err(Error::Query(QueryError {
1614 kind: QueryErrorKind::Cancelled,
1615 message: format!("Cancelled: {r:?}"),
1616 sqlstate: None,
1617 sql: None,
1618 detail: None,
1619 hint: None,
1620 position: None,
1621 source: None,
1622 })),
1623 Outcome::Panicked(p) => Err(Error::Protocol(ProtocolError {
1624 message: format!("Panicked: {p:?}"),
1625 raw_data: None,
1626 source: None,
1627 })),
1628 }
1629 }
1630}
1631
1632impl<'conn> TransactionOps for SharedPgTransaction<'conn> {
1633 fn query(
1634 &self,
1635 cx: &Cx,
1636 sql: &str,
1637 params: &[Value],
1638 ) -> impl Future<Output = Outcome<Vec<Row>, Error>> + Send {
1639 let inner = Arc::clone(&self.inner);
1640 let sql = sql.to_string();
1641 let params = params.to_vec();
1642 async move {
1643 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1644 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1645 };
1646 guard.query_async(cx, &sql, ¶ms).await
1647 }
1648 }
1649
1650 fn query_one(
1651 &self,
1652 cx: &Cx,
1653 sql: &str,
1654 params: &[Value],
1655 ) -> impl Future<Output = Outcome<Option<Row>, Error>> + Send {
1656 let inner = Arc::clone(&self.inner);
1657 let sql = sql.to_string();
1658 let params = params.to_vec();
1659 async move {
1660 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1661 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1662 };
1663 let rows = match guard.query_async(cx, &sql, ¶ms).await {
1664 Outcome::Ok(r) => r,
1665 Outcome::Err(e) => return Outcome::Err(e),
1666 Outcome::Cancelled(r) => return Outcome::Cancelled(r),
1667 Outcome::Panicked(p) => return Outcome::Panicked(p),
1668 };
1669 Outcome::Ok(rows.into_iter().next())
1670 }
1671 }
1672
1673 fn execute(
1674 &self,
1675 cx: &Cx,
1676 sql: &str,
1677 params: &[Value],
1678 ) -> impl Future<Output = Outcome<u64, Error>> + Send {
1679 let inner = Arc::clone(&self.inner);
1680 let sql = sql.to_string();
1681 let params = params.to_vec();
1682 async move {
1683 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1684 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1685 };
1686 guard.execute_async(cx, &sql, ¶ms).await
1687 }
1688 }
1689
1690 fn savepoint(&self, cx: &Cx, name: &str) -> impl Future<Output = Outcome<(), Error>> + Send {
1691 let inner = Arc::clone(&self.inner);
1692 let name = name.to_string();
1693 async move {
1694 if let Err(e) = validate_savepoint_name(&name) {
1695 return Outcome::Err(e);
1696 }
1697 let sql = format!("SAVEPOINT {}", name);
1698 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1699 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1700 };
1701 guard.execute_async(cx, &sql, &[]).await.map(|_| ())
1702 }
1703 }
1704
1705 fn rollback_to(&self, cx: &Cx, name: &str) -> impl Future<Output = Outcome<(), Error>> + Send {
1706 let inner = Arc::clone(&self.inner);
1707 let name = name.to_string();
1708 async move {
1709 if let Err(e) = validate_savepoint_name(&name) {
1710 return Outcome::Err(e);
1711 }
1712 let sql = format!("ROLLBACK TO SAVEPOINT {}", name);
1713 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1714 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1715 };
1716 guard.execute_async(cx, &sql, &[]).await.map(|_| ())
1717 }
1718 }
1719
1720 fn release(&self, cx: &Cx, name: &str) -> impl Future<Output = Outcome<(), Error>> + Send {
1721 let inner = Arc::clone(&self.inner);
1722 let name = name.to_string();
1723 async move {
1724 if let Err(e) = validate_savepoint_name(&name) {
1725 return Outcome::Err(e);
1726 }
1727 let sql = format!("RELEASE SAVEPOINT {}", name);
1728 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1729 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1730 };
1731 guard.execute_async(cx, &sql, &[]).await.map(|_| ())
1732 }
1733 }
1734
1735 #[allow(unused_assignments)]
1737 fn commit(mut self, cx: &Cx) -> impl Future<Output = Outcome<(), Error>> + Send {
1738 let inner = Arc::clone(&self.inner);
1739 async move {
1740 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1741 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1742 };
1743 let result = guard.execute_async(cx, "COMMIT", &[]).await;
1744 if matches!(result, Outcome::Ok(_)) {
1745 self.committed = true;
1746 }
1747 result.map(|_| ())
1748 }
1749 }
1750
1751 #[allow(unused_assignments)]
1752 fn rollback(mut self, cx: &Cx) -> impl Future<Output = Outcome<(), Error>> + Send {
1753 let inner = Arc::clone(&self.inner);
1754 async move {
1755 let Ok(mut guard) = OwnedMutexGuard::lock(Arc::clone(&inner), cx).await else {
1756 return Outcome::Err(connection_error("Failed to acquire connection lock"));
1757 };
1758 let result = guard.execute_async(cx, "ROLLBACK", &[]).await;
1759 if matches!(result, Outcome::Ok(_)) {
1760 self.committed = true;
1761 }
1762 result.map(|_| ())
1763 }
1764 }
1765}
1766
1767struct PgQueryResult {
1770 rows: Vec<Row>,
1771 command_tag: Option<String>,
1772}
1773
1774fn connection_error(msg: impl Into<String>) -> Error {
1775 Error::Connection(ConnectionError {
1776 kind: ConnectionErrorKind::Connect,
1777 message: msg.into(),
1778 source: None,
1779 })
1780}
1781
1782fn auth_error(msg: impl Into<String>) -> Error {
1783 Error::Connection(ConnectionError {
1784 kind: ConnectionErrorKind::Authentication,
1785 message: msg.into(),
1786 source: None,
1787 })
1788}
1789
1790fn protocol_error(msg: impl Into<String>) -> Error {
1791 Error::Protocol(ProtocolError {
1792 message: msg.into(),
1793 raw_data: None,
1794 source: None,
1795 })
1796}
1797
1798fn query_error_msg(msg: impl Into<String>, kind: QueryErrorKind) -> Error {
1799 Error::Query(QueryError {
1800 kind,
1801 message: msg.into(),
1802 sqlstate: None,
1803 sql: None,
1804 detail: None,
1805 hint: None,
1806 position: None,
1807 source: None,
1808 })
1809}
1810
1811fn error_from_fields(fields: &ErrorFields) -> Error {
1812 let kind = match fields.code.get(..2) {
1813 Some("08") => {
1814 return Error::Connection(ConnectionError {
1815 kind: ConnectionErrorKind::Connect,
1816 message: fields.message.clone(),
1817 source: None,
1818 });
1819 }
1820 Some("28") => {
1821 return Error::Connection(ConnectionError {
1822 kind: ConnectionErrorKind::Authentication,
1823 message: fields.message.clone(),
1824 source: None,
1825 });
1826 }
1827 Some("42") => QueryErrorKind::Syntax,
1828 Some("23") => QueryErrorKind::Constraint,
1829 Some("40") => {
1830 if fields.code == "40001" {
1831 QueryErrorKind::Serialization
1832 } else {
1833 QueryErrorKind::Deadlock
1834 }
1835 }
1836 Some("57") => {
1837 if fields.code == "57014" {
1838 QueryErrorKind::Cancelled
1839 } else {
1840 QueryErrorKind::Timeout
1841 }
1842 }
1843 _ => QueryErrorKind::Database,
1844 };
1845
1846 Error::Query(QueryError {
1847 kind,
1848 sql: None,
1849 sqlstate: Some(fields.code.clone()),
1850 message: fields.message.clone(),
1851 detail: fields.detail.clone(),
1852 hint: fields.hint.clone(),
1853 position: fields.position.map(|p| p as usize),
1854 source: None,
1855 })
1856}
1857
1858fn parse_rows_affected(tag: Option<&str>) -> Option<u64> {
1859 let tag = tag?;
1860 let mut parts = tag.split_whitespace().collect::<Vec<_>>();
1861 parts.pop().and_then(|last| last.parse::<u64>().ok())
1862}
1863
1864fn validate_savepoint_name(name: &str) -> sqlmodel_core::Result<()> {
1866 if name.is_empty() {
1867 return Err(query_error_msg(
1868 "Savepoint name cannot be empty",
1869 QueryErrorKind::Syntax,
1870 ));
1871 }
1872 if name.len() > 63 {
1873 return Err(query_error_msg(
1874 "Savepoint name exceeds maximum length of 63 characters",
1875 QueryErrorKind::Syntax,
1876 ));
1877 }
1878 let mut chars = name.chars();
1879 let Some(first) = chars.next() else {
1880 return Err(query_error_msg(
1881 "Savepoint name cannot be empty",
1882 QueryErrorKind::Syntax,
1883 ));
1884 };
1885 if !first.is_ascii_alphabetic() && first != '_' {
1886 return Err(query_error_msg(
1887 "Savepoint name must start with a letter or underscore",
1888 QueryErrorKind::Syntax,
1889 ));
1890 }
1891 for c in chars {
1892 if !c.is_ascii_alphanumeric() && c != '_' {
1893 return Err(query_error_msg(
1894 format!("Savepoint name contains invalid character: '{c}'"),
1895 QueryErrorKind::Syntax,
1896 ));
1897 }
1898 }
1899 Ok(())
1900}
1901
1902fn md5_password(user: &str, password: &str, salt: [u8; 4]) -> String {
1903 use std::fmt::Write;
1904
1905 let inner = format!("{password}{user}");
1906 let inner_hash = md5::compute(inner.as_bytes());
1907
1908 let mut outer_input = format!("{inner_hash:x}").into_bytes();
1909 outer_input.extend_from_slice(&salt);
1910 let outer_hash = md5::compute(&outer_input);
1911
1912 let mut result = String::with_capacity(35);
1913 result.push_str("md5");
1914 write!(&mut result, "{outer_hash:x}").unwrap();
1915 result
1916}
1917
1918