1use std::{
4 collections::{HashMap, VecDeque},
5 fmt,
6 pin::Pin,
7 sync::{
8 Arc, Mutex,
9 atomic::{AtomicBool, Ordering},
10 },
11 task::{Context, Poll},
12};
13
14use bytes::{Bytes, BytesMut};
15use futures_util::Stream;
16use indexmap::IndexMap;
17use postgresql_protocol::{
18 DbError,
19 backend::BackendMessage,
20 error::Error as ProtocolError,
21 frontend,
22 oid::{Format, Oid},
23 scram::ScramClient,
24};
25use small_collections::SmallVec;
26use tokio::{
27 io::{AsyncReadExt, AsyncWriteExt},
28 net::TcpStream,
29 sync::{broadcast, mpsc, oneshot},
30};
31use xxhash::{Checksum, Xxh3_128};
32
33use crate::{
34 config::Config,
35 encode::{IsNull, ToSql},
36 error::Error,
37 row::{Columns, Row},
38 stream::PgStream,
39};
40
41const READ_BUFFER_SIZE: usize = 8192;
42
43const INTERNER_CAPACITY: usize = 256;
45
46const ROW_CHANNEL_CAPACITY: usize = 32;
48
49const COPY_FLUSH_THRESHOLD: usize = 8 * 1024;
51
52const COPY_CHANNEL_CAPACITY: usize = 16;
56
57const ABANDONED_QUERY_CANCEL_DELAY: std::time::Duration = std::time::Duration::from_secs(2);
66
67const CANCEL_QUEUE_CAPACITY: usize = 256;
73
74const CANCEL_CONCURRENCY: usize = 16;
76
77const CANCEL_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);
79
80const MAX_AUTH_MESSAGES: usize = 1024;
87
88#[derive(Debug, Clone)]
90pub struct Notification {
91 pub process_id: i32,
93 pub channel: String,
95 pub payload: String,
97}
98
99#[derive(Clone)]
107pub struct CancelToken {
108 config: Arc<Config>,
109 process_id: i32,
110 secret_key: i32,
111}
112
113impl CancelToken {
114 pub async fn cancel(&self) -> Result<(), Error> {
120 self.cancel_with_timeout(CANCEL_TIMEOUT).await
121 }
122
123 pub(crate) async fn cancel_with_timeout(&self, timeout: std::time::Duration) -> Result<(), Error> {
125 tokio::time::timeout(timeout, async {
126 let address = format!("{}:{}", self.config.host, self.config.port);
127 let tcp = TcpStream::connect(&address).await.map_err(Error::Io)?;
128 let _ = tcp.set_nodelay(true);
129 let mut stream = negotiate_tls(tcp, &self.config).await?;
130 let mut buf = BytesMut::with_capacity(16);
131 frontend::cancel_request(&mut buf, self.process_id, self.secret_key);
132 stream.write_all(&buf).await.map_err(Error::Io)?;
133 stream.flush().await.map_err(Error::Io)?;
134 Ok(())
135 })
136 .await
137 .map_err(|_| Error::Config("timed out sending the cancellation request".into()))?
138 }
139}
140
141static PENDING_CANCELS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
146
147fn cancel_semaphore() -> Arc<tokio::sync::Semaphore> {
152 static SEMAPHORE: std::sync::OnceLock<Arc<tokio::sync::Semaphore>> = std::sync::OnceLock::new();
153 SEMAPHORE
154 .get_or_init(|| Arc::new(tokio::sync::Semaphore::new(CANCEL_CONCURRENCY)))
155 .clone()
156}
157
158struct CancelSlot {
163 permit: Option<tokio::sync::OwnedSemaphorePermit>,
164}
165
166impl CancelSlot {
167 fn acquire() -> Option<Self> {
171 let previous = PENDING_CANCELS.fetch_add(1, Ordering::AcqRel);
172 if previous >= CANCEL_QUEUE_CAPACITY {
173 PENDING_CANCELS.fetch_sub(1, Ordering::AcqRel);
174 return None;
175 }
176 match cancel_semaphore().try_acquire_owned() {
177 Ok(permit) => Some(CancelSlot {
178 permit: Some(permit),
179 }),
180 Err(_) => {
181 PENDING_CANCELS.fetch_sub(1, Ordering::AcqRel);
182 None
183 }
184 }
185 }
186}
187
188impl Drop for CancelSlot {
189 fn drop(&mut self) {
190 drop(self.permit.take());
191 PENDING_CANCELS.fetch_sub(1, Ordering::AcqRel);
192 }
193}
194
195struct QueryGuard {
197 completed: Arc<AtomicBool>,
198 cancel: Option<CancelToken>,
199}
200
201impl Drop for QueryGuard {
202 fn drop(&mut self) {
203 cancel_when_stuck(&self.completed, self.cancel.take());
204 }
205}
206
207fn cancel_when_stuck(completed: &Arc<AtomicBool>, cancel: Option<CancelToken>) {
221 let Some(token) = cancel else { return };
222 if tokio::runtime::Handle::try_current().is_err() {
223 return;
224 }
225 let Some(slot) = CancelSlot::acquire() else { return };
226 let completed = completed.clone();
227 tokio::spawn(async move {
228 let _slot = slot;
229 let jitter_ms = (ABANDONED_QUERY_CANCEL_DELAY.as_millis() as u64) / 2;
230 let extra = rand::random_range(0..=jitter_ms);
231 tokio::time::sleep(ABANDONED_QUERY_CANCEL_DELAY + std::time::Duration::from_millis(extra)).await;
232 if !completed.load(Ordering::Acquire) {
233 let _ = token.cancel_with_timeout(CANCEL_TIMEOUT).await;
234 }
235 });
236}
237
238struct Interner {
241 map: HashMap<u128, Arc<str>>,
242 order: VecDeque<u128>,
243 capacity: usize,
244}
245
246impl Interner {
247 fn new(capacity: usize) -> Self {
248 Interner {
249 map: HashMap::with_capacity(capacity),
250 order: VecDeque::with_capacity(capacity),
251 capacity,
252 }
253 }
254
255 fn intern(&mut self, sql: &str) -> Arc<str> {
256 let key = xxhash::xxh3_128(sql.as_bytes());
257 if let Some(existing) = self.map.get(&key) {
258 if existing.as_ref() == sql {
259 return existing.clone();
260 }
261 self.map.remove(&key);
264 self.order.retain(|&k| k != key);
265 }
266 if self.capacity == 0 {
267 return Arc::from(sql);
268 }
269 while self.map.len() >= self.capacity {
270 match self.order.pop_front() {
271 Some(old) => {
272 self.map.remove(&old);
273 }
274 None => break,
275 }
276 }
277 let arc: Arc<str> = Arc::from(sql);
278 self.map.insert(key, arc.clone());
279 self.order.push_back(key);
280 arc
281 }
282}
283
284pub(crate) const COPY_HEADER: &[u8] = b"PGCOPY\n\xff\r\n\0\x00\x00\x00\x00\x00\x00\x00\x00";
286
287pub(crate) struct EncodedParams {
290 pub oids: SmallVec<Oid, 8>,
291 pub values: BytesMut,
292}
293
294pub(crate) fn encode_params(params: &[&dyn ToSql]) -> Result<EncodedParams, Error> {
295 let mut values = BytesMut::with_capacity(params.len() * 16);
296 let mut oids: SmallVec<Oid, 8> = SmallVec::new();
297 for param in params {
298 oids.push(param.oid());
299 let len_pos = values.len();
300 values.extend_from_slice(&0i32.to_be_bytes());
301 let start = values.len();
302 match param.encode(&mut values)? {
303 IsNull::Null => {
304 values.truncate(len_pos);
305 values.extend_from_slice(&(-1i32).to_be_bytes());
306 }
307 IsNull::NotNull => {
308 let len = i32::try_from(values.len() - start)
309 .map_err(|_| Error::Encode("parameter is larger than 2 GiB".into()))?;
310 values[len_pos..len_pos + 4].copy_from_slice(&len.to_be_bytes());
311 }
312 }
313 }
314 Ok(EncodedParams {
315 oids,
316 values,
317 })
318}
319
320pub(crate) struct QueryRequest {
321 sql: Arc<str>,
322 params: EncodedParams,
323 rows: mpsc::Sender<Result<Row, Error>>,
324 done: oneshot::Sender<Result<u64, Error>>,
325 max_rows: i32,
326 completed: Arc<AtomicBool>,
327}
328
329pub(crate) struct ScriptRequest {
330 sql: String,
331 done: oneshot::Sender<Result<u64, Error>>,
332}
333
334pub(crate) enum CopyInChunk {
335 Data(Bytes),
336 Done,
337 Fail(String),
338}
339
340pub(crate) struct CopyInRequest {
341 sql: String,
342 chunks: mpsc::Receiver<CopyInChunk>,
343 done: oneshot::Sender<Result<u64, Error>>,
344}
345
346pub(crate) struct CopyOutRequest {
347 sql: String,
348 chunks: mpsc::Sender<Result<Bytes, Error>>,
349 done: oneshot::Sender<Result<u64, Error>>,
350}
351
352pub(crate) enum Request {
353 Query(QueryRequest),
354 Script(ScriptRequest),
355 CopyIn(CopyInRequest),
356 CopyOut(CopyOutRequest),
357}
358
359struct AttemptError {
365 error: Error,
366 rows_sent: bool,
367}
368
369impl AttemptError {
370 fn before_rows(error: impl Into<Error>) -> Self {
372 AttemptError {
373 error: error.into(),
374 rows_sent: false,
375 }
376 }
377}
378
379impl From<Error> for AttemptError {
380 fn from(error: Error) -> Self {
381 AttemptError::before_rows(error)
382 }
383}
384
385impl From<ProtocolError> for AttemptError {
386 fn from(error: ProtocolError) -> Self {
387 AttemptError::before_rows(error)
388 }
389}
390
391#[derive(Clone)]
402pub struct Connection {
403 tx: mpsc::UnboundedSender<Request>,
404 interner: Arc<Mutex<Interner>>,
405 broken: Arc<AtomicBool>,
406 config: Arc<Config>,
407 notifications: broadcast::Sender<Notification>,
408 process_id: i32,
409 secret_key: i32,
410}
411
412impl fmt::Debug for Connection {
413 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
414 f.debug_struct("Connection").finish_non_exhaustive()
415 }
416}
417
418struct CachedStatement {
419 sql: Arc<str>,
420 oids: SmallVec<Oid, 8>,
421 name: Arc<str>,
422 fields: Arc<Columns>,
423}
424
425impl CachedStatement {
426 fn matches(&self, sql: &str, oids: &[Oid]) -> bool {
427 self.sql.as_ref() == sql && self.oids.as_slice() == oids
428 }
429}
430
431struct Actor {
432 stream: PgStream,
433 read_buf: BytesMut,
434 write_buf: BytesMut,
435 cache: IndexMap<u128, CachedStatement>,
436 pending_closes: Vec<Arc<str>>,
437 statement_counter: u64,
438 broken: Arc<AtomicBool>,
439 zone: time::TimeZone,
440 notifications: broadcast::Sender<Notification>,
441 statement_cache_size: usize,
442 max_message_len: usize,
443}
444
445impl Actor {
446 fn mark_broken(&self) {
447 self.broken.store(true, Ordering::Release);
448 }
449
450 fn is_broken(&self) -> bool {
451 self.broken.load(Ordering::Acquire)
452 }
453}
454
455fn resolve_zone(config: &Config) -> Result<time::TimeZone, Error> {
457 match &config.timezone {
458 Some(name) => time::TimeZone::named(name).map_err(|e| Error::Config(format!("invalid timezone `{name}`: {e}"))),
459 None => Ok(time::TimeZone::UTC),
460 }
461}
462
463fn statement_key(sql: &str, oids: &[Oid]) -> u128 {
469 let mut hasher = Xxh3_128::new();
470 hasher.update(sql.as_bytes());
471 for oid in oids {
472 hasher.update(&oid.to_be_bytes());
473 }
474 hasher.sum()
475}
476
477fn is_retryable_plan_error(code: &str) -> bool {
480 code == "0A000" || code == "26000"
481}
482
483fn should_retry(attempt: u8, rows_sent: bool, error: &Error) -> bool {
489 attempt == 1 && !rows_sent && matches!(error, Error::Server(db) if is_retryable_plan_error(&db.code))
490}
491
492impl Connection {
493 pub async fn connect(url: &str) -> Result<Self, Error> {
531 let config = Config::parse(url)?;
532 Connection::connect_with_config(config).await
533 }
534
535 pub(crate) async fn connect_with_config(config: Config) -> Result<Self, Error> {
537 let (stream, read_buf, process_id, secret_key) =
541 tokio::time::timeout(config.connect_timeout, establish(&config))
542 .await
543 .map_err(|_| Error::Config(format!("timed out connecting to {}:{}", config.host, config.port)))??;
544 let zone = resolve_zone(&config)?;
545 let broken = Arc::new(AtomicBool::new(false));
546 let (notifications, _) = broadcast::channel(64);
547 let actor = Actor {
548 stream,
549 read_buf,
550 write_buf: BytesMut::with_capacity(512),
551 cache: IndexMap::new(),
552 pending_closes: Vec::new(),
553 statement_counter: 0,
554 broken: broken.clone(),
555 zone,
556 notifications: notifications.clone(),
557 statement_cache_size: config.statement_cache_size,
558 max_message_len: config.max_message_len,
559 };
560 let (tx, rx) = mpsc::unbounded_channel();
561 tokio::spawn(actor.run(rx));
562 Ok(Connection {
563 tx,
564 interner: Arc::new(Mutex::new(Interner::new(INTERNER_CAPACITY))),
565 broken,
566 config: Arc::new(config),
567 notifications,
568 process_id,
569 secret_key,
570 })
571 }
572
573 pub fn is_closed(&self) -> bool {
575 self.broken.load(Ordering::Acquire) || self.tx.is_closed()
576 }
577
578 pub(crate) fn max_message_len(&self) -> usize {
580 self.config.max_message_len
581 }
582
583 pub fn notifications(&self) -> broadcast::Receiver<Notification> {
588 self.notifications.subscribe()
589 }
590
591 pub fn cancel_token(&self) -> CancelToken {
593 CancelToken {
594 config: self.config.clone(),
595 process_id: self.process_id,
596 secret_key: self.secret_key,
597 }
598 }
599
600 pub async fn ping(&self) -> Result<(), Error> {
602 self.execute("SELECT 1", &[]).await?;
603 Ok(())
604 }
605
606 fn intern(&self, sql: &str) -> Arc<str> {
607 self.interner
608 .lock()
609 .unwrap_or_else(|poisoned| poisoned.into_inner())
610 .intern(sql)
611 }
612
613 pub(crate) async fn fetch_rows(&self, sql: &str, params: &[&dyn ToSql], max_rows: i32) -> Result<RowStream, Error> {
614 let sql = self.intern(sql);
615 let encoded = encode_params(params)?;
616 let (rows, rx) = mpsc::channel(ROW_CHANNEL_CAPACITY);
617 let (done, _done_rx) = oneshot::channel();
618 let completed = Arc::new(AtomicBool::new(false));
619 self.tx
620 .send(Request::Query(QueryRequest {
621 sql,
622 params: encoded,
623 rows,
624 done,
625 max_rows,
626 completed: completed.clone(),
627 }))
628 .map_err(|_| Error::Closed)?;
629 Ok(RowStream::new(
630 rx,
631 completed,
632 if max_rows == 0 { Some(self.cancel_token()) } else { None },
636 ))
637 }
638
639 pub(crate) async fn execute(&self, sql: &str, params: &[&dyn ToSql]) -> Result<u64, Error> {
640 let sql = self.intern(sql);
641 let encoded = encode_params(params)?;
642 let (rows, rx) = mpsc::channel(1);
647 drop(rx);
648 let (done, done_rx) = oneshot::channel();
649 let completed = Arc::new(AtomicBool::new(false));
650 let guard = QueryGuard {
651 completed: completed.clone(),
652 cancel: Some(self.cancel_token()),
653 };
654 self.tx
655 .send(Request::Query(QueryRequest {
656 sql,
657 params: encoded,
658 rows,
659 done,
660 max_rows: 0,
661 completed: completed.clone(),
662 }))
663 .map_err(|_| Error::Closed)?;
664 let result = match done_rx.await {
665 Ok(result) => result,
666 Err(_) => Err(Error::Closed),
667 };
668 completed.store(true, Ordering::Release);
669 drop(guard);
670 result
671 }
672
673 pub(crate) async fn execute_script(&self, sql: &str) -> Result<u64, Error> {
680 let (done, done_rx) = oneshot::channel();
681 self.tx
682 .send(Request::Script(ScriptRequest {
683 sql: sql.to_string(),
684 done,
685 }))
686 .map_err(|_| Error::Closed)?;
687 match done_rx.await {
688 Ok(result) => result,
689 Err(_) => Err(Error::Closed),
690 }
691 }
692
693 pub(crate) fn enqueue(&self, sql: &str) {
698 let sql = self.intern(sql);
699 let Ok(params) = encode_params(&[]) else {
700 return;
701 };
702 let (rows, rx) = mpsc::channel(1);
703 drop(rx);
704 let (done, _done_rx) = oneshot::channel();
705 let completed = Arc::new(AtomicBool::new(false));
706 let _ = self.tx.send(Request::Query(QueryRequest {
707 sql,
708 params,
709 rows,
710 done,
711 max_rows: 0,
712 completed,
713 }));
714 }
715
716 pub(crate) async fn copy_in(&self, sql: &str) -> Result<CopyInWriter, Error> {
726 let (tx, rx) = mpsc::channel(16);
727 let (done, done_rx) = oneshot::channel();
728 self.tx
729 .send(Request::CopyIn(CopyInRequest {
730 sql: sql.to_string(),
731 chunks: rx,
732 done,
733 }))
734 .map_err(|_| Error::Closed)?;
735 let _ = tx.send(CopyInChunk::Data(Bytes::from_static(COPY_HEADER))).await;
737 Ok(CopyInWriter {
738 tx,
739 done: Some(done_rx),
740 finished: false,
741 buf: Mutex::new(BytesMut::with_capacity(COPY_FLUSH_THRESHOLD * 2)),
742 })
743 }
744
745 pub(crate) async fn copy_out(&self, sql: &str) -> Result<CopyOutStream, Error> {
752 let (chunks, rx) = mpsc::channel(COPY_CHANNEL_CAPACITY);
753 let (done, _done_rx) = oneshot::channel();
754 self.tx
755 .send(Request::CopyOut(CopyOutRequest {
756 sql: sql.to_string(),
757 chunks,
758 done,
759 }))
760 .map_err(|_| Error::Closed)?;
761 Ok(CopyOutStream {
762 rx,
763 })
764 }
765}
766
767pub fn encode_copy_row(values: &[&dyn ToSql], buf: &mut BytesMut) -> Result<(), Error> {
770 let count = u16::try_from(values.len())
771 .map_err(|_| Error::Encode(format!("too many columns in COPY row: {} (max {})", values.len(), u16::MAX)))?;
772 buf.extend_from_slice(&count.to_be_bytes());
773 for value in values {
774 let len_pos = buf.len();
775 buf.extend_from_slice(&0i32.to_be_bytes());
776 let start = buf.len();
777 match value.encode(buf)? {
778 IsNull::Null => {
779 buf.truncate(len_pos);
780 buf.extend_from_slice(&(-1i32).to_be_bytes());
781 }
782 IsNull::NotNull => {
783 let len = i32::try_from(buf.len() - start)
784 .map_err(|_| Error::Encode("COPY field is larger than 2 GiB".into()))?;
785 buf[len_pos..len_pos + 4].copy_from_slice(&len.to_be_bytes());
786 }
787 }
788 }
789 Ok(())
790}
791
792pub(crate) struct CopyInWriter {
794 tx: mpsc::Sender<CopyInChunk>,
795 done: Option<oneshot::Receiver<Result<u64, Error>>>,
796 finished: bool,
797 buf: Mutex<BytesMut>,
798}
799
800impl CopyInWriter {
801 pub(crate) async fn append(&self, encode: impl FnOnce(&mut BytesMut) -> Result<(), Error>) -> Result<(), Error> {
811 let chunk = {
812 let mut buf = self.buf.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
813 encode(&mut buf)?;
814 if buf.len() < COPY_FLUSH_THRESHOLD {
815 None
816 } else {
817 Some(buf.split().freeze())
818 }
819 };
820 match chunk {
821 Some(chunk) => self.tx.send(CopyInChunk::Data(chunk)).await.map_err(|_| Error::Closed),
822 None => Ok(()),
823 }
824 }
825
826 pub async fn finish(mut self) -> Result<u64, Error> {
834 self.append(|buf| {
836 buf.extend_from_slice(&[0xff, 0xff]);
837 Ok(())
838 })
839 .await?;
840 if let Some(rest) = {
841 let mut buf = self.buf.lock().unwrap_or_else(|p| p.into_inner());
842 (!buf.is_empty()).then(|| buf.split().freeze())
843 } {
844 let _ = self.tx.send(CopyInChunk::Data(rest)).await;
845 }
846 let _ = self.tx.send(CopyInChunk::Done).await;
847 let done = self.done.take().expect("COPY already finished");
848 self.finished = true;
849 match done.await {
850 Ok(result) => result,
851 Err(_) => Err(Error::Closed),
852 }
853 }
854}
855
856impl Drop for CopyInWriter {
857 fn drop(&mut self) {
858 if !self.finished {
859 let _ = self.tx.try_send(CopyInChunk::Fail("COPY cancelled".into()));
864 }
865 }
866}
867
868pub(crate) struct CopyOutStream {
870 pub(crate) rx: mpsc::Receiver<Result<Bytes, Error>>,
871}
872
873impl Stream for CopyOutStream {
874 type Item = Result<Bytes, Error>;
875
876 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
877 self.rx.poll_recv(cx)
878 }
879}
880
881pub struct RowStream {
887 rx: mpsc::Receiver<Result<Row, Error>>,
888 completed: Arc<AtomicBool>,
889 cancel: Option<CancelToken>,
890 keepalive: Option<Box<dyn Send + 'static>>,
891}
892
893impl RowStream {
894 pub(crate) fn new(
895 rx: mpsc::Receiver<Result<Row, Error>>,
896 completed: Arc<AtomicBool>,
897 cancel: Option<CancelToken>,
898 ) -> Self {
899 RowStream {
900 rx,
901 completed,
902 cancel,
903 keepalive: None,
904 }
905 }
906
907 pub(crate) fn with_keepalive(mut self, guard: impl Send + 'static) -> Self {
910 self.keepalive = Some(Box::new(guard));
911 self
912 }
913}
914
915impl Stream for RowStream {
916 type Item = Result<Row, Error>;
917
918 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
919 let this = self.get_mut();
920 match this.rx.poll_recv(cx) {
921 Poll::Ready(None) => {
924 this.keepalive.take();
925 Poll::Ready(None)
926 }
927 other => other,
928 }
929 }
930}
931
932impl Drop for RowStream {
933 fn drop(&mut self) {
934 if !self.completed.load(Ordering::Acquire) {
938 cancel_when_stuck(&self.completed, self.cancel.take());
939 }
940 }
941}
942
943impl Actor {
944 async fn run(mut self, mut rx: mpsc::UnboundedReceiver<Request>) {
945 loop {
946 let broken = self.is_broken();
947 tokio::select! {
948 request = rx.recv() => {
949 let Some(request) = request else { break };
950 if broken || self.is_broken() {
951 fail_request(request, Error::Closed);
952 continue;
953 }
954 match request {
955 Request::Query(query) => self.handle_query(query).await,
956 Request::Script(script) => self.handle_script(script).await,
957 Request::CopyIn(copy) => self.handle_copy_in(copy).await,
958 Request::CopyOut(copy) => self.handle_copy_out(copy).await,
959 }
960 self.maybe_shrink_read_buf();
961 }
962 read = self.stream.read_buf(&mut self.read_buf), if !broken => {
963 match read {
964 Ok(0) => self.mark_broken(),
965 Ok(_) => self.drain_notifications(),
966 Err(_) => self.mark_broken(),
967 }
968 }
969 }
970 }
971
972 self.write_buf.clear();
975 let _ = frontend::terminate(&mut self.write_buf);
976 let _ = self.flush().await;
977 }
978
979 fn maybe_shrink_read_buf(&mut self) {
986 const SHRINK_THRESHOLD: usize = 1024 * 1024;
987 if self.read_buf.is_empty() && self.read_buf.capacity() > SHRINK_THRESHOLD {
988 self.read_buf = BytesMut::with_capacity(READ_BUFFER_SIZE);
989 }
990 }
991
992 fn drain_notifications(&mut self) {
999 loop {
1000 match postgresql_protocol::decode_with_limit(&mut self.read_buf, self.max_message_len) {
1001 Ok(Some(BackendMessage::NotificationResponse {
1002 pid,
1003 channel,
1004 payload,
1005 })) => {
1006 let _ = self.notifications.send(Notification {
1007 process_id: pid,
1008 channel,
1009 payload,
1010 });
1011 }
1012 Ok(Some(BackendMessage::ParameterStatus {
1013 ..
1014 }))
1015 | Ok(Some(BackendMessage::NoticeResponse(_))) => {}
1016 Ok(Some(other)) => {
1017 tracing::warn!("postgresql: unexpected message while idle: {other:?}");
1018 self.mark_broken();
1019 return;
1020 }
1021 Ok(None) => break,
1022 Err(err) => {
1023 tracing::warn!("postgresql: protocol error while idle: {err}");
1024 self.mark_broken();
1025 return;
1026 }
1027 }
1028 }
1029 }
1030
1031 async fn handle_script(&mut self, request: ScriptRequest) {
1033 tracing::debug!(sql_len = request.sql.len(), "postgresql: script");
1034 self.write_buf.clear();
1035 if let Err(err) = frontend::query(&mut self.write_buf, &request.sql) {
1036 self.mark_broken();
1037 let _ = request.done.send(Err(err.into()));
1038 return;
1039 }
1040 if let Err(err) = self.flush().await {
1041 self.mark_broken();
1042 let _ = request.done.send(Err(err));
1043 return;
1044 }
1045
1046 let mut affected = 0u64;
1047 let mut pending_error: Option<Error> = None;
1048 loop {
1049 match self.read_message().await {
1050 Ok(BackendMessage::CommandComplete(tag)) => affected = parse_command_tag(&tag),
1051 Ok(BackendMessage::ReadyForQuery(_)) => break,
1052 Ok(BackendMessage::RowDescription(_)) => {}
1053 Ok(BackendMessage::DataRow(_)) => {}
1054 Ok(BackendMessage::NoticeResponse(_)) => {}
1055 Ok(BackendMessage::EmptyQueryResponse) => {}
1056 Ok(BackendMessage::CopyInResponse {
1059 ..
1060 }) => {
1061 pending_error = Some(self.abort_unexpected_copy(true, false).await);
1062 break;
1063 }
1064 Ok(BackendMessage::CopyOutResponse {
1065 ..
1066 }) => {
1067 pending_error = Some(self.abort_unexpected_copy(false, false).await);
1068 break;
1069 }
1070 Ok(_) => {}
1071 Err(Error::Server(db)) => pending_error = Some(Error::Server(db)),
1072 Err(err) => {
1073 self.mark_broken();
1074 let _ = request.done.send(Err(err));
1075 return;
1076 }
1077 }
1078 }
1079
1080 let _ = request.done.send(match pending_error {
1081 Some(err) => Err(err),
1082 None => Ok(affected),
1083 });
1084 }
1085
1086 async fn handle_copy_in(&mut self, request: CopyInRequest) {
1087 tracing::debug!(sql = %request.sql, "postgresql: copy in");
1088 self.write_buf.clear();
1089 let mut encode_error = frontend::parse(&mut self.write_buf, "", &request.sql, &[]).err();
1090 if encode_error.is_none() {
1091 match frontend::bind_start(&mut self.write_buf, "", "", 0) {
1092 Ok(len_pos) => {
1093 encode_error = frontend::bind_finish(&mut self.write_buf, Format::Binary, len_pos)
1094 .and_then(|()| frontend::execute(&mut self.write_buf, "", 0))
1095 .err();
1096 }
1097 Err(err) => encode_error = Some(err),
1098 }
1099 }
1100 if let Some(err) = encode_error {
1101 self.mark_broken();
1102 let _ = request.done.send(Err(err.into()));
1103 return;
1104 }
1105 if let Err(err) = self.flush().await {
1106 self.mark_broken();
1107 let _ = request.done.send(Err(err));
1108 return;
1109 }
1110
1111 let mut pending_error: Option<Box<DbError>> = None;
1112 loop {
1113 match self.read_message().await {
1114 Ok(BackendMessage::ParseComplete) => {}
1115 Ok(BackendMessage::BindComplete) => {}
1116 Ok(BackendMessage::CopyInResponse {
1117 ..
1118 }) => break,
1119 Ok(BackendMessage::NoticeResponse(_)) => {}
1120 Ok(_) => {}
1121 Err(Error::Server(db)) => {
1122 pending_error = Some(db);
1123 break;
1124 }
1125 Err(err) => {
1126 self.mark_broken();
1127 let _ = request.done.send(Err(err));
1128 return;
1129 }
1130 }
1131 }
1132
1133 if let Some(db) = pending_error {
1134 let _ = self.sync_and_drain().await;
1135 let _ = request.done.send(Err(Error::Server(db)));
1136 return;
1137 }
1138
1139 let mut chunks = request.chunks;
1140 let mut stream_error: Option<Error> = None;
1141 let mut finished = false;
1142 while let Some(chunk) = chunks.recv().await {
1143 self.write_buf.clear();
1144 match chunk {
1145 CopyInChunk::Data(data) => {
1146 if let Err(err) = frontend::copy_data(&mut self.write_buf, &data) {
1147 stream_error = Some(err.into());
1148 break;
1149 }
1150 }
1151 CopyInChunk::Done => {
1152 if let Err(err) = frontend::copy_done(&mut self.write_buf) {
1153 stream_error = Some(err.into());
1154 break;
1155 }
1156 finished = true;
1157 if let Err(err) = self.flush().await {
1158 self.mark_broken();
1159 let _ = request.done.send(Err(err));
1160 return;
1161 }
1162 break;
1163 }
1164 CopyInChunk::Fail(message) => {
1165 if let Err(err) = frontend::copy_fail(&mut self.write_buf, &message) {
1166 stream_error = Some(err.into());
1167 break;
1168 }
1169 finished = true;
1170 if let Err(err) = self.flush().await {
1171 self.mark_broken();
1172 let _ = request.done.send(Err(err));
1173 return;
1174 }
1175 break;
1176 }
1177 }
1178 if let Err(err) = self.flush().await {
1179 self.mark_broken();
1180 let _ = request.done.send(Err(err));
1181 return;
1182 }
1183 }
1184
1185 if !finished {
1191 self.write_buf.clear();
1192 let message = if stream_error.is_some() {
1193 "COPY aborted by the client"
1194 } else {
1195 "COPY writer was dropped before completion"
1196 };
1197 if let Err(err) = frontend::copy_fail(&mut self.write_buf, message) {
1198 self.mark_broken();
1199 let _ = request.done.send(Err(err.into()));
1200 return;
1201 }
1202 if let Err(err) = self.flush().await {
1203 self.mark_broken();
1204 let _ = request.done.send(Err(err));
1205 return;
1206 }
1207 }
1208
1209 let mut result = self.sync_and_drain().await;
1210 if let Some(err) = stream_error {
1211 result = Err(err);
1212 }
1213 let _ = request.done.send(result);
1214 }
1215
1216 async fn handle_copy_out(&mut self, request: CopyOutRequest) {
1217 tracing::debug!(sql = %request.sql, "postgresql: copy out");
1218 self.write_buf.clear();
1219 let mut encode_error = frontend::parse(&mut self.write_buf, "", &request.sql, &[]).err();
1220 if encode_error.is_none() {
1221 match frontend::bind_start(&mut self.write_buf, "", "", 0) {
1222 Ok(len_pos) => {
1223 encode_error = frontend::bind_finish(&mut self.write_buf, Format::Binary, len_pos)
1224 .and_then(|()| frontend::execute(&mut self.write_buf, "", 0))
1225 .and_then(|()| frontend::sync(&mut self.write_buf))
1226 .err();
1227 }
1228 Err(err) => encode_error = Some(err),
1229 }
1230 }
1231 if let Some(err) = encode_error {
1232 self.mark_broken();
1233 let _ = request.done.send(Err(err.into()));
1234 return;
1235 }
1236 if let Err(err) = self.flush().await {
1237 self.mark_broken();
1238 let _ = request.done.send(Err(err));
1239 return;
1240 }
1241
1242 let mut pending_error: Option<Error> = None;
1243 loop {
1244 match self.read_message().await {
1245 Ok(BackendMessage::CopyData(data)) => {
1246 if request.chunks.send(Ok(data)).await.is_err() {
1248 continue;
1251 }
1252 }
1253 Ok(BackendMessage::ReadyForQuery(_)) => break,
1254 Ok(BackendMessage::NoticeResponse(_)) => {}
1255 Ok(_) => {}
1256 Err(Error::Server(db)) => {
1257 pending_error = Some(Error::Server(db));
1258 }
1259 Err(err) => {
1260 self.mark_broken();
1261 pending_error = Some(err);
1262 break;
1263 }
1264 }
1265 }
1266
1267 match pending_error {
1268 Some(Error::Server(db)) => {
1271 let _ = request.chunks.send(Err(Error::Server(db.clone()))).await;
1272 let _ = request.done.send(Err(Error::Server(db)));
1273 }
1274 Some(err) => {
1275 let _ = request.chunks.send(Err(Error::Closed)).await;
1276 let _ = request.done.send(Err(err));
1277 }
1278 None => {
1279 let _ = request.done.send(Ok(0));
1280 }
1281 }
1282 }
1283
1284 async fn sync_and_drain(&mut self) -> Result<u64, Error> {
1287 self.write_buf.clear();
1288 if let Err(err) = frontend::sync(&mut self.write_buf) {
1289 self.mark_broken();
1290 return Err(err.into());
1291 }
1292 if let Err(err) = self.flush().await {
1293 self.mark_broken();
1294 return Err(err);
1295 }
1296 let mut affected = 0;
1297 let mut result = Ok(affected);
1298 loop {
1299 match self.read_message().await {
1300 Ok(BackendMessage::CommandComplete(tag)) => {
1301 affected = parse_command_tag(&tag);
1302 }
1303 Ok(BackendMessage::ReadyForQuery(_)) => break,
1304 Ok(BackendMessage::NoticeResponse(_)) => {}
1305 Ok(_) => {}
1306 Err(Error::Server(db)) => {
1307 result = Err(Error::Server(db));
1308 }
1309 Err(err) => {
1310 self.mark_broken();
1311 result = Err(err);
1312 break;
1313 }
1314 }
1315 }
1316 match result {
1317 Ok(_) => Ok(affected),
1318 Err(err) => Err(err),
1319 }
1320 }
1321
1322 async fn handle_query(&mut self, query: QueryRequest) {
1323 tracing::debug!(
1324 sql = %query.sql,
1325 params = query.params.oids.len(),
1326 "postgresql: execute"
1327 );
1328
1329 let mut attempts = 0u8;
1330 let result = loop {
1331 attempts += 1;
1332 match self.attempt_query(&query).await {
1333 Ok(affected) => break Ok(affected),
1334 Err(AttemptError {
1335 error,
1336 rows_sent,
1337 }) => {
1338 let retryable = should_retry(attempts, rows_sent, &error);
1341 if retryable {
1342 let hash = statement_key(&query.sql, query.params.oids.as_slice());
1343 if let Some(cached) = self.cache.swap_remove(&hash) {
1344 self.pending_closes.push(cached.name);
1345 }
1346 tracing::debug!("postgresql: re-preparing statement after a stale plan");
1347 continue;
1348 }
1349 break Err(error);
1350 }
1351 }
1352 };
1353
1354 query.completed.store(true, Ordering::Release);
1357 match result {
1358 Ok(affected) => {
1359 let _ = query.done.send(Ok(affected));
1360 }
1361 Err(err) => {
1362 if !query.rows.is_closed() {
1363 let for_rows = match &err {
1367 Error::Server(db) => Error::Server(db.clone()),
1368 Error::Closed => Error::Closed,
1369 other => Error::ConnectionFailed(other.to_string()),
1370 };
1371 let _ = query.rows.send(Err(for_rows)).await;
1372 }
1373 let _ = query.done.send(Err(err));
1374 }
1375 }
1376 }
1377
1378 async fn attempt_query(&mut self, query: &QueryRequest) -> Result<u64, AttemptError> {
1383 let hash = statement_key(&query.sql, query.params.oids.as_slice());
1384
1385 let (name, fields): (Arc<str>, Arc<Columns>) = if self.statement_cache_size == 0 {
1386 let fields = self.prepare("", &query.sql, query.params.oids.as_slice()).await?;
1389 (Arc::from(""), fields)
1390 } else {
1391 let cached_matches = self
1392 .cache
1393 .get(&hash)
1394 .map(|cached| cached.matches(&query.sql, query.params.oids.as_slice()))
1395 .unwrap_or(false);
1396 if cached_matches {
1397 let (_, cached) = self.cache.swap_remove_entry(&hash).expect("checked");
1402 let name = cached.name.clone();
1403 let fields = cached.fields.clone();
1404 self.cache.insert(hash, cached);
1405 (name, fields)
1406 } else {
1407 self.statement_counter += 1;
1408 let name: Arc<str> = Arc::from(format!("s{}", self.statement_counter));
1409 let fields = self.prepare(&name, &query.sql, query.params.oids.as_slice()).await?;
1410 let entry = CachedStatement {
1411 sql: query.sql.clone(),
1412 oids: query.params.oids.clone(),
1413 name: name.clone(),
1414 fields: fields.clone(),
1415 };
1416 if let Some(old) = self.cache.insert(hash, entry) {
1419 self.pending_closes.push(old.name);
1420 }
1421 self.evict_statements();
1422 (name, fields)
1423 }
1424 };
1425
1426 let param_count = query.params.oids.len();
1427 self.write_buf.clear();
1428 self.write_pending_closes()?;
1429 let len_pos = frontend::bind_start(&mut self.write_buf, "", &name, param_count)?;
1430 self.write_buf.extend_from_slice(&query.params.values);
1431 frontend::bind_finish(&mut self.write_buf, Format::Binary, len_pos)?;
1432 frontend::execute(&mut self.write_buf, "", query.max_rows)?;
1433 frontend::sync(&mut self.write_buf)?;
1434
1435 if let Err(err) = self.flush().await {
1436 self.mark_broken();
1437 return Err(AttemptError::before_rows(err));
1438 }
1439
1440 let mut pending_error: Option<Box<DbError>> = None;
1441 let mut affected = 0u64;
1442 let mut rows_sent = false;
1443
1444 loop {
1445 match self.read_message().await {
1446 Ok(BackendMessage::BindComplete) => {}
1447 Ok(BackendMessage::DataRow(payload)) => {
1448 rows_sent = true;
1449 if !query.rows.is_closed() {
1450 match Row::parse(fields.clone(), &payload, self.zone) {
1451 Ok(row) => {
1452 let _ = query.rows.send(Ok(row)).await;
1454 }
1455 Err(err) => {
1456 let _ = query.rows.send(Err(err)).await;
1457 }
1458 }
1459 }
1460 }
1461 Ok(BackendMessage::CommandComplete(tag)) => {
1462 affected = parse_command_tag(&tag);
1463 }
1464 Ok(BackendMessage::NoticeResponse(_notice)) => {}
1465 Ok(BackendMessage::EmptyQueryResponse) => {}
1466 Ok(BackendMessage::PortalSuspended) => {}
1469 Ok(BackendMessage::CopyInResponse {
1474 ..
1475 }) => {
1476 let error = self.abort_unexpected_copy(true, true).await;
1477 return Err(AttemptError {
1478 error,
1479 rows_sent,
1480 });
1481 }
1482 Ok(BackendMessage::CopyOutResponse {
1483 ..
1484 }) => {
1485 let error = self.abort_unexpected_copy(false, true).await;
1486 return Err(AttemptError {
1487 error,
1488 rows_sent,
1489 });
1490 }
1491 Ok(BackendMessage::ReadyForQuery(_)) => break,
1492 Ok(_) => {}
1493 Err(Error::Server(db)) => {
1494 tracing::debug!(code = %db.code, message = %db.message, "postgresql: server error");
1495 pending_error = Some(db);
1496 }
1497 Err(err) => {
1498 self.mark_broken();
1499 return Err(AttemptError {
1500 error: err,
1501 rows_sent,
1502 });
1503 }
1504 }
1505 }
1506
1507 match pending_error {
1508 Some(db) => Err(AttemptError {
1509 error: Error::Server(db),
1510 rows_sent,
1511 }),
1512 None => Ok(affected),
1513 }
1514 }
1515
1516 async fn abort_unexpected_copy(&mut self, copy_in: bool, extended: bool) -> Error {
1528 if copy_in {
1529 self.write_buf.clear();
1530 let encode =
1531 frontend::copy_fail(&mut self.write_buf, "COPY ... FROM STDIN is not supported here; use copy_in!")
1532 .and_then(|()| {
1533 if extended {
1534 frontend::sync(&mut self.write_buf)
1535 } else {
1536 Ok(())
1537 }
1538 });
1539 if let Err(err) = encode {
1540 self.mark_broken();
1541 return err.into();
1542 }
1543 if let Err(err) = self.flush().await {
1544 self.mark_broken();
1545 return err;
1546 }
1547 }
1548 loop {
1549 match self.read_message().await {
1550 Ok(BackendMessage::ReadyForQuery(_)) => break,
1551 Ok(_) => {}
1552 Err(Error::Server(_)) => {}
1553 Err(err) => {
1554 self.mark_broken();
1555 return err;
1556 }
1557 }
1558 }
1559 Error::Decode(
1560 if copy_in {
1561 "COPY ... FROM STDIN cannot be run as a parameterized query; use copy_in!"
1562 } else {
1563 "COPY ... TO STDOUT cannot be run as a parameterized query; use copy_out!"
1564 }
1565 .into(),
1566 )
1567 }
1568
1569 fn evict_statements(&mut self) {
1576 if self.statement_cache_size == 0 {
1577 return;
1578 }
1579 while self.cache.len() > self.statement_cache_size {
1580 let Some((_, cached)) = self.cache.swap_remove_index(0) else {
1581 break;
1582 };
1583 self.pending_closes.push(cached.name);
1584 }
1585 }
1586
1587 fn write_pending_closes(&mut self) -> Result<(), Error> {
1589 for name in self.pending_closes.drain(..) {
1590 frontend::close(&mut self.write_buf, b'S', &name)?;
1591 }
1592 Ok(())
1593 }
1594
1595 async fn prepare(&mut self, name: &str, sql: &str, param_oids: &[Oid]) -> Result<Arc<Columns>, Error> {
1596 self.write_buf.clear();
1597 self.write_pending_closes()?;
1598 frontend::parse(&mut self.write_buf, name, sql, param_oids)?;
1599 frontend::describe(&mut self.write_buf, b'S', name)?;
1600 frontend::sync(&mut self.write_buf)?;
1601 self.flush().await?;
1602
1603 let mut fields: Option<Vec<postgresql_protocol::backend::FieldDescription>> = None;
1604 let mut pending_error: Option<Box<DbError>> = None;
1605 loop {
1606 match self.read_message().await {
1607 Ok(BackendMessage::ParseComplete) => {}
1608 Ok(BackendMessage::ParameterDescription(_)) => {}
1609 Ok(BackendMessage::RowDescription(described)) => fields = Some(described),
1610 Ok(BackendMessage::NoData) => fields = Some(Vec::new()),
1611 Ok(BackendMessage::NoticeResponse(_)) => {}
1612 Ok(BackendMessage::ReadyForQuery(_)) => break,
1613 Ok(_) => {}
1614 Err(Error::Server(db)) => pending_error = Some(db),
1615 Err(err) => return Err(err),
1616 }
1617 }
1618
1619 if let Some(db) = pending_error {
1620 return Err(Error::Server(db));
1621 }
1622
1623 Ok(Columns::from_fields(&fields.unwrap_or_default()))
1624 }
1625
1626 async fn flush(&mut self) -> Result<(), Error> {
1627 self.stream.write_all(&self.write_buf).await.map_err(Error::Io)?;
1628 self.stream.flush().await.map_err(Error::Io)?;
1629 self.write_buf.clear();
1630 Ok(())
1631 }
1632
1633 async fn read_message(&mut self) -> Result<BackendMessage, Error> {
1634 loop {
1635 match postgresql_protocol::decode_with_limit(&mut self.read_buf, self.max_message_len) {
1636 Ok(Some(BackendMessage::NotificationResponse {
1639 pid,
1640 channel,
1641 payload,
1642 })) => {
1643 let _ = self.notifications.send(Notification {
1644 process_id: pid,
1645 channel,
1646 payload,
1647 });
1648 continue;
1649 }
1650 Ok(Some(message)) => return Ok(message),
1651 Ok(None) => {}
1652 Err(ProtocolError::Server(db)) => return Err(Error::Server(db)),
1653 Err(err) => return Err(Error::Protocol(err)),
1654 }
1655 self.read_buf.reserve(READ_BUFFER_SIZE);
1656 let read = self.stream.read_buf(&mut self.read_buf).await.map_err(Error::Io)?;
1657 if read == 0 {
1658 return Err(Error::Closed);
1659 }
1660 }
1661 }
1662}
1663
1664fn fail_request(request: Request, err: Error) {
1665 match request {
1666 Request::Query(query) => {
1667 let _ = query.done.send(Err(err));
1668 }
1669 Request::Script(script) => {
1670 let _ = script.done.send(Err(err));
1671 }
1672 Request::CopyIn(copy) => {
1673 let _ = copy.done.send(Err(err));
1674 }
1675 Request::CopyOut(copy) => {
1676 let _ = copy.done.send(Err(err));
1677 }
1678 }
1679}
1680
1681fn parse_command_tag(tag: &Bytes) -> u64 {
1682 let Ok(text) = std::str::from_utf8(tag) else {
1683 return 0;
1684 };
1685 text.rsplit(' ').next().and_then(|n| n.parse::<u64>().ok()).unwrap_or(0)
1686}
1687
1688async fn establish(config: &Config) -> Result<(PgStream, BytesMut, i32, i32), Error> {
1689 let address = format!("{}:{}", config.host, config.port);
1690 let tcp = tokio::time::timeout(config.connect_timeout, TcpStream::connect(&address))
1691 .await
1692 .map_err(|_| Error::Config(format!("timed out connecting to {address}")))?
1693 .map_err(Error::Io)?;
1694 let _ = tcp.set_nodelay(true);
1695
1696 let mut stream = negotiate_tls(tcp, config).await?;
1697
1698 let mut params: SmallVec<(&str, &str), 5> = SmallVec::new();
1699 params.push(("client_encoding", "UTF8"));
1700 params.push(("user", &config.user));
1701 if let Some(database) = &config.database {
1702 params.push(("database", database));
1703 }
1704 if let Some(app) = &config.application_name {
1705 params.push(("application_name", app));
1706 }
1707 if let Some(options) = &config.options {
1708 params.push(("options", options));
1709 }
1710
1711 let mut write_buf = BytesMut::with_capacity(256);
1712 frontend::startup(&mut write_buf, ¶ms)?;
1713 stream.write_all(&write_buf).await.map_err(Error::Io)?;
1714 stream.flush().await.map_err(Error::Io)?;
1715
1716 let mut read_buf = BytesMut::with_capacity(READ_BUFFER_SIZE);
1717 let (process_id, secret_key) = authenticate(&mut stream, &mut read_buf, config).await?;
1718 tracing::debug!(
1719 host = %config.host,
1720 port = config.port,
1721 user = %config.user,
1722 "postgresql: connected"
1723 );
1724 Ok((stream, read_buf, process_id, secret_key))
1725}
1726
1727async fn negotiate_tls(tcp: TcpStream, config: &Config) -> Result<PgStream, Error> {
1728 let mut tcp = tcp;
1729 let mut request = BytesMut::new();
1730 frontend::ssl_request(&mut request);
1731 tcp.write_all(&request).await.map_err(Error::Io)?;
1732 tcp.flush().await.map_err(Error::Io)?;
1733
1734 let mut response = [0u8; 1];
1735 tcp.read_exact(&mut response).await.map_err(Error::Io)?;
1736
1737 match response[0] {
1738 b'S' => {
1739 let connector = crate::stream::tls::connector(config)?;
1740 let server_name = rustls::pki_types::ServerName::try_from(config.host.clone())
1741 .map_err(|_| Error::Config(format!("invalid TLS server name `{}`", config.host)))?;
1742 let stream = connector.connect(server_name, tcp).await.map_err(Error::Io)?;
1743 Ok(PgStream::Tls(Box::new(stream)))
1744 }
1745 b'N' => Err(Error::Config(
1746 "the server does not support TLS; this client always requires TLS".into(),
1747 )),
1748 other => Err(Error::Protocol(ProtocolError::Protocol(format!(
1749 "unexpected response to SSLRequest: {other}"
1750 )))),
1751 }
1752}
1753
1754async fn authenticate(stream: &mut PgStream, read_buf: &mut BytesMut, config: &Config) -> Result<(i32, i32), Error> {
1755 let mut write_buf = BytesMut::with_capacity(256);
1756 let mut integer_datetimes: Option<String> = None;
1757 let mut backend_key: Option<(i32, i32)> = None;
1758 let mut messages = 0usize;
1759
1760 loop {
1761 messages += 1;
1762 if messages > MAX_AUTH_MESSAGES {
1763 return Err(Error::Protocol(ProtocolError::Protocol(format!(
1764 "the server sent more than {MAX_AUTH_MESSAGES} messages during authentication"
1765 ))));
1766 }
1767 let message = read_backend(stream, read_buf, config.max_message_len).await?;
1768 match message {
1769 BackendMessage::AuthenticationOk => {}
1770 BackendMessage::AuthenticationCleartextPassword => {
1771 let password = config.password.as_deref().unwrap_or("");
1772 write_buf.clear();
1773 frontend::password(&mut write_buf, password)?;
1774 stream.write_all(&write_buf).await.map_err(Error::Io)?;
1775 stream.flush().await.map_err(Error::Io)?;
1776 }
1777 BackendMessage::AuthenticationSasl(mechanisms) => {
1778 if !mechanisms.iter().any(|m| m == "SCRAM-SHA-256") {
1779 return Err(Error::Server(Box::new(DbError {
1780 severity: "FATAL".into(),
1781 code: Default::default(),
1782 message: "server does not offer SCRAM-SHA-256 authentication".into(),
1783 ..DbError::default()
1784 })));
1785 }
1786 let mut client = ScramClient::with_max_iterations(
1787 config.password.as_deref().unwrap_or(""),
1788 config.max_scram_iterations,
1789 )?;
1790 write_buf.clear();
1791 frontend::sasl_initial_response(
1792 &mut write_buf,
1793 "SCRAM-SHA-256",
1794 client.client_first_message().as_bytes(),
1795 )?;
1796 stream.write_all(&write_buf).await.map_err(Error::Io)?;
1797 stream.flush().await.map_err(Error::Io)?;
1798
1799 let continue_message = read_backend(stream, read_buf, config.max_message_len).await?;
1800 match continue_message {
1801 BackendMessage::AuthenticationSaslContinue(data) => {
1802 let (returned, final_message) = tokio::task::spawn_blocking(move || {
1807 client.parse_server_first_message(&data)?;
1808 let final_message = client.build_client_final_message()?;
1809 Ok::<_, ProtocolError>((client, final_message))
1810 })
1811 .await
1812 .map_err(|_| Error::Closed)??;
1813 client = returned;
1814 write_buf.clear();
1815 frontend::sasl_response(&mut write_buf, &final_message)?;
1816 stream.write_all(&write_buf).await.map_err(Error::Io)?;
1817 stream.flush().await.map_err(Error::Io)?;
1818 }
1819 other => {
1820 return Err(Error::Protocol(ProtocolError::Protocol(format!(
1821 "expected SASLContinue, got {other:?}"
1822 ))));
1823 }
1824 }
1825
1826 let final_message = read_backend(stream, read_buf, config.max_message_len).await?;
1827 match final_message {
1828 BackendMessage::AuthenticationSaslFinal(data) => {
1829 tokio::task::spawn_blocking(move || client.parse_server_final_message(&data))
1832 .await
1833 .map_err(|_| Error::Closed)??;
1834 }
1835 other => {
1836 return Err(Error::Protocol(ProtocolError::Protocol(format!(
1837 "expected SASLFinal, got {other:?}"
1838 ))));
1839 }
1840 }
1841 }
1842 BackendMessage::AuthenticationMd5Password(_) => {
1843 return Err(Error::Server(Box::new(DbError {
1844 severity: "FATAL".into(),
1845 code: Default::default(),
1846 message: "MD5 authentication is not supported; configure the server to use SCRAM-SHA-256".into(),
1847 ..DbError::default()
1848 })));
1849 }
1850 BackendMessage::ParameterStatus {
1851 name,
1852 value,
1853 } => {
1854 if name == "integer_datetimes" {
1855 integer_datetimes = Some(value);
1856 }
1857 }
1858 BackendMessage::BackendKeyData {
1859 pid,
1860 secret_key,
1861 } => {
1862 backend_key = Some((pid, secret_key));
1863 }
1864 BackendMessage::NoticeResponse(_) => {}
1865 BackendMessage::ReadyForQuery(_) => break,
1866 other => {
1867 return Err(Error::Protocol(ProtocolError::Protocol(format!(
1868 "unexpected message during startup: {other:?}"
1869 ))));
1870 }
1871 }
1872 }
1873
1874 if let Some(setting) = integer_datetimes {
1875 if setting != "on" {
1876 return Err(Error::Config(
1877 "the server reports integer_datetimes=off, which is not supported".into(),
1878 ));
1879 }
1880 }
1881
1882 Ok(backend_key.unwrap_or((0, 0)))
1883}
1884
1885async fn read_backend(
1886 stream: &mut PgStream,
1887 buf: &mut BytesMut,
1888 max_message_len: usize,
1889) -> Result<BackendMessage, Error> {
1890 loop {
1891 match postgresql_protocol::decode_with_limit(buf, max_message_len) {
1892 Ok(Some(message)) => return Ok(message),
1893 Ok(None) => {}
1894 Err(ProtocolError::Server(db)) => return Err(Error::Server(db)),
1895 Err(err) => return Err(Error::Protocol(err)),
1896 }
1897 buf.reserve(READ_BUFFER_SIZE);
1898 let read = stream.read_buf(buf).await.map_err(Error::Io)?;
1899 if read == 0 {
1900 return Err(Error::Closed);
1901 }
1902 }
1903}
1904
1905impl crate::query::sealed::Sealed for Connection {}
1906
1907impl crate::query::Capable for Connection {
1908 fn execute<'a>(
1909 &'a self,
1910 sql: &'a str,
1911 params: &'a [&'a dyn ToSql],
1912 ) -> impl std::future::Future<Output = Result<u64, Error>> + Send + 'a {
1913 async move { Connection::execute(self, sql, params).await }
1914 }
1915
1916 fn fetch_rows<'a>(
1917 &'a self,
1918 sql: &'a str,
1919 params: &'a [&'a dyn ToSql],
1920 max_rows: i32,
1921 ) -> impl std::future::Future<Output = Result<RowStream, Error>> + Send + 'a {
1922 async move { Connection::fetch_rows(self, sql, params, max_rows).await }
1923 }
1924}
1925
1926impl crate::query::ScriptExecutor for Connection {
1927 fn execute_script<'a>(&'a self, sql: &'a str) -> impl std::future::Future<Output = Result<u64, Error>> + Send + 'a {
1928 async move { Connection::execute_script(self, sql).await }
1929 }
1930}
1931
1932#[cfg(test)]
1933mod tests {
1934 use super::*;
1935
1936 #[test]
1937 fn stale_plan_is_only_retried_before_rows_are_delivered() {
1938 let stale = Error::Server(Box::new(DbError {
1939 code: "0A000".into(),
1940 ..DbError::default()
1941 }));
1942 assert!(should_retry(1, false, &stale));
1943 assert!(
1944 !should_retry(1, true, &stale),
1945 "retrying after rows were delivered would duplicate them"
1946 );
1947 assert!(!should_retry(2, false, &stale), "only one retry is allowed");
1948
1949 let missing = Error::Server(Box::new(DbError {
1950 code: "26000".into(),
1951 ..DbError::default()
1952 }));
1953 assert!(should_retry(1, false, &missing));
1954
1955 let other = Error::Server(Box::new(DbError {
1956 code: "23505".into(),
1957 ..DbError::default()
1958 }));
1959 assert!(!should_retry(1, false, &other));
1960
1961 assert!(!should_retry(1, false, &Error::Closed));
1962 }
1963}