From 6ae17e0f2d174fc4d5592ac7869909d7bdd346d9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 15 Sep 2024 20:14:38 -0400 Subject: [PATCH 01/37] Release postgres v0.19.9 --- postgres/CHANGELOG.md | 2 ++ postgres/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 6feb629e4..c3e686714 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## v0.19.9 - 2024-09-15 + ### Added * Added support for `jiff` 0.1 via the `with-jiff-01` feature. diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index e0e580f7d..9e360c2a4 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.19.8" +version = "0.19.9" authors = ["Steven Fackler "] edition = "2018" license = "MIT OR Apache-2.0" @@ -41,7 +41,7 @@ bytes = "1.0" fallible-iterator = "0.2" futures-util = { version = "0.3.14", features = ["sink"] } log = "0.4" -tokio-postgres = { version = "0.7.11", path = "../tokio-postgres" } +tokio-postgres = { version = "0.7.12", path = "../tokio-postgres" } tokio = { version = "1.0", features = ["rt", "time"] } [dev-dependencies] From 60c11825f4254c493ea553d66ed858e87cd991ca Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Fri, 5 Jul 2024 15:06:41 +0800 Subject: [PATCH 02/37] feat: add ssl_negotiation option --- postgres/src/config.rs | 14 +++++++++ tokio-postgres/src/cancel_query.rs | 15 ++++++++-- tokio-postgres/src/cancel_query_raw.rs | 5 ++-- tokio-postgres/src/cancel_token.rs | 5 +++- tokio-postgres/src/client.rs | 6 +++- tokio-postgres/src/config.rs | 39 ++++++++++++++++++++++++++ tokio-postgres/src/connect_raw.rs | 17 +++++++++-- tokio-postgres/src/connect_tls.rs | 25 +++++++++-------- tokio-postgres/tests/test/parse.rs | 6 +++- 9 files changed, 111 insertions(+), 21 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index a32ddc78e..f8acbaa4d 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -10,6 +10,7 @@ use std::str::FromStr; use std::sync::Arc; use std::time::Duration; use tokio::runtime; +use tokio_postgres::config::SslNegotiation; #[doc(inline)] pub use tokio_postgres::config::{ ChannelBinding, Host, LoadBalanceHosts, SslMode, TargetSessionAttrs, @@ -40,6 +41,8 @@ use tokio_postgres::{Error, Socket}; /// path to the directory containing Unix domain sockets. Otherwise, it is treated as a hostname. Multiple hosts /// can be specified, separated by commas. Each host will be tried in turn when connecting. Required if connecting /// with the `connect` method. +/// * `sslnegotiation` - TLS negotiation method. If set to `direct`, the client will perform direct TLS handshake, this only works for PostgreSQL 17 and newer. +/// If set to `postgres`, the default value, it follows original postgres wire protocol to perform the negotiation. /// * `hostaddr` - Numeric IP address of host to connect to. This should be in the standard IPv4 address format, /// e.g., 172.28.40.9. If your machine supports IPv6, you can also use those addresses. /// If this parameter is not specified, the value of `host` will be looked up to find the corresponding IP address, @@ -230,6 +233,17 @@ impl Config { self.config.get_ssl_mode() } + /// Sets the SSL negotiation method + pub fn ssl_negotiation(&mut self, ssl_negotiation: SslNegotiation) -> &mut Config { + self.config.ssl_negotiation(ssl_negotiation); + self + } + + /// Gets the SSL negotiation method + pub fn get_ssl_negotiation(&self) -> SslNegotiation { + self.config.get_ssl_negotiation() + } + /// Adds a host to the configuration. /// /// Multiple hosts can be specified by calling this method multiple times, and each will be tried in order. On Unix diff --git a/tokio-postgres/src/cancel_query.rs b/tokio-postgres/src/cancel_query.rs index 078d4b8b6..2dfd47c06 100644 --- a/tokio-postgres/src/cancel_query.rs +++ b/tokio-postgres/src/cancel_query.rs @@ -1,5 +1,5 @@ use crate::client::SocketConfig; -use crate::config::SslMode; +use crate::config::{SslMode, SslNegotiation}; use crate::tls::MakeTlsConnect; use crate::{cancel_query_raw, connect_socket, Error, Socket}; use std::io; @@ -7,6 +7,7 @@ use std::io; pub(crate) async fn cancel_query( config: Option, ssl_mode: SslMode, + ssl_negotiation: SslNegotiation, mut tls: T, process_id: i32, secret_key: i32, @@ -38,6 +39,14 @@ where ) .await?; - cancel_query_raw::cancel_query_raw(socket, ssl_mode, tls, has_hostname, process_id, secret_key) - .await + cancel_query_raw::cancel_query_raw( + socket, + ssl_mode, + ssl_negotiation, + tls, + has_hostname, + process_id, + secret_key, + ) + .await } diff --git a/tokio-postgres/src/cancel_query_raw.rs b/tokio-postgres/src/cancel_query_raw.rs index 41aafe7d9..886606497 100644 --- a/tokio-postgres/src/cancel_query_raw.rs +++ b/tokio-postgres/src/cancel_query_raw.rs @@ -1,4 +1,4 @@ -use crate::config::SslMode; +use crate::config::{SslMode, SslNegotiation}; use crate::tls::TlsConnect; use crate::{connect_tls, Error}; use bytes::BytesMut; @@ -8,6 +8,7 @@ use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; pub async fn cancel_query_raw( stream: S, mode: SslMode, + negotiation: SslNegotiation, tls: T, has_hostname: bool, process_id: i32, @@ -17,7 +18,7 @@ where S: AsyncRead + AsyncWrite + Unpin, T: TlsConnect, { - let mut stream = connect_tls::connect_tls(stream, mode, tls, has_hostname).await?; + let mut stream = connect_tls::connect_tls(stream, mode, negotiation, tls, has_hostname).await?; let mut buf = BytesMut::new(); frontend::cancel_request(process_id, secret_key, &mut buf); diff --git a/tokio-postgres/src/cancel_token.rs b/tokio-postgres/src/cancel_token.rs index c925ce0ca..1652bec72 100644 --- a/tokio-postgres/src/cancel_token.rs +++ b/tokio-postgres/src/cancel_token.rs @@ -1,4 +1,4 @@ -use crate::config::SslMode; +use crate::config::{SslMode, SslNegotiation}; use crate::tls::TlsConnect; #[cfg(feature = "runtime")] use crate::{cancel_query, client::SocketConfig, tls::MakeTlsConnect, Socket}; @@ -12,6 +12,7 @@ pub struct CancelToken { #[cfg(feature = "runtime")] pub(crate) socket_config: Option, pub(crate) ssl_mode: SslMode, + pub(crate) ssl_negotiation: SslNegotiation, pub(crate) process_id: i32, pub(crate) secret_key: i32, } @@ -37,6 +38,7 @@ impl CancelToken { cancel_query::cancel_query( self.socket_config.clone(), self.ssl_mode, + self.ssl_negotiation, tls, self.process_id, self.secret_key, @@ -54,6 +56,7 @@ impl CancelToken { cancel_query_raw::cancel_query_raw( stream, self.ssl_mode, + self.ssl_negotiation, tls, true, self.process_id, diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 92eabde36..b38bbba37 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -1,5 +1,5 @@ use crate::codec::BackendMessages; -use crate::config::SslMode; +use crate::config::{SslMode, SslNegotiation}; use crate::connection::{Request, RequestMessages}; use crate::copy_out::CopyOutStream; #[cfg(feature = "runtime")] @@ -180,6 +180,7 @@ pub struct Client { #[cfg(feature = "runtime")] socket_config: Option, ssl_mode: SslMode, + ssl_negotiation: SslNegotiation, process_id: i32, secret_key: i32, } @@ -188,6 +189,7 @@ impl Client { pub(crate) fn new( sender: mpsc::UnboundedSender, ssl_mode: SslMode, + ssl_negotiation: SslNegotiation, process_id: i32, secret_key: i32, ) -> Client { @@ -200,6 +202,7 @@ impl Client { #[cfg(feature = "runtime")] socket_config: None, ssl_mode, + ssl_negotiation, process_id, secret_key, } @@ -550,6 +553,7 @@ impl Client { #[cfg(feature = "runtime")] socket_config: self.socket_config.clone(), ssl_mode: self.ssl_mode, + ssl_negotiation: self.ssl_negotiation, process_id: self.process_id, secret_key: self.secret_key, } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 62b45f793..e78f489f8 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -50,6 +50,16 @@ pub enum SslMode { Require, } +/// TLS negotiation configuration +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub enum SslNegotiation { + /// Use PostgreSQL SslRequest for Ssl negotiation + Postgres, + /// Start Ssl handshake without negotiation, only works for PostgreSQL 17+ + Direct, +} + /// Channel binding configuration. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[non_exhaustive] @@ -106,6 +116,8 @@ pub enum Host { /// path to the directory containing Unix domain sockets. Otherwise, it is treated as a hostname. Multiple hosts /// can be specified, separated by commas. Each host will be tried in turn when connecting. Required if connecting /// with the `connect` method. +/// * `sslnegotiation` - TLS negotiation method. If set to `direct`, the client will perform direct TLS handshake, this only works for PostgreSQL 17 and newer. +/// If set to `postgres`, the default value, it follows original postgres wire protocol to perform the negotiation. /// * `hostaddr` - Numeric IP address of host to connect to. This should be in the standard IPv4 address format, /// e.g., 172.28.40.9. If your machine supports IPv6, you can also use those addresses. /// If this parameter is not specified, the value of `host` will be looked up to find the corresponding IP address, @@ -198,6 +210,7 @@ pub struct Config { pub(crate) options: Option, pub(crate) application_name: Option, pub(crate) ssl_mode: SslMode, + pub(crate) ssl_negotiation: SslNegotiation, pub(crate) host: Vec, pub(crate) hostaddr: Vec, pub(crate) port: Vec, @@ -227,6 +240,7 @@ impl Config { options: None, application_name: None, ssl_mode: SslMode::Prefer, + ssl_negotiation: SslNegotiation::Postgres, host: vec![], hostaddr: vec![], port: vec![], @@ -325,6 +339,19 @@ impl Config { self.ssl_mode } + /// Sets the SSL negotiation method. + /// + /// Defaults to `postgres`. + pub fn ssl_negotiation(&mut self, ssl_negotiation: SslNegotiation) -> &mut Config { + self.ssl_negotiation = ssl_negotiation; + self + } + + /// Gets the SSL negotiation method. + pub fn get_ssl_negotiation(&self) -> SslNegotiation { + self.ssl_negotiation + } + /// Adds a host to the configuration. /// /// Multiple hosts can be specified by calling this method multiple times, and each will be tried in order. On Unix @@ -550,6 +577,18 @@ impl Config { }; self.ssl_mode(mode); } + "sslnegotiation" => { + let mode = match value { + "postgres" => SslNegotiation::Postgres, + "direct" => SslNegotiation::Direct, + _ => { + return Err(Error::config_parse(Box::new(InvalidValue( + "sslnegotiation", + )))) + } + }; + self.ssl_negotiation(mode); + } "host" => { for host in value.split(',') { self.host(host); diff --git a/tokio-postgres/src/connect_raw.rs b/tokio-postgres/src/connect_raw.rs index 19be9eb01..cf7476cab 100644 --- a/tokio-postgres/src/connect_raw.rs +++ b/tokio-postgres/src/connect_raw.rs @@ -89,7 +89,14 @@ where S: AsyncRead + AsyncWrite + Unpin, T: TlsConnect, { - let stream = connect_tls(stream, config.ssl_mode, tls, has_hostname).await?; + let stream = connect_tls( + stream, + config.ssl_mode, + config.ssl_negotiation, + tls, + has_hostname, + ) + .await?; let mut stream = StartupStream { inner: Framed::new(stream, PostgresCodec), @@ -107,7 +114,13 @@ where let (process_id, secret_key, parameters) = read_info(&mut stream).await?; let (sender, receiver) = mpsc::unbounded(); - let client = Client::new(sender, config.ssl_mode, process_id, secret_key); + let client = Client::new( + sender, + config.ssl_mode, + config.ssl_negotiation, + process_id, + secret_key, + ); let connection = Connection::new(stream.inner, stream.delayed, parameters, receiver); Ok((client, connection)) diff --git a/tokio-postgres/src/connect_tls.rs b/tokio-postgres/src/connect_tls.rs index 2b1229125..c7a093064 100644 --- a/tokio-postgres/src/connect_tls.rs +++ b/tokio-postgres/src/connect_tls.rs @@ -1,4 +1,4 @@ -use crate::config::SslMode; +use crate::config::{SslMode, SslNegotiation}; use crate::maybe_tls_stream::MaybeTlsStream; use crate::tls::private::ForcePrivateApi; use crate::tls::TlsConnect; @@ -10,6 +10,7 @@ use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; pub async fn connect_tls( mut stream: S, mode: SslMode, + negotiation: SslNegotiation, tls: T, has_hostname: bool, ) -> Result, Error> @@ -25,18 +26,20 @@ where SslMode::Prefer | SslMode::Require => {} } - let mut buf = BytesMut::new(); - frontend::ssl_request(&mut buf); - stream.write_all(&buf).await.map_err(Error::io)?; + if negotiation == SslNegotiation::Postgres { + let mut buf = BytesMut::new(); + frontend::ssl_request(&mut buf); + stream.write_all(&buf).await.map_err(Error::io)?; - let mut buf = [0]; - stream.read_exact(&mut buf).await.map_err(Error::io)?; + let mut buf = [0]; + stream.read_exact(&mut buf).await.map_err(Error::io)?; - if buf[0] != b'S' { - if SslMode::Require == mode { - return Err(Error::tls("server does not support TLS".into())); - } else { - return Ok(MaybeTlsStream::Raw(stream)); + if buf[0] != b'S' { + if SslMode::Require == mode { + return Err(Error::tls("server does not support TLS".into())); + } else { + return Ok(MaybeTlsStream::Raw(stream)); + } } } diff --git a/tokio-postgres/tests/test/parse.rs b/tokio-postgres/tests/test/parse.rs index 04d422e27..35eeca72b 100644 --- a/tokio-postgres/tests/test/parse.rs +++ b/tokio-postgres/tests/test/parse.rs @@ -1,5 +1,5 @@ use std::time::Duration; -use tokio_postgres::config::{Config, TargetSessionAttrs}; +use tokio_postgres::config::{Config, SslNegotiation, TargetSessionAttrs}; fn check(s: &str, config: &Config) { assert_eq!(s.parse::().expect(s), *config, "`{}`", s); @@ -42,6 +42,10 @@ fn settings() { .keepalives_idle(Duration::from_secs(30)) .target_session_attrs(TargetSessionAttrs::ReadOnly), ); + check( + "sslnegotiation=direct", + Config::new().ssl_negotiation(SslNegotiation::Direct), + ); } #[test] From 6a6fdb9957a65692346fafc76c60ea978c85c8a5 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 6 Jul 2024 15:26:13 +0800 Subject: [PATCH 03/37] test: updte tests for direct tls --- docker-compose.yml | 2 +- postgres-native-tls/Cargo.toml | 2 +- postgres-native-tls/src/test.rs | 16 ++++++++++++++++ postgres-openssl/src/test.rs | 13 +++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0ed44148d..5593abb5a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '2' services: postgres: - image: postgres:14 + image: docker.io/postgres:17beta2 ports: - 5433:5433 volumes: diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index 02259b3dc..e86c7ce2d 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -16,7 +16,7 @@ default = ["runtime"] runtime = ["tokio-postgres/runtime"] [dependencies] -native-tls = "0.2" +native-tls = { version = "0.2", features = ["alpn"] } tokio = "1.0" tokio-native-tls = "0.3" tokio-postgres = { version = "0.7.11", path = "../tokio-postgres", default-features = false } diff --git a/postgres-native-tls/src/test.rs b/postgres-native-tls/src/test.rs index 25cc6fdbd..a02d96034 100644 --- a/postgres-native-tls/src/test.rs +++ b/postgres-native-tls/src/test.rs @@ -42,6 +42,22 @@ async fn require() { .await; } +#[tokio::test] +async fn direct() { + let connector = native_tls::TlsConnector::builder() + .add_root_certificate( + Certificate::from_pem(include_bytes!("../../test/server.crt")).unwrap(), + ) + .request_alpns(&["postgresql"]) + .build() + .unwrap(); + smoke_test( + "user=ssl_user dbname=postgres sslmode=require sslnegotiation=direct", + TlsConnector::new(connector, "localhost"), + ) + .await; +} + #[tokio::test] async fn prefer() { let connector = native_tls::TlsConnector::builder() diff --git a/postgres-openssl/src/test.rs b/postgres-openssl/src/test.rs index b361ee446..780f9d16d 100644 --- a/postgres-openssl/src/test.rs +++ b/postgres-openssl/src/test.rs @@ -37,6 +37,19 @@ async fn require() { .await; } +#[tokio::test] +async fn direct() { + let mut builder = SslConnector::builder(SslMethod::tls()).unwrap(); + builder.set_ca_file("../test/server.crt").unwrap(); + builder.set_alpn_protos(b"\x0apostgresql").unwrap(); + let ctx = builder.build(); + smoke_test( + "user=ssl_user dbname=postgres sslmode=require sslnegotiation=direct", + TlsConnector::new(ctx.configure().unwrap(), "localhost"), + ) + .await; +} + #[tokio::test] async fn prefer() { let mut builder = SslConnector::builder(SslMethod::tls()).unwrap(); From 9441ce101749cac4245ae20fa6b75d33e273c232 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 6 Jul 2024 15:38:33 +0800 Subject: [PATCH 04/37] feat: provide built-in functions for setting ALPN --- postgres-native-tls/src/lib.rs | 8 ++++++++ postgres-native-tls/src/test.rs | 14 ++++++-------- postgres-openssl/src/lib.rs | 9 ++++++++- postgres-openssl/src/test.rs | 2 +- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/postgres-native-tls/src/lib.rs b/postgres-native-tls/src/lib.rs index a06f185b5..c599165a1 100644 --- a/postgres-native-tls/src/lib.rs +++ b/postgres-native-tls/src/lib.rs @@ -53,6 +53,7 @@ //! ``` #![warn(rust_2018_idioms, clippy::all, missing_docs)] +use native_tls::TlsConnectorBuilder; use std::future::Future; use std::io; use std::pin::Pin; @@ -180,3 +181,10 @@ where } } } + +/// Set ALPN for `TlsConnectorBuilder` +/// +/// This is required when using `sslnegotiation=direct` +pub fn set_postgresql_alpn(builder: &mut TlsConnectorBuilder) -> &mut TlsConnectorBuilder { + builder.request_alpns(&["postgresql"]) +} diff --git a/postgres-native-tls/src/test.rs b/postgres-native-tls/src/test.rs index a02d96034..b34fa7351 100644 --- a/postgres-native-tls/src/test.rs +++ b/postgres-native-tls/src/test.rs @@ -5,7 +5,7 @@ use tokio_postgres::tls::TlsConnect; #[cfg(feature = "runtime")] use crate::MakeTlsConnector; -use crate::TlsConnector; +use crate::{set_postgresql_alpn, TlsConnector}; async fn smoke_test(s: &str, tls: T) where @@ -44,13 +44,11 @@ async fn require() { #[tokio::test] async fn direct() { - let connector = native_tls::TlsConnector::builder() - .add_root_certificate( - Certificate::from_pem(include_bytes!("../../test/server.crt")).unwrap(), - ) - .request_alpns(&["postgresql"]) - .build() - .unwrap(); + let connector = set_postgresql_alpn(native_tls::TlsConnector::builder().add_root_certificate( + Certificate::from_pem(include_bytes!("../../test/server.crt")).unwrap(), + )) + .build() + .unwrap(); smoke_test( "user=ssl_user dbname=postgres sslmode=require sslnegotiation=direct", TlsConnector::new(connector, "localhost"), diff --git a/postgres-openssl/src/lib.rs b/postgres-openssl/src/lib.rs index 837663fe7..232cccd05 100644 --- a/postgres-openssl/src/lib.rs +++ b/postgres-openssl/src/lib.rs @@ -53,7 +53,7 @@ use openssl::hash::MessageDigest; use openssl::nid::Nid; #[cfg(feature = "runtime")] use openssl::ssl::SslConnector; -use openssl::ssl::{self, ConnectConfiguration, SslRef}; +use openssl::ssl::{self, ConnectConfiguration, SslConnectorBuilder, SslRef}; use openssl::x509::X509VerifyResult; use std::error::Error; use std::fmt::{self, Debug}; @@ -250,3 +250,10 @@ fn tls_server_end_point(ssl: &SslRef) -> Option> { }; cert.digest(md).ok().map(|b| b.to_vec()) } + +/// Set ALPN for `SslConnectorBuilder` +/// +/// This is required when using `sslnegotiation=direct` +pub fn set_postgresql_alpn(builder: &mut SslConnectorBuilder) -> Result<(), ErrorStack> { + builder.set_alpn_protos(b"\x0apostgresql") +} diff --git a/postgres-openssl/src/test.rs b/postgres-openssl/src/test.rs index 780f9d16d..66bb22641 100644 --- a/postgres-openssl/src/test.rs +++ b/postgres-openssl/src/test.rs @@ -41,7 +41,7 @@ async fn require() { async fn direct() { let mut builder = SslConnector::builder(SslMethod::tls()).unwrap(); builder.set_ca_file("../test/server.crt").unwrap(); - builder.set_alpn_protos(b"\x0apostgresql").unwrap(); + set_postgresql_alpn(&mut builder).unwrap(); let ctx = builder.build(); smoke_test( "user=ssl_user dbname=postgres sslmode=require sslnegotiation=direct", From cfdc66f6f56a7fa40934d1b9f4c9ae7656838fed Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sat, 6 Jul 2024 22:07:26 +0800 Subject: [PATCH 05/37] refactor: pub use sslnegotiation --- postgres/src/config.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index f8acbaa4d..8c4949825 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -10,10 +10,9 @@ use std::str::FromStr; use std::sync::Arc; use std::time::Duration; use tokio::runtime; -use tokio_postgres::config::SslNegotiation; #[doc(inline)] pub use tokio_postgres::config::{ - ChannelBinding, Host, LoadBalanceHosts, SslMode, TargetSessionAttrs, + ChannelBinding, Host, LoadBalanceHosts, SslMode, SslNegotiation, TargetSessionAttrs, }; use tokio_postgres::error::DbError; use tokio_postgres::tls::{MakeTlsConnect, TlsConnect}; From db308ef095f29a6bc348db953af62fc9b1d1962d Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 7 Jul 2024 10:12:41 +0800 Subject: [PATCH 06/37] refactor: apply review comments --- postgres-native-tls/src/lib.rs | 4 ++-- postgres/src/config.rs | 1 + tokio-postgres/src/config.rs | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/postgres-native-tls/src/lib.rs b/postgres-native-tls/src/lib.rs index c599165a1..9ee7da653 100644 --- a/postgres-native-tls/src/lib.rs +++ b/postgres-native-tls/src/lib.rs @@ -185,6 +185,6 @@ where /// Set ALPN for `TlsConnectorBuilder` /// /// This is required when using `sslnegotiation=direct` -pub fn set_postgresql_alpn(builder: &mut TlsConnectorBuilder) -> &mut TlsConnectorBuilder { - builder.request_alpns(&["postgresql"]) +pub fn set_postgresql_alpn(builder: &mut TlsConnectorBuilder) { + builder.request_alpns(&["postgresql"]); } diff --git a/postgres/src/config.rs b/postgres/src/config.rs index 8c4949825..ae710d16b 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -41,6 +41,7 @@ use tokio_postgres::{Error, Socket}; /// can be specified, separated by commas. Each host will be tried in turn when connecting. Required if connecting /// with the `connect` method. /// * `sslnegotiation` - TLS negotiation method. If set to `direct`, the client will perform direct TLS handshake, this only works for PostgreSQL 17 and newer. +/// Note that you will need to setup ALPN of TLS client configuration to `postgresql` when using direct TLS. /// If set to `postgres`, the default value, it follows original postgres wire protocol to perform the negotiation. /// * `hostaddr` - Numeric IP address of host to connect to. This should be in the standard IPv4 address format, /// e.g., 172.28.40.9. If your machine supports IPv6, you can also use those addresses. diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index e78f489f8..fb673b9b9 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -117,6 +117,7 @@ pub enum Host { /// can be specified, separated by commas. Each host will be tried in turn when connecting. Required if connecting /// with the `connect` method. /// * `sslnegotiation` - TLS negotiation method. If set to `direct`, the client will perform direct TLS handshake, this only works for PostgreSQL 17 and newer. +/// Note that you will need to setup ALPN of TLS client configuration to `postgresql` when using direct TLS. /// If set to `postgres`, the default value, it follows original postgres wire protocol to perform the negotiation. /// * `hostaddr` - Numeric IP address of host to connect to. This should be in the standard IPv4 address format, /// e.g., 172.28.40.9. If your machine supports IPv6, you can also use those addresses. From 331e968a9f3f4d8e5aa6beefa291c55eff6f52c6 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Thu, 26 Sep 2024 19:26:36 -0700 Subject: [PATCH 07/37] chore: update postgres for ci --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5593abb5a..991df2d01 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '2' services: postgres: - image: docker.io/postgres:17beta2 + image: docker.io/postgres:17 ports: - 5433:5433 volumes: From eea7f13cea9f96e4ebc8176a3357922e25bef013 Mon Sep 17 00:00:00 2001 From: Sidney Cammeresi Date: Fri, 25 Oct 2024 13:43:57 -0700 Subject: [PATCH 08/37] Add support for cidr 0.3 under separate feature --- postgres-types/Cargo.toml | 2 ++ postgres-types/src/cidr_03.rs | 44 +++++++++++++++++++++++++++++++++++ postgres-types/src/lib.rs | 2 ++ 3 files changed, 48 insertions(+) create mode 100644 postgres-types/src/cidr_03.rs diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index ec8cea4dc..d417664ea 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -16,6 +16,7 @@ array-impls = ["array-init"] js = ["postgres-protocol/js"] with-bit-vec-0_6 = ["bit-vec-06"] with-cidr-0_2 = ["cidr-02"] +with-cidr-0_3 = ["cidr-03"] with-chrono-0_4 = ["chrono-04"] with-eui48-0_4 = ["eui48-04"] with-eui48-1 = ["eui48-1"] @@ -41,6 +42,7 @@ chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, "clock", ], optional = true } cidr-02 = { version = "0.2", package = "cidr", optional = true } +cidr-03 = { version = "0.3", package = "cidr", optional = true } # eui48-04 will stop compiling and support will be removed # See https://github.com/sfackler/rust-postgres/issues/1073 eui48-04 = { version = "0.4", package = "eui48", optional = true } diff --git a/postgres-types/src/cidr_03.rs b/postgres-types/src/cidr_03.rs new file mode 100644 index 000000000..6a0178711 --- /dev/null +++ b/postgres-types/src/cidr_03.rs @@ -0,0 +1,44 @@ +use bytes::BytesMut; +use cidr_03::{IpCidr, IpInet}; +use postgres_protocol::types; +use std::error::Error; + +use crate::{FromSql, IsNull, ToSql, Type}; + +impl<'a> FromSql<'a> for IpCidr { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let inet = types::inet_from_sql(raw)?; + Ok(IpCidr::new(inet.addr(), inet.netmask())?) + } + + accepts!(CIDR); +} + +impl ToSql for IpCidr { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + types::inet_to_sql(self.first_address(), self.network_length(), w); + Ok(IsNull::No) + } + + accepts!(CIDR); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for IpInet { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let inet = types::inet_from_sql(raw)?; + Ok(IpInet::new(inet.addr(), inet.netmask())?) + } + + accepts!(INET); +} + +impl ToSql for IpInet { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + types::inet_to_sql(self.address(), self.network_length(), w); + Ok(IsNull::No) + } + + accepts!(INET); + to_sql_checked!(); +} diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 6ad2eff50..c5593cff8 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -268,6 +268,8 @@ mod bit_vec_06; mod chrono_04; #[cfg(feature = "with-cidr-0_2")] mod cidr_02; +#[cfg(feature = "with-cidr-0_3")] +mod cidr_03; #[cfg(feature = "with-eui48-0_4")] mod eui48_04; #[cfg(feature = "with-eui48-1")] From 7eb6f8e91b2b0841c02ee88b475e7a463050a974 Mon Sep 17 00:00:00 2001 From: Harris Kaufmann Date: Wed, 18 Dec 2024 14:17:00 +0100 Subject: [PATCH 09/37] add `load_balance_hosts` to `Debug` impl for `Config` --- tokio-postgres/src/config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 62b45f793..5bca418bd 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -744,6 +744,7 @@ impl fmt::Debug for Config { config_dbg .field("target_session_attrs", &self.target_session_attrs) .field("channel_binding", &self.channel_binding) + .field("load_balance_hosts", &self.load_balance_hosts) .finish() } } From 2df69c970f4b5e496898311e60e8f2c96915b2c9 Mon Sep 17 00:00:00 2001 From: Jacek Malec Date: Fri, 10 Jan 2025 14:15:46 +0000 Subject: [PATCH 10/37] perf: simplify typeinfo queries --- postgres-types/src/lib.rs | 21 ++------------------- postgres-types/src/type_gen.rs | 1 - tokio-postgres/src/error/mod.rs | 6 ++++++ tokio-postgres/src/prepare.rs | 20 ++++++-------------- 4 files changed, 14 insertions(+), 34 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index c56eebba6..0c979812d 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -313,23 +313,14 @@ impl fmt::Debug for Type { impl fmt::Display for Type { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.schema() { - "public" | "pg_catalog" => {} - schema => write!(fmt, "{}.", schema)?, - } fmt.write_str(self.name()) } } impl Type { /// Creates a new `Type`. - pub fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Type { - Type(Inner::Other(Arc::new(Other { - name, - oid, - kind, - schema, - }))) + pub fn new(name: String, oid: Oid, kind: Kind) -> Type { + Type(Inner::Other(Arc::new(Other { name, oid, kind }))) } /// Returns the `Type` corresponding to the provided `Oid` if it @@ -348,14 +339,6 @@ impl Type { self.0.kind() } - /// Returns the schema of this type. - pub fn schema(&self) -> &str { - match self.0 { - Inner::Other(ref u) => &u.schema, - _ => "pg_catalog", - } - } - /// Returns the name of this type. pub fn name(&self) -> &str { self.0.name() diff --git a/postgres-types/src/type_gen.rs b/postgres-types/src/type_gen.rs index a1bc3f85c..311dbdb96 100644 --- a/postgres-types/src/type_gen.rs +++ b/postgres-types/src/type_gen.rs @@ -8,7 +8,6 @@ pub struct Other { pub name: String, pub oid: Oid, pub kind: Kind, - pub schema: String, } #[derive(PartialEq, Eq, Clone, Debug, Hash)] diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index 75664d258..07b3fd152 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -357,6 +357,7 @@ enum Kind { #[cfg(feature = "runtime")] Connect, Timeout, + UnsupportedType, } struct ErrorInner { @@ -399,6 +400,7 @@ impl fmt::Display for Error { #[cfg(feature = "runtime")] Kind::Connect => fmt.write_str("error connecting to server")?, Kind::Timeout => fmt.write_str("timeout waiting for server")?, + Kind::UnsupportedType => fmt.write_str("unsupported type")?, }; if let Some(ref cause) = self.0.cause { write!(fmt, ": {}", cause)?; @@ -450,6 +452,10 @@ impl Error { Error::new(Kind::UnexpectedMessage, None) } + pub(crate) fn unsupported_type() -> Error { + Error::new(Kind::UnsupportedType, None) + } + #[allow(clippy::needless_pass_by_value)] pub(crate) fn db(error: ErrorResponseBody) -> Error { match DbError::parse(&mut error.fields()) { diff --git a/tokio-postgres/src/prepare.rs b/tokio-postgres/src/prepare.rs index f2aeea007..78181a91a 100644 --- a/tokio-postgres/src/prepare.rs +++ b/tokio-postgres/src/prepare.rs @@ -17,18 +17,15 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; const TYPEINFO_QUERY: &str = "\ -SELECT t.typname, t.typtype, t.typelem, r.rngsubtype, t.typbasetype, n.nspname, t.typrelid +SELECT t.typname, t.typtype, t.typelem, t.typbasetype, t.typrelid FROM pg_catalog.pg_type t -LEFT OUTER JOIN pg_catalog.pg_range r ON r.rngtypid = t.oid -INNER JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid WHERE t.oid = $1 "; // Range types weren't added until Postgres 9.2, so pg_range may not exist const TYPEINFO_FALLBACK_QUERY: &str = "\ -SELECT t.typname, t.typtype, t.typelem, NULL::OID, t.typbasetype, n.nspname, t.typrelid +SELECT t.typname, t.typtype, t.typelem, t.typbasetype, t.typrelid FROM pg_catalog.pg_type t -INNER JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid WHERE t.oid = $1 "; @@ -153,10 +150,8 @@ pub(crate) async fn get_type(client: &Arc, oid: Oid) -> Result = row.try_get(3)?; - let basetype: Oid = row.try_get(4)?; - let schema: String = row.try_get(5)?; - let relid: Oid = row.try_get(6)?; + let basetype: Oid = row.try_get(3)?; + let relid: Oid = row.try_get(4)?; let kind = if type_ == b'e' as i8 { // Note: Quaint is not using the variants information at any time. @@ -173,14 +168,11 @@ pub(crate) async fn get_type(client: &Arc, oid: Oid) -> Result Date: Fri, 10 Jan 2025 14:28:56 +0000 Subject: [PATCH 11/37] fix: handle base type --- tokio-postgres/src/prepare.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tokio-postgres/src/prepare.rs b/tokio-postgres/src/prepare.rs index 78181a91a..91dda738a 100644 --- a/tokio-postgres/src/prepare.rs +++ b/tokio-postgres/src/prepare.rs @@ -168,6 +168,8 @@ pub(crate) async fn get_type(client: &Arc, oid: Oid) -> Result Date: Sun, 19 Jan 2025 23:53:23 -0500 Subject: [PATCH 12/37] Fix time 0.3 infinity panics Getting `PrimitiveDateTime` panics if the value is infinity. This commit fixes the panic. An infinity test is added, mirroring the existing one for chrono. --- postgres-types/src/time_02.rs | 4 ++- postgres-types/src/time_03.rs | 9 +++-- tokio-postgres/tests/test/types/time_03.rs | 38 +++++++++++++++++++++- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/postgres-types/src/time_02.rs b/postgres-types/src/time_02.rs index 19a8909e7..1f2ba1ce1 100644 --- a/postgres-types/src/time_02.rs +++ b/postgres-types/src/time_02.rs @@ -14,7 +14,9 @@ const fn base() -> PrimitiveDateTime { impl<'a> FromSql<'a> for PrimitiveDateTime { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let t = types::timestamp_from_sql(raw)?; - Ok(base() + Duration::microseconds(t)) + Ok(base() + .checked_add(Duration::microseconds(t)) + .ok_or("value too large to decode")?) } accepts!(TIMESTAMP); diff --git a/postgres-types/src/time_03.rs b/postgres-types/src/time_03.rs index f136fab7c..4deea663f 100644 --- a/postgres-types/src/time_03.rs +++ b/postgres-types/src/time_03.rs @@ -13,7 +13,9 @@ fn base() -> PrimitiveDateTime { impl<'a> FromSql<'a> for PrimitiveDateTime { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let t = types::timestamp_from_sql(raw)?; - Ok(base() + Duration::microseconds(t)) + Ok(base() + .checked_add(Duration::microseconds(t)) + .ok_or("value too large to decode")?) } accepts!(TIMESTAMP); @@ -62,7 +64,10 @@ impl ToSql for OffsetDateTime { impl<'a> FromSql<'a> for Date { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let jd = types::date_from_sql(raw)?; - Ok(base().date() + Duration::days(i64::from(jd))) + Ok(base() + .date() + .checked_add(Duration::days(i64::from(jd))) + .ok_or("value too large to decode")?) } accepts!(DATE); diff --git a/tokio-postgres/tests/test/types/time_03.rs b/tokio-postgres/tests/test/types/time_03.rs index df013c9bf..fca940a97 100644 --- a/tokio-postgres/tests/test/types/time_03.rs +++ b/tokio-postgres/tests/test/types/time_03.rs @@ -1,5 +1,11 @@ +use std::fmt; + +use postgres_types::FromSqlOwned; use time_03::{format_description, OffsetDateTime, PrimitiveDateTime}; -use tokio_postgres::types::{Date, Timestamp}; +use tokio_postgres::{ + types::{Date, Timestamp}, + Client, +}; use crate::types::test_type; @@ -147,3 +153,33 @@ async fn test_time_params() { ) .await; } + +#[tokio::test] +async fn test_special_params_without_wrapper() { + async fn assert_overflows(client: &mut Client, val: &str, sql_type: &str) + where + T: FromSqlOwned + fmt::Debug, + { + let err = client + .query_one(&*format!("SELECT {}::{}", val, sql_type), &[]) + .await + .unwrap() + .try_get::<_, T>(0) + .unwrap_err(); + assert_eq!( + err.to_string(), + "error deserializing column 0: value too large to decode" + ); + } + + let mut client = crate::connect("user=postgres").await; + + assert_overflows::(&mut client, "'-infinity'", "timestamptz").await; + assert_overflows::(&mut client, "'infinity'", "timestamptz").await; + + assert_overflows::(&mut client, "'-infinity'", "timestamp").await; + assert_overflows::(&mut client, "'infinity'", "timestamp").await; + + assert_overflows::(&mut client, "'-infinity'", "date").await; + assert_overflows::(&mut client, "'infinity'", "date").await; +} From 24d3234a38c79e1c063396015d70c9ffd5c010f0 Mon Sep 17 00:00:00 2001 From: Allan <6740989+allan2@users.noreply.github.com> Date: Mon, 20 Jan 2025 01:40:22 -0500 Subject: [PATCH 13/37] Fix clippy needless_lifetimes --- postgres-protocol/src/message/backend.rs | 8 ++++---- postgres-protocol/src/types/mod.rs | 4 ++-- postgres-types/src/lib.rs | 20 ++++++++++---------- postgres/src/notifications.rs | 6 +++--- postgres/src/transaction.rs | 2 +- tokio-postgres/src/query.rs | 2 +- tokio-postgres/src/row.rs | 4 ++-- tokio-postgres/src/to_statement.rs | 2 +- tokio-postgres/src/transaction.rs | 2 +- tokio-postgres/src/transaction_builder.rs | 2 +- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/postgres-protocol/src/message/backend.rs b/postgres-protocol/src/message/backend.rs index 73b169288..013bfbb81 100644 --- a/postgres-protocol/src/message/backend.rs +++ b/postgres-protocol/src/message/backend.rs @@ -475,7 +475,7 @@ pub struct ColumnFormats<'a> { remaining: u16, } -impl<'a> FallibleIterator for ColumnFormats<'a> { +impl FallibleIterator for ColumnFormats<'_> { type Item = u16; type Error = io::Error; @@ -557,7 +557,7 @@ pub struct DataRowRanges<'a> { remaining: u16, } -impl<'a> FallibleIterator for DataRowRanges<'a> { +impl FallibleIterator for DataRowRanges<'_> { type Item = Option>; type Error = io::Error; @@ -645,7 +645,7 @@ pub struct ErrorField<'a> { value: &'a [u8], } -impl<'a> ErrorField<'a> { +impl ErrorField<'_> { #[inline] pub fn type_(&self) -> u8 { self.type_ @@ -717,7 +717,7 @@ pub struct Parameters<'a> { remaining: u16, } -impl<'a> FallibleIterator for Parameters<'a> { +impl FallibleIterator for Parameters<'_> { type Item = Oid; type Error = io::Error; diff --git a/postgres-protocol/src/types/mod.rs b/postgres-protocol/src/types/mod.rs index 05f515f76..37dc793b1 100644 --- a/postgres-protocol/src/types/mod.rs +++ b/postgres-protocol/src/types/mod.rs @@ -582,7 +582,7 @@ impl<'a> Array<'a> { /// An iterator over the dimensions of an array. pub struct ArrayDimensions<'a>(&'a [u8]); -impl<'a> FallibleIterator for ArrayDimensions<'a> { +impl FallibleIterator for ArrayDimensions<'_> { type Item = ArrayDimension; type Error = StdBox; @@ -950,7 +950,7 @@ pub struct PathPoints<'a> { buf: &'a [u8], } -impl<'a> FallibleIterator for PathPoints<'a> { +impl FallibleIterator for PathPoints<'_> { type Item = Point; type Error = StdBox; diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 6ad2eff50..e57f29fbb 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -914,7 +914,7 @@ pub enum Format { Binary, } -impl<'a, T> ToSql for &'a T +impl ToSql for &T where T: ToSql, { @@ -963,7 +963,7 @@ impl ToSql for Option { to_sql_checked!(); } -impl<'a, T: ToSql> ToSql for &'a [T] { +impl ToSql for &[T] { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { let member_type = match *ty.kind() { Kind::Array(ref member) => member, @@ -1004,7 +1004,7 @@ impl<'a, T: ToSql> ToSql for &'a [T] { to_sql_checked!(); } -impl<'a> ToSql for &'a [u8] { +impl ToSql for &[u8] { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { types::bytea_to_sql(self, w); Ok(IsNull::No) @@ -1064,7 +1064,7 @@ impl ToSql for Box<[T]> { to_sql_checked!(); } -impl<'a> ToSql for Cow<'a, [u8]> { +impl ToSql for Cow<'_, [u8]> { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { <&[u8] as ToSql>::to_sql(&self.as_ref(), ty, w) } @@ -1088,7 +1088,7 @@ impl ToSql for Vec { to_sql_checked!(); } -impl<'a> ToSql for &'a str { +impl ToSql for &str { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { match ty.name() { "ltree" => types::ltree_to_sql(self, w), @@ -1109,7 +1109,7 @@ impl<'a> ToSql for &'a str { to_sql_checked!(); } -impl<'a> ToSql for Cow<'a, str> { +impl ToSql for Cow<'_, str> { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { <&str as ToSql>::to_sql(&self.as_ref(), ty, w) } @@ -1256,17 +1256,17 @@ impl BorrowToSql for &dyn ToSql { } } -impl<'a> sealed::Sealed for Box {} +impl sealed::Sealed for Box {} -impl<'a> BorrowToSql for Box { +impl BorrowToSql for Box { #[inline] fn borrow_to_sql(&self) -> &dyn ToSql { self.as_ref() } } -impl<'a> sealed::Sealed for Box {} -impl<'a> BorrowToSql for Box { +impl sealed::Sealed for Box {} +impl BorrowToSql for Box { #[inline] fn borrow_to_sql(&self) -> &dyn ToSql { self.as_ref() diff --git a/postgres/src/notifications.rs b/postgres/src/notifications.rs index c31d4f631..0c040dedf 100644 --- a/postgres/src/notifications.rs +++ b/postgres/src/notifications.rs @@ -77,7 +77,7 @@ pub struct Iter<'a> { connection: ConnectionRef<'a>, } -impl<'a> FallibleIterator for Iter<'a> { +impl FallibleIterator for Iter<'_> { type Item = Notification; type Error = Error; @@ -100,7 +100,7 @@ pub struct BlockingIter<'a> { connection: ConnectionRef<'a>, } -impl<'a> FallibleIterator for BlockingIter<'a> { +impl FallibleIterator for BlockingIter<'_> { type Item = Notification; type Error = Error; @@ -129,7 +129,7 @@ pub struct TimeoutIter<'a> { timeout: Duration, } -impl<'a> FallibleIterator for TimeoutIter<'a> { +impl FallibleIterator for TimeoutIter<'_> { type Item = Notification; type Error = Error; diff --git a/postgres/src/transaction.rs b/postgres/src/transaction.rs index 5c8c15973..8126b1dbe 100644 --- a/postgres/src/transaction.rs +++ b/postgres/src/transaction.rs @@ -12,7 +12,7 @@ pub struct Transaction<'a> { transaction: Option>, } -impl<'a> Drop for Transaction<'a> { +impl Drop for Transaction<'_> { fn drop(&mut self) { if let Some(transaction) = self.transaction.take() { let _ = self.connection.block_on(transaction.rollback()); diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index 3ab002871..e269de3a0 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -20,7 +20,7 @@ use std::task::{Context, Poll}; struct BorrowToSqlParamsDebug<'a, T>(&'a [T]); -impl<'a, T> fmt::Debug for BorrowToSqlParamsDebug<'a, T> +impl fmt::Debug for BorrowToSqlParamsDebug<'_, T> where T: BorrowToSql, { diff --git a/tokio-postgres/src/row.rs b/tokio-postgres/src/row.rs index 767c26921..ccb8817d0 100644 --- a/tokio-postgres/src/row.rs +++ b/tokio-postgres/src/row.rs @@ -79,9 +79,9 @@ impl RowIndex for str { } } -impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {} +impl Sealed for &T where T: ?Sized + Sealed {} -impl<'a, T> RowIndex for &'a T +impl RowIndex for &T where T: ?Sized + RowIndex, { diff --git a/tokio-postgres/src/to_statement.rs b/tokio-postgres/src/to_statement.rs index 427f77dd7..7e1299272 100644 --- a/tokio-postgres/src/to_statement.rs +++ b/tokio-postgres/src/to_statement.rs @@ -11,7 +11,7 @@ mod private { Query(&'a str), } - impl<'a> ToStatementType<'a> { + impl ToStatementType<'_> { pub async fn into_statement(self, client: &Client) -> Result { match self { ToStatementType::Statement(s) => Ok(s.clone()), diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index 17a50b60f..782c476c4 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -33,7 +33,7 @@ struct Savepoint { depth: u32, } -impl<'a> Drop for Transaction<'a> { +impl Drop for Transaction<'_> { fn drop(&mut self) { if self.done { return; diff --git a/tokio-postgres/src/transaction_builder.rs b/tokio-postgres/src/transaction_builder.rs index 93e9e9801..88c883176 100644 --- a/tokio-postgres/src/transaction_builder.rs +++ b/tokio-postgres/src/transaction_builder.rs @@ -113,7 +113,7 @@ impl<'a> TransactionBuilder<'a> { done: bool, } - impl<'a> Drop for RollbackIfNotDone<'a> { + impl Drop for RollbackIfNotDone<'_> { fn drop(&mut self) { if self.done { return; From 7046518af836be42b3ee342eca9177c5b6ec9b97 Mon Sep 17 00:00:00 2001 From: Allan <6740989+allan2@users.noreply.github.com> Date: Mon, 20 Jan 2025 01:41:11 -0500 Subject: [PATCH 14/37] Fix clippy extra_unused_lifetimes --- tokio-postgres/src/query.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index e269de3a0..2fcb22d57 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -61,7 +61,7 @@ where }) } -pub async fn query_typed<'a, P, I>( +pub async fn query_typed( client: &Arc, query: &str, params: I, From b13052a970689d465f481be5cf41682b6d03064a Mon Sep 17 00:00:00 2001 From: Allan <6740989+allan2@users.noreply.github.com> Date: Mon, 20 Jan 2025 01:55:08 -0500 Subject: [PATCH 15/37] Fix for Rust 2024 match ergonomics Fixes an error related to https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html --- postgres-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index e57f29fbb..d0fcfc440 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -955,7 +955,7 @@ impl ToSql for Option { fn encode_format(&self, ty: &Type) -> Format { match self { - Some(ref val) => val.encode_format(ty), + &Some(ref val) => val.encode_format(ty), None => Format::Binary, } } From 4d03ed88bf4c73ef2a2e451bc0d8ad28dae43c1a Mon Sep 17 00:00:00 2001 From: Allan <6740989+allan2@users.noreply.github.com> Date: Mon, 20 Jan 2025 01:58:58 -0500 Subject: [PATCH 16/37] Fix another needless_lifetimes --- tokio-postgres/tests/test/types/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index f962bf10a..875164c3b 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -509,7 +509,7 @@ async fn domain() { to_sql_checked!(); } - impl<'a> FromSql<'a> for SessionId { + impl FromSql<'_> for SessionId { fn from_sql(ty: &Type, raw: &[u8]) -> result::Result> { Vec::::from_sql(ty, raw).map(SessionId) } From 7490e51639310d9d2406d38d6e9b3e31897b96c5 Mon Sep 17 00:00:00 2001 From: Allan <6740989+allan2@users.noreply.github.com> Date: Mon, 20 Jan 2025 02:00:36 -0500 Subject: [PATCH 17/37] Fix clippy needless_borrowed_reference The applied suggestion for 2024 match ergonomics trips another lint. This fixes the lint. --- postgres-types/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index d0fcfc440..05b2ac135 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -955,7 +955,7 @@ impl ToSql for Option { fn encode_format(&self, ty: &Type) -> Format { match self { - &Some(ref val) => val.encode_format(ty), + Some(val) => val.encode_format(ty), None => Format::Binary, } } From 852ae499947cd20a37aeb44e3d73c9eae1611a21 Mon Sep 17 00:00:00 2001 From: Allan <6740989+allan2@users.noreply.github.com> Date: Mon, 20 Jan 2025 02:06:22 -0500 Subject: [PATCH 18/37] Bump CI Rust version to 1.75.0 cargo tests in CI are [failing](https://github.com/sfackler/rust-postgres/actions/runs/12862700447/job/35858038081?pr=1198) because of a dependency requirement: ``` Run cargo test --all error: package `geo-types v0.7.15` cannot be built because it requires rustc 1.75 or newer, while the currently active rustc version is 1.74.0 Either upgrade to rustc 1.75 or newer, or use cargo update geo-types@0.7.15 --precise ver where `ver` is the latest version of `geo-types` supporting rustc 1.74.0 ``` This bumps the Rust version so tests will run. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 641a42722..81c3db8b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,7 +82,7 @@ jobs: - run: docker compose up -d - uses: sfackler/actions/rustup@master with: - version: 1.74.0 + version: 1.75.0 - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - uses: actions/cache@v3 From 66622f3dfbfcefc999c1e0892dd857581a93faa0 Mon Sep 17 00:00:00 2001 From: Allan <6740989+allan2@users.noreply.github.com> Date: Mon, 20 Jan 2025 02:09:36 -0500 Subject: [PATCH 19/37] Bump actions/checkout --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81c3db8b8..c14751e94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,7 +78,7 @@ jobs: name: test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: docker compose up -d - uses: sfackler/actions/rustup@master with: From 0a25fd191010925cfec38f29086e51a567d3aa79 Mon Sep 17 00:00:00 2001 From: Allan Zhang <6740989+allan2@users.noreply.github.com> Date: Mon, 20 Jan 2025 17:21:23 -0500 Subject: [PATCH 20/37] Empty commit (re-run CI) From e00ceb168fc9aeee5a28dd17527e89b3a2d312d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:32:09 +0000 Subject: [PATCH 21/37] Update rand requirement from 0.8 to 0.9 Updates the requirements on [rand](https://github.com/rust-random/rand) to permit the latest version. - [Release notes](https://github.com/rust-random/rand/releases) - [Changelog](https://github.com/rust-random/rand/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-random/rand/compare/0.8.5...0.9.0) --- updated-dependencies: - dependency-name: rand dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- postgres-protocol/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 49cf2d59c..7525532d6 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -20,7 +20,7 @@ fallible-iterator = "0.2" hmac = "0.12" md-5 = "0.10" memchr = "2.0" -rand = "0.8" +rand = "0.9" sha2 = "0.10" stringprep = "0.1" getrandom = { version = "0.2", optional = true } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index ee6fefb81..3fea01ff0 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -59,7 +59,7 @@ postgres-protocol = { version = "0.6.7", path = "../postgres-protocol" } postgres-types = { version = "0.2.8", path = "../postgres-types" } tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } -rand = "0.8.5" +rand = "0.9.0" whoami = "1.4.1" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] From 96f23479caa7ff6c1f1daf66863593cc94765164 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Thu, 30 Jan 2025 18:10:18 +0800 Subject: [PATCH 22/37] refactor: address review comments --- tokio-postgres/src/config.rs | 18 ++++++++++++++---- tokio-postgres/src/connect_tls.rs | 3 +++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index fb673b9b9..20190f4e4 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -51,10 +51,14 @@ pub enum SslMode { } /// TLS negotiation configuration -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +/// +/// See more information at +/// https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLNEGOTIATION +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] #[non_exhaustive] pub enum SslNegotiation { /// Use PostgreSQL SslRequest for Ssl negotiation + #[default] Postgres, /// Start Ssl handshake without negotiation, only works for PostgreSQL 17+ Direct, @@ -116,9 +120,15 @@ pub enum Host { /// path to the directory containing Unix domain sockets. Otherwise, it is treated as a hostname. Multiple hosts /// can be specified, separated by commas. Each host will be tried in turn when connecting. Required if connecting /// with the `connect` method. -/// * `sslnegotiation` - TLS negotiation method. If set to `direct`, the client will perform direct TLS handshake, this only works for PostgreSQL 17 and newer. -/// Note that you will need to setup ALPN of TLS client configuration to `postgresql` when using direct TLS. -/// If set to `postgres`, the default value, it follows original postgres wire protocol to perform the negotiation. +/// * `sslnegotiation` - TLS negotiation method. If set to `direct`, the client +/// will perform direct TLS handshake, this only works for PostgreSQL 17 and +/// newer. +/// Note that you will need to setup ALPN of TLS client configuration to +/// `postgresql` when using direct TLS. If you are using postgres_openssl +/// as TLS backend, a `postgres_openssl::set_postgresql_alpn` helper is +/// provided for that. +/// If set to `postgres`, the default value, it follows original postgres +/// wire protocol to perform the negotiation. /// * `hostaddr` - Numeric IP address of host to connect to. This should be in the standard IPv4 address format, /// e.g., 172.28.40.9. If your machine supports IPv6, you can also use those addresses. /// If this parameter is not specified, the value of `host` will be looked up to find the corresponding IP address, diff --git a/tokio-postgres/src/connect_tls.rs b/tokio-postgres/src/connect_tls.rs index c7a093064..d220cd3b5 100644 --- a/tokio-postgres/src/connect_tls.rs +++ b/tokio-postgres/src/connect_tls.rs @@ -23,6 +23,9 @@ where SslMode::Prefer if !tls.can_connect(ForcePrivateApi) => { return Ok(MaybeTlsStream::Raw(stream)) } + SslMode::Prefer if negotiation == SslNegotiation::Direct => { + return Err(Error::tls("weak sslmode \"prefer\" may not be used with sslnegotiation=direct (use \"require\", \"verify-ca\", or \"verify-full\")".into())) + } SslMode::Prefer | SslMode::Require => {} } From 02463b12c124ecb3a7780b72005c368a5166e166 Mon Sep 17 00:00:00 2001 From: Kristof Mattei <864376+Kristof-Mattei@users.noreply.github.com> Date: Fri, 31 Jan 2025 23:02:01 -0700 Subject: [PATCH 23/37] chore: addressed rand 0.9's deprecations --- postgres-protocol/src/authentication/sasl.rs | 4 ++-- postgres-protocol/src/password/mod.rs | 2 +- tokio-postgres/src/connect.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/postgres-protocol/src/authentication/sasl.rs b/postgres-protocol/src/authentication/sasl.rs index 4a77507e9..ccd40e8d0 100644 --- a/postgres-protocol/src/authentication/sasl.rs +++ b/postgres-protocol/src/authentication/sasl.rs @@ -136,10 +136,10 @@ impl ScramSha256 { /// Constructs a new instance which will use the provided password for authentication. pub fn new(password: &[u8], channel_binding: ChannelBinding) -> ScramSha256 { // rand 0.5's ThreadRng is cryptographically secure - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let nonce = (0..NONCE_LENGTH) .map(|_| { - let mut v = rng.gen_range(0x21u8..0x7e); + let mut v = rng.random_range(0x21u8..0x7e); if v == 0x2c { v = 0x7e } diff --git a/postgres-protocol/src/password/mod.rs b/postgres-protocol/src/password/mod.rs index f03bb811d..445fb0c0e 100644 --- a/postgres-protocol/src/password/mod.rs +++ b/postgres-protocol/src/password/mod.rs @@ -28,7 +28,7 @@ const SCRAM_DEFAULT_SALT_LEN: usize = 16; /// special characters that would require escaping in an SQL command. pub fn scram_sha_256(password: &[u8]) -> String { let mut salt: [u8; SCRAM_DEFAULT_SALT_LEN] = [0; SCRAM_DEFAULT_SALT_LEN]; - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); rng.fill_bytes(&mut salt); scram_sha_256_salt(password, salt) } diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 8189cb91c..e97a7a2a3 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -44,7 +44,7 @@ where let mut indices = (0..num_hosts).collect::>(); if config.load_balance_hosts == LoadBalanceHosts::Random { - indices.shuffle(&mut rand::thread_rng()); + indices.shuffle(&mut rand::rng()); } let mut error = None; @@ -101,7 +101,7 @@ where .collect::>(); if config.load_balance_hosts == LoadBalanceHosts::Random { - addrs.shuffle(&mut rand::thread_rng()); + addrs.shuffle(&mut rand::rng()); } let mut last_err = None; From 14a1216e7b7db45217182edb7019929269a9de3c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 15:00:05 -0500 Subject: [PATCH 24/37] fix build --- postgres-native-tls/src/test.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/postgres-native-tls/src/test.rs b/postgres-native-tls/src/test.rs index b34fa7351..738c04bd7 100644 --- a/postgres-native-tls/src/test.rs +++ b/postgres-native-tls/src/test.rs @@ -44,11 +44,12 @@ async fn require() { #[tokio::test] async fn direct() { - let connector = set_postgresql_alpn(native_tls::TlsConnector::builder().add_root_certificate( + let mut builder = native_tls::TlsConnector::builder(); + builder.add_root_certificate( Certificate::from_pem(include_bytes!("../../test/server.crt")).unwrap(), - )) - .build() - .unwrap(); + ); + set_postgresql_alpn(&mut builder); + let connector = builder.build().unwrap(); smoke_test( "user=ssl_user dbname=postgres sslmode=require sslnegotiation=direct", TlsConnector::new(connector, "localhost"), From 720ffe83216714bf9716a03122c547a2e8e9bfd9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 15:03:12 -0500 Subject: [PATCH 25/37] fix clippy --- postgres-protocol/src/message/backend.rs | 8 ++++---- postgres-protocol/src/types/mod.rs | 4 ++-- postgres-types/src/lib.rs | 20 ++++++++++---------- postgres/src/notifications.rs | 6 +++--- postgres/src/transaction.rs | 2 +- tokio-postgres/src/generic_client.rs | 4 ++-- tokio-postgres/src/query.rs | 4 ++-- tokio-postgres/src/row.rs | 4 ++-- tokio-postgres/src/to_statement.rs | 2 +- tokio-postgres/src/transaction.rs | 2 +- tokio-postgres/src/transaction_builder.rs | 2 +- tokio-postgres/tests/test/types/mod.rs | 2 +- 12 files changed, 30 insertions(+), 30 deletions(-) diff --git a/postgres-protocol/src/message/backend.rs b/postgres-protocol/src/message/backend.rs index 73b169288..013bfbb81 100644 --- a/postgres-protocol/src/message/backend.rs +++ b/postgres-protocol/src/message/backend.rs @@ -475,7 +475,7 @@ pub struct ColumnFormats<'a> { remaining: u16, } -impl<'a> FallibleIterator for ColumnFormats<'a> { +impl FallibleIterator for ColumnFormats<'_> { type Item = u16; type Error = io::Error; @@ -557,7 +557,7 @@ pub struct DataRowRanges<'a> { remaining: u16, } -impl<'a> FallibleIterator for DataRowRanges<'a> { +impl FallibleIterator for DataRowRanges<'_> { type Item = Option>; type Error = io::Error; @@ -645,7 +645,7 @@ pub struct ErrorField<'a> { value: &'a [u8], } -impl<'a> ErrorField<'a> { +impl ErrorField<'_> { #[inline] pub fn type_(&self) -> u8 { self.type_ @@ -717,7 +717,7 @@ pub struct Parameters<'a> { remaining: u16, } -impl<'a> FallibleIterator for Parameters<'a> { +impl FallibleIterator for Parameters<'_> { type Item = Oid; type Error = io::Error; diff --git a/postgres-protocol/src/types/mod.rs b/postgres-protocol/src/types/mod.rs index 05f515f76..37dc793b1 100644 --- a/postgres-protocol/src/types/mod.rs +++ b/postgres-protocol/src/types/mod.rs @@ -582,7 +582,7 @@ impl<'a> Array<'a> { /// An iterator over the dimensions of an array. pub struct ArrayDimensions<'a>(&'a [u8]); -impl<'a> FallibleIterator for ArrayDimensions<'a> { +impl FallibleIterator for ArrayDimensions<'_> { type Item = ArrayDimension; type Error = StdBox; @@ -950,7 +950,7 @@ pub struct PathPoints<'a> { buf: &'a [u8], } -impl<'a> FallibleIterator for PathPoints<'a> { +impl FallibleIterator for PathPoints<'_> { type Item = Point; type Error = StdBox; diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 6ad2eff50..e57f29fbb 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -914,7 +914,7 @@ pub enum Format { Binary, } -impl<'a, T> ToSql for &'a T +impl ToSql for &T where T: ToSql, { @@ -963,7 +963,7 @@ impl ToSql for Option { to_sql_checked!(); } -impl<'a, T: ToSql> ToSql for &'a [T] { +impl ToSql for &[T] { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { let member_type = match *ty.kind() { Kind::Array(ref member) => member, @@ -1004,7 +1004,7 @@ impl<'a, T: ToSql> ToSql for &'a [T] { to_sql_checked!(); } -impl<'a> ToSql for &'a [u8] { +impl ToSql for &[u8] { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { types::bytea_to_sql(self, w); Ok(IsNull::No) @@ -1064,7 +1064,7 @@ impl ToSql for Box<[T]> { to_sql_checked!(); } -impl<'a> ToSql for Cow<'a, [u8]> { +impl ToSql for Cow<'_, [u8]> { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { <&[u8] as ToSql>::to_sql(&self.as_ref(), ty, w) } @@ -1088,7 +1088,7 @@ impl ToSql for Vec { to_sql_checked!(); } -impl<'a> ToSql for &'a str { +impl ToSql for &str { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { match ty.name() { "ltree" => types::ltree_to_sql(self, w), @@ -1109,7 +1109,7 @@ impl<'a> ToSql for &'a str { to_sql_checked!(); } -impl<'a> ToSql for Cow<'a, str> { +impl ToSql for Cow<'_, str> { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { <&str as ToSql>::to_sql(&self.as_ref(), ty, w) } @@ -1256,17 +1256,17 @@ impl BorrowToSql for &dyn ToSql { } } -impl<'a> sealed::Sealed for Box {} +impl sealed::Sealed for Box {} -impl<'a> BorrowToSql for Box { +impl BorrowToSql for Box { #[inline] fn borrow_to_sql(&self) -> &dyn ToSql { self.as_ref() } } -impl<'a> sealed::Sealed for Box {} -impl<'a> BorrowToSql for Box { +impl sealed::Sealed for Box {} +impl BorrowToSql for Box { #[inline] fn borrow_to_sql(&self) -> &dyn ToSql { self.as_ref() diff --git a/postgres/src/notifications.rs b/postgres/src/notifications.rs index c31d4f631..0c040dedf 100644 --- a/postgres/src/notifications.rs +++ b/postgres/src/notifications.rs @@ -77,7 +77,7 @@ pub struct Iter<'a> { connection: ConnectionRef<'a>, } -impl<'a> FallibleIterator for Iter<'a> { +impl FallibleIterator for Iter<'_> { type Item = Notification; type Error = Error; @@ -100,7 +100,7 @@ pub struct BlockingIter<'a> { connection: ConnectionRef<'a>, } -impl<'a> FallibleIterator for BlockingIter<'a> { +impl FallibleIterator for BlockingIter<'_> { type Item = Notification; type Error = Error; @@ -129,7 +129,7 @@ pub struct TimeoutIter<'a> { timeout: Duration, } -impl<'a> FallibleIterator for TimeoutIter<'a> { +impl FallibleIterator for TimeoutIter<'_> { type Item = Notification; type Error = Error; diff --git a/postgres/src/transaction.rs b/postgres/src/transaction.rs index 5c8c15973..8126b1dbe 100644 --- a/postgres/src/transaction.rs +++ b/postgres/src/transaction.rs @@ -12,7 +12,7 @@ pub struct Transaction<'a> { transaction: Option>, } -impl<'a> Drop for Transaction<'a> { +impl Drop for Transaction<'_> { fn drop(&mut self) { if let Some(transaction) = self.transaction.take() { let _ = self.connection.block_on(transaction.rollback()); diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index 6e7dffeb1..dcda147b5 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -80,7 +80,7 @@ pub trait GenericClient: private::Sealed { ) -> Result; /// Like [`Client::transaction`]. - async fn transaction(&mut self) -> Result, Error>; + async fn transaction<'a>(&'a mut self) -> Result, Error>; /// Like [`Client::batch_execute`]. async fn batch_execute(&self, query: &str) -> Result<(), Error>; @@ -180,7 +180,7 @@ impl GenericClient for Client { self.prepare_typed(query, parameter_types).await } - async fn transaction(&mut self) -> Result, Error> { + async fn transaction<'a>(&'a mut self) -> Result, Error> { self.transaction().await } diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index 3ab002871..2fcb22d57 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -20,7 +20,7 @@ use std::task::{Context, Poll}; struct BorrowToSqlParamsDebug<'a, T>(&'a [T]); -impl<'a, T> fmt::Debug for BorrowToSqlParamsDebug<'a, T> +impl fmt::Debug for BorrowToSqlParamsDebug<'_, T> where T: BorrowToSql, { @@ -61,7 +61,7 @@ where }) } -pub async fn query_typed<'a, P, I>( +pub async fn query_typed( client: &Arc, query: &str, params: I, diff --git a/tokio-postgres/src/row.rs b/tokio-postgres/src/row.rs index 767c26921..ccb8817d0 100644 --- a/tokio-postgres/src/row.rs +++ b/tokio-postgres/src/row.rs @@ -79,9 +79,9 @@ impl RowIndex for str { } } -impl<'a, T> Sealed for &'a T where T: ?Sized + Sealed {} +impl Sealed for &T where T: ?Sized + Sealed {} -impl<'a, T> RowIndex for &'a T +impl RowIndex for &T where T: ?Sized + RowIndex, { diff --git a/tokio-postgres/src/to_statement.rs b/tokio-postgres/src/to_statement.rs index 427f77dd7..7e1299272 100644 --- a/tokio-postgres/src/to_statement.rs +++ b/tokio-postgres/src/to_statement.rs @@ -11,7 +11,7 @@ mod private { Query(&'a str), } - impl<'a> ToStatementType<'a> { + impl ToStatementType<'_> { pub async fn into_statement(self, client: &Client) -> Result { match self { ToStatementType::Statement(s) => Ok(s.clone()), diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index 17a50b60f..782c476c4 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -33,7 +33,7 @@ struct Savepoint { depth: u32, } -impl<'a> Drop for Transaction<'a> { +impl Drop for Transaction<'_> { fn drop(&mut self) { if self.done { return; diff --git a/tokio-postgres/src/transaction_builder.rs b/tokio-postgres/src/transaction_builder.rs index 93e9e9801..88c883176 100644 --- a/tokio-postgres/src/transaction_builder.rs +++ b/tokio-postgres/src/transaction_builder.rs @@ -113,7 +113,7 @@ impl<'a> TransactionBuilder<'a> { done: bool, } - impl<'a> Drop for RollbackIfNotDone<'a> { + impl Drop for RollbackIfNotDone<'_> { fn drop(&mut self) { if self.done { return; diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index f962bf10a..875164c3b 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -509,7 +509,7 @@ async fn domain() { to_sql_checked!(); } - impl<'a> FromSql<'a> for SessionId { + impl FromSql<'_> for SessionId { fn from_sql(ty: &Type, raw: &[u8]) -> result::Result> { Vec::::from_sql(ty, raw).map(SessionId) } From acd17edf612e99249530760573901e2a1875ccd1 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 15:20:41 -0500 Subject: [PATCH 26/37] fix wasm build --- .github/workflows/ci.yml | 2 ++ postgres-protocol/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c14751e94..10181f09b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,8 @@ jobs: path: target key: check-wasm32-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - run: cargo check --target wasm32-unknown-unknown --manifest-path tokio-postgres/Cargo.toml --no-default-features --features js + env: + RUSTFLAGS: --cfg getrandom_backend="wasm_js" test: name: test diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 7525532d6..efb283d6e 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -10,7 +10,7 @@ readme = "../README.md" [features] default = [] -js = ["getrandom/js"] +js = ["getrandom/wasm_js"] [dependencies] base64 = "0.22" From 0d18b95f4e0f03681345fdfa68fd6213e1e4d7eb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 15:23:13 -0500 Subject: [PATCH 27/37] bump getrandom --- postgres-protocol/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index efb283d6e..f7a34b2d8 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -23,4 +23,4 @@ memchr = "2.0" rand = "0.9" sha2 = "0.10" stringprep = "0.1" -getrandom = { version = "0.2", optional = true } +getrandom = { version = "0.3", optional = true } From 9754f1310999077cd1f54b66d7f660c69a15c403 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 15:34:29 -0500 Subject: [PATCH 28/37] Revert time 0.2 change --- postgres-types/src/time_02.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/postgres-types/src/time_02.rs b/postgres-types/src/time_02.rs index 1f2ba1ce1..19a8909e7 100644 --- a/postgres-types/src/time_02.rs +++ b/postgres-types/src/time_02.rs @@ -14,9 +14,7 @@ const fn base() -> PrimitiveDateTime { impl<'a> FromSql<'a> for PrimitiveDateTime { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let t = types::timestamp_from_sql(raw)?; - Ok(base() - .checked_add(Duration::microseconds(t)) - .ok_or("value too large to decode")?) + Ok(base() + Duration::microseconds(t)) } accepts!(TIMESTAMP); From 89b91b4ca0b18fdb22e74a746a315827815e3cff Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 15:41:17 -0500 Subject: [PATCH 29/37] Propagate features --- postgres/Cargo.toml | 2 ++ tokio-postgres/Cargo.toml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 9e360c2a4..db74d8af4 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -24,6 +24,8 @@ circle-ci = { repository = "sfackler/rust-postgres" } array-impls = ["tokio-postgres/array-impls"] with-bit-vec-0_6 = ["tokio-postgres/with-bit-vec-0_6"] with-chrono-0_4 = ["tokio-postgres/with-chrono-0_4"] +with-cidr-0_2 = ["tokio-postgres/with-cidr-0_2"] +with-cidr-0_3 = ["tokio-postgres/with-cidr-0_3"] with-eui48-0_4 = ["tokio-postgres/with-eui48-0_4"] with-eui48-1 = ["tokio-postgres/with-eui48-1"] with-geo-types-0_6 = ["tokio-postgres/with-geo-types-0_6"] diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 3fea01ff0..4e143ee27 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -30,6 +30,8 @@ runtime = ["tokio/net", "tokio/time"] array-impls = ["postgres-types/array-impls"] with-bit-vec-0_6 = ["postgres-types/with-bit-vec-0_6"] with-chrono-0_4 = ["postgres-types/with-chrono-0_4"] +with-cidr-0_2 = ["postgres-types/with-cidr-0_2"] +with-cidr-0_3 = ["postgres-types/with-cidr-0_3"] with-eui48-0_4 = ["postgres-types/with-eui48-0_4"] with-eui48-1 = ["postgres-types/with-eui48-1"] with-geo-types-0_6 = ["postgres-types/with-geo-types-0_6"] From bfb35b24c6dc43c3ae00bb5ecb1a6cfa59d8d896 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 15:42:53 -0500 Subject: [PATCH 30/37] add docs --- postgres-types/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index a31077ea0..db044bcbd 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -491,6 +491,8 @@ impl WrongType { /// | `chrono::DateTime` | TIMESTAMP WITH TIME ZONE | /// | `chrono::NaiveDate` | DATE | /// | `chrono::NaiveTime` | TIME | +/// | `cidr::IpCidr` | CIDR | +/// | `cidr::IpInet` | INET | /// | `time::PrimitiveDateTime` | TIMESTAMP | /// | `time::OffsetDateTime` | TIMESTAMP WITH TIME ZONE | /// | `time::Date` | DATE | @@ -842,6 +844,8 @@ pub enum IsNull { /// | `chrono::DateTime` | TIMESTAMP WITH TIME ZONE | /// | `chrono::NaiveDate` | DATE | /// | `chrono::NaiveTime` | TIME | +/// | `cidr::IpCidr` | CIDR | +/// | `cidr::IpInet` | INET | /// | `time::PrimitiveDateTime` | TIMESTAMP | /// | `time::OffsetDateTime` | TIMESTAMP WITH TIME ZONE | /// | `time::Date` | DATE | From a5eaea14474d6a0d40881870abd3c044d58a6d50 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 15:46:21 -0500 Subject: [PATCH 31/37] fix ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10181f09b..3426d624b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,7 +84,7 @@ jobs: - run: docker compose up -d - uses: sfackler/actions/rustup@master with: - version: 1.75.0 + version: 1.81.0 - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - uses: actions/cache@v3 From 14f3b9e2b74987df99605a77a4c91d1de54b211d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 15:56:49 -0500 Subject: [PATCH 32/37] Release postgres-native-tls v0.5.1 --- postgres-native-tls/CHANGELOG.md | 6 ++++++ postgres-native-tls/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-native-tls/CHANGELOG.md b/postgres-native-tls/CHANGELOG.md index 9eb7ab800..5fe0a9c7a 100644 --- a/postgres-native-tls/CHANGELOG.md +++ b/postgres-native-tls/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.5.1 - 2025-02-02 + +### Added + +* Added `set_postgresql_alpn`. + ## v0.5.0 - 2020-12-25 ### Changed diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index e86c7ce2d..f79ae5491 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-native-tls" -version = "0.5.0" +version = "0.5.1" authors = ["Steven Fackler "] edition = "2018" license = "MIT OR Apache-2.0" From 1ed6365d5c416e410c87388ca5228bbaf0f262fa Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 15:58:25 -0500 Subject: [PATCH 33/37] Release postgres-openssl v0.5.1 --- postgres-openssl/CHANGELOG.md | 6 ++++++ postgres-openssl/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-openssl/CHANGELOG.md b/postgres-openssl/CHANGELOG.md index 346214ae8..33f5a127a 100644 --- a/postgres-openssl/CHANGELOG.md +++ b/postgres-openssl/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.5.1 - 2025-02-02 + +### Added + +* Added `set_postgresql_alpn`. + ## v0.5.0 - 2020-12-25 ### Changed diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index 9013384a2..6ebb86bef 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-openssl" -version = "0.5.0" +version = "0.5.1" authors = ["Steven Fackler "] edition = "2018" license = "MIT OR Apache-2.0" From 966724c37784014a0e1f9d463c5c245102c75b33 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 16:01:02 -0500 Subject: [PATCH 34/37] Release postgres-protocol v0.6.8 --- postgres-protocol/CHANGELOG.md | 6 ++++++ postgres-protocol/Cargo.toml | 2 +- postgres-types/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index 54dce91b0..25e717128 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.6.8 - 2025-02-02 + +### Changed + +* Upgraded `getrandom`. + ## v0.6.7 - 2024-07-21 ### Deprecated diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index f7a34b2d8..9351ea14f 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.6.7" +version = "0.6.8" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index d417664ea..2d2408ddf 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -33,7 +33,7 @@ with-time-0_3 = ["time-03"] [dependencies] bytes = "1.0" fallible-iterator = "0.2" -postgres-protocol = { version = "0.6.7", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.8", path = "../postgres-protocol" } postgres-derive = { version = "0.4.6", optional = true, path = "../postgres-derive" } array-init = { version = "2", optional = true } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 4e143ee27..71c36a9e7 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -57,7 +57,7 @@ parking_lot = "0.12" percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.11" -postgres-protocol = { version = "0.6.7", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.8", path = "../postgres-protocol" } postgres-types = { version = "0.2.8", path = "../postgres-types" } tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } From 43c7049ce6feab933c1f89347369ab9d177e7b99 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 16:04:41 -0500 Subject: [PATCH 35/37] Release postgres-types v0.2.9 --- postgres-types/CHANGELOG.md | 10 ++++++++++ postgres-types/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index 777f999a7..7fa6d6506 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -2,6 +2,16 @@ ## Unreleased +## v0.2.9 - 2025-02-02 + +### Added + +* Added support for `cidr` 0.3 via the `with-cidr-0_3` feature. + +### Fixed + +* Fixed deserialization of out of bounds inputs to `time` 0.3 types to return an error rather than panic. + ## v0.2.8 - 2024-09-15 ### Added diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 2d2408ddf..8d56f99ec 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.2.8" +version = "0.2.9" authors = ["Steven Fackler "] edition = "2018" license = "MIT OR Apache-2.0" diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 71c36a9e7..a297d4f66 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -58,7 +58,7 @@ percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.11" postgres-protocol = { version = "0.6.8", path = "../postgres-protocol" } -postgres-types = { version = "0.2.8", path = "../postgres-types" } +postgres-types = { version = "0.2.9", path = "../postgres-types" } tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } rand = "0.9.0" From ad68abfd48b39a433bb4127bf1ae140b9be64d9e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 2 Feb 2025 16:08:13 -0500 Subject: [PATCH 36/37] Release tokio-postgres v0.7.13 --- postgres/Cargo.toml | 2 +- tokio-postgres/CHANGELOG.md | 15 +++++++++++++++ tokio-postgres/Cargo.toml | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index db74d8af4..cd7b164b1 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -43,7 +43,7 @@ bytes = "1.0" fallible-iterator = "0.2" futures-util = { version = "0.3.14", features = ["sink"] } log = "0.4" -tokio-postgres = { version = "0.7.12", path = "../tokio-postgres" } +tokio-postgres = { version = "0.7.13", path = "../tokio-postgres" } tokio = { version = "1.0", features = ["rt", "time"] } [dev-dependencies] diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 9ee470db6..a67f69ea7 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -2,6 +2,21 @@ ## Unreleased +## v0.7.13 - 2025-02-02 + +### Added + +* Added support for direct TLS negotiation. +* Added support for `cidr` 0.3 via the `with-cidr-0_3` feature. + +### Fixes + +* Added `load_balance_hosts` to `Config`'s `Debug` implementation. + +### Changes + +* Upgraded `rand`. + ## v0.7.12 - 2024-09-15 ### Fixed diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index a297d4f66..e9cc5fcfc 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.12" +version = "0.7.13" authors = ["Steven Fackler "] edition = "2018" license = "MIT OR Apache-2.0" From 278641fa1a08b7e7d35841342ab4426c5b063d9a Mon Sep 17 00:00:00 2001 From: Alexey Orlenko Date: Tue, 29 Apr 2025 12:54:10 +0200 Subject: [PATCH 37/37] Consume the `Responses` in `Statement::drop` (#8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of dropping the `Responses` in `Statement::drop` and closing the channel stored in there, poll it for the response messages. This appears to fix a weird failure that causes us to never read a response to the query back from the stream if we write a close packet for a prepared statement, and a packet for the portal created by `query_typed` in quick succession, and then start polling the read part of the stream. Somehow we receive the close success response but not the response to the query. However, if we poll the channel through which the `Connection` sends the response back to the caller in `Drop`, everything works fine. Note that it should not be necessary and this raises more questions than answers. Reading subsequent messages is not blocked on the response to the close packet not being read. `Connection` always reads through everything, and it sends the parsed responses to the intrerested parties if the channel for that specific response is still alive, otherwise it just skips over it but it always reads everything to completion. That part works well and there are no issues with it. Moreover, if I just `std::mem::forget` the `Responses` in `Statement::drop` to keep it alive and force the `Connection` to write the response to the channel's buffer without ever reading it, the bug is still reproducible, it makes no difference. What actually does make difference, judging from the traces, is that polling `Responses::next` notifies the `Connection` task's waker: this has a rather subtle effect and influences the timing of the operations, making us poll the socket for reading (which happens concurrently with us writing the query) a little bit earlier. Similarly, not doing anything in `Statement::drop`, and instead making the `Connection` artificially wake itself and busy-loop on CPU by calling `cx.waker.wake_by_ref()` also completely resolves the issue. The connection task is not deadlocked, and it is periodically woken up on socket. If we leave the seemingly frozen application running, after some time we actually start receiving unrelated asynchronous notices from the server, and we successfully read them! There's just genuinely no response to the query ever received from the server. This means one of the two things: either the write is never actually finished (contrary to the fact that we receive `Poll::Ready` in `poll_flush`), or the bug is actually on the server side. That said, _something somewhere else_ does seem to be blocked, as Ctrl+C doesn't work when the issue occurs, which means the signal handler task is not being polled for some reason. It was a big red herring that turned out to be a separate problem, possibly on our side. The possibility of a server side bug dependent on the order or timing of operations would also answer the question of "what does any of this have to do with pgbouncer or Supavisor?" to which I don't have a good answer. The fact that the issue is not reproducible when using normal Postgres is certainly interesting. This patch is probably not upstremable (for one, the introduced dependency on `rt` feature is somewhat of a breaking change, as it tightly couples the library with Tokio — without it, I believe, it's technically possible to use `tokio_postgres` with other runtimes or even WASM despite the name) and it's treating the symptom and not the root cause. That said, it's safe and doesn't hurt (for us) and it reliably and consistently fixes [#26537](https://github.com/prisma/prisma/issues/26537)/[ORM-796](https://linear.app/prisma-company/issue/ORM-796/regression-with-pgbouncer-tracing), at least on my machine. It didn't test though if this still fixes the issue (or if it occurs in the first place) if there's less than 3 threads available (to be able to run the tasks for mobc connection, tokio_postgres connection and the background task spawned in `Statement::drop` in parallel) and I'd rather not block on the future in `Statement::drop` and degrade the latency for everyone else for the sake of fixing an exotic issue. --- tokio-postgres/Cargo.toml | 2 +- tokio-postgres/src/statement.rs | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 77b0ec700..d619c19ce 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -60,7 +60,7 @@ phf = "0.11" postgres-protocol = { version = "0.6.8", path = "../postgres-protocol" } postgres-types = { version = "0.2.9", path = "../postgres-types" } socket2 = "0.5.3" -tokio = { version = "1.27", features = ["io-util"] } +tokio = { version = "1.27", features = ["io-util", "rt"] } tokio-util = { version = "0.7", features = ["codec"] } rand = "0.9.0" whoami = "1.4.1" diff --git a/tokio-postgres/src/statement.rs b/tokio-postgres/src/statement.rs index bf9db30bb..1e9aba5fb 100644 --- a/tokio-postgres/src/statement.rs +++ b/tokio-postgres/src/statement.rs @@ -2,6 +2,7 @@ use crate::client::InnerClient; use crate::codec::FrontendMessage; use crate::connection::RequestMessages; use crate::types::Type; +use postgres_protocol::message::backend::Message; use postgres_protocol::message::frontend; use std::fmt; use std::sync::{Arc, Weak}; @@ -19,13 +20,28 @@ impl Drop for StatementInner { // Unnamed statements don't need to be closed return; } + if let Some(client) = self.client.upgrade() { let buf = client.with_buf(|buf| { frontend::close(b'S', &self.name, buf).unwrap(); frontend::sync(buf); buf.split().freeze() }); - let _ = client.send(RequestMessages::Single(FrontendMessage::Raw(buf))); + + let response = client.send(RequestMessages::Single(FrontendMessage::Raw(buf))); + + tokio::spawn(async move { + let result = async move { + match response?.next().await? { + Message::CloseComplete => Ok(()), + _ => Err(crate::Error::unexpected_message()), + } + }; + + if let Err(err) = result.await { + log::error!("failed to deallocate prepared statement: {err}"); + } + }); } } }